最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

剖析Spring WebFlux反應(yīng)式編程設(shè)計及工作原理

 更新時間:2022年02月25日 14:31:55   作者:kl  
這篇文章主要為大家介紹了Spring WebFlux反應(yīng)式編程模型工作原理的剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪

前言

Spring 5發(fā)布有兩年了,隨Spring 5一起發(fā)布了一個和Spring WebMvc同級的Spring WebFlux。這是一個支持反應(yīng)式編程模型的新框架體系。反應(yīng)式模型區(qū)別于傳統(tǒng)的MVC最大的不同是異步的、事件驅(qū)動的、非阻塞的,這使得應(yīng)用程序的并發(fā)性能會大大提高,單位時間能夠處理更多的請求。這里不講WebFlux是怎么用的,有什么用,這類文章網(wǎng)上有太多了,而且都寫的非常不錯。下面主要看下WebFlux是怎么從無到有,框架怎么設(shè)計的,已期能夠更靈活的使用WebFlux。

接口抽象

Spring最牛逼的地方就是,無論啥東西,都可以無縫的集成到Spring。這得益于Spring體系優(yōu)良的抽象封裝能力。WebFlux框架也一樣,底層實現(xiàn)其實不是Spring的,它依賴reactor和netty等。Spring做的就是通過抽象和封裝,把reactor的能力通過你最熟悉不過的Controller來使用。而且不局限于此,除了支持和Spring Mvc一樣的控制器編碼模式,還支持路由器模式(RouterFunctions),還支持端點模式(EndPoint)等。WebFlux所有功能其實內(nèi)部只由幾個抽象類構(gòu)建而成:

org.springframework.boot.web.reactive.server.ReactiveWebServerFactory

org.springframework.boot.web.server.WebServer

org.springframework.http.server.reactive.HttpHandler

org.springframework.web.reactive.HandlerMapping

org.springframework.web.server.WebHandler

WebServer

我們從最底層往上層剖析,WebServer見名之意,就是Reacive服務(wù)器的抽象類,它定義了服務(wù)的基本方法行為,包含啟動,停止等接口。結(jié)構(gòu)如下:

public interface WebServer {
	void start() throws WebServerException;
	void stop() throws WebServerException;
	int getPort();
}

Spring默認有五個WebServer的實現(xiàn),默認的不特別指定情況下,在spring-boot-starter-webflux自帶的是Netty的實現(xiàn),其實現(xiàn)類如下:

ReactiveWebServerFactory

對應(yīng)WebServer,每個實現(xiàn)都會有一個工廠類對應(yīng),主要準備創(chuàng)建WebServer實例的資源,如NettyReactiveWebServerFactory生產(chǎn)WebServer方法:

public WebServer getWebServer(HttpHandler httpHandler) {
		HttpServer httpServer = createHttpServer();
		ReactorHttpHandlerAdapter handlerAdapter = new ReactorHttpHandlerAdapter(
				httpHandler);
		return new NettyWebServer(httpServer, handlerAdapter, this.lifecycleTimeout);
	}

可以看到,在創(chuàng)建WebServer實例時,傳入了一個入?yún)?,HttpHandler。而且進而傳入了一個HttpHandlerAdapter實例里,這是因為每個WebServer的接收處理接口的適配器是不一樣的,在每個不同的WebServer工廠里通過不過的適配器去適配不同的實現(xiàn)。最后轉(zhuǎn)化成統(tǒng)一設(shè)計的HttpHandler里,見下面。

HttpHandler

接下來看下HttpHandler,上面在創(chuàng)建WebServer的時候,傳了一個入?yún)?,類型就是Httphandler。為了適配不同的WebServer請求響應(yīng)體,Spring設(shè)計了HttpHandler用來轉(zhuǎn)化底層的Http請求響應(yīng)語義,用來接收處理底層容器的Http請求。其結(jié)構(gòu)如下:

public interface HttpHandler {
	Monohandle(ServerHttpRequest request, ServerHttpResponse response);
}

如在Netty的實現(xiàn)中,Netty接收請求處理的適配器ReactorHttpHandlerAdapter的apply中轉(zhuǎn)化的偽代碼如下:

public Monoapply(HttpServerRequest reactorRequest, HttpServerResponse reactorResponse) {
		NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(reactorResponse.alloc());
		try {
			ReactorServerHttpRequest request = new ReactorServerHttpRequest(reactorRequest, bufferFactory);
			ServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory);
			if (request.getMethod() == HttpMethod.HEAD) {
				response = new HttpHeadResponseDecorator(response);
			}
			return this.httpHandler.handle(request, response)
					.doOnError(ex -> logger.trace(request.getLogPrefix() + "Failed to complete: " + ex.getMessage()))
					.doOnSuccess(aVoid -> logger.trace(request.getLogPrefix() + "Handling completed"));
		}
}

WebHandler其實一般來講設(shè)計到HttpHandler這一層級基本就差不多了,有一致的請求體和響應(yīng)體了。但是Spring說還不夠,對Web開發(fā)來講不夠簡潔,就又造了一個WebHandler,WebHandler架構(gòu)更簡單,如下:

public interface WebHandler {
	Monohandle(ServerWebExchange exchange);
}

這回夠簡潔了,只有一個入?yún)?,那請求提和響?yīng)體去哪里了呢?被包裝到ServerWebExchange中了。我么看下當HttpHandler接收到請求后,是怎么處理然后在調(diào)用WebHandler的,最終處理HttpHandler實現(xiàn)是HttpWebHandlerAdapter.java,通過其內(nèi)部的createExchange方法將請求和響應(yīng)體封裝在ServerWebExchange中了。其handle代碼如下:

public Monohandle(ServerHttpRequest request, ServerHttpResponse response) {
		if (this.forwardedHeaderTransformer != null) {
			request = this.forwardedHeaderTransformer.apply(request);
		}
		ServerWebExchange exchange = createExchange(request, response);
		LogFormatUtils.traceDebug(logger, traceOn ->
				exchange.getLogPrefix() + formatRequest(exchange.getRequest()) +
						(traceOn ? ", headers=" + formatHeaders(exchange.getRequest().getHeaders()) : ""));
		return getDelegate().handle(exchange)
				.doOnSuccess(aVoid -> logResponse(exchange))
				.onErrorResume(ex -> handleUnresolvedError(exchange, ex))
				.then(Mono.defer(response::setComplete));
	}

HandlerMapping首先看下HandlerMapping的構(gòu)造,可以看到就是根據(jù)web交換器返回了一個Handler對象

public interface HandlerMapping {
	String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler";
	String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
	String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
	String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
	String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";
	String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";
	MonogetHandler(ServerWebExchange exchange);
}

上面的“請求“已經(jīng)到WebHandler了,那么最終是怎么到我們定義的控制器接口的呢?其實,沒有HandlerMapping,Spring WebFlux的功能也是完整的,也是可編程的,因為可以基于WebHandler直接編碼。我們最弄的一個網(wǎng)關(guān)最后就是直接走自定義的WebHandler,根本沒有HandlerMapping的什么事情,但是你這么做的話就失去了Spring編碼的友好性了。WebFlux的初始化過程中,會去Spring上下文中找name是“webHandler”的的WebHandler實現(xiàn)。默認情況下,Spring會在上下文中初始化一個DispatcherHandler.java的實現(xiàn),Bean的name就是“webHandler”。這個里面維護了一個HandlerMapping列表,當請求過來時會迭代HandlerMapping列表,返回一個WebHandler處理,代碼如下:

public Monohandle(ServerWebExchange exchange) {
		if (this.handlerMappings == null) {
			return Mono.error(HANDLER_NOT_FOUND_EXCEPTION);
		}
		return Flux.fromIterable(this.handlerMappings)
				.concatMap(mapping -> mapping.getHandler(exchange))
				.next()
				.switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION))
				.flatMap(handler -> invokeHandler(exchange, handler))
				.flatMap(result -> handleResult(exchange, result));
	}

上面mapping的內(nèi)部結(jié)構(gòu)如下:

上面箭頭指向的地方說明了為什么WebFlux支持控制器和路由器模式模式的編碼,因為他們分別有實現(xiàn)的HandlerMapping,能夠在WebHandler的handler里路由到具體的業(yè)務(wù)方法里。紅框中正是通過@Controller和@ResultMaping定義的接口信息。

啟動流程分析

上面介紹了五個主要的抽象接口定義,以及功能。這五個接口在Spring WebFlux里是靈魂一樣的存在。不過想要徹底的搞懂Web Flux的設(shè)計以及實現(xiàn)原理,僅僅了解上面這些接口定義是遠遠不夠的,看完上面接口的分析肯定有中模糊的似懂非懂的感覺,不著急,接下來分析下,在Spring Boot環(huán)境中,Spring WebFlux的啟動流程。

ReactiveWebServerApplicationContext

WebFlux的啟動都在Reactive的上下文中完成,和WebMvc類似,Mvc也有一個ServletWebServerApplicationContext,他們是同宗同脈的。

ReactiveWebServerApplicationContext還有一個父類AnnotationConfigReactiveWebServerApplicationContext

在Spring boot啟動中,創(chuàng)建的就是這個父類的實例。

在Spring boot的run()方法中創(chuàng)建上下文時有如下代碼:

protected ConfigurableApplicationContext createApplicationContext() {
		Class contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, "
								+ "please specify an ApplicationContextClass",
						ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

可以看到,當webApplicationType是REACTIVE時,加載的就是DEFAULT_REACTIVE_WEB_CONTEXT_CLASS。webApplicationType類型是通過識別你加載了哪個依賴來做的。熟悉Spring啟動流程的同學都知道,基礎(chǔ) 的Spring上下文是在AbstractApplicationContext的refresh()方法內(nèi)完成的,針對不同的上下文文實現(xiàn)實例還會有一個onRefresh()方法,完成一些特定的Bean的實例化,如WebFlux的上下文實例就在onRefresh()中完成了WebServer的創(chuàng)建:

protected void onRefresh() {
		super.onRefresh();
		try {
			createWebServer();
		}
		catch (Throwable ex) {
			throw new ApplicationContextException("Unable to start reactive web server",
					ex);
		}
	}
	private void createWebServer() {
		ServerManager serverManager = this.serverManager;
		if (serverManager == null) {
			this.serverManager = ServerManager.get(getWebServerFactory());
		}
		initPropertySources();
	}

文末WebFlux里面啟動流程太復(fù)雜,全盤脫出寫的太長嚴重影響閱讀體驗。所以上面權(quán)當拋磚引玉,開一個好頭。不過,WebFlux的啟動流程節(jié)點博主都已分析并整理成流程圖了,結(jié)合上面的接口設(shè)計分析,搞懂WebFlux的設(shè)計及工作原理應(yīng)該冒點問題

以上就是剖析Spring WebFlux反應(yīng)式編程模型工作原理的詳細內(nèi)容,更多關(guān)于Spring WebFlux反應(yīng)式編程模型的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java中JDBC的使用教程詳解

    Java中JDBC的使用教程詳解

    Java語言操作數(shù)據(jù)庫?JDBC本質(zhì):其實是官方(sun公司)定義的一套操作所有關(guān)系型數(shù)據(jù)庫的規(guī)則,即接口。本文講解了JDBC的使用方法,需要的可以參考一下
    2022-06-06
  • 基于Spring監(jiān)聽Binlog日志的方法詳解

    基于Spring監(jiān)聽Binlog日志的方法詳解

    MySQL 的二進制日志(binlog)有三種不同的格式,通常被稱為 binlog 模式,這三種模式分別是 Statement 模式、Row 模式和Mixed 模式,本文將給大家介紹如何基于Spring監(jiān)聽Binlog日志,需要的朋友可以參考下
    2024-09-09
  • java中每月等額與先息后本計算

    java中每月等額與先息后本計算

    一般信用貸款會提供兩種還款方式:每月等額或者先息后本。每月等額,就是每月歸還等同的部分本金和利息,你手里在使用的本金其實是逐月減少的。先息后本就是先還利息,到期歸還本金。本文將介紹他們的實現(xiàn)方法。具有很好的參考價值,下面跟著小編一起來看下吧
    2017-03-03
  • Java 實現(xiàn)定時任務(wù)的三種方法

    Java 實現(xiàn)定時任務(wù)的三種方法

    這篇文章主要介紹了Java 實現(xiàn)定時任務(wù)的三種方法,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下
    2021-03-03
  • 完美解決idea突然間很卡的問題

    完美解決idea突然間很卡的問題

    這篇文章主要介紹了完美解決idea突然間很卡的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • java中Class類的基礎(chǔ)知識點及實例

    java中Class類的基礎(chǔ)知識點及實例

    在本篇文章里小編給大家分享了關(guān)于java中Class類的基礎(chǔ)知識點及實例內(nèi)容,有興趣的朋友們可以學習下。
    2021-05-05
  • springboot整合security和vue的實踐

    springboot整合security和vue的實踐

    本文主要介紹了springboot整合security和vue的實踐,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • springboot創(chuàng)建的web項目整合Quartz框架的項目實踐

    springboot創(chuàng)建的web項目整合Quartz框架的項目實踐

    本文主要介紹了springboot創(chuàng)建的web項目整合Quartz框架的項目實踐,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06
  • SpringSession 請求與響應(yīng)重寫的實現(xiàn)

    SpringSession 請求與響應(yīng)重寫的實現(xiàn)

    這篇文章主要介紹了SpringSession 請求與響應(yīng)重寫的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • Java中Spring Boot+Socket實現(xiàn)與html頁面的長連接實例詳解

    Java中Spring Boot+Socket實現(xiàn)與html頁面的長連接實例詳解

    這篇文章主要介紹了Java中Spring Boot+Socket實現(xiàn)與html頁面的長連接實例詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07

最新評論

芜湖市| 永吉县| 上思县| 射阳县| 莱芜市| 石景山区| 金华市| 石景山区| 莱西市| 喀喇沁旗| 平泉县| 大田县| 资中县| 容城县| 诸暨市| 珠海市| 桃园市| 棋牌| 元阳县| 兰溪市| 桐城市| 蚌埠市| 太仆寺旗| 郎溪县| 上饶市| 宿州市| 赤峰市| 建水县| 乐昌市| 土默特左旗| 双牌县| 文山县| 独山县| 福清市| 兴义市| 木兰县| 旬邑县| 前郭尔| 子长县| 桓台县| 夹江县|