欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring Boot超詳細(xì)講解請(qǐng)求處理流程機(jī)制

 更新時(shí)間:2022年07月13日 09:19:02   作者:麥神-mirson  
SpringBoot是一種整合Spring技術(shù)棧的方式(或者說(shuō)是框架),同時(shí)也是簡(jiǎn)化Spring的一種快速開(kāi)發(fā)的腳手架,本篇讓我們一起分析請(qǐng)求處理流程機(jī)制

1. 背景

之前我們對(duì)Spring Boot做了研究講解,我們知道怎么去集成配置, 知道它如何啟動(dòng), 如何實(shí)現(xiàn)自動(dòng)化配置,那么它如何接收并處理外部請(qǐng)求, 具體原理是怎樣, 又要流轉(zhuǎn)哪些關(guān)鍵環(huán)節(jié)? filter,interceptor, view是在哪調(diào)用, 處理順序是怎樣?Spring Boot 和Spring MVC以及內(nèi)置容器又是怎樣的作用關(guān)系? 這里我們作具體剖析研究。

2. Spring Boot 的請(qǐng)求處理流程設(shè)計(jì)

整理處理流程:

從流程圖可以看到, 從內(nèi)嵌的服務(wù)器接收請(qǐng)求到Spring Web包的處理, 再調(diào)用Spring MVC框架, 最后再到自定義的Controller。經(jīng)過(guò)層層處理, 我們接下來(lái)再研究具體的處理機(jī)制。

UML關(guān)系圖:

從UML圖中可以看到, 層級(jí)較為復(fù)雜, 主要關(guān)注兩個(gè)層面:

一是繼承GenericWebApplicationContext類,具備上下文BEAN的管理能力;

另外是實(shí)現(xiàn)ConfigurableWebServerApplicationContext接口, 具備上下文配置能力。

3. Servlet服務(wù)模式請(qǐng)求流程分析

3.1 ServletWebServerApplicationContext分析

Spring Boot啟動(dòng)時(shí),會(huì)判斷應(yīng)用服務(wù)類型, 有兩種, 一種是Servlet服務(wù), 另一種是Reactive響應(yīng)式服務(wù)。ServletWebServerApplicationContext就是Servlet服務(wù)核心實(shí)現(xiàn)類。

它實(shí)現(xiàn) ConfigurableWebServerApplicationContext 接口,繼承 GenericWebApplicationContext 類:

public interface ConfigurableWebServerApplicationContext
		extends ConfigurableApplicationContext, WebServerApplicationContext {
	/**
	 * 設(shè)置服務(wù)的命名空間
	 */
	void setServerNamespace(String serverNamespace);
}

繼承ConfigurableApplicationContext, WebServerApplicationContext兩個(gè)接口, 并定義setServerNamespace接口, 設(shè)置服務(wù)的命名空間。

看下WebServerApplicationContext源碼:

public interface WebServerApplicationContext extends ApplicationContext {
	/**
	 * 獲取WebServer管理對(duì)象
	 */
	WebServer getWebServer();
	/**
	 * 獲取服務(wù)的命名空間
	 */
	String getServerNamespace();
}

webServer是一個(gè)服務(wù)管理接口, 包含服務(wù)的啟動(dòng)與停止管理功能。

ServletWebServerApplicationContext 的構(gòu)造方法:

   /**
	 * 默認(rèn)構(gòu)造方法
	 */
	public ServletWebServerApplicationContext() {
	}
	/**
	 * 指定beanFactory的構(gòu)造方法
	 */
	public ServletWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {
		super(beanFactory);
	}

支持傳遞指定beanFactory進(jìn)行對(duì)象初始化。

ServletWebServerApplicationContext 的refresh方法:

@Override
public final void refresh() throws BeansException, IllegalStateException {
    try {
        // 由父類方法初始化Spring上下文
        super.refresh();
    }
    catch (RuntimeException ex) {
        // 如果異常, 停止WebServer啟動(dòng)并釋放資源
        stopAndReleaseWebServer();
        throw ex;
    }
}

refresh()方法, 可以參考【Spring Boot啟動(dòng)流程】第一章的3.2.4章節(jié)第12點(diǎn)說(shuō)明, 里面做了具體說(shuō)明, 就不再贅述。

ServletWebServerApplicationContext 的createWebServer方法:

private void createWebServer() {
		WebServer webServer = this.webServer;
        // 獲取ServletContext上下文
		ServletContext servletContext = getServletContext();
		if (webServer == null && servletContext == null) {
            // 如果為空, 則進(jìn)行初始化創(chuàng)建
			ServletWebServerFactory factory = getWebServerFactory();
			this.webServer = factory.getWebServer(getSelfInitializer());
		}
		else if (servletContext != null) {
			try {
                // 如果不為空,則直接啟動(dòng)
				getSelfInitializer().onStartup(servletContext);
			}
			catch (ServletException ex) {
				throw new ApplicationContextException("Cannot initialize servlet context", ex);
			}
		}
    	// 初始化屬性資源配置信息
		initPropertySources();
	}

ServletWebServerApplicationContext 的selfInitialize方法:

	private void selfInitialize(ServletContext servletContext) throws ServletException {
        // 將ServeltContext設(shè)置為WebApplicationContext相關(guān)屬性
		prepareWebApplicationContext(servletContext);
        // 注冊(cè)ApplicationScope作用域
		registerApplicationScope(servletContext);
        // 注冊(cè)環(huán)境變量中的bean信息, 在BeanFactory中也可以獲得servletContext上下文信息
		WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
		for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
            // 設(shè)置Bean在ServletContext加載完畢后進(jìn)行初始化
			beans.onStartup(servletContext);
		}
	}

ServletWebServerApplicationContext 的finishRefresh方法:

	@Override
	protected void finishRefresh() 
        // 完成刷新邏輯處理, 比如清除緩存, 發(fā)布刷新事件等
		super.finishRefresh();
		// 啟動(dòng)WebServer
		WebServer webServer = startWebServer();
		if (webServer != null) 
            // 發(fā)布WebServer初始化完成事件
			publishEvent(new ServletWebServerInitializedEvent(webServer, this));
		}
	}

以上是整個(gè)Servlet模式服務(wù)的啟動(dòng)流程, ServletWebServerApplicationContext作為核心處理類,介紹了主要方法的處理邏輯 。

3.2 Servlet服務(wù)模式之請(qǐng)求流程具體分析

Spring Boot 是基于MVC做的封裝,先看下Spring MVC的處理流程:

Spring Boot 默認(rèn)是采用Tomcat作為容器, WebServer的實(shí)現(xiàn)類為TomcatWebServer, start啟動(dòng)方法:

    @Override
	public void start() throws WebServerException {
        // 增加同步鎖
		synchronized (this.monitor) {
			if (this.started) {
                // 如果啟動(dòng), 則直接返回
				return;
			}
			try {
                //處理tomcat的Connectors連接配置信息, 就是tomcat得xml配置得Connector信息
				addPreviouslyRemovedConnectors();
				Connector connector = this.tomcat.getConnector();
				if (connector != null && this.autoStart) {
                    // 如果存在Connector, 且為自動(dòng)啟動(dòng), 設(shè)置Tomcat的內(nèi)置上下文延遲處理(服務(wù)成功啟動(dòng)后執(zhí)行)
					performDeferredLoadOnStartup();
				}
                // 檢查配置的Connectors是否已經(jīng)啟動(dòng), 避免沖突
				checkThatConnectorsHaveStarted();
				this.started = true;
				logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
						+ getContextPath() + "'");
			}
			catch (ConnectorStartFailedException ex) {
                // 出現(xiàn)異常, 靜默停止
				stopSilently();
				throw ex;
			}
			catch (Exception ex) {
				if (findBindException(ex) != null) {
					throw new PortInUseException(this.tomcat.getConnector().getPort());
				}
				throw new WebServerException("Unable to start embedded Tomcat server", ex);
			}
			finally {
                // 獲取TOMCAT內(nèi)置上下文
				Context context = findContext();
                // 解除與classloader類加載器的綁定關(guān)系
				ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
			}
		}
	}

Web接口調(diào)用棧關(guān)系:

我們編寫(xiě)一個(gè)測(cè)試的Web接口, 看下其調(diào)用棧結(jié)構(gòu):

調(diào)用棧關(guān)系可以看到, 從tomcat的httpServlet接收到請(qǐng)求, 交給Spring MVC的DispatchServlet處理, 再分到我們自定義的WEB接口, 我們經(jīng)常定義的過(guò)濾器Filter, 在進(jìn)入httpServlet之前已經(jīng)被處理。

DispatcherServlet的doService方法

我們查看下核心的, 請(qǐng)求分發(fā)處理流程:

    @Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception 
		// LOG日志記錄請(qǐng)求信息
		logRequest(request);
		// 記錄Request級(jí)別作用域的請(qǐng)求變量信息, 必須要開(kāi)啟INCLUDE_REQUEST_URI_ATTRIBUTE屬性
		Map<String, Object> attributesSnapshot = null;
		if (WebUtils.isIncludeRequest(request)) {
			attributesSnapshot = new HashMap<>();
			Enumeration<?> attrNames = request.getAttributeNames();
			while (attrNames.hasMoreElements()) {
				String attrName = (String) attrNames.nextElement();
				if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
					attributesSnapshot.put(attrName, request.getAttribute(attrName));
				}
			}
		}
		// 設(shè)置context上下文信息
		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
		// 設(shè)置locale區(qū)域信息
		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
		// 設(shè)置theme解析器
		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
		// 設(shè)置theme源信息
		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
		// 設(shè)置flashmap信息, FlashMap 是傳遞重定向參數(shù)的時(shí)候要用到的一個(gè)類
		if (this.flashMapManager != null) {
            
			FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
			if (inputFlashMap != null) {
				request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
			}
			request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
			request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
		}
		try {
            // 分發(fā)請(qǐng)求, 對(duì)請(qǐng)求做真正的邏輯處理
			doDispatch(request, response);
		}
		finally {
            // 判斷是否異步處理請(qǐng)求
			if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
				// 上面初始化設(shè)置attributesSnapshot, 這里如果有記錄, 做還原處理
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
		}
	}

DispatcherServlet的doDispatch方法

doDispatch方法負(fù)責(zé)請(qǐng)求分發(fā)處理, 內(nèi)部會(huì)找到我們定義的處理器, 負(fù)責(zé)處理具體的請(qǐng)求邏輯。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 定義初始變量
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;
		// 獲取Web異步請(qǐng)求管理器
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		try {
			ModelAndView mv = null;
			Exception dispatchException = null;
			try {
                // 檢查請(qǐng)求是否為form-multipart提交類型,我們常見(jiàn)的文件上傳就是采用此類型
				processedRequest = checkMultipart(request);
                // 如果是multipart該類型, 通過(guò)MultipartResolver解析
				multipartRequestParsed = (processedRequest != request);

				// 獲取當(dāng)前請(qǐng)求的映射處理器, 也就是自定義的controller, 如果沒(méi)有找到, 則返回, 不做下面邏輯處理
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}
				// 根據(jù)映射處理器, 獲取處理適配器(實(shí)際為RequestMappingHandlerAdapter) 
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
				// 獲取請(qǐng)求類型,包含GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS等
				String method = request.getMethod();
                // 判斷是否為GET類型 
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
                    // 獲取上次請(qǐng)求修改標(biāo)記, 如果沒(méi)有修改, 默認(rèn)返回-1
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}
				// 在進(jìn)入處理器之前, 先要判斷有沒(méi)設(shè)置攔截器, 如果有, 進(jìn)入攔截器的前置處理邏輯, 默認(rèn)有ResourceUrlProviderExposingInterceptor等攔截器
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}
				// 這里就是真正調(diào)用處理器, 也就是我們?cè)赾ontroller中定義的方法
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				// 異步處理判斷
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				// 判斷有沒(méi)采用ModelAndView返回, 并進(jìn)行對(duì)應(yīng)設(shè)置
				applyDefaultViewName(processedRequest, mv);
                // 這里是攔截器的后置處理邏輯, 如果有匹配設(shè)置, 則會(huì)進(jìn)行調(diào)用處理
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
            // 設(shè)置分發(fā)處理結(jié)果, 如果處理器的執(zhí)行出現(xiàn)異常,會(huì)根據(jù)設(shè)置做對(duì)應(yīng)渲染; 如果有設(shè)置視圖, 則會(huì)進(jìn)行渲染解析
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
            // 異步請(qǐng)求標(biāo)記處理
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				//如果采用multipart類型提交, 會(huì)做一些清除工作, 比如上傳文件緩存等
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

通過(guò)以上分析, 我們可以了解到Servlet模式服務(wù)的請(qǐng)求流程, 重點(diǎn)是DispatcherServlet的doDispatch方法,要了解一個(gè)請(qǐng)求進(jìn)入之前所做的事情, 請(qǐng)求處理完成之后所做的事情, 以及對(duì)于filter, interceptor執(zhí)行順序這些都要清楚, 可以幫助我們更好的運(yùn)用, 以及排查請(qǐng)求過(guò)程中出現(xiàn)的問(wèn)題。

4. Reactive服務(wù)模式請(qǐng)求流程分析

4.1 ReactiveWebServerApplicationContext分析

ReactiveWebServerApplicationContext為響應(yīng)式服務(wù)容器管理, 是提供Reactive Web環(huán)境的Spring 容器。 Spring WebFlux應(yīng)用就采用ReactiveWebServerApplicationContext實(shí)現(xiàn), ReactiveWebServerApplicationContext與ServletWebServerApplicationContext 的實(shí)現(xiàn)類似, 都是由SpringBoot統(tǒng)一封裝設(shè)計(jì), 總體處理流程基本一致。

ReactiveWebServerApplicationContext 構(gòu)造方法

public class ReactiveWebServerApplicationContext extends GenericReactiveWebApplicationContext
		implements ConfigurableWebServerApplicationContext {
	// 服務(wù)管理類, 包含服務(wù)啟動(dòng)與停止, 以及請(qǐng)求handler處理
	private volatile ServerManager serverManager;
	// 服務(wù)命名空間
	private String serverNamespace;
	/**
	 * 默認(rèn)構(gòu)造方法
	 */
	public ReactiveWebServerApplicationContext() {
	}
	/**
	 * 指定beanFactory的構(gòu)造方法
	 */
	public ReactiveWebServerApplicationContext(DefaultListableBeanFactory beanFactory) {
		super(beanFactory);
	}

ReactiveWebServerApplicationContext#ServerManager內(nèi)部類:

    /**
	 * 服務(wù)管理類
	 */
	static final class ServerManager implements HttpHandler {
		// WebServer服務(wù)
		private final WebServer server;
		// 是否懶加載
		private final boolean lazyInit;
		// Http Handler請(qǐng)求處理器
		private volatile HttpHandler handler;
		// 構(gòu)造方法, 注入serverFactory與延遲加載標(biāo)記
		private ServerManager(ReactiveWebServerFactory factory, boolean lazyInit) {
			this.handler = this::handleUninitialized;
			this.server = factory.getWebServer(this);
			this.lazyInit = lazyInit;
		}
		// 處理未初始化的請(qǐng)求, 暫未實(shí)現(xiàn)
		private Mono<Void> handleUninitialized(ServerHttpRequest request, ServerHttpResponse response) {
			throw new IllegalStateException("The HttpHandler has not yet been initialized");
		}
		// 重載方法, 處理Web請(qǐng)求
		@Override
		public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
			return this.handler.handle(request, response);
		}
		public HttpHandler getHandler() {
			return this.handler;
		}
		// 獲取ServerManager服務(wù)管理類
		public static ServerManager get(ReactiveWebServerFactory factory, boolean lazyInit) {
			return new ServerManager(factory, lazyInit);
		}
        // 獲取WebServer服務(wù)
		public static WebServer getWebServer(ServerManager manager) {
			return (manager != null) ? manager.server : null;
		}
        // 通過(guò)serverManager啟動(dòng)服務(wù)
		public static void start(ServerManager manager, Supplier<HttpHandler> handlerSupplier) {
			if (manager != null && manager.server != null) {
				manager.handler = manager.lazyInit ? new LazyHttpHandler(Mono.fromSupplier(handlerSupplier))
						: handlerSupplier.get();
				manager.server.start();
			}
		}
		// 通過(guò)serverManager停止服務(wù)
		public static void stop(ServerManager manager) {
			if (manager != null && manager.server != null) {
				try {
					manager.server.stop();
				}
				catch (Exception ex) {
					throw new IllegalStateException(ex);
				}
			}
		}
	}

ReactiveWebServerApplicationContext#startReactiveWebServer方法:

	private WebServer startReactiveWebServer() {        
		ServerManager serverManager = this.serverManager;
        // 啟動(dòng)WebServer, 從BeanFactory中獲取HttpHandler
		ServerManager.start(serverManager, this::getHttpHandler);
        // 獲取返回WebServer
		return ServerManager.getWebServer(serverManager);
	}

查看getHttpHandler方法:

protected HttpHandler getHttpHandler() {
		// 獲取所有實(shí)現(xiàn)HttpHandler接口的實(shí)現(xiàn)類
		String[] beanNames = getBeanFactory().getBeanNamesForType(HttpHandler.class);
    	// HttpHandler實(shí)現(xiàn)類只能存在一個(gè), 沒(méi)有配置或多個(gè)都會(huì)拋出異常
		if (beanNames.length == 0) {
            // 
			throw new ApplicationContextException(
					"Unable to start ReactiveWebApplicationContext due to missing HttpHandler bean.");
		}
    	// 存在多個(gè), 拋出異常
		if (beanNames.length > 1) {
			throw new ApplicationContextException(
					"Unable to start ReactiveWebApplicationContext due to multiple HttpHandler beans : "
							+ StringUtils.arrayToCommaDelimitedString(beanNames));
		}
    	// 返回HttpHandler
		return getBeanFactory().getBean(beanNames[0], HttpHandler.class);
	}

ReactiveWebServerApplicationContext#onClose方法:

@Override
protected void onClose() {
    // 先調(diào)用父類方法, 關(guān)閉邏輯處理, 目前是空實(shí)現(xiàn)
    super.onClose();
    // 通過(guò)ServerManager停止服務(wù)
    stopAndReleaseReactiveWebServer();
}

4.2 webflux服務(wù)模式之請(qǐng)求流程具體分析

上面講解了ReactiveWebServerApplicationContext的代碼實(shí)現(xiàn)流程, 我們看下webflux服務(wù)的請(qǐng)求處理流程。

定義HttpHandler

// 定義Reactive服務(wù)的HttpHandler, 
@Bean
public HttpHandler httpHandler() {
   return WebHttpHandlerBuilder.applicationContext(this.applicationContext)
         .build();
}

webflux使用的httpHandler類型是HttpWebHandlerAdapter, 創(chuàng)建的webserver為NettyWebServer類型

@Override
public WebServer getWebServer(HttpHandler httpHandler) {
   // 創(chuàng)建HTTP SERVER服務(wù)
   HttpServer httpServer = createHttpServer();
   // 定義HTTP HANDLER處理適配器 
   ReactorHttpHandlerAdapter handlerAdapter = new ReactorHttpHandlerAdapter(
         httpHandler);
   // 采用Netty作為WebServer實(shí)現(xiàn) 
   return new NettyWebServer(httpServer, handlerAdapter, this.lifecycleTimeout);
}

創(chuàng)建ReactorHttpHandlerAdapter使用的httpHandler就是我們上面定義的WebHttpHandlerBuilder。

當(dāng)一個(gè)請(qǐng)求進(jìn)來(lái)的時(shí)候,就是通過(guò)ReactorHttpHandlerAdapter的apply()方法然后進(jìn)入了了HttpWebHandlerAdapter類的handle方法, 再執(zhí)行DispatcherHandler的handle方法:

public Mono<Void> handle(ServerWebExchange exchange) {
        // 校驗(yàn)handlerMappings是否存在
		if (this.handlerMappings == null) {
			return createNotFoundError();
		}
    	// 響應(yīng)式操作, 調(diào)用Handler實(shí)現(xiàn)類處理邏輯, handleResult處理執(zhí)行結(jié)果
		return Flux.fromIterable(this.handlerMappings)
				.concatMap(mapping -> mapping.getHandler(exchange))
				.next()
				.switchIfEmpty(createNotFoundError())
				.flatMap(handler -> invokeHandler(exchange, handler))
				.flatMap(result -> handleResult(exchange, result));
	}

通過(guò)RequestMappingHandlerMapping找到對(duì)應(yīng)的HandlerMethod(就是我們Controller中對(duì)應(yīng)的方法),然后執(zhí)行invokeHandler方法:

	private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
        // 校驗(yàn)Handler適配器是否存在
		if (this.handlerAdapters != null) {
            // 遍歷handlerAdapters
			for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
                // 判斷是否支持的適配器類型
				if (handlerAdapter.supports(handler)) {
                    // 處理Handler適配器具體邏輯
					return handlerAdapter.handle(exchange, handler);
				}
			}
		}
		return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
	}

HandlerAdapter是RequestMappingHandlerAdapter,在RequestMappingHandlerAdapter方法中執(zhí)行了InvocableHandlerMethod的invode方法,然后通過(guò)反射執(zhí)行了Controller中的方法, 最后把Controller方法執(zhí)行的結(jié)果,通過(guò)DispatcherHandler中的handlerResult方法,輸出返回給調(diào)用客戶端。

5. 總結(jié)

學(xué)習(xí)研究Spring Boot的請(qǐng)求流程, 理解其內(nèi)置容器, Spring MVC和自定義controller之間是如何流轉(zhuǎn)處理的, 各自所做的事情, 每個(gè)環(huán)節(jié)的作用, 相互之間的調(diào)用關(guān)系, 才算是理解和掌握Spring Boot的使用, 在實(shí)際工作當(dāng)中, 可能更多的是停留在使用層面, 但是如果能夠?qū)?shí)現(xiàn)原理有進(jìn)一步認(rèn)知, 我們才知道更合理的去使用, 以及更高效的去排查使用過(guò)程當(dāng)中出現(xiàn)的各種問(wèn)題。

到此這篇關(guān)于Spring Boot超詳細(xì)講解請(qǐng)求處理流程機(jī)制的文章就介紹到這了,更多相關(guān)Spring Boot請(qǐng)求處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java 模仿拼多多紅包遞減算法的實(shí)現(xiàn)

    java 模仿拼多多紅包遞減算法的實(shí)現(xiàn)

    這篇文章主要介紹了java 模仿拼多多紅包遞減算法的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • MyBatis學(xué)習(xí)教程(三)-MyBatis配置優(yōu)化

    MyBatis學(xué)習(xí)教程(三)-MyBatis配置優(yōu)化

    這篇文章主要介紹了MyBatis學(xué)習(xí)教程(三)-MyBatis配置優(yōu)化的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-05-05
  • Java?Zip壓縮之簡(jiǎn)化文件和文件夾的壓縮操作

    Java?Zip壓縮之簡(jiǎn)化文件和文件夾的壓縮操作

    這篇文章主要給大家介紹了關(guān)于Java?Zip壓縮之簡(jiǎn)化文件和文件夾的壓縮操作,Zip壓縮是一種常見(jiàn)的文件壓縮格式,它將多個(gè)文件和文件夾打包成一個(gè)以.zip為后綴的壓縮包,需要的朋友可以參考下
    2023-10-10
  • resty的緩存技術(shù)設(shè)計(jì)及使用

    resty的緩存技術(shù)設(shè)計(jì)及使用

    這篇文章主要為大家介紹了resty緩存技術(shù)的設(shè)計(jì)及使用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-03-03
  • Java中異常處理之try和catch代碼塊的使用

    Java中異常處理之try和catch代碼塊的使用

    這篇文章主要介紹了Java中異常處理之try和catch代碼塊的使用,是Java入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • 解決Springboot項(xiàng)目bootstrap.yml不生效問(wèn)題

    解決Springboot項(xiàng)目bootstrap.yml不生效問(wèn)題

    Spring Boot 2.4版本開(kāi)始,配置文件加載方式進(jìn)行了重構(gòu),只會(huì)識(shí)別application.* 配置文件,并不會(huì)自動(dòng)識(shí)別bootstrap.yml,所以本文給大家介紹Springboot項(xiàng)目bootstrap.yml不生效問(wèn)題的解決方案,需要的朋友可以參考下
    2023-09-09
  • Java擴(kuò)展Nginx之共享內(nèi)存

    Java擴(kuò)展Nginx之共享內(nèi)存

    這篇文章主要介紹了Java擴(kuò)展Nginx之共享內(nèi)存的相關(guān)資料,需要的朋友可以參考下
    2023-07-07
  • mybatis簡(jiǎn)單resultMap使用詳解

    mybatis簡(jiǎn)單resultMap使用詳解

    resultMap是Mybatis最強(qiáng)大的元素,它可以將查詢到的復(fù)雜數(shù)據(jù)(比如查詢到幾個(gè)表中數(shù)據(jù))映射到一個(gè)結(jié)果集當(dāng)中。這篇文章主要介紹了mybatis簡(jiǎn)單resultMap使用詳解的相關(guān)資料,需要的朋友可以參考下
    2021-04-04
  • Java實(shí)現(xiàn)無(wú)向圖的示例詳解

    Java實(shí)現(xiàn)無(wú)向圖的示例詳解

    邊沒(méi)有方向的圖稱為無(wú)向圖,直觀來(lái)說(shuō),若一個(gè)圖中每條邊都是無(wú)方向的,則稱為無(wú)向圖。本文將通過(guò)示例詳細(xì)講解Java如何實(shí)現(xiàn)無(wú)向圖,需要的可以參考一下
    2022-04-04
  • Java獲取網(wǎng)頁(yè)數(shù)據(jù)步驟方法詳解

    Java獲取網(wǎng)頁(yè)數(shù)據(jù)步驟方法詳解

    這篇文章主要介紹了Java獲取網(wǎng)頁(yè)數(shù)據(jù)步驟方法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03

最新評(píng)論