一、回顾 SpringMVC 原理
二、 SpringMVC 源码分析
1 DispatcherServlet
1.1 DispatcherServlet 继承结构
1.1.1 HttpServletBean
HttpServletBean 覆写了 init 方法,主要做一些初始化的工作,将 web.xml 中配置的参数设置到 Servlet 中。比如 servlet 标签的子标签 init-param 标签中配置的参数
1.1.1.1 ServletConfigPropertyValues :
ServletConfigPropertyValues 是 HttpServletBean 的静态内部类。在其构造方法中通过传递的 ServletConfig 对象对 web.xml 文件中的 DispatcherServlet 节点中的参数进行解析处理。
1.1.1.2 BeanWrapper bw=PropertyAccessorFactory.forBeanPropertyAccess(this) :
将 HttpServletBean 类型转换为 BeanWrapper 类型,从而能对 init-parameter 的值进行注入。
1.1.1.3 bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader,getEnvironment())) :
注册自定义属性编辑器,遇到 Resource 类型的属性将会使用 ResourceEditor 进行解析
1.1.1.4 initBeanWrapper(bw) :
该方法并未做什么,为了留给子类覆盖。
1.1.1.5 bw.setPropertyValues(pvs, true) :
设置 DispatcherServlet 属性
1.1.1.6 initServletBean() :
调用在 FrameworkServlet 中覆盖的该方法
1.1.2 FrameworkServlet
将 Servlet 上下文与 Spring 容器上下文关联。其实也就是初始化 FrameworkServlet 的属性 webApplicationContext , 这 个 属 性 代 表 SpringMVC 上 下 文 对 象 , 实 际 类 型ConfigurableWebApplicationContext。如果项目中用到 spring 了那么它有个父容器,既 web.xml中配置的 ContextLoaderListener 监听器初始化的容器上下文
1.1.2.1 this.webApplicationContext =initWebApplicationContext():
可以看到,最重要的就是 this.webApplicationContext = initWebApplicationContext();这段代码,这个方法的作用是创建或刷新 WebApplicationContext 实例。如果项目中使用到了 spring,则进行父子容器关联。
1.1.2.2 initWebApplicationContext() 方法:
获取 spring 框架的根容器
如果项目中使用 spring 框架,并且在 web.xml 文件中配置了 Listener 来启动 spring。那么在监 听器中 spring 会创建 WebApplicationContext 容器。 此时会将 该容器转换 为ConfigurableWebApplicationContext 即 SpringMVC 容器。
如果没有在 web.mxl 文件中配置 Listener 那么此时 webApplicationContext为 空 则 去 ServletContext 中 根 据 attrname 查 找 。 如 果 为 找 到 , 执 行createWebApplicationContext 方法来创建 SpringMVC 的容器。
1.1.2.3 createWebApplicationContext(rootContext) :
1.1.2.4 createWebApplicationContext(ApplicationContext parent) :
1.1.2.5 configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) :
1.1.2.6 refresh() :
解析配置文件初始化 SpringMVC 的 IOC 容器环境。
解析 springmvc 配置文件:
初始化所有的 Bean 对象
解析命名空间
1.1.3DispatcherServlet
1.1.3.1 ContextRefreshListener
1.1.3.2 onRefresh(ApplicationContext context) :
1.1.3.3 initStrategies(ApplicationContext context) :
初始化 SpringMVC 其他组件:如多部件解析器、处理器映射器、处理器适配器、视图解析器等。
1.2 Debug 走读 DispatcherServlet
2 HandlerMapping 接口
2.1 初始化 HandlerMapping
2.1.1 initStrategies
2.1.2 initHandlerMappings
2.2 HandlerMapping 接口介绍
作用是根据当前请求的找到对应的 Handler(HandlerMethod(Controller 中的方法)、Controller 对 象 ) , 并 将 Handler 与 一 堆 HandlerInterceptor ( 拦 截 器 ) 封 装 到HandlerExecutionChain 对象中。在 HandlerMapping 接口的内部只有一个方法:HandlerExecutionChain getHandler(HttpServletRequest request);
2.3 HandlerMapping 接口实现类
HandlerMapping 实现类有两个分支,分别继承自 AbstractHandlerMethodMapping(得到 HandlerMethod)和 AbstractUrlHandlerMapping(得到 Controller t),它们又统一继承于AbstractHandlerMapping。
2.3.1 AbstractHandlerMapping 抽象类
它实现了 HandlerMapping 接口中的 getHandler() 方法
2.3.1.1 AbstractHandlerMethodMapping
AbstractHandlerMethodMapping 这个分支获取的 Handler 的类型是 HandlerMethod,即这个 Handler 是一个方法,它保存了方法的信息(如 Method),这样一个 Controller 就可以处理多个请求了。
上述代码中 lookupHandlerMethod() 方法主要工作是在 Map<T, HandlerMethod> handlerMethods 中找到 HandlerMethod,这里的 T 是 HandlerMappingInfo,它封装了@RequestMapping 注解中的信息。
2.3.1.2 AbstractUrlHandlerMapping 抽象类
AbstractUrlHandlerMapping 这个分支获取的 Handler 的类型实际就是一个 Controller类。
2.4 Debug 走读 HandlerMapping
3 HandlerAdapter 接口
SpringMVC 中使用适配器模式来解决不同的 Handler 的执行。根据 Handler 来找到支持它的 HandlerAdapter,通过 HandlerAdapter 执行这个 Handler 得到 ModelAndView 对象。
3.1 接口中的抽象方法
boolean supports(Object handler); 判断是否支持传入的 Handler
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) 用来使用 Handler 处理请求
long getLastModified(HttpServletRequest request, Object handler); 用 来 获 取 资 料 的Last-Modified 值
3.2HandlerAdapter 继承结构
3.3 AbstractHandlerMethodAdapter 抽象类
利用 RequestMappingHandlerMapping 获取的 Handler 是 HadnlerMethod 类型,它代表 Controller 里要执行的方法。handlerInternal 是子类 RequestMappingHandlerAdapter 中的方法。
3.4 RequestMappingHandlerAdapter 类
RequestMappingHandlerAdapter 实际就是执行@RequestMapping 注解的方法
3.4.1 handleInternal 方法
在 handlerInternal 方法中通过调用 invokeHandleMethod 方法执行 HandlerMethod 并返回一个 ModelAndView。
3.4.2 invokeHandleMethod 方法
3.5 HttpRequestHandlerAdapter 类
HttpRequestHandlerAdapter 。 是 HttpRequestHandler 的 适 配 器 可 以 执 行
HttpRequestHandler 类型的 Handler。其实就是 Controller 中的 handleRequest 方法
3.6 SimpleControllerHandlerAdapter 类
SimpleControllerHandlerAdapter 是 Controller 实现类的适配器类,其本质也是执行Controller 中的 handleRequest 方法。
3.7 SimpleServletHandlerAdapter 类
SimpleServletHandlerAdapter 其实是一个 Servlet 的适配器,其最终执行的方法是 Servlet的 service 方法
3.8 Debug 走读 DispatcherServlet 中初始化处理器适配器
3.8.1 在配置文件中配置<mvc:annotation-driven />
{org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter# 0=org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter@4e afea11, org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter=org.springframework.we b.servlet.mvc.HttpRequestHandlerAdapter@1a4d6190, org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter=org.springframewor k.web.servlet.mvc.SimpleControllerHandlerAdapter@710d6556} |
3.8.2 未在配置文件中配置<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] |
4 ViewResolver 接口
根据视图的名称将其解析为 View 类型的视图,如通过 ModelAndView 中的视图名称将其解析成 View,View 是用来渲染页面的,也就是将 Model 填入模板中,生成 html 或其他格式的文件。
4.1 接口中抽象方法
View resolveViewName(String viewName, Locale locale) throws Exception;
4.2 ViewResolver 接口结构
4.3 AbstractCachingViewResolver 抽象类
AbstractCachingViewResolver 是带有缓存的 ViewResolver,它每次解析时先从缓存里查找,如果找到视图就返回,没有就创建新的视图,且创建新视图的方法由其子类实现。
4.3.1 resolveViewName 方法
4.3.2 createView 方法
通过调用不同的子类中的 loadView 来指定不同视图解析器处理视图。
4.4 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");
4.5 XmlViewResolver 类
XmlViewResolver 根据 xml 文件来解析视图
<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");
4.6 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>
4.7 InternalResourceViewResolver 类
InternalResourceViewResolver 是 UrlBasedViewResolver 的 子 类 , 将InternalResourceView 作为默认的 View 类,但如果当前 classpath 中有 jstl 的 jar 包时则使用 JstlView 作为 view 来渲染。
4.7.1 UrlBasedViewResolver 类
4.7.2 InternalResourceViewResolver 类
5 View 接口
视图渲染器,在该接口中定义了渲染视图的抽象方法。
何为渲染:所谓渲染其实就是将 Model 中的数据放到 HttpServletRequest 中传递 jsp。
void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
5.1 接口结构
5.2 InternalResourceView 类
继承自 AbstractUrlBasedView 抽象类的类,表示 JSP 视图