前言
學(xué)了一遍SpringMVC以后,想著做一個總結(jié),復(fù)習(xí)一下。復(fù)習(xí)寫下面的總結(jié)的時候才發(fā)現(xiàn),其實自己學(xué)得并不徹底、牢固、也沒有學(xué)全,視頻跟書本是要結(jié)合起來一起,每一位老師的視頻可能提到的東西都不一致,也導(dǎo)致也不是很全面,書本上會講的筆記系統(tǒng)、全面。同時我自己也是一個初學(xué)者,下面總結(jié)的可能并不完善、正確,希望看到的大神給我指出,在此非常感謝。
目錄
- SpringMVC流程及源碼分析
- 一 、Spring核心模塊
- 1、核心模塊
- 2、Spring版本命名規(guī)則(補(bǔ)充)
- 二、SpringMVC流程及原理
- 1、執(zhí)行流程
- 1.1、執(zhí)行流程
- 1.2、執(zhí)行流程說明:
- 1.2.1、第02、03說明
- 1.2.2、第04說明
- 1.2.2、SpringMVC組件說明
- 1.2.3、SpringMVC詳細(xì)流程圖
- 1、執(zhí)行流程
- 二、源碼分析
- 1、初始化
- 1.1、ApplicationContext
- 2、前端控制器(中央處理器)DistepcherServlet
- 2.1、查找處理器映射器HandlerMapping
- 2.2、根據(jù)處理器映射器HandlerMapping返回結(jié)果調(diào)用處理器適配器HandlerAdapter
- 2.3、檢查攔截器Interceptor
- 2.3、處理器適配器HandlerAdapter執(zhí)行Handler(Controller)返回ModelAndView
- 2.4、視圖解析器ViewResolver
- 2.5、視圖View
- 2.5.1、視圖對象的作用
- 2.5.2、View接口圖
- 2.5.3、View的實現(xiàn)類圖
- 2.5.4、View的UML圖
- 2.5.5、常用的View視圖類
- 2.6、其他重要的點(diǎn)
- 2.6.1、DispatcherServlet.properties
- 1、初始化
- 三、引用參考資料
- 1、引用資料
- 2、參考資料
一 、Spring核心模塊
1、核心模塊
Spring Web MVC (下文簡稱為 SpringMVC )是 Spring 提供 Web 應(yīng)用的框架設(shè)計,屬于表現(xiàn)層的框架。SpringMVC是Spring框架的一部分。
Spring框架包括大致六大模塊,核心容器(Core Container)、AOP和設(shè)備支持、數(shù)據(jù)訪問及集成、Web、報文發(fā)送、Test
圖片來源于Spring官網(wǎng)5.0.0.M5:
? https://docs.spring.io/spring-framework/docs/5.0.0.M5/spring-framework-reference/html/overview.html#overview-modules
對于Spring5模塊圖,有2點(diǎn)疑問:
1、不清楚為什么在Spring官網(wǎng)上5.0版本以后,Release版(穩(wěn)定版)的都未找到模塊圖,但是在M(里程碑版)版找到 了,如果有人在5.0以后的Release版(穩(wěn)定版)找到,麻煩給我留個言,謝謝。
2、在其他博文中看到Spring5模塊結(jié)構(gòu)圖是這樣的:
挺奇怪這個圖是哪里來的?(路過的大神請指點(diǎn))
對于問題2,我在Spring5.2.13.RELEASE GA中,找到了如下所示信息:
拷貝以上信息:
Spring Framework Documentation
Version 5.2.13.RELEASE
What’s New, Upgrade Notes, Supported Versions, and other topics, independent of release cadence, are maintained externally on the project’s Github Wiki.
Overview |
history, design philosophy, feedback, getting started. |
Core |
IoC Container, Events, Resources, i18n, Validation, Data Binding, Type Conversion, SpEL, AOP. |
Testing |
Mock Objects, TestContext Framework, Spring MVC Test, WebTestClient. |
Data Access |
Transactions, DAO Support, JDBC, O/R Mapping, XML Marshalling. |
Web Servlet |
Spring MVC, WebSocket, SockJS, STOMP Messaging. |
Web Reactive |
Spring WebFlux, WebClient, WebSocket. |
Integration |
Remoting, JMS, JCA, JMX, Email, Tasks, Scheduling, Caching. |
Languages |
Kotlin, Groovy, Dynamic Languages. |
按照以上信息的Web Servlet、Web Reactive已經(jīng)是分屬于不同的模塊了。
- Web Servlet:Spring MVC, WebSocket, SockJS, STOMP Messaging.
- Web Reactive:Spring WebFlux, WebClient, WebSocket.
Spring官方文檔:
https://spring.io/projects/spring-framework#learn/
2、Spring版本命名規(guī)則(補(bǔ)充)
上面提到了Spring有不同的版本,在此記錄一下各個版本的意義。
描述方式 |
說明 |
含義 |
Snapshot |
快照版 |
尚不穩(wěn)定,仍處于開發(fā)中的版本 |
Release |
穩(wěn)定版 |
功能相對穩(wěn)定,可以對外發(fā)行,但有時間限制 |
GA |
正式版 |
代表廣泛可用的穩(wěn)定版(General Availability) |
M |
里程碑版 |
(M是Milestone的意思)具有一些全新的功能或是有意義的版本 |
RC |
終測版 |
Release Candidate(最終測試),即將作為正式版發(fā)布 |
二、SpringMVC流程及原理
1、執(zhí)行流程
SpringMVC執(zhí)行流程圖
圖片來源:三、引用參考資料
1.1、執(zhí)行流程
- 01、用戶發(fā)送出請求到前端控制器(中央處理器)DispatcherServlet進(jìn)行處理。
- 02、前端控制器DispatcherServlet收到請求后,調(diào)用處理器映射器HandlerMapping。
- 03、處理器映射器HandlerMapping(處理器映射器)根據(jù)request請求的URL等信息查找能夠進(jìn)行處理的Handler,以及相關(guān)攔截器interceptor,并構(gòu)造HandlerExecutionChain執(zhí)行鏈,然后將構(gòu)造好的HandlerExecutionChain執(zhí)行鏈對象返回給前端控制器DispatcherServlet。
- 04、前端控制器DispatcherServlet根據(jù)處理器映射器HandlerMapping的
- 05、處理器適配器HandlerAdapter經(jīng)過適配調(diào)用具體的處理器(Handler/Controller),即業(yè)務(wù)中自己寫的Controller。
- 06、Controller處理完后返回ModelAndView(springmvc的封裝對象,將model和view封裝在一起)給處理器適配器HandlerAdapter;
- 07、處理器適配器HandlerAdapter將Controller執(zhí)行結(jié)果ModelAndView返回給前端控制器DispatcherServlet。
- 08、前端控制器DispatcherServlet調(diào)用視圖解析器ViewReslover處理ModelAndView。
- 09、視圖解析器ViewReslover解析后根據(jù)邏輯視圖名解析成物理視圖名即具體的頁面地址,生成并返回具體對象View(springmvc封裝對象,是一個接口)。
- 10、前端控制器DispatcherServlet根據(jù)對象View進(jìn)行視圖渲染,填充Model。
- 11、前端控制器DispatcherServlet向用戶返回響應(yīng)
1.2、執(zhí)行流程說明:
1.2.1、第02、03說明
(1) 處理器映射器:springmvc框架中的一種對象,框架把實現(xiàn)了HandlerMapping接口的類都叫做映射器(多個);
(2) 處理器映射器作用:根據(jù)請求,從springmvc容器對象中獲取處理器對象(MyController controller = ctx.getBean("some")
(3) 框架把找到的處理器對象放到一個叫做處理器執(zhí)行鏈(HandlerExecutionChain)的類保存
(4) HandlerExecutionchain:類中保存著
a:處理器對象(MyController);
b:項目中的所有的攔截器List
(5) 方法調(diào)用:HandlerExecutionChain mappedHandler - getHandler (processedRequest);
1.2.2、第04說明
(1) HandlerExecutionChain執(zhí)行鏈找到對應(yīng)的處理器映射器HandlerAdapter。
(2) 處理器適配器:springmvc框架中的對象,需要實現(xiàn)HandlerAdapter接口,
(3) 處理器適配器作用:執(zhí)行處理器方法(調(diào)用MyController.doSome()得到返回值ModelAndView )
(4) 前端控制器中調(diào)用適配器:HandlerAdapter ha =getHandlerAdapter (mappedHandler.getHandler());
(5) 執(zhí)行處理器方法:mv= ha.handle (processedRequest, response, mappedHandler.getHandler());
第08說明:
(1) 視圖解析器:springmvc中的對象,需要實現(xiàn)ViewResoler接口(可以有多個)
(2) 視圖解析器作用:組成視圖完整路徑,使用前綴,后綴。并創(chuàng)建View對象。
(3) view是一個接口,表示視圖的,在框架中jsp,htm1不是string表示,而是使用view和他的實現(xiàn)類表示視圖。
InternalResourceview:視圖類,表示jsp文件,視圖解析器會創(chuàng)建InternalResourceView類對象。 這個對象的里面,有一個屬性
url-/WEB-INF/view/show.jsp
1.2.2、SpringMVC組件說明
- (1). 前端控制器(DispatcherServlet):接收請求,響應(yīng)結(jié)果,相當(dāng)于電腦的CPU。
- (2). 處理器映射器(HandlerMapping):根據(jù)URL去查找處理器.
- (3). 處理器(Handler):(需要程序員去寫代碼處理邏輯的).
- (4). 處理器適配器(HandlerAdapter):會把處理器包裝成適配器,這樣就可以支持多種類型的處理器,類比筆記本的適配器(適配器模式的應(yīng)用).
- (5). 視圖解析器(ViewResovler):進(jìn)行視圖解析,多返回的字符串,進(jìn)行處理,可以解析成對應(yīng)的頁面.
1.2.3、SpringMVC詳細(xì)流程圖
綜上所述,總結(jié)下SpringMVC的詳細(xì)流程圖:
圖片來源:三、引用參考資料
二、源碼分析
以下源碼來源jar包:
spring-webmvc-5.25.RELEASE.jar
1、初始化
1.1、ApplicationContext
? ApplicationContext初始化入口類:ApplicationObjectSupport的setApplicationContext方法,setApplicationContext方法中核心部分就是初始化容器initApplicationContext(context),子類
AbstractDetectingUrlHandlerMapping實現(xiàn)了該方法。
類圖:
UML圖:
?
RequestMappingHandlerMapping ,用于注解@Controller,@RequestMapping來定義controller.
初始化時,3個類的大致分工如下:
- AbstractHandlerMethodMapping定義整個算法流程;
- RequestMappingInfoHandlerMapping提供匹配條件RequestMappingInfo的解析處理;
- RequestMappingHandlerMapping根據(jù)@RequestMapping注解生成 RequestMappingInfo,同時提供isHandler實現(xiàn)
2、前端控制器(中央處理器)DistepcherServlet
? 從上面的流程圖可以看到前端控制器(中央處理器)DistepcherServlet是SpringMVC核心,查看DistepcherServlet類的繼承情況。
UML圖:
![
2021022601-08-DispatcherServlet UML圖](
https://gitee.com/chuchq/blogs-gallery/raw/master/images /
2021/2021022601-08-DispatcherServlet UML圖.png)
從繼承關(guān)系看出:
? DistepcherServlet ---> FrameworkServlet ---> HttpServletBean---> HttpServlet
? 那就說明DistepcherServlet 類也是一個Servlet類,那最終核心的方法就是service()方法,即Servlet的核心方法。
? 那就找service()方法,在DistepcherServlet中沒有servic()方法,在父類FrameworkServlet有service()方法,源碼如下:
來源:
org.springframework.web.servlet.FrameworkServlet.service(HttpServletRequest request, HttpServletResponse response)
/**
* Override the parent class implementation in order to intercept PATCH requests.
*/
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}
可以看到:
FrameworkServlet.service(HttpServletRequest request, HttpServletResponse response)拿到request請求,判斷當(dāng)前請求是否是PATCH請求,不是的就調(diào)用父類的servic()方法,調(diào)用父類中的service方法就是去調(diào)用該類中doPost(),doGet()方法,根據(jù)不同的請求方式然后走doPost()或者doGet(),調(diào)用中以doGet()為例,
FrameworkServlet類的doGet()源碼:
/**
* Delegate GET requests to processRequest/doService.
* <p>Will also be invoked by HttpServlet's default implementation of {@code doHead},
* with a {@code NoBodyResponse} that just captures the content length.
* @see #doService
* @see #doHead
*/
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
? doGet()又調(diào)用FrameworkServlet類中的processRequest(request, response);
/**
* Process this request, publishing an event regardless of the outcome.
* <p>The actual event handling is performed by the abstract
* {@link #doService} template method.
*/
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
initContextHolders(request, localeContext, requestAttributes);
try {
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
logResult(request, response, failureCause, asyncManager);
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
? processRequest(request, response)方法中最關(guān)鍵的又調(diào)用了doService(request, response);查看FrameworkServlet類中的doService(request, response),或者是調(diào)試跟蹤可知,doService(request, response)由子類DispatcherServlet實現(xiàn)。
源碼來源:
org.springframework.web.servlet.FrameworkServlet.doService(HttpServletRequest request, HttpServletResponse response)
/**
* Subclasses must implement this method to do the work of request handling,
* receiving a centralized callback for GET, POST, PUT and DELETE.
* <p>The contract is essentially the same as that for the commonly overridden
* {@code doGet} or {@code doPost} methods of HttpServlet.
* <p>This class intercepts calls to ensure that exception handling and
* event publication takes place.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
* @see JAVAx.servlet.http.HttpServlet#doGet
* @see javax.servlet.http.HttpServlet#doPost
*/
protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
throws Exception;
? 查看DispatcherServlet中的doService(HttpServletRequest request, HttpServletResponse response)方法
/**
* Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
* for the actual dispatching.
*/
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(request);
// Keep a snapshot of the request attributes in case of an include,
// to be able to restore the original attributes after the include.
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));
}
}
}
// Make framework objects available to handlers and view objects.
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
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 {
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
? DispatcherServlet的doService()方法中最終調(diào)用doDispatch(request, response),查看源碼如下:
org.springframework.web.servlet.DispatcherServlet.doDispatch()
/**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 文件上傳相關(guān),判斷是不是二進(jìn)制請求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 取得處理當(dāng)前請求的controller,這里也稱為hanlder處理器,第一個步驟的意義就在這里體現(xiàn)了.這里并不是直接返回controller,而是返回的HandlerExecutionChain請求處理器鏈對象,該對象封裝了handler和攔截器interceptors.
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
// 如果handler為空,則返回404
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
//3. 獲取處理request的處理器適配器HandlerAdapter
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//處理器適配器執(zhí)行之前,檢查攔截器的方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//處理器適配器根據(jù)找到,執(zhí)行handler,返回ModelAndView
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
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);
}
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 {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
? 可以看出doDispatch()就是SpringMVC的核心代碼了,分析doDispatch():
2.1、查找處理器映射器HandlerMapping
? 首先看下處理器映射器HandlerMapping類圖:
doDispatch()關(guān)鍵代碼:
HandlerExecutionChain mappedHandler = null;
mappedHandler = getHandler(processedRequest);
? mappedHandler是一個執(zhí)行鏈HandlerExecutionChain 對象,這里封裝了handler和攔截器interceptors,getHandler(processedRequest)方法就是從處理器映射器HandlerMapping中找到url和controller的對應(yīng)關(guān)系,并返回給前端控制器DispatchServlet。
查看getHandler(processedRequest);源碼:
/**
* Return the HandlerExecutionChain for this request.
* <p>Tries all handler mappings in order.
* @param request current HTTP request
* @return the HandlerExecutionChain, or {@code null} if no handler could be found
*/
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
調(diào)試代碼如下:
從代碼調(diào)試中可以看到handlerMapping中有三個對象:
this.handlerMappings = {ArrayList@4662} size = 3
0 = {BeanNameUrlHandlerMapping@4791}
1 = {RequestMappingHandlerMapping@4792}
2 = {RouterFunctionMapping@4793}
- BeanNameUrlHandlerMapping:初始化時會將urlpath做映射存儲(xml);
- RequestMappingHandlerMapping:初始化時會將Controller中配置@RequestMapping注解的方法做映射存儲(注解);
- RouterFunctionMapping:
(這個對象不是太理解)這也就是為什么要去HandlerMapping找一個Handler了,因為處理器映射器HandlerMapping有不同的實現(xiàn): - 1、xml方式
- 2、注解方式
接著看getHandler(HttpServletRequest request)方法,先遍歷HandlerMappers,查找控制器找到之后就返回執(zhí)行鏈HandlerExecutionChain類型的Handler。
可以看到返回的Handler中,拿到的就是我們自己編碼的Controller類,以及攔截器(演示項目中未編寫,所以調(diào)試匯總返回的Handler最后是0 interceptors)
HandlerExecutionChain with [
com.bjpowernode.controller.MyController#doSome()] and 0 interceptors
將正在調(diào)試的idea打開自己編寫的Controller來對照,發(fā)現(xiàn)一致:
2.2、根據(jù)處理器映射器HandlerMapping返回結(jié)果調(diào)用處理器適配器HandlerAdapter
doDispatch()里面的關(guān)鍵代碼:
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
源碼如下:
/**
* Return the HandlerAdapter for this handler object.
* @param handler the handler object to find an adapter for
* @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
為什么還要獲取處理器適配器HandlerAdapter:與獲取處理器映射器HandlerMapping一樣,Spring提供了不通的處理器適配器。
調(diào)試如下:
查看DEBUG調(diào)試模式中g(shù)etHandlerAdapter()方法在中的:
handler、adapter、this.handlerAdapters
以下是拷貝的結(jié)果:
handler
handler = {HandlerMethod@4792} "com.bjpowernode.controller.MyController#doSome()"
logger = {LogAdapter$JavaUtilLog@4858}
bean = {MyController@4859}
beanFactory = {DefaultListableBeanFactory@4847} "org.springframework.beans.factory.support.DefaultListableBeanFactory@56b5a4c3: defining beans [myController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,org.springframework.web.servlet.view.InternalResourceViewResolver#0]; root of factory hierarchy"
beanType = {Class@3782} "class com.bjpowernode.controller.MyController"
method = {Method@4860} "public org.springframework.web.servlet.ModelAndView com.bjpowernode.controller.MyController.doSome()"
bridgedMethod = {Method@4860} "public org.springframework.web.servlet.ModelAndView com.bjpowernode.controller.MyController.doSome()"
parameters = {MethodParameter[0]@4861}
responseStatus = null
responseStatusReason = null
resolvedFromHandlerMethod = {HandlerMethod@4863} "com.bjpowernode.controller.MyController#doSome()"
interfaceParameterAnnotations = null
description = "com.bjpowernode.controller.MyController#doSome()"
adapter
adapter = {RequestMappingHandlerAdapter@4827}
customArgumentResolvers = null
argumentResolvers = {HandlerMethodArgumentResolverComposite@4833}
initBinderArgumentResolvers = {HandlerMethodArgumentResolverComposite@4834}
customReturnValueHandlers = null
returnValueHandlers = {HandlerMethodReturnValueHandlerComposite@4835}
modelAndViewResolvers = null
contentNegotiationManager = {ContentNegotiationManager@4836}
messageConverters = {ArrayList@4837} size = 4
requestResponseBodyAdvice = {ArrayList@4838} size = 0
webBindingInitializer = null
taskExecutor = {SimpleAsyncTaskExecutor@4839}
asyncRequestTimeout = null
callableInterceptors = {CallableProcessingInterceptor[0]@4840}
deferredResultInterceptors = {DeferredResultProcessingInterceptor[0]@4842}
reactiveAdapterRegistry = {ReactiveAdapterRegistry@4844}
ignoreDefaultModelOnRedirect = false
cacheSecondsForSessionAttributeHandlers = 0
synchronizeOnSession = false
sessionAttributeStore = {DefaultSessionAttributeStore@4845}
parameterNameDiscoverer = {DefaultParameterNameDiscoverer@4846}
beanFactory = {DefaultListableBeanFactory@4847} "org.springframework.beans.factory.support.DefaultListableBeanFactory@56b5a4c3: defining beans [myController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,org.springframework.web.servlet.view.InternalResourceViewResolver#0]; root of factory hierarchy"
sessionAttributesHandlerCache = {ConcurrentHashMap@4848} size = 0
initBinderCache = {ConcurrentHashMap@4849} size = 0
initBinderAdviceCache = {LinkedHashMap@4850} size = 0
modelAttributeCache = {ConcurrentHashMap@4851} size = 0
modelAttributeAdviceCache = {LinkedHashMap@4852} size = 0
order = 2147483647
supportedMethods = null
allowHeader = "GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS"
requireSession = false
cacheControl = null
cacheSeconds = -1
varyByRequestHeaders = null
useExpiresHeader = false
useCacheControlHeader = true
useCacheControlNoStore = true
alwaysMustRevalidate = false
servletContext = {ApplicationContextFacade@4754}
logger = {LogAdapter$JavaUtilLog@4854}
applicationContext = {XmlWebApplicationContext@4665} "WebApplicationContext for namespace 'myweb-servlet', started on Tue Mar 02 23:25:35 CST 2021"
messageSourceAccessor = {MessageSourceAccessor@4855}
this.handlerAdapters
this.handlerAdapters = {ArrayList@4658} size = 4
0 = {HttpRequestHandlerAdapter@4810}
1 = {SimpleControllerHandlerAdapter@4820} //XML方式
2 = {RequestMappingHandlerAdapter@4827} //注解方式
3 = {HandlerFunctionAdapter@4832}
可以看到找到4個處理器適配器。通過DEBUG模式可以看到,此次取到的處理器適配器HandlerAdapter是:
RequestMappingHandlerAdapter
ha = {RequestMappingHandlerAdapter@4827}
2.3、檢查攔截器Interceptor
doDispatch()中的關(guān)鍵代碼:
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle
applyPreHandle(processedRequest, response)源碼:
/**
* Apply preHandle methods of registered interceptors.
* @return {@code true} if the execution chain should proceed with the
* next interceptor or the handler itself. Else, DispatcherServlet assumes
* that this interceptor has already dealt with the response itself.
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
2.3、處理器適配器HandlerAdapter執(zhí)行Handler(Controller)返回ModelAndView
doDispatch()中的關(guān)鍵代碼:
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
DEBUG模式調(diào)試,是調(diào)到了:
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle
源碼如下:
/**
* This implementation expects the handler to be an {@link HandlerMethod}.
*/
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
再往下看handleInternal(request, response, (HandlerMethod) handler)方法,
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No HttpSession available -> no mutex necessary
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// No synchronization on session demanded at all...
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
注意,handleInternal(request, response, (HandlerMethod) handler)方法的返回值是ModelAndView ,這里就完成了處理器適配器HandlerAdapter執(zhí)行Handler(Controller)并將結(jié)果ModelAndView返回給前端控制器DistepchServlet
2.4、視圖解析器ViewResolver
接上2.3:前端控制器DistepchServlet接收到處理器適配器HandlerAdapter返回的ModelAndView以后,這里分2種情況:
- (1)、如果ModelAndView里面是邏輯視圖
前端控制器DistepchServlet調(diào)用視圖解析器ViewResolver通過邏輯視圖查找真正的視圖對象View,并返回給前端控制器DistepchServlet。 - (2)、如果ModelAndView里面是非邏輯視圖:
如:MappingJackson2JsonView(把當(dāng)前數(shù)據(jù)轉(zhuǎn)為為JSON數(shù)據(jù),并不需要對視圖邏輯名稱進(jìn)行轉(zhuǎn)換)
總結(jié)一下:
視圖解析器ViewResolver接口主要作用是解析前端控制器DispatcherServlet傳遞的邏輯視圖名,并將解析結(jié)果的真正的視圖對象View傳回給前端控制器DispatcherServlet
ViewResolverd的實現(xiàn)類:
ViewResolver的UML:
2.5、視圖View
2.5.1、視圖對象的作用
- (1)、將控制器返回的數(shù)據(jù)處理渲染,最終返回客戶端展示給用戶,主要就是完成轉(zhuǎn)發(fā)或者是重定向的操作.。
- (2)、為了實現(xiàn)視圖模型和具體實現(xiàn)技術(shù)的解耦(指的是Spring在org.springframework.web.servlet包中定義的抽象View接口),詳見2.5.2View接口圖。
- (3)、視圖對象View由視圖解析器負(fù)責(zé)實例化。由于視圖是無狀態(tài)(每一次請求都會創(chuàng)建一個新的view對象)的,所以不會有線程安全的問題.
2.5.2、View接口圖
2.5.3、View的實現(xiàn)類圖
2.5.4、View的UML圖
![2021022601-20-01-View-uml(hierarchic group layout)](https://gitee.com/chuchq/blogs-gallery/raw/master/images / 2021/2021022601-20-01-View-uml(hierarchic group layout).png)
2.5.5、常用的View視圖類
視圖類型 |
簡介 |
|
URL視圖資源圖 |
InternalResourceView |
將JSP或其他資源封裝成一個視圖。被視圖解析器 |
JstlView |
InternalResourceView的子類。如果JSP中使用了JSTL的國際化標(biāo)簽,就需要使用該視圖類。 |
|
文檔視圖 |
AbstractExcelView |
Excel文檔視圖的抽象類。 |
AbstractPdfView |
PDF文檔視圖的抽象類 |
|
報表視圖 |
ConfigurableJasperReportsView |
常用的JasperReports報表視圖 |
JasperReportsHtmlView |
||
JasperReportsPdfView |
||
JasperReportsXlsView |
||
JSON視圖 |
MappingJackson2JsonView |
將數(shù)據(jù)通過Jackson框架的ObjectMapper對象,以JSON方式輸出 |
2.6、其他重要的點(diǎn)
2.6.1、DispatcherServlet.properties
DispatcherServlet.properties文件是在SpringMVC架包中:
DispatcherServlet.properties內(nèi)容:
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=
org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=
org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,
org.springframework.web.servlet.function.support.RouterFunctionMapping
org.springframework.web.servlet.HandlerAdapter=
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,
org.springframework.web.servlet.function.support.HandlerFunctionAdapter
org.springframework.web.servlet.HandlerExceptionResolver=
org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=
org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=
org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=
org.springframework.web.servlet.support.SessionFlashMapManager
SpringMVC為什么能加載不同處理器映射器HandlerMapping、處理器適配器handlerAdapter,就是因為框架配置了這個
DispatcherServlet.properties文件。
轉(zhuǎn)載于:
https://www.cnblogs.com/chuchq/p/14489716.html