共计 25975 个字符,预计需要花费 65 分钟才能阅读完成。
SpringMVC 流程及源码剖析
前言
学了一遍 SpringMVC 当前,想着做一个总结,温习一下。温习写上面的总结的时候才发现,其实本人学的并不彻底、牢固、也没有学全,视频跟书本是要联合起来一起,每一位老师的视频可能提到的货色都不统一,也导致也不是很全面,书本上会讲的笔记零碎、全面。同时我本人也是一个初学者,上面总结的可能并不欠缺、正确,心愿看到的大神给我指出,在此非常感谢。
[TOC]
一、Spring 外围模块
1、外围模块
Spring Web MVC(下文简称为 SpringMVC)是 Spring 提供 Web 利用的框架设计,属于体现层的框架。SpringMVC 是 Spring 框架的一部分。
Spring 框架包含大抵六大模块,外围容器(Core Container)、AOP 和设施反对、数据拜访及集成、Web、报文发送、Test
图片来源于 Spring 官网 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 点疑难:
1、不分明为什么在 Spring 官网上 5.0 版本当前,Release 版(稳定版)的都未找到模块图,然而在 M(里程碑版)版找到 了,如果有人在 5.0 当前的 Release 版(稳定版)找到,麻烦给我留个言,谢谢。2、在其余博文中看到 Spring5 模块结构图是这样的:
挺奇怪这个图是哪里来的?(路过的大神请指导)
对于问题 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 曾经是分属于不同的模块了。
- Web Servlet:Spring MVC, WebSocket, SockJS, STOMP Messaging.
- Web Reactive:Spring WebFlux, WebClient, WebSocket.
Spring 官网文档:https://spring.io/projects/spring-framework#learn/
2、Spring 版本命名规定(补充)
下面提到了 Spring 又不同的版本,在此记录一下各个版本的意义。
形容形式 | 阐明 | 含意 |
---|---|---|
Snapshot | 快照版 | 尚不稳固,仍处于开发中的版本 |
Release | 稳定版 | 性能绝对稳固,能够对外发行,但有工夫限度 |
GA | 正式版 | 代表宽泛可用的稳定版(General Availability) |
M | 里程碑版 | (M 是 Milestone 的意思)具备一些全新的性能或是有意义的版本 |
RC | 终测版 | Release Candidate(最终测试),行将作为正式版公布 |
二、SpringMVC 流程及原理
1、执行流程
SpringMVC 执行流程图
<font size=4 color=red> 图片起源:三、援用参考资料 </font>
1.1、执行流程
- 01、用户发送出申请到前端控制器(中央处理器)DispatcherServlet 进行解决。
- 02、前端控制器 DispatcherServlet 收到申请后,调用处理器映射器 HandlerMapping。
- 03、处理器映射器 HandlerMapping(处理器映射器)依据 request 申请的 URL 等信息查找可能进行解决的 Handler,以及相干拦截器 interceptor,并结构 HandlerExecutionChain 执行链,而后将结构好的 HandlerExecutionChain 执行链对象返回给前端控制器 DispatcherServlet。
- 04、前端控制器 DispatcherServlet 依据处理器映射器 HandlerMapping 的
- 05、处理器适配器 HandlerAdapter 通过适配调用具体的处理器(Handler/Controller),即业务中本人写的 Controller。
- 06、Controller 解决完后返回 ModelAndView(springmvc 的封装对象,将 model 和 view 封装在一起)给处理器适配器 HandlerAdapter;
- 07、处理器适配器 HandlerAdapter 将 Controller 执行后果 ModelAndView 返回给前端控制器 DispatcherServlet。
- 08、前端控制器 DispatcherServlet 调用视图解析器 ViewReslover 解决 ModelAndView。
- 09、视图解析器 ViewReslover 解析后依据逻辑视图名解析成物理视图名即具体的页面地址,生成并返回具体对象 View(springmvc 封装对象,是一个接口)。
- 10、前端控制器 DispatcherServlet 依据对象 View 进行视图渲染, 填充 Model。
- 11、前端控制器 DispatcherServlet 向用户返回响应
1.2、执行流程阐明:
1.2.1、第 02、03 阐明
(1) 处理器映射器:springmvc 框架中的一种对象,框架把实现了 HandlerMapping 接口的类都叫做映射器(多个);
(2) 处理器映射器作用: 依据申请,从 springmvc 容器对象中获取处理器对象(MyController controller = ctx.getBean(“some”)
(3) 框架把找到的处理器对象放到一个叫做处理器执行链 (HandlerExecutionChain) 的类保留
(4) HandlerExecutionchain: 类中保留着
a:处理器对象(MyController);
b:我的项目中的所有的拦截器 List<HandlerInterceptor>
(5) 办法调用:HandlerExecutionChain mappedHandler – getHandler (processedRequest);
1.2.2、第 04 阐明
(1) HandlerExecutionChain 执行链找到对应的处理器映射器 HandlerAdapter。
(2) 处理器适配器:springmvc 框架中的对象,须要实现 HandlerAdapter 接口,
(3) 处理器适配器作用:执行处理器办法 (调用 MyController.doSome() 失去返回值 ModelAndView )
(4) 前端控制器中调用适配器:HandlerAdapter ha =getHandlerAdapter (mappedHandler.getHandler());
(5) 执行处理器办法:mv= ha.handle (processedRequest, response, mappedHandler.getHandler());
第 08 阐明:
(1) 视图解析器:springmvc 中的对象,须要实现 ViewResoler 接口(能够有多个)
(2) 视图解析器作用:组成视图残缺门路,应用前缀,后缀。并创立 View 对象。
(3) view 是一个接口,示意视图的,在框架中 jsp,htm1 不是 string 示意,而是应用 view 和他的实现类示意视图。
InternalResourceview:视图类,示意 jsp 文件,视图解析器会创立 InternalResourceView 类对象。这个对象的外面,有一个属性 url-/WEB-INF/view/show.jsp
1.2.2、SpringMVC 组件阐明
- (1). 前端控制器(DispatcherServlet):接管申请,响应后果,相当于电脑的 CPU。
- (2). 处理器映射器(HandlerMapping):依据 URL 去查找处理器.
- (3). 处理器(Handler):(须要程序员去写代码解决逻辑的).
- (4). 处理器适配器(HandlerAdapter):会把处理器包装成适配器,这样就能够反对多种类型的处理器,类比笔记本的适配器(适配器模式的利用).
- (5). 视图解析器(ViewResovler):进行视图解析,多返回的字符串,进行解决,能够解析成对应的页面.
1.2.3、SpringMVC 具体流程图
综上所述,总结下 SpringMVC 的具体流程图:
<font size=4 color=red> 图片起源:三、援用参考资料 </font>
二、源码剖析
以下源码起源 jar 包:spring-webmvc-5.25.RELEASE.jar
1、初始化
1.1、ApplicationContext
ApplicationContext 初始化入口类:ApplicationObjectSupport 的 setApplicationContext 办法,setApplicationContext 办法中外围局部就是初始化容器 initApplicationContext(context),子类 AbstractDetectingUrlHandlerMapping 实现了该办法。
类图:
UML 图:
RequestMappingHandlerMapping , 用于注解 @Controller,@RequestMapping 来定义 controller.
初始化时,3 个类的大抵分工如下:
- AbstractHandlerMethodMapping 定义整个算法流程;
- RequestMappingInfoHandlerMapping 提供匹配条件 RequestMappingInfo 的解析解决;
- RequestMappingHandlerMapping 依据 @RequestMapping 注解生成 RequestMappingInfo, 同时提供 isHandler 实现
2、前端控制器(中央处理器)DistepcherServlet
从下面的流程图能够看到前端控制器(中央处理器)DistepcherServlet 是 SpringMVC 外围,查看 DistepcherServlet 类的继承状况。
UML 图:
从继承关系看出:
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 申请,判断以后申请是否是 PATCH 申请,不是的就调用父类的 servic()办法,掉用父类中的 service 办法就是去调用该类中 doPost(),doGet()办法,依据不同的申请形式而后走 doPost()或者 doGet(),调用中以 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()又调用 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)办法中最要害的又调用了 doService(request, response);查看 FrameworkServlet 类中的 doService(request, response),或者是调试跟踪可知,doService(request, response)由子类 DispatcherServlet 实现。
源码起源:
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()办法中最终调用 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 {
// 文件上传相干,判断是不是二进制申请
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获得解决以后申请的 controller, 这里也称为 hanlder 处理器, 第一个步骤的意义就在这里体现了. 这里并不是间接返回 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;}
}
// 处理器适配器执行之前,查看拦截器的办法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}
// 处理器适配器依据找到,执行 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()要害代码:
HandlerExecutionChain mappedHandler = null;
mappedHandler = getHandler(processedRequest);
mappedHandler 是一个执行链 HandlerExecutionChain 对象,这里封装了 handler 和拦截器 interceptors,getHandler(processedRequest)办法就是从处理器映射器 HandlerMapping 中找到 url 和 controller 的对应关系,并返回给前端控制器 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;
}
调试代码如下:
从代码调试中能够看到 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 有不同的实现:
- 1、xml 形式
- 2、注解形式
接着看 getHandler(HttpServletRequest request)办法,先遍历 HandlerMappers,查找控制器找到之后就返回执行链 HandlerExecutionChain 类型的 Handler。
能够看到返回的 Handler 中,拿到的就是咱们本人编码的 Controller 类,以及拦截器(演示我的项目中未编写,所以调试汇总返回的 Handler 最初是 0 interceptors)
HandlerExecutionChain with [com.bjpowernode.controller.MyController#doSome()] and 0 interceptors
将正在调试的 idea 关上本人编写的 Controller 来对照,发现统一:
2.2、依据处理器映射器 HandlerMapping 返回后果调用处理器适配器 HandlerAdapter
doDispatch()外面的要害代码:
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 提供了不通的处理器适配器。
调试如下:
查看 DEBUG 调试模式中 getHandlerAdapter()办法在中的:
handler、adapter、this.handlerAdapters
以下是拷贝的后果:
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()中的要害代码:
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 执行 Handler(Controller)返回 ModelAndView
doDispatch()中的要害代码:
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
DEBUG 模式调试,是跳到了:
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 执行 Handler(Controller)并将后果 ModelAndView 返回给前端控制器 DistepchServlet
2.4、视图解析器 ViewResolver
接上 2.3:前端控制器 DistepchServlet 接管到处理器适配器 HandlerAdapter 返回的 ModelAndView 当前,这里分 2 种状况:
- (1)、如果 ModelAndView 外面是逻辑视图
前端控制器 DistepchServlet 调用视图解析器 ViewResolver 通过逻辑视图查找真正的视图对象 View,并返回给前端控制器 DistepchServlet。
- (2)、如果 ModelAndView 外面是非逻辑视图:
如:MappingJackson2JsonView(把以后数据转为为 JSON 数据,并不需要对视图逻辑名称进行转换)
总结一下:
视图解析器 ViewResolver 接口次要作用是解析前端控制器 DispatcherServlet 传递的逻辑视图名,并将解析后果的真正的视图对象 View 传回给前端控制器 DispatcherServlet
ViewResolverd 的实现类:
ViewResolver 的 UML:
2.5、视图 View
2.5.1、视图对象的作用
- (1)、将控制器返回的数据处理渲染,最终返回客户端展现给用户,次要就是实现转发或者是重定向的操作.。
- (2)、为了实现视图模型和具体实现技术的解耦(指的是 Spring 在 org.springframework.web.servlet 包中定义的形象 View 接口),详见 2.5.2View 接口图。
- (3)、视图对象 View 由视图解析器负责实例化。因为视图是无状态(每一次申请都会创立一个新的 view 对象)的,所以不会有线程平安的问题.
2.5.2、View 接口图
2.5.3、View 的实现类图
2.5.4、View 的 UML 图
.png)
2.5.5、罕用的 View 视图类
视图类型 | 简介 | |
URL 视图资源图 | InternalResourceView | 将 JSP 或其余资源封装成一个视图。被视图解析器 InternalResourceViewResolver 默认应用。 |
JstlView | InternalResourceView 的子类。如果 JSP 中应用了 JSTL 的国际化标签,就须要应用该视图类。 | |
文档视图 | AbstractExcelView | Excel 文档视图的抽象类。 |
AbstractPdfView | PDF 文档视图的抽象类 | |
报表视图 | ConfigurableJasperReportsView | 罕用的 JasperReports 报表视图 |
JasperReportsHtmlView | ||
JasperReportsPdfView | ||
JasperReportsXlsView | ||
JSON 视图 | MappingJackson2JsonView | 将数据通过 Jackson 框架的 ObjectMapper 对象,以 JSON 形式输入 |
2.6、其余重要的点
2.6.1、DispatcherServlet.properties
DispatcherServlet.properties 文件是在 SpringMVC 架包中:
DispatcherServlet.properties 内容:
# 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 文件。
三、援用参考资料
1、援用材料
- SpringMVC 流程图援用地址:https://www.iqiyi.com/w_19s2gmyazh.html
- SpringMVC 流程图援用地址 2:https://blog.csdn.net/win7system/article/details/90674757
- View 视图作用援用地址:https://blog.csdn.net/qq_43193797/article/details/84928603
- Spring 官网文档:https://spring.io/projects/spring-framework#learn/
在写此文的时候可能还有少部分是参考了其余材料,然而整顿的时候我曾经找不到原文出处了,如果原文作者看到,请及时分割我,我在文章中加上援用出处,谢谢!
2、参考资料
- 参考:w3cschool-Spring MVC 4.2.4.RELEASE 中文文档:
https://www.w3cschool.cn/spring_mvc_documentation_linesh_translation/
- 参考:https://www.cnblogs.com/leftthen/category/790002.html
免责申明:
本文中应用的局部图片来自于网络(地址见:三、援用参考资料),如有侵权, 请分割博主进行删除。
转载申明:
** 写博客不易,请尊重原作者!!**
欢送大家浏览、转载,如果是 ** 整文转载 ** 请在文章结尾或者结尾处 ** 注明 原文地址、作者 **,如果是 ** 大段参考 ** 请 ** 备注 参考链接 **。