SpringMVC 源码分析
SpringMVC的运行原理图

SpringMVC 源码分析
DispatcherServlet:
DispatcherServlet 继承结构

HttpServletBean
HttpServletBean 覆写了 init 方法,主要做一些初始化的工作,将 web.xml 中配置的参数设置到 Servlet 中。比如 servlet 标签的子标签 init-param 标签中配置的参数

ServletConfigPropertyValues:
ServletConfigPropertyValues 是 HttpServletBean 的静态内部类。在其构造方法中通过传递的 ServletConfig 对象对 web.xml 文件中的 DispatcherServlet 节点中的参数进行解析处理。
BeanWrapper bw=PropertyAccessorFactory.forBeanPropertyAccess(this):
将 HttpServletBean 类型转换为 BeanWrapper 类型,从而能对 init-parameter 的值进行注入。
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())):
注册自定义属性编辑器,遇到 Resource 类型的属性将会使用 ResourceEditor 进行解析
initBeanWrapper(bw):
该方法并未做什么,为了留给子类覆盖。
bw.setPropertyValues(pvs, true):
设置 DispatcherServlet 属性
initServletBean():
调用在 FrameworkServlet 中覆盖的该方法
FrameworkServlet
将Servlet上下文与Spring容器上下文关联。其实也就是初始化FrameworkServlet的属性webApplicationContext,这个属性代表SpringMVC上下文对象 , 实际类型ConfigurableWebApplicationContext。如果项目中用到spring了那么它有个父容器,既web.xml中配置的ContextLoaderListener监听器初始化的容器上下文

this.webApplicationContext =initWebApplicationContext():
可以看到,最重要的就是 this.webApplicationContext = initWebApplicationContext();这段代码,这个方法的作用是创建或刷新 WebApplicationContext 实例。如果项目中使用到了 spring,则进行父子容器关联。
initWebApplicationContext()方法:


如果项目中使用 spring 框架,并且在 web.xml 文件中配置了 Listener 来启动 spring。那么 在 监 听 器 中 spring 会 创 建 WebApplicationContext容器 。此时会将该容器转换为ConfigurableWebApplicationContext 即 SpringMVC 容器。

如果没有在 web.mxl 文件中配置 Listener 那么此时 webApplicationContext为 空 则 去 ServletContext 中 根 据 attrname 查 找 。 如 果 为 找 到 , 执 行 createWebApplicationContext 方法来创建 SpringMVC 的容器。
createWebApplicationContext(rootContext):

createWebApplicationContext(ApplicationContext parent):

configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac):

refresh():
解析配置文件初始化 SpringMVC 的 IOC 容器环境。
解析 springmvc 配置文件:






等等。。。。。。。
DispatcherServlet
ContextRefreshListener

onRefresh(ApplicationContext context):

initStrategies(ApplicationContext context):
初始化 SpringMVC 其他组件:如多部件解析器、处理器映射器、处理器适配器、视图解析器等。

HandlerMapping 接口
初始化 HandlerMapping
initStrategies

initHandlerMappings


HandlerMapping 接口介绍
作用是根据当前请求的找到对应的 Handler(HandlerMethod(Controller中的方法)、Controller对象) ,并将Handler与一堆 HandlerInterceptor ( 拦 截 器 ) 封 装 到HandlerExecutionChain 对象中。在HandlerMapping 接口的内部只有一个方法:
HandlerExecutionChain getHandler(HttpServletRequest request);
HandlerMapping 接口实现类
HandlerMapping 实现类有两个分支,分别继承自 AbstractHandlerMethodMapping(得到 HandlerMethod)和 AbstractUrlHandlerMapping(得到 Controller t),它们又统一继承于AbstractHandlerMapping。

AbstractHandlerMapping 抽象类
它实现了 HandlerMapping 接口中的 getHandler() 方法

AbstractHandlerMethodMapping
AbstractHandlerMethodMapping 这个分支获取的 Handler 的类型是 HandlerMethod,即这个 Handler 是一个方法,它保存了方法的信息(如 Method),这样一个 Controller 就可以处理多个请求了。

上 述 代 码 中 lookupHandlerMethod() 方 法 主 要 工 作 是 在 Map<T, HandlerMethod> handlerMethods 中找到 HandlerMethod,这里的 T 是 HandlerMappingInfo,它封装了@RequestMapping 注解中的信息。
AbstractUrlHandlerMapping 抽象类
AbstractUrlHandlerMapping 这个分支获取的 Handler 的类型实际就是一个 Controller类。

Debug 走读 HandlerMapping

HandlerAdapter 接口
SpringMVC 中使用适配器模式来解决不同的 Handler 的执行。根据 Handler 来找到支持它的 HandlerAdapter,通过 HandlerAdapter 执行这个 Handler 得到 ModelAndView 对象。
接口中的抽象方法
boolean supports(Object handler); 判断是否支持传入的 HandlerModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) 用来使用 Handler 处理请求
long getLastModified(HttpServletRequest request, Object handler); 用 来 获 取 资 料 的Last-Modified 值
HandlerAdapter 继承结构

AbstractHandlerMethodAdapter 抽象类

RequestMappingHandlerAdapter 类
RequestMappingHandlerAdapter 实际就是执行@RequestMapping 注解的方法
handleInternal 方法
在 handlerInternal 方法中通过调用 invokeHandleMethod 方法执行 HandlerMethod 并返回一个 ModelAndView。

invokeHandleMethod 方法

HttpRequestHandlerAdapter 类
HttpRequestHandlerAdapter 。是HttpRequestHandler的适配器可以执行HttpRequestHandler 类型的 Handler。其实就是 Controller中的handleRequest方法

SimpleControllerHandlerAdapter 类
SimpleControllerHandlerAdapter 是 Controller 实现类的适配器类,其本质也是执行Controller 中的 handleRequest 方法。

SimpleServletHandlerAdapter 类
SimpleServletHandlerAdapter 其实是一个 Servlet 的适配器,其最终执行的方法是 Servlet的 service 方法

DispatcherServlet 中初始化处理器适配器
在配置文件中配置<mvc:annotation-driven />

未在配置文件中配置<mvc:annotation-driven />
[org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter@508cddf9,
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter@688a3991, org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter@6f15d 959]
ViewResolver 接口
根据视图的名称将其解析为 View 类型的视图,如通过 ModelAndView 中的视图名称将其解析成 View,View 是用来渲染页面的,也就是将 Model 填入模板中,生成 html 或其他格式的文件。
接口中抽象方法
View resolveViewName(String viewName, Locale locale) throws Exception;
ViewResolver 接口结构

AbstractCachingViewResolver 抽象类
AbstractCachingViewResolver 是带有缓存的 ViewResolver,它每次解析时先从缓存里查找,如果找到视图就返回,没有就创建新的视图,且创建新视图的方法由其子类实现。
resolveViewName 方法

createView 方法
通过调用不同的子类中的 loadView 来指定不同视图解析器处理视图。

ResourceBundleViewResolver 类
ResourceBundleViewResolver 根据 views.properties 文件来解析视图,这个文件应位于classpath 路径下
<bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<!-- 设定属性文件名为 views -->
<property name="basename" value="views">
</property>
</bean>
user.(class)=org.springframework.web.servlet.view.JstlView
user.url=/WEB-INF/jsp/user.jsp
ModelAndView mv = new ModelAndView("user","msg", "aaa");

XmlViewResolver 类
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="location">
<value>spring-views.xml</value>
</property>
</bean>
<bean id="internalResource" class="org.springframework.web.servlet.view.JstlView">
<property name="url" value="/index.jsp" />
</bean>
ModelAndView mv = new ModelAndView("internalResource","msg", "aaa");

UrlBasedViewResolver 类
UrlBasedViewResolver 提供了拼接 URL 的方式来解析视图,通过 prefix 属性拼接一个前缀,通过 suffix 属性拼接一个后缀,就得到了视图的 URL。还可以加入 redirect: 与forword: 前缀,使用 redirect: 前缀会调用 HttpServletResponse 对象sendRedirect() 方法进行重定向,使用 forword: 前缀会利用 RequestDispatcher 的 forword 方式跳转到指定的地址。另外,使用时还要指定viewClass 属性,表示要解析成哪种 View。
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jsp" />
<property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView" />
</bean>

InternalResourceViewResolver 类
InternalResourceViewResolver 是 UrlBasedViewResolver 的 子 类 , 将InternalResourceView 作为默认的 View 类,但如果当前 classpath 中有 jstl 的 jar 包时则使用 JstlView 作为 view 来渲染。
UrlBasedViewResolver 类

InternalResourceViewResolver 类

View 接口
视图渲染器,在该接口中定义了渲染视图的抽象方法。
何为渲染:所谓渲染其实就是将 Model 中的数据放到 HttpServletRequest 中传递 jsp。
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
接口结构

InternalResourceView 类
继承自 AbstractUrlBasedView 抽象类的类,表示 JSP 视图
ViewResolver
DispatcherServlet 初始化视图解析器


浙公网安备 33010602011771号