首页 » PHP教程 » phpspringmvc技巧_SpringMVC流程及源码分析

phpspringmvc技巧_SpringMVC流程及源码分析

访客 2024-11-19 0

扫一扫用手机浏览

文章目录 [+]

学了一遍SpringMVC往后,想着做一个总结,复习一下。
复习写下面的总结的时候才创造,实在自己学得并不彻底、稳定、也没有学全,视频跟书本是要结合起来一起,每一位老师的视频可能提到的东西都不一致,也导致也不是很全面,书本上会讲的条记系统、全面。
同时我自己也是一个初学者,下面总结的可能并不完善、精确,希望看到的大神给我指出,在此非常感谢。

目录

phpspringmvc技巧_SpringMVC流程及源码分析

SpringMVC流程及源码剖析一 、Spring核心模块1、核心模块2、Spring版本命名规则(补充)二、SpringMVC流程及事理1、实行流程1.1、实行流程1.2、实行流程解释:1.2.1、第02、03解释1.2.2、第04解释1.2.2、SpringMVC组件解释1.2.3、SpringMVC详细流程图二、源码剖析1、初始化1.1、ApplicationContext2、前端掌握器(中心处理器)DistepcherServlet2.1、查找处理器映射器HandlerMapping2.2、根据处理器映射器HandlerMapping返回结果调用处理器适配器HandlerAdapter2.3、检讨拦截器Interceptor2.3、处理器适配器HandlerAdapter实行Handler(Controller)返回ModelAndView2.4、视图解析器ViewResolver2.5、视图View2.5.1、视图工具的浸染2.5.2、View接口图2.5.3、View的实现类图2.5.4、View的UML图2.5.5、常用的View视图类2.6、其他主要的点2.6.1、DispatcherServlet.properties三、引用参考资料1、引用资料2、参考资料一 、Spring核心模块1、核心模块

Spring Web MVC (下文简称为 SpringMVC )是 Spring 供应 Web 运用的框架设计,属于表现层的框架。
SpringMVC是Spring框架的一部分。
Spring框架包括大致六大模块,核心容器(Core Container)、AOP和设备支持、数据访问及集成、Web、报文发送、Test

phpspringmvc技巧_SpringMVC流程及源码分析
(图片来自网络侵删)

图片来源于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实行流程图

图片来源:三、引用参考资料

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

(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的详细流程图:

图片来源:三、引用参考资料

二、源码剖析

以下源码来源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图:![2021022601-08-DispatcherServlet UML图](https://gitee.com/chuchq/blogs-gallery/raw/master/images / 2021/2021022601-08-DispatcherServlet UML图.png)从继续关系看出:​ 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. /@Overrideprotected 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 /@Overrideprotected 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. /@Overrideprotected 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为空,则返回404if (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 afterCompletionif (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 /@Nullableprotected 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@Nullablepublic 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

@Overrideprotected 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 necessarymav = 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、视图View2.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图

![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或其他资源封装成一个视图。
被视图解析器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.AcceptHeaderLocaleResolverorg.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolverorg.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\org.springframework.web.servlet.function.support.RouterFunctionMappingorg.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.HandlerFunctionAdapterorg.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.DefaultHandlerExceptionResolverorg.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslatororg.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolverorg.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

SpringMVC为什么能加载不同处理器映射器HandlerMapping、处理器适配器handlerAdapter,便是由于框架配置了这个DispatcherServlet.properties文件。

转载于:https://www.cnblogs.com/chuchq/p/14489716.html

相关文章

Java代码虚拟化保护技术与应用前景

软件应用的需求日益增长,软件开发过程中对代码的保护成为了一个重要议题。Java作为一种广泛应用于企业级应用的编程语言,其代码虚拟化...

PHP教程 2025-03-02 阅读1 评论0

CAD插件错误代码与应对步骤

CAD(计算机辅助设计)软件在工程设计领域得到了广泛应用。CAD插件作为提升设计效率的重要工具,在提高设计师工作效率的也带来了一定...

PHP教程 2025-03-02 阅读1 评论0

上古卷轴代码规则大全游戏背后的编程奥秘

《上古卷轴》作为一款深受玩家喜爱的角色扮演游戏,自问世以来便以其丰富的世界观、独特的游戏体验和深厚的文化底蕴吸引了无数玩家。在这款...

PHP教程 2025-03-02 阅读1 评论0