SpringMVC的运行原理图
SpringMVC
源码分析
DispatcherServlet:
DispatcherServlet
继承结构
![](https://i-blog.csdnimg.cn/blog_migrate/e3400fcfb7f20d844d4b4293a02eb570.png)
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()
方法:
![](https://i-blog.csdnimg.cn/blog_migrate/c7acd53bec387915f037a8d222697ced.png)
如果项目中使用
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
配置文件:
![](https://i-blog.csdnimg.cn/blog_migrate/28e66d58d9bdfd10de0a698fe6825a1d.png)
等等。。。。。。。
DispatcherServlet
ContextRefreshListener
![](https://i-blog.csdnimg.cn/blog_migrate/80354d1c6548839811abc96b785df59a.png)
onRefresh(ApplicationContext context)
:
initStrategies(ApplicationContext context)
:
初始化
SpringMVC
其他组件:如多部件解析器、处理器映射器、处理器适配器、视图
解析器等。
HandlerMapping 接口
初始化
HandlerMapping
initStrategies
![](https://i-blog.csdnimg.cn/blog_migrate/d61044ef256dea7e256a6dbd5abe4c11.png)
initHandlerMappings
![](https://i-blog.csdnimg.cn/blog_migrate/5c592d16c52083d33f370ccb2e0f6a6d.png)
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
![](https://i-blog.csdnimg.cn/blog_migrate/386af776da7b55a059c1d018bf7b87cf.png)
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
接口结构
![](https://i-blog.csdnimg.cn/blog_migrate/0eaf62bb9bf5aeba88c1444015ce782f.png)
AbstractCachingViewResolver
抽象类
AbstractCachingViewResolver
是带有缓存的
ViewResolver
,它每次解析时先从缓存里查找,如果找到视图就返回,没有就创建新的视图,且创建新视图的方法由其子类实现。
resolveViewName
方法
![](https://i-blog.csdnimg.cn/blog_migrate/69c61417a35d2033bdcef86a8106bbe4.png)
createView
方法
通过调用不同的子类中的
loadView
来指定不同视图解析器处理视图。
![](https://i-blog.csdnimg.cn/blog_migrate/124100b5e3fc594a8f21e08ad6b619c2.png)
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
类
![](https://i-blog.csdnimg.cn/blog_migrate/4872244d1d9fd180ed2e70aedf0b1fe4.png)
InternalResourceViewResolver
类
![](https://i-blog.csdnimg.cn/blog_migrate/10aec9e8d87c2e5a175b4e707cdf1f3f.png)
View
接口
视图渲染器,在该接口中定义了渲染视图的抽象方法。
何为渲染:所谓渲染其实就是将
Model
中的数据放到
HttpServletRequest
中传递
jsp
。
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse
response) throws Exception;
接口结构
![](https://i-blog.csdnimg.cn/blog_migrate/f228ad3d22995d66d31a02a501dffc51.png)
InternalResourceView
类
继承自
AbstractUrlBasedView
抽象类的类,表示
JSP
视图
ViewResolver
DispatcherServlet
初始化视图解析器