SpringMVC源码解析
xml配置文件版
0. 准备阶段
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<!-- spring主配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-config/spring-*.xml</param-value>
</context-param>
<!-- 配置监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置中央调度器 -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-config/springmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 配置字符集过滤器 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
springmvc-config.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<!-- 静态资源处理器 -->
<mvc:default-servlet-handler/>
<!-- 配置注解驱动 -->
<mvc:annotation-driven/>
<!-- controller扫描器 -->
<context:component-scan base-package="com.tca.springmvc.learning.controller"/>
</beans>
controller
/**
* @author zhouan
* @Date 2021/6/7
*/
@Controller
@RequestMapping("/hello")
public class HelloController {
@GetMapping("/test")
@ResponseBody
public String test() {
return String.valueOf(System.currentTimeMillis());
}
@RequestMapping("/message")
@ResponseBody
public String message(@RequestBody JSONObject request) {
System.out.println("收到消息: " + request.toJSONString());
return "ok";
}
}
1.java web基础
1.1 启动原理
1.web容器(如tomcat)启动时, 会根据tomcat的配置文件读取项目的web.xml配置文件, web.xml配置文件中主要涉及的标签有:
<context-param>、<listener>、<fileter>、<servlet>
加载的顺序是: <context-param>、<listener>、<fileter>、<servlet>
2.web容器启动时(如tomcat), 首先加载依赖的jar, 然后读取web.xml文件, 创建ServletContext, 容器会将context-param的配置以key-value键值对形式传给servletContext, 并且实例化<listener>标签中配置的类, 然后初始化Filter和Servlet
3.我们在springmvc工程中配置的<listener>为org.springframework.web.context.ContextLoaderListener, 它实现了ServletContextListener接口, 这个接口用于监听web容器的开启和关闭, 并有对应方法进行回调
1.2 ServletContextListener
public interface ServletContextListener extends EventListener {
/**
** Notification that the web application initialization
** process is starting.
** All ServletContextListeners are notified of context
** initialization before any filter or servlet in the web
** application is initialized.
*/
public void contextInitialized ( ServletContextEvent sce );
/**
** Notification that the servlet context is about to be shut down.
** All servlets and filters have been destroy()ed before any
** ServletContextListeners are notified of context
** destruction.
*/
public void contextDestroyed ( ServletContextEvent sce );
}
这个接口提供了两个方法,分别用来监听web容器启动和关闭进行回调,可以看到:contextInitialized的执行顺序优先于filter和servlet的初始化!
2.ContextLoaderListener
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public ContextLoaderListener() {
}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
/**
* Initialize the root web application context.
*/
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
/**
* Close the root web application context.
*/
@Override
public void contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
2.1ContextLoaderListener#contextInitialized(ServletContextEvent event)
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
2.2 ContextLoader#initWebApplicationContext(ServletContext servletContext)
/**
* Initialize Spring's web application context for the given servlet context,
* using the application context provided at construction time, or creating a new one
* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
* "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
* @param servletContext current servlet context
* @return the new WebApplicationContext
* @see #ContextLoader(WebApplicationContext)
* @see #CONTEXT_CLASS_PARAM
* @see #CONFIG_LOCATION_PARAM
*/
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
// 1.判断servletContext中是否已有ROOT
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
// 2.判断是否有WebApplicationContext实例, 如果没有需要创建
if (this.context == null) {
// 3.创建WebApplicationContext, 这里是 XmlWebApplicationContext, 这里仅仅是创建父容器, 并没有进行配置和启动
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
// 4.进入
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
// 5.容器如果没有启动
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
// 6.父容器为null
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
// 7.设置父容器为null
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
// 8.封装容器XmlWebApplicationContext, 并启动容器refresh()方法
// 这个方法会对父容器 XmlWebApplicationContext 进行配置并启动, 配置中包括读取ServletContext的初始化参数:contextConfigLocation, 这个参数对应的value, 在web.xml文件中的开头就进行了配置: <context-param>, value为: classpath:spring-config/spring-*.xml, 即为父容器的主配置文件!!!
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
// 9.将spring容器设为servletContext的ROOT属性
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
// 10.这里的ClassLoader是 WebAppClassLoader
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
// 11.返回当前容器
return this.context;
}
catch (RuntimeException ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
catch (Error err) {
logger.error("Context initialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
}
总结
1.web容器(如tomcat)启动时, 创建ServletContext对象, 作为web容器Servlet上下文, 同时去加载web.xml文件
2.web.xml文件中配置了<listener>监听器, 其实现类为ContextLoaderListener, 用于监听web容器的开启和关闭, 因此web容器启动时会回调ContextLoaderListener#initWebApplicationContext(ServletContext servletContext)方法, 该方法用于创建一个XmlWebApplicationContext的spring-web容器, 并将其作为ServletContext的一个属性, 属性为ROOT
问题
1.父容器的作用是什么? 为什么需要设置父子容器?
3.FrameworkServlet
想要了解另一个核心类DispatcherServlet,需要先熟悉其父类FrameworkServlet
3.1 结构图
可以看到,其继承了HttpServletBean,同时实现了ApplicationContextAware接口
3.2 初始化
3.2.1 流程
step1:web容器在实例化servlet时会调用Servlet的init(ServletConfig)方法,由Servlet子类GenericServlet实现了该方法,因而最终会调用GenericServlet.init(ServletConfig)方法。
GenericServlet#init(ServletConfig)
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
step2:调用init()方法,init()方法由GenericServlet的子类HttpServletBean实现,实际上是执行了HttpServletBean.init()方法
HttpServletBean#init()
@Override
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
// Set bean properties from init parameters.
try {
// 1.获取web.xml中 DispatcherServlet的<init-param>参数配置, contextConfigLocation -- classpath:spring-config/springmvc-config.xml
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
// Let subclasses do whatever initialization they like.
// 2.调用子类方法
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
step3 上述中调用了HttpServletBean.init()方法,这个方法中调用了initServletBean()方法,这个方法由子类FrameworkServlet实现
FrameworkServlet#initServletBean()
@Override
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis();
try {
// 1.创建并初始化子容器
this.webApplicationContext = initWebApplicationContext();
// 2.空实现
initFrameworkServlet();
}
catch (ServletException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
catch (RuntimeException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
if (this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
elapsedTime + " ms");
}
}
FrameworkServlet#initWebApplicationContext()
protected WebApplicationContext initWebApplicationContext() {
// 1.获取Root的 XmlWebApplicationContext, 这里是从servletContext中获取ContextLoaderListener中创建的 webApplicationContext
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
// 2.为空, 跳过
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
// 3.wac == null, 子容器没有创建
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
// 4.创建子容器, 并启动
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
onRefresh(wac);
}
// 5.进入
if (this.publishContext) {
// Publish the context as a servlet context attribute.
// 6.创建完子容器后, 将子容器也存储到servletContext的属性中
// (org.springframework.web.servlet.FrameworkServlet.CONTEXT.springMVC --> 子容器)
// ("org.springframework.web.context.WebApplicationContext.ROOT" -> 父容器)
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
FrameworkServlet#createWebApplicationContext(ApplicationContext parent)
/**
* Instantiate the WebApplicationContext for this servlet, either a default
* {@link org.springframework.web.context.support.XmlWebApplicationContext}
* or a {@link #setContextClass custom context class}, if set.
* <p>This implementation expects custom contexts to implement the
* {@link org.springframework.web.context.ConfigurableWebApplicationContext}
* interface. Can be overridden in subclasses.
* <p>Do not forget to register this servlet instance as application listener on the
* created context (for triggering its {@link #onRefresh callback}, and to call
* {@link org.springframework.context.ConfigurableApplicationContext#refresh()}
* before returning the context instance.
* @param parent the parent ApplicationContext to use, or {@code null} if none
* @return the WebApplicationContext for this servlet
* @see org.springframework.web.context.support.XmlWebApplicationContext
* 创建子容器 webApplicationContext, 跟当前FrameworkServlet(DispatcherServlet)绑定
* 父容器 --> servletContext中存储
* 子容器 --> FrameworkServlet(DispatcherServlet)中存储 servletContext中存储
*/
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
// 1.contextClass == org.springframework.web.context.support.XmlWebApplicationContext
Class<?> contextClass = getContextClass();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Servlet with name '" + getServletName() +
"' will try to create custom WebApplicationContext context of class '" +
contextClass.getName() + "'" + ", using parent context [" + parent + "]");
}
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException(
"Fatal initialization error in servlet with name '" + getServletName() +
"': custom WebApplicationContext class [" + contextClass.getName() +
"] is not of type ConfigurableWebApplicationContext");
}
// 2.实例化 XmlWebApplicationContext
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
// 3.设置当前 XmlWebApplicationContext的父容器为 ROOT(ContextLoaderListener创建的容器, 并存储到servletContext中的)
wac.setParent(parent);
// 4.设置配置文件路径, 这里的路径是web.xml文件中DispatcherServlet中, init-param中配置的变量 -- contextConfigLocation, 这里是: classpath:spring-config/springmvc-config.xml
wac.setConfigLocation(getContextConfigLocation());
// 5.配置并启动子容器
configureAndRefreshWebApplicationContext(wac);
return wac;
}
FrameworkServlet#configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac)
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value
// -> assign a more useful id based on available information
if (this.contextId != null) {
wac.setId(this.contextId);
}
else {
// 1.生成容器id: org.springframework.web.context.WebApplicationContext:/springMVC
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
}
}
// 2.设置servletContext
wac.setServletContext(getServletContext());
// 3.设置servletConfig
wac.setServletConfig(getServletConfig());
// 4.设置namespace
wac.setNamespace(getNamespace());
// 5.添加容器监听器, 这个监听器很重要, 容器启动完成后会发布refresh事件, 会被ContextRefreshListener监听
wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
// The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
postProcessWebApplicationContext(wac);
applyInitializers(wac);
// 6.启动容器
wac.refresh();
}
3.2.2 回调
上述,创建完子容器之后,添加了监听器new SourceFilteringListener(wac, new ContextRefreshListener())监听容器refresh,容器启动时会回调ContextRefreshListener的onApplicationEvent(ContextRefreshedEvent event)方法
/**
* ApplicationListener endpoint that receives events from this servlet's WebApplicationContext
* only, delegating to {@code onApplicationEvent} on the FrameworkServlet instance.
*/
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// 调用FrameworkServlet#onApplicationEvent(event)
FrameworkServlet.this.onApplicationEvent(event);
}
}
FrameworkServlet#onApplicationEvent(ContextRefreshedEvent event)
public void onApplicationEvent(ContextRefreshedEvent event) {
this.refreshEventReceived = true;
// 这里 onRefresh(ApplicationContext context) 被子类DispatcherServlet重写, 调用的是子类DispatcherServlet的onRefresh(ApplicationContext context)方法
onRefresh(event.getApplicationContext());
}
总结
web容器启动时, 会加载并初始化web.xml文件中配置的<servlet>, 这里只有核心类DispatcherServlet, 继承了FrameworkServlet, 初始化FrameworkServlet时会创建子spring web容器XmlWebApplicationContext, 创建时会添加监听器ContextRefreshListener, 所以创建完成时回调其onApplicationEvent(ContextRefreshedEvent event)方法, 该方法用于初始化DispatcherServlet相关组件!
4.DispatcherServlet
4.1 初始化
综上,子容器XmlWebApplicationContext启动时,发布ContextRefreshedEvent事件,被已经添加的ContextRefreshListener监听,回调其onApplicationEvent(ContextRefreshedEvent event)方法,这个方法中调用了DispatcherServlet的onRefresh(ApplicationContext context)方法
DispatcherServlet#onRefresh(ApplicationContext context)
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
DispatcherServlet#initStrategies(ApplicationContext context)
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
// 入参的ApplicationContext是子容器
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
initMultipartResolver(ApplicationContext context)
/**
* Initialize the MultipartResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* no multipart handling is provided.
*/
private void initMultipartResolver(ApplicationContext context) {
try {
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// Default is no multipart resolver.
this.multipartResolver = null;
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
"': no multipart request handling provided");
}
}
}
初始化MultipartResolver, 用于处理文件上传, 这个是可配置的, 如果未配置, 为空
initLocaleResolver(ApplicationContext context)
/**
* Initialize the LocaleResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* we default to AcceptHeaderLocaleResolver.
*/
private void initLocaleResolver(ApplicationContext context) {
try {
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
// 使用默认的LocaleResolver
this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
"': using default [" + this.localeResolver + "]");
}
}
}
初始化LocaleResolver,如果没有配置,使用默认的
initThemeResolver(ApplicationContext context)
/**
* Initialize the ThemeResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* we default to a FixedThemeResolver.
*/
private void initThemeResolver(ApplicationContext context) {
try {
this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ThemeResolver [" + this.themeResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
// 使用默认的ThemeResolver
this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ThemeResolver with name '" + THEME_RESOLVER_BEAN_NAME +
"': using default [" + this.themeResolver + "]");
}
}
}
初始化ThemeResolver,如果没有配置,使用默认的
initHandlerMappings(ApplicationContext context)
/**
* Initialize the HandlerMappings used by this class.
* <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
* we default to BeanNameUrlHandlerMapping.
*/
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
// 1.从子容器中获取所有的HandlerMapping, 这里有3个
// org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
// org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
// org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
// 2.排序handlerMapping
// RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
从容器中获取所有HandlerMapping处理器,并排序,目前有三个,顺序为:RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping
initHandlerAdapters(ApplicationContext context)
/**
* Initialize the HandlerAdapters used by this class.
* <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace,
* we default to SimpleControllerHandlerAdapter.
*/
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
// 1.从子容器中获取所有HandlerAdapter, 这里有三个:
// org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
// org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
// org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
// 2.排序HandlerAdapter
// HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
if (this.handlerAdapters == null) {
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
}
}
}
从容器中获取所有HandlerAdapter处理器,并排序,目前有三个,顺序为:HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter
initHandlerExceptionResolvers(ApplicationContext context)
/**
* Initialize the HandlerExceptionResolver used by this class.
* <p>If no bean is defined with the given name in the BeanFactory for this namespace,
* we default to no exception resolver.
*/
private void initHandlerExceptionResolvers(ApplicationContext context) {
this.handlerExceptionResolvers = null;
if (this.detectAllHandlerExceptionResolvers) {
// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
// 1.从子容器中获取所有 HandlerExceptionResolver, 这里找到3个:
// org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver
// org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver
// org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerExceptionResolvers = new ArrayList<HandlerExceptionResolver>(matchingBeans.values());
// We keep HandlerExceptionResolvers in sorted order.
// 2.排序HandlerExceptionResolver:
// ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
}
else {
try {
HandlerExceptionResolver her =
context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
this.handlerExceptionResolvers = Collections.singletonList(her);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, no HandlerExceptionResolver is fine too.
}
}
// Ensure we have at least some HandlerExceptionResolvers, by registering
// default HandlerExceptionResolvers if no other resolvers are found.
if (this.handlerExceptionResolvers == null) {
this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default");
}
}
}
从容器中获取所有HandlerExceptionResolver处理器,并排序,目前有三个,顺序为:ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver
initRequestToViewNameTranslator(ApplicationContext context)
/**
* Initialize the RequestToViewNameTranslator used by this servlet instance.
* <p>If no implementation is configured then we default to DefaultRequestToViewNameTranslator.
*/
private void initRequestToViewNameTranslator(ApplicationContext context) {
try {
this.viewNameTranslator =
context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
if (logger.isDebugEnabled()) {
logger.debug("Using RequestToViewNameTranslator [" + this.viewNameTranslator + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate RequestToViewNameTranslator with name '" +
REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME + "': using default [" + this.viewNameTranslator +
"]");
}
}
}
初始化RequestToViewNameTranslator,如果没有配置,使用默认的
initViewResolvers(ApplicationContext context)
/**
* Initialize the ViewResolvers used by this class.
* <p>If no ViewResolver beans are defined in the BeanFactory for this
* namespace, we default to InternalResourceViewResolver.
*/
private void initViewResolvers(ApplicationContext context) {
this.viewResolvers = null;
if (this.detectAllViewResolvers) {
// Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
// 1.从子容器中获取所有ViewResolver, 没有获取到
Map<String, ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.viewResolvers = new ArrayList<ViewResolver>(matchingBeans.values());
// We keep ViewResolvers in sorted order.
AnnotationAwareOrderComparator.sort(this.viewResolvers);
}
}
else {
try {
ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
this.viewResolvers = Collections.singletonList(vr);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default ViewResolver later.
}
}
// Ensure we have at least one ViewResolver, by registering
// a default ViewResolver if no other resolvers are found.
if (this.viewResolvers == null) {
// 2.使用默认的ViewResolver
this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default");
}
}
}
初始化ViewResolver,如果没有配置,使用默认的
initFlashMapManager(ApplicationContext context)
/**
* Initialize the {@link FlashMapManager} used by this servlet instance.
* <p>If no implementation is configured then we default to
* {@code org.springframework.web.servlet.support.DefaultFlashMapManager}.
*/
private void initFlashMapManager(ApplicationContext context) {
try {
this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);
if (logger.isDebugEnabled()) {
logger.debug("Using FlashMapManager [" + this.flashMapManager + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate FlashMapManager with name '" +
FLASH_MAP_MANAGER_BEAN_NAME + "': using default [" + this.flashMapManager + "]");
}
}
}
初始化FlashMapManager,如果没有配置,使用默认的
总结
这里主要初始化DispatcherServlet的相关组件, 其中最重要的组件有: HandlerMapping、 HandlerAdapter
4.2 建立Map<url, controller>关系
综上,我们从容器中获取所有的HandlerMapping对象时,会获取到其中的BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping和RequestMappingHandlerMapping,这个类继承了AbstractDetectingUrlHandlerMapping,AbstractDetectingUrlHandlerMapping继承了AbstractUrlHandlerMapping,AbstractUrlHandlerMapping继承了WebApplicationObjectSupport,WebApplicationObjectSupport继承了ApplicationObjectSupport,ApplicationObjectSupport实现了ApplicationContextAware接口
即:HandlerMapping实例间接实现了ApplicationContextAware接口
4.2.1 SimpleUrlHandlerMapping
4.2.1.1 结构图
根据[@Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext](/Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext) context)方法
4.3.1.2 ApplicationObjectSupport#setApplicationContext(ApplicationContext context)
@Override
public final void setApplicationContext(ApplicationContext context) throws BeansException {
if (context == null && !isContextRequired()) {
// Reset internal context state.
this.applicationContext = null;
this.messageSourceAccessor = null;
}
else if (this.applicationContext == null) {
// Initialize with passed-in context.
if (!requiredContextClass().isInstance(context)) {
throw new ApplicationContextException(
"Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
}
// 1.赋值子容器
this.applicationContext = context;
// 2.初始化messageSourceAccessor
this.messageSourceAccessor = new MessageSourceAccessor(context);
// 3.这里的initApplicationContext(context)由子类WebApplicationObjectSupport复写
initApplicationContext(context);
}
else {
// Ignore reinitialization if same context passed in.
if (this.applicationContext != context) {
throw new ApplicationContextException(
"Cannot reinitialize with different application context: current one is [" +
this.applicationContext + "], passed-in one is [" + context + "]");
}
}
}
4.2.1.3 WebApplicationObjectSupport#initApplicationContext(ApplicationContext context)
/**
* Calls {@link #initServletContext(javax.servlet.ServletContext)} if the
* given ApplicationContext is a {@link WebApplicationContext}.
*/
@Override
protected void initApplicationContext(ApplicationContext context) {
// 1.这里会先调用父类的方法, 即ApplicationObjectSupport的initApplicationContext(ApplicationContext context), 最终会回调到
// SimpleUrlHandlerMapping#initApplicationContext()
super.initApplicationContext(context);
if (this.servletContext == null && context instanceof WebApplicationContext) {
this.servletContext = ((WebApplicationContext) context).getServletContext();
if (this.servletContext != null) {
initServletContext(this.servletContext);
}
}
}
4.2.1.4 SimpleUrlHandlerMapping#initApplicationContext()
@Override
public void initApplicationContext() throws BeansException {
// 先调用父类的initApplicationContext(), 这里调用的是 AbstractHandlerMapping#initApplicationContext()
super.initApplicationContext();
// 这里的urlMap存的是url和处理器的关联关系, 初始化时已经有了1个
// ("/**", DefaultServletHttpRequestHandler字符串)
registerHandlers(this.urlMap);
}
4.2.1.5 SimpleUrlHandlerMapping#registerHandlers(Map<String, Object> urlMap)
/**
* Register all handlers specified in the URL map for the corresponding paths.
* @param urlMap Map with URL paths as keys and handler beans or bean names as values
* @throws BeansException if a handler couldn't be registered
* @throws IllegalStateException if there is a conflicting handler registered
*/
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
if (urlMap.isEmpty()) {
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
}
else {
// 1.urlMap不为空, ("/**", DefaultServletHttpRequestHandler)
for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
String url = entry.getKey();
Object handler = entry.getValue();
// Prepend with slash if not already present.
if (!url.startsWith("/")) {
url = "/" + url;
}
// Remove whitespace from handler bean name.
if (handler instanceof String) {
handler = ((String) handler).trim();
}
// 2.注册handler, 向父类AbstractUrlHandlerMapping中注册, urlMap
// handlerMap成员变量添加("/**", DefaultServletHttpRequestHandler)
registerHandler(url, handler);
}
}
}
4.2.2 BeanNameUrlHandlerMapping
4.2.2.1 结构图
根据[@Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext](/Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext) context)方法
4.3.2.2 ApplicationObjectSupport#setApplicationContext(ApplicationContext context)
@Override
public final void setApplicationContext(ApplicationContext context) throws BeansException {
if (context == null && !isContextRequired()) {
// Reset internal context state.
this.applicationContext = null;
this.messageSourceAccessor = null;
}
else if (this.applicationContext == null) {
// Initialize with passed-in context.
if (!requiredContextClass().isInstance(context)) {
throw new ApplicationContextException(
"Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
}
// 1.赋值子容器
this.applicationContext = context;
// 2.初始化messageSourceAccessor
this.messageSourceAccessor = new MessageSourceAccessor(context);
// 3.这里的initApplicationContext(context)由子类WebApplicationObjectSupport复写
initApplicationContext(context);
}
else {
// Ignore reinitialization if same context passed in.
if (this.applicationContext != context) {
throw new ApplicationContextException(
"Cannot reinitialize with different application context: current one is [" +
this.applicationContext + "], passed-in one is [" + context + "]");
}
}
}
4.2.2.3 WebApplicationObjectSupport#initApplicationContext(ApplicationContext context)
/**
* Calls {@link #initServletContext(javax.servlet.ServletContext)} if the
* given ApplicationContext is a {@link WebApplicationContext}.
*/
@Override
protected void initApplicationContext(ApplicationContext context) {
// 1.这里会先调用父类的方法, 即ApplicationObjectSupport的initApplicationContext(ApplicationContext context), 最终会回调到
// AbstractDelectingUrlHandlerMapping#initApplicationContext()
super.initApplicationContext(context);
if (this.servletContext == null && context instanceof WebApplicationContext) {
this.servletContext = ((WebApplicationContext) context).getServletContext();
if (this.servletContext != null) {
initServletContext(this.servletContext);
}
}
}
4.2.2.4 AbstractDelectingUrlHandlerMapping#initApplicationContext()
/**
* Calls the {@link #detectHandlers()} method in addition to the
* superclass's initialization.
*/
@Override
public void initApplicationContext() throws ApplicationContextException {
// 1.调用父类 AbstractHandlerMapping#initApplicationContext()
super.initApplicationContext();
// 2.调用
detectHandlers();
}
4.2.2.5 AbstractDelectingUrlHandlerMapping#detectHandlers()
/**
* Register all handlers found in the current ApplicationContext.
* <p>The actual URL determination for a handler is up to the concrete
* {@link #determineUrlsForHandler(String)} implementation. A bean for
* which no such URLs could be determined is simply not considered a handler.
* @throws org.springframework.beans.BeansException if the handler couldn't be registered
* @see #determineUrlsForHandler(String)
*/
protected void detectHandlers() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
}
String[] beanNames = (this.detectHandlersInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
// Take any bean name that we can determine URLs for.
for (String beanName : beanNames) {
// 目前determineUrlsForHandler(beanName)都返回空
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
// URL paths found: Let's consider it a handler.
registerHandler(urls, beanName);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
}
}
}
}
4.2.3 RequestMappingHandlerMapping(重点)
4.2.3.1 结构图
根据[@Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext](/Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext) context)方法
4.3 处理请求
4.3.1 预备
1.当一个请求过来时,优先使用Filter处理,处理完之后根据配置找到对应的Servlet,我们这里只配置了一个DispatcherServlet用于处理所有请求
2.Dispatcher处理请求时,优先调用service(req, resp)方法,该方法由其父类FrameworkServlet实现
4.3.2 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.PATCH == httpMethod || httpMethod == null) {
processRequest(request, response);
}
else {
// 调用父类的service(req,resp)方法, 见@4.3.3
super.service(request, response);
}
}
4.3.3 HttpServlet#service(HttpServletRequest req, HttpServletResponse resp)
这个方法根据不同的请求方法调用不同的处理方法,如doGet(),doPost()等,具体的方法有子类FrameworkServlet实现
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
4.3.4 Framework#doGet(HttpServletRequest request, HttpServletResponse response)
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 见@4.3.5
processRequest(request, response);
}
4.3.5 Framework#processRequest(HttpServletRequest request, HttpServletResponse 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();
// 1.构建localeContext
LocaleContext localeContext = buildLocaleContext(request);
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
// 2.构建ServletRequestAttributes
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
// 3.初始化LocaleContextHolder, 主要是一些线程共享变量 ThreadLocal
initContextHolders(request, localeContext, requestAttributes);
try {
// 4.调用doService(req, resp), 由子类DispatcherServlet实现,见@4.3.6
doService(request, response);
}
catch (ServletException ex) {
failureCause = ex;
throw ex;
}
catch (IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
// 5.销毁LocaleContextHolder, 主要是一些线程共享变量 ThreadLocal
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
if (logger.isDebugEnabled()) {
if (failureCause != null) {
this.logger.debug("Could not complete request", failureCause);
}
else {
if (asyncManager.isConcurrentHandlingStarted()) {
logger.debug("Leaving response open for concurrent processing");
}
else {
this.logger.debug("Successfully completed request");
}
}
}
// 6.发布处理请求事件
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
4.3.6 DispatcherServlet#doService(HttpServletRequest request, HttpServletResponse response)
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
" processing " + request.getMethod() + " request for [" + getRequestUri(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<String, Object>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
// 1.将框架中的一些对象暴露给其他处理器, 比如localeResolver
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());
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 {
// 2.核心方法, 作请求分发处理, 见@4.3.7
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);
}
}
}
}
4.3.7 DispatcherServlet#doDispatch(HttpServletRequest request, HttpServletResponse response)
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 {
// 1.判断是否是文件上传
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// 2.根据请求获取HandlerExecutionChain, 见@4.3.8
// 这里由RequestMappingHandlerMapping根据请求url匹配到对应的Controller的对应方法, 封装成HandlerExecutionChain
// 这个chain封装了一个HandlerMethod(url对应的Controller和对应的method)以及一个拦截器: ConversionServiceExpodingInterceptor
mappedHandler = getHandler(processedRequest);
// 3.没找到直接返回404
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 4.根据handlerMethod找到HandlerAdapter, 这里获取的是RequestMappingHandlerAdapter
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 (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 5.前面: mappedHandler是HandlerExecutionChain, 是对对应处理器HandlerMethod以及拦截器的封装,
// 这里会先调用拦截器的preHandle方法进行拦截
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 6.调用处理器方法, 见@4.3.10
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 7.mv == null, 直接跳过
applyDefaultViewName(processedRequest, mv);
// 8.调用拦截器的postHandle
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);
}
}
}
}
4.3.8 DispatcherServlet#getHandler(HttpServletRequest request)
/**
* 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
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 这里的handlerMappings有三个, 且已经排序了, 第一个是RequestMappingHandlerMapping
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
// 这里由RequestMappingHandlerMapping根据请求url匹配到对应的HandlerMethod, 封装成HandlerExecutionChain
// 这个chain封装了对应的HandlerMethod以及一个拦截器: ConversionServiceExpodingInterceptor
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
4.3.9 DispatcherServlet#getHandlerAdapter(Object handler)
/**
* 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 {
// 这里的handlerAdapters有三个: HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
// 因为前期用的RequestMappingHandlerMapping, 所以这里获取到的是 RequestMappingHandlerAdapter
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
4.3.10 AbstractHandlerMethodAdapter#handle(HttpServletRequest request, HttpServletResponse response, Object handler)
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 这里由子类 RequstMappingHandlerAdapter 实现, 见@4.3.11
return handleInternal(request, response, (HandlerMethod) handler);
}
4.3.11 RequstMappingHandlerAdapter#handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod)
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
// 1.校验请求方法和是否需要session
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...
// 2.进入, 返回ModelAndView, 这里使用的rest方法, 不会返回ModelAndView
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
5.springmvc组件解析
5.1 入口
1.由前面分析, servlet容器在加载web.xml时, 会初始化DispatcherServlet, 此时会执行DispatcherServlet的静态代码块
static {
try {
// DEFAULT_STRATEGIES_PATH == DispatcherServlet.properties
// 即加载DispatcherServlet类时会加载 DispatcherServlet.properties 配置文件, 存储在 defaultStrategies
// 查看 DispatcherServlet.properties, 可以看到, 是DispatcherServlet中九大组件的默认实现类, 其中有八个组件的默认实现类, 缺少一个MultipartResolver, 因此, 如果没有在 springmvc-config.xml文件中配置, 则不会有 MultipartResolver, 此时无法解析文件上传等功能
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
}
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.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.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
2.子容器XmlWebApplicationContext启动时,发布ContextRefreshedEvent事件,被已经添加的ContextRefreshListener监听,回调其onApplicationEvent(ContextRefreshedEvent event)方法,这个方法中调用了DispatcherServlet的onRefresh(ApplicationContext context)方法,在onRefresh方法中会调用核心方法 initStrategies,在 initStrategies 方法中完成九大组件的初始化
3.注意:以上配置文件中的组件不会一开始就加载到子容器XmlWebApplicationContext中,子容器一开始只会加载其他核心bean以及配置文件springmvc中bean,所以如果我们在springmvc.xml文件中配置了相关组件,优先会使用我们配置的,如果没有,才会使用 DispatcherServlet.properties 配置的相关组件
DispatcherServlet#onRefresh(ApplicationContext context)
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
DispatcherServlet#initStrategies(ApplicationContext context)
/**
* Initialize the strategy objects that this servlet uses.
* <p>May be overridden in subclasses in order to initialize further strategy objects.
*/
// 入参的ApplicationContext是子容器
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
5.2 MultipartResolver
MultipartResolver是九大组件之一,用于处理文件上传
5.2.1 初始化
private void initMultipartResolver(ApplicationContext context) {
try {
// 1.直接从子spring容器中获取, 如果springmvc-config.xml文件中没有配置, 则获取失败
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.multipartResolver);
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
}
}
catch (NoSuchBeanDefinitionException ex) {
// Default is no multipart resolver.
// 2.获取失败后, 也不会从 DispatcherServlet.properties 配置中读取, 因为 DispatcherServlet.properties 配置文件中也没有配置当前组件
this.multipartResolver = null;
if (logger.isTraceEnabled()) {
logger.trace("No MultipartResolver '" + MULTIPART_RESOLVER_BEAN_NAME + "' declared");
}
}
}
5.2.2 实现
MultipartResolver有两个实现:CommonsMultipartResolver 和 StandardServletMultipartResolver,如果在springmvc中需要使用,则需要在springmvc-config.xml文件中进行注册,否则默认无法解析文件上传
5.2.2.1 CommonsMultipartResolver
1.在springmvc.config文件中配置CommonsMultipartResolver
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="104857600" />
<property name="maxInMemorySize" value="104857600" />
</bean>
2.pom.xml文件中需要引入commons-file,因为CommonsMultipartResolver借助了commons-file
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
5.2.2.2 StandardServletMultipartResolver
这个是springboot中默认引入的bean,springboot采用spi机制,在spring-boot-autoconfigure包的resources/META-INF/spring.factories文件中,引入了MultipartAutoConfiguration,在MultipartAutoConfiguration中根据条件,向spring容器中注册了 StandardServletMultipartResolver
5.2.3 应用
在核心处理流程中,DispatcherServlet#doDispatch方法中
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 {
// 1.判断是否是文件上传, 判断条件: Content-Type 是否以 multipart/ 开头
// 并将 HttpServletRequest 封装成 MultipartHttpServletRequest, 具体实现暂略
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
......
}
5.3 HandlerMapping
HandlerMapping是九大组件之一,负责为请求找到合适的 HandlerExecutionChain 处理器执行链,包含处理器(handler)和拦截器(interceptors),处理器通常就是我们在@Controller下@RequestMapping注解对应的方法的封装,拦截器是对处理请求进行增强处理,用于对处理器的增强
5.3.1 初始化
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// 1.如果开启探测功能, 则会从springmvc容器中扫描所有的 HandlerMapping, 添加到 handlerMappings 中, 默认开启, 默认找到3个
// 默认3个是何时添加到springmvc容器中?是在初始化子springmvc容器的过程中, 解析springmvc-config.xml配置文件的过程中创建的BeanDefinition, 这个后期有空再具体写文档
// SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping、RequestMappingHandlerMapping, 下面会进行重新排序
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
// 重新排序: RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
// 2.关闭探测功能时, 获得Bean名称为 handlerMapping 对应的 Bean, 将其添加至 handlerMappings
else {
try {
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerMapping later.
}
}
// Ensure we have at least one HandlerMapping, by registering
// a default HandlerMapping if no other mappings are found.
// 3.如果未获得到, 则获得默认配置 DispatcherServlet.properties 中的 HandlerMapping 类
if (this.handlerMappings == null) {
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
5.3.2 实现
5.3.2.1 结构图
1.蓝色框 AbstractHandlerMapping 抽象类, 实现了getHandler方法, 用于处理器映射器找到对应的 HandlerExecutionChain, getHandler中采用模板方法模式, 子类需要实现 getHandlerInternal(HttpServletRequest request) 抽象方法
2.AbstractHandlerMapping的子类主要分为两类:
黄色框 AbstractUrlHandlerMapping, 是基于url进行匹配的, 目前这种方式已经基本不用了, 我们初始化获取的 SimpleUrlHandlerMapping 和 BeanNameUrlHandlerMapping 就是属于此类, 所以接下来也不会分析了
红色框 AbstractHandlerMethodMapping系, 基于Method匹配, 我们现在使用的@RequestMapping注解就是基于这种方式, 这个是我们接下来会具体分析的
5.3.2.2 AbstractHandlerMapping
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered, BeanNameAware {
/**
* 默认处理器
*/
@Nullable
private Object defaultHandler;
/**
* URL 路径工具类
*/
private UrlPathHelper urlPathHelper = new UrlPathHelper();
/**
* 路径匹配器
*/
private PathMatcher pathMatcher = new AntPathMatcher();
/**
* 配置的拦截器数组.
*
* 在 {@link #initInterceptors()} 方法中,初始化到 {@link #adaptedInterceptors} 中
*
* 添加方式有两种:
* 1. {@link #setInterceptors(Object...)} 方法
* 2. {@link #extendInterceptors(List)} 方法
*/
private final List<Object> interceptors = new ArrayList<>();
/**
* 初始化后的拦截器 HandlerInterceptor 数组
*/
private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();
......
}
initApplicationContext
@Override
protected void initApplicationContext() throws BeansException {
// 1.空实现,交给子类实现, 用于注册自定义的拦截器到 interceptors 中, 目前暂无子类实现
extendInterceptors(this.interceptors);
// 2.扫描已注册的 MappedInterceptor 的 Bean,添加到 mappedInterceptors 中
detectMappedInterceptors(this.adaptedInterceptors);
// 3.将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中
initInterceptors();
}
getHandler
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 1.获得处理器(HandlerMethod 或者 HandlerExecutionChain), 该方法是抽象方法, 由子类实现
Object handler = getHandlerInternal(request);
// 2.获得不到, 则使用默认处理器
if (handler == null) {
handler = getDefaultHandler();
}
// 3.还是获得不到, 则返回 null
if (handler == null) {
return null;
}
// Bean name or resolved handler?
// 4.如果找到的处理器是 String 类型, 则从 Spring 容器中找到对应的 Bean 作为处理器
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
// 5.创建 HandlerExecutionChain 对象(包含处理器和拦截器), 见下
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (logger.isTraceEnabled()) {
logger.trace("Mapped to " + handler);
}
else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
logger.debug("Mapped to " + executionChain.getHandler());
}
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
getHandlerExecutionChain
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 1.创建 HandlerExecutionChain 对象
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler
: new HandlerExecutionChain(handler));
// 2.获得请求路径
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
// 3.遍历 adaptedInterceptors 数组, 获得请求匹配的拦截器
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
//4.需要匹配,若路径匹配,则添加到 chain 中
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { // 匹配
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
// 5.无需匹配,直接添加到 chain 中
else {
chain.addInterceptor(interceptor);
}
}
return chain
}
5.3.2.3 RequestMappingHandlerMapping
结构图
由结构图可以看出,RequestMappingHandlerMapping间接继承了父类ApplicationObjectSupport,实现了Aware接口,根据[@Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext](/Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext) context)方法
ApplicationObjectSupport#setApplicationContext(ApplicationContext context)
@Override
public final void setApplicationContext(ApplicationContext context) throws BeansException {
if (context == null && !isContextRequired()) {
// Reset internal context state.
this.applicationContext = null;
this.messageSourceAccessor = null;
}
else if (this.applicationContext == null) {
// Initialize with passed-in context.
if (!requiredContextClass().isInstance(context)) {
throw new ApplicationContextException(
"Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
}
// 1.赋值子容器
this.applicationContext = context;
// 2.初始化messageSourceAccessor
this.messageSourceAccessor = new MessageSourceAccessor(context);
// 3.这里的initApplicationContext(context)由子类WebApplicationObjectSupport复写
initApplicationContext(context);
}
else {
// Ignore reinitialization if same context passed in.
if (this.applicationContext != context) {
throw new ApplicationContextException(
"Cannot reinitialize with different application context: current one is [" +
this.applicationContext + "], passed-in one is [" + context + "]");
}
}
}
WebApplicationObjectSupport#initApplicationContext(ApplicationContext context)
/**
* Calls {@link #initServletContext(javax.servlet.ServletContext)} if the
* given ApplicationContext is a {@link WebApplicationContext}.
*/
@Override
protected void initApplicationContext(ApplicationContext context) {
// 1.这里会先调用父类的方法, 即ApplicationObjectSupport的initApplicationContext(ApplicationContext context), 最终会回调到
// AbstractHandlerMapping#initApplicationContext()
super.initApplicationContext(context);
if (this.servletContext == null && context instanceof WebApplicationContext) {
this.servletContext = ((WebApplicationContext) context).getServletContext();
if (this.servletContext != null) {
initServletContext(this.servletContext);
}
}
}
AbstractHandlerMapping#initApplicationContext()
/**
* Initializes the interceptors.
* @see #extendInterceptors(java.util.List)
* @see #initInterceptors()
*/
@Override
protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors);
detectMappedInterceptors(this.adaptedInterceptors);
initInterceptors();
}
在第七次BeanPostProcessor调用后,会调用bean的初始化方法,因为RequestMappingHandlerMapping实现了InitializingBean接口,所以会回调其afterPropertiesSet()方法,在这里真正完成url和HandlerMethod的绑定
RequestMappingHandlerMapping#afterPropertiesSet()
@Override
public void afterPropertiesSet() {
this.config = new RequestMappingInfo.BuilderConfiguration();
this.config.setUrlPathHelper(getUrlPathHelper());
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
this.config.setContentNegotiationManager(getContentNegotiationManager());
// 调用父类 afterPropertiesSet(), 由AbstractHandlerMethodMapping实现
super.afterPropertiesSet();
}
AbstractHandlerMethodMapping#afterPropertiesSet()
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
AbstractHandlerMethodMapping#initHandlerMethods()
/**
* Scan beans in the ApplicationContext, detect and register handler methods.
* @see #getCandidateBeanNames()
* @see #processCandidateBean
* @see #handlerMethodsInitialized
*/
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {
// 不以 scopedTarget. 开头, 则进入
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
AbstractHandlerMethodMapping#processCandidateBean(String beanName)
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
// 1.获取Class对象
beanType = obtainApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isTraceEnabled()) {
logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
}
}
// 2.判断Class是否有@RequestMapping注解或者@Controller注解
if (beanType != null && isHandler(beanType)) {
// 3.封装 HandlerMethod, 存储到mappingLookup中
// key = @RequestMapping中的url
// value = HandlerMethod
// 在这里绑定了url和对应Controller的处理方法的封装 HandlerMethod, 存储到了其父类AbstractHandlerMehodMapping的属性mappingRegistry中, 见下
detectHandlerMethods(beanName);
}
}
AbstractHandlerMethodMapping#detectHandlerMethods
protected void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
(MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex);
}
});
if (logger.isTraceEnabled()) {
logger.trace("Mapped " + methods.size() + " handler method(s) for " + userType + ": " + methods);
}
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 注册url和对应的Method, 见下
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
AbstractHandlerMethodMapping#registerHandlerMethod
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
// 核心方法
this.mappingRegistry.register(mapping, handler, method);
}
MappingRegistry#register
public void register(T mapping, Object handler, Method method) {
// 1.获取写锁
this.readWriteLock.writeLock().lock();
try {
// 2.创建 Method 对应的 HandlerMethod
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping);
// 3.存储 (mapping, HandlerMethod) 关联关系到 mappingLookup属性
this.mappingLookup.put(mapping, handlerMethod);
// 4.获得 mapping 对应的普通 URL 数组
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
// 5.将 url 和 mapping 的映射关系保存至 urlLookup属性
this.urlLookup.add(url, mapping);
}
String name = null;
// 6.初始化 nameLookup
if (getNamingStrategy() != null) {
// 7.获得 Mapping 的名字
name = getNamingStrategy().getName(handlerMethod, mapping);
// 8.将 mapping 的名字与 HandlerMethod 的映射关系保存至 nameLookup
addMappingName(name, handlerMethod);
}
// 9.初始化 CorsConfiguration 配置对象
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
// 10.创建 MappingRegistration 对象, 与 mapping 映射添加到 registry 注册表中
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
5.3.2.4 总结
初始化HandlerMapping时, 扫描有 @Controller 或者 @RequestMapping 注解的类下面的方法, 如果方法上面有 @RequestMapping 注解(包括GetMapping, PostMapping等), 则会为该方法创建对应的 RequestMappingInfo 对象, 将所有的 RequestMappingInfo 对象和 Method 以及方法所在类, 往 MappingRegistry 进行注册, 会生成 HandlerMethod 处理器(Method 所有信息)对象。这样一来, 当 Spring MVC 的 DispatcherServlet 处理请求的时候, 获取到对应的 HandlerMethod 处理器, 就可以通过反射执行对应的方法了
5.3.3 应用
在 DispatcherServlet 的doDispatch的方法中
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 {
// 1.使用MultipartResolver处理文件上传
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 2.根据请求获取到对应的 HandlerExectionChain, HandlerExectionChain是对 HandlerMethod 和 HandlerInterceptor 的封装, HandlerMethod一般是我们使用@RequestMapping注解中对应的方法
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
......
}
DispatcherServlet#getHandler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 这里 handlerMappings, 默认有三个, 在initHandlerMapping方法中完成初始化并排序, 排序后为
// RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping,
// 其中第一个 RequestMappingHandlerMapping 就是我们现在常用的用于处理 @RequestMapping 注解方式的 handlerMapping
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
// 按顺序依次调用 handlerMapping#getHandler 方法, getHandler方法由其父类 AbstractHandlerMapping 实现, 上文已分析
// HandlerExecutionChain的具体调用后面会分析
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
在AbstractHandlerMapping中的getHandler方法,采用模板方法设计模式,回调子类的getHandlerInternal方法,这里我们看 RequestMappingHandlerMapping 的getHandlerInternal方法
RequestMappingHandlerMapping#getHandlerInternal
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 1.根据请求获取请求url
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
// 2.获得读锁
this.mappingRegistry.acquireReadLock();
try {
// 3.【重要】根据请求和url获取对应的HandlerMethod, 见下
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
// 4.响应
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
// 5.释放锁
this.mappingRegistry.releaseReadLock();
}
}
RequestMappingHandlerMapping#lookupHandlerMethod
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 1.首先, 从 urlLookup 属性中找, urlLookup (key --> url, value --> List<RequestMappingInfo>)
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
// 2.如果找到, 则再根据 RequestMappingInfo 找到对应的 HandlerMethod, 并封装成 Match, 添加到 matches 中
// 这里会用到 mappingRegistry 的 mappingLookup 属性 (key --> RequestMappingInfo, value --> HandlerMethod)
addMatchingMappings(directPathMatches, matches, request);
}
// 2.这里跳过
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
// 3.上述如果匹配到, 则会进行排序, 选择最佳Match
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (logger.isTraceEnabled()) {
logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
5.4 HandlerAdapter
HandlerAdapter组件, 是DispatcherServlet的九大组件之一。在上一步中, 我们通过HandlerMapping组件获取了 HandlerExecutionChain, HandlerExecutionChain 是对对应handler和interceptor的封装, 这里的 handler 是object类型, 需要有一个调用者来实现 handler 是怎么被执行。Spring 中的处理器的有多种实现, 比如用户的处理器可以实现 Controller 接口或者 HttpRequestHandler 接口(这两种方式基本不用了), 也可以用 @RequestMapping 注解将方法作为一个处理器等(这是目前主流的方式), 这就导致 SpringMVC 无法直接执行这个处理器。所以这里需要一个处理器适配器,由它去执行处理器。
5.4.1 初始化
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
// 1.如果开启探测功能, 则会从springmvc容器中扫描所有的 HandlerAdapter, 添加到 handlerAdapters 中, 默认开启, 默认找到3个
// 默认3个是何时添加到springmvc容器中?是在初始化子springmvc容器的过程中, 解析springmvc-config.xml配置文件的过程中创建的BeanDefinition, 这个后期有空再具体写文档
// 这里默认有3个: HttpRequestHandlerAdapter、 SimpleControllerHandlerAdapter、 RequestMappingHandlerAdapter
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
// 排序: HttpRequestHandlerAdapter、 SimpleControllerHandlerAdapter、 RequestMappingHandlerAdapter(重点分析)
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
try {
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, we'll add a default HandlerAdapter later.
}
}
// Ensure we have at least some HandlerAdapters, by registering
// default HandlerAdapters if no other adapters are found.
if (this.handlerAdapters == null) {
// 从DispatcherServlet.properties 中获取
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
这里的初始化和 HandlerMapping 的初始化类似,首先从子springmvc容器中获取,即先获取我们在springmvc-config.xml配置文件中配置的 HandlerAdapter以及springmvc容器中自带的(子springmvc容器在初始化时会向容器中注册一些默认的bean, 其中包括一些组件),如果未配置,则获得默认配置 DispatcherServlet.properties 中的 HandlerAdapter 类
5.4.2 实现
5.4.2.1 结构图
5.4.2.2 HandlerAdapter
public interface HandlerAdapter {
// 使用适配器模式, 判断是否支持当前处理器
boolean supports(Object handler);
// 执行处理器, 返回ModelAndView
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
// 返回请求的最新更新时间, 如果不支持该操作, 则返回 -1 即可
long getLastModified(HttpServletRequest request, Object handler);
}
5.4.2.3 AbstractHandlerMethodAdapter
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
// 优先级最低
private int order = Ordered.LOWEST_PRECEDENCE;
public AbstractHandlerMethodAdapter() {
// no restriction of HTTP methods by default
// 参数 restrictDefaultSupportedMethods 参数为 false , 表示不需要严格校验 HttpMethod
super(false);
}
@Override
public final boolean supports(Object handler) {
// handler的类型需要是 HandlerMethod, 这个是@RequestMapping配置创建的对应的 HandlerMethod, 且交由子类实现另一个条件
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
// 必须同时满足support才成立, 子类一般直接返回true
protected abstract boolean supportsInternal(HandlerMethod handlerMethod);
/**
* 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);
}
@Nullable
protected abstract ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;
@Override
public final long getLastModified(HttpServletRequest request, Object handler) {
return getLastModifiedInternal(request, (HandlerMethod) handler);
}
protected abstract long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod);
}
5.4.2.4 RequestMappingHandlerAdapter
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
...
}
由上可以看到,其实现了InitializingBean接口,由@spring源码可知,实例化时会回调其afterPropertiesSet方法
RequestMappingHandlerAdapter#afterPropertiesSet
@Override
public void afterPropertiesSet() {
// Do this first, it may add ResponseBody advice beans
// 1.初始化 ControllerAdvice 相关
initControllerAdviceCache();
// 2.初始化 argumentResolvers 属性
if (this.argumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 3.初始化 initBinderArgumentResolvers 属性
if (this.initBinderArgumentResolvers == null) {
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
// 4.初始化 returnValueHandlers 属性
if (this.returnValueHandlers == null) {
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
RequestMappingHandlerAdapter#initControllerAdviceCache
private void initControllerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
// 1.从spring获取中获取有 @ControllerAdvice 注解的bean, 并封装成 ControllerAdviceBean
// @ControllerAdvice 通常我们用来做全局异常处理等
List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
// 2.排序
AnnotationAwareOrderComparator.sort(adviceBeans);
List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();
// 3.遍历 adviceBeans
for (ControllerAdviceBean adviceBean : adviceBeans) {
Class<?> beanType = adviceBean.getBeanType();
if (beanType == null) {
throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
}
// 扫描有 @ModelAttribute, 没有 @RequestMapping 注解的方法,添加到 modelAttributeAdviceCache 属性中
// 该类方法用于在执行方法前修改 Model 对象
Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) {
this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
}
// 扫描有 @InitBinder 注解的方法,添加到 initBinderAdviceCache 属性中
// 该类方法用于在执行方法前初始化数据绑定器
Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) {
this.initBinderAdviceCache.put(adviceBean, binderMethods);
}
// 如果是 RequestBodyAdvice 或 ResponseBodyAdvice 的子类, 添加到 requestResponseBodyAdviceBeans 中
if (RequestBodyAdvice.class.isAssignableFrom(beanType)) {
requestResponseBodyAdviceBeans.add(adviceBean);
}
if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
requestResponseBodyAdviceBeans.add(adviceBean);
}
}
// 将 requestResponseBodyAdviceBeans 添加到 this.requestResponseBodyAdvice 属性
if (!requestResponseBodyAdviceBeans.isEmpty()) {
this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
}
if (logger.isDebugEnabled()) {
int modelSize = this.modelAttributeAdviceCache.size();
int binderSize = this.initBinderAdviceCache.size();
int reqCount = getBodyAdviceCount(RequestBodyAdvice.class);
int resCount = getBodyAdviceCount(ResponseBodyAdvice.class);
if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) {
logger.debug("ControllerAdvice beans: none");
}
else {
logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +
" @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + ", ResponseBodyAdvice");
}
}
}
总结
@ControllerAdvice 注解:用于 Controller 类的增强类, 其中可定义多种增强的方法, 例如 @ExceptionHandler 注解的方法用于处理器 Controller 抛出的异常等
RequestMappingHandlerAdapter#handleInternal
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav;
// 1.请求校验
checkRequest(request);
// Execute invokeHandlerMethod in synchronized block if required.
// 2.synchronizeOnSession == false
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...
// 3.核心方法
mav = invokeHandlerMethod(request, response, handlerMethod);
}
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}
return mav;
}
RequestMappingHandlerAdapter#invokeHandlerMethod
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 1.创建 ServletWebRequest 对象
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 2.创建 WebDataBinderFactory 对象
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 3.创建 ModelFactory 对象
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 4.创建 ServletInvocableHandlerMethod 对象, 并设置其相关属性
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// 5.创建 ModelAndViewContainer 对象, 并初始其相关属性
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// 6.创建 AsyncWebRequest 异步请求对象
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
// 7.创建 WebAsyncManager 异步请求管理器对象
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(result, !traceOn);
return "Resume with async result [" + formatted + "]";
});
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 8.执行, 核心方法, 见下
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 9.获得 ModelAndView 对象
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
5.4.2.5 ServletInvocableHandlerMethod
结构图
ServletInvocableHandlerMethod#invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 1.执行方法, 调用的是其父类 InvocableHandlerMethod#invokeForRequest(见下方) 在该方法中, 会回调子类的 doInvoke 方法
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 2.设置响应状态码
setResponseStatus(webRequest);
// 3.设置 ModelAndViewContainer 为请求已处理, 返回, 和 @ResponseStatus 注解相关
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
// 4.设置 ModelAndViewContainer 为请求未处理
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
// 5.使用 HandlerMethodReturnValueHandler 处理返回值
// 这里的 returnValueHandlers 为 HandlerMethodReturnValueHandlerComposite 组合对象, 包含了许多的返回值解析器, 采用适配器设计模式, 适配到某个具体的返回值解析器;
// 如: 解析 @ResponseBody 参数, 使用的是 RequestResponseBodyMethodProcessor, 参数解析, 需要借助 HttpMessageConverter
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(formatErrorForReturnValue(returnValue), ex);
}
throw ex;
}
}
InvocableHandlerMethod#invokeForRequest
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 1.解析请求参数, 见下
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
// 2.回调子类方法
return doInvoke(args);
}
InvocableHandlerMethod#getMethodArgumentValues
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
// 1.获取方法的参数
MethodParameter[] parameters = getMethodParameters();
// 2.将参数解析成对应的类型
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
// 获得当前遍历的 MethodParameter 对象,并设置 parameterNameDiscoverer
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
// 先从 providedArgs 中获得参数。如果获得到, 则进入下一个参数的解析, 默认情况 providedArgs 不会传参
args[i] = resolveProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
// 3.判断 resolvers 是否支持当前的参数解析
// 这里的 argumentResolvers 为 HandlerMethodArgumentResolverComposite 组合对象, 包含了许多的参数解析器, 默认26个, 采用适配器设计模式, 适配到某个具体的参数解析器;
// 如: 解析 @RequestBody 参数, 使用的是 RequestResponseBodyMethodProcessor
// 解析 @RequestParam 参数, 使用的是 RequestParamMethodArgumentResolver
// 解析 @PathVariable 参数, 使用的是 PathVariableMethodArgumentResolver
if (this.argumentResolvers.supportsParameter(parameter)) {
try {
// 参数解析, 这里需要借助 HttpMessageConverter
args[i] = this.argumentResolvers.resolveArgument(
parameter, mavContainer, request, this.dataBinderFactory);
continue;
}
catch (Exception ex) {
// Leave stack trace for later, e.g. AbstractHandlerExceptionResolver
if (logger.isDebugEnabled()) {
String message = ex.getMessage();
if (message != null && !message.contains(parameter.getExecutable().toGenericString())) {
logger.debug(formatArgumentError(parameter, message));
}
}
throw ex;
}
}
if (args[i] == null) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
}
return args;
}
5.4.3 应用
综上, 在我们最常见的 @RequestMapping 注解类型, 首先会由对应的 HandlerMapping --> RequestMappingHandlerMapping, 获取到对应的HandlerExecutionChain, HandlerExecutionChain封装了的 HandlerMethod 和 HandlerInterceptor, 再由适配器模式根据Handler(这里是HandlerMethod)获取到对应的HandlerAdapter --> RequestMappingHandlerAdapter, 由 RequestMappingHandlerAdapter 执行对应的 HandlerMethod 和 HandlerInterceptor。
具体执行过程:
RequestMappingHandlerAdapter 会先将 HandlerMethod 封装成 ServletInvocableHandlerMethod, 通过 HandlerMethodArgumentResolver 组件解析请求参数,如:通过 RequestResponseBodyMethodProcessor 解析 @RequestBody 参数等; 然后再通过反射机制调用对应的方法(controller中对应的方法), 获取到执行结果后需要通过 HandlerMethodReturnValueHandler 结果处理器来进行处理。
在 HandlerMethodArgumentResolver 解析参数和 HandlerMethodReturnValueHandler 解析返回值的过程中, 会借助 HttpMessageConverter 进行参数解析
5.5 HandlerExceptionResolver
HandlerExceptionResolver是处理器异常解析器,将处理器执行时发生的异常,解析转换成对应的ModelAndView
5.5.1 初始化
private void initHandlerExceptionResolvers(ApplicationContext context) {
this.handlerExceptionResolvers = null;
if (this.detectAllHandlerExceptionResolvers) {
// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
// We keep HandlerExceptionResolvers in sorted order.
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
}
else {
try {
HandlerExceptionResolver her =
context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
this.handlerExceptionResolvers = Collections.singletonList(her);
}
catch (NoSuchBeanDefinitionException ex) {
// Ignore, no HandlerExceptionResolver is fine too.
}
}
// Ensure we have at least some HandlerExceptionResolvers, by registering
// default HandlerExceptionResolvers if no other resolvers are found.
if (this.handlerExceptionResolvers == null) {
this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
if (logger.isTraceEnabled()) {
logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +
"': using default strategies from DispatcherServlet.properties");
}
}
}
初始化的过程和上述组件初始化过程类似,先从springmvc容器中获取相关组件并排序,如果获取失败,则获取 DispatcherServlet.properties 配置文件中的默认配置,这里默认获取3个:ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver
5.5.2 应用
DispatcherServlet#doDispatch
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 {
// 1.判断是否文件上传
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 2.使用HandlerMapping, 获取 HandlerExecutionChain, HandlerExecutionChain 是对 Handler 和 Interceptor的封装
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 3.根据 Handler 找到对应的 HandlerAdapter
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;
}
}
// 4.执行相关 Interceptor 的 preHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 5.执行 Handler
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 6.执行相关 Interceptor 的 postHandle
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);
}
// 7.处理结果和异常
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);
}
}
}
}
DispatcherServlet#processDispatchResult
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
// 处理异常
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("No view rendering, null ModelAndView returned.");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
DispatcherServlet#processHandlerException
@Nullable
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler, Exception ex) throws Exception {
// Success and error responses may use different content types
request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
// 遍历 HandlerExceptionResolver, 解析异常, 生成 ModelAndView 对象
// ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver
// ExceptionHandlerExceptionResolver 是基于 @ExceptionHandler 注解来配置对应的异常处理器
ModelAndView exMv = null;
if (this.handlerExceptionResolvers != null) {
for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
exMv = resolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
}
if (exMv != null) {
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
}
// We might still need view name translation for a plain error model...
if (!exMv.hasView()) {
String defaultViewName = getDefaultViewName(request);
if (defaultViewName != null) {
exMv.setViewName(defaultViewName);
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using resolved error view: " + exMv, ex);
}
if (logger.isDebugEnabled()) {
logger.debug("Using resolved error view: " + exMv);
}
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}
throw ex;
}
5.6 RequestToViewNameTranslator
5.6.1 初始化
private void initRequestToViewNameTranslator(ApplicationContext context) {
try {
this.viewNameTranslator =
context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
if (logger.isTraceEnabled()) {
logger.trace("Detected " + this.viewNameTranslator.getClass().getSimpleName());
}
else if (logger.isDebugEnabled()) {
logger.debug("Detected " + this.viewNameTranslator);
}
}
catch (NoSuchBeanDefinitionException ex) {
// We need to use the default.
this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
if (logger.isTraceEnabled()) {
logger.trace("No RequestToViewNameTranslator '" + REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME +
"': using default [" + this.viewNameTranslator.getClass().getSimpleName() + "]");
}
}
}
初始化的过程和上述组件初始化过程类似,先从springmvc容器中获取相关组件并排序,如果获取失败,则获取 DispatcherServlet.properties 配置文件中的默认配置,这里默认获取1个:DefaultRequestToViewNameTranslator
5.6.2 应用
在 DispatcherServlet #doDispatch方法中,调用了applyDefaultViewName
DispatcherServlet#applyDefaultViewName
private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
if (mv != null && !mv.hasView()) {
// 使用 DefaultRequestToViewNameTranslator 获取viewName
String defaultViewName = getDefaultViewName(request);
if (defaultViewName != null) {
mv.setViewName(defaultViewName);
}
}
}
DefaultRequestToViewNameTranslator#getViewName
public String getViewName(HttpServletRequest request) {
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
return (this.prefix + transformPath(lookupPath) + this.suffix);
}
5.7 LocaleResolver
LocaleResolver 组件, 本地化(国际化)解析器, 提供国际化支持, 这里暂略
5.8 ViewResolver
ViewResolver 组件, 是试图解析器, 这里暂略
注解版
0.准备阶段
WebAppInitializer
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
config
// 这个是根容器, 相当于ApplicationContext.xml, 包扫描的时候要排除@Controller注解, 避免重复扫描
@ComponentScan(value ={"com.tca"},
excludeFilters={@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class})})
public class RootConfig {
}
// 这个是子容器, 相当于springmvc-config.xml, 只扫描@Controller注解, 避免重复扫描
@EnableWebMvc
@Configuration
@ComponentScan(value = {"com.tca"}, includeFilters={@ComponentScan.Filter(
type= FilterType.ANNOTATION, value={Controller.class})}, useDefaultFilters = false)
public class WebConfig {
}
controller
@RequestMapping("/hello")
@Controller
public class HelloController {
@Autowired
private HelloService helloService;
@GetMapping("/test")
@ResponseBody
public String test() {
return helloService.test();
}
}
service
@Service
public class HelloService {
public String test() {
return "test";
}
}
1.Servlet3.0
1.1 servlet3.0规范
目的
servlet3.0规范主要是用于去web.xml化, 使用纯注解的方式
实现
实现servlet3.0规范的servlet容器(如tomcat),必须实现以下规范
1.servlet容器(如tomcat)启动时会扫描当前应用里所有的jar中ServletContainerInitializer的实现类
2.当前jar中ServletContainerInitializer的实现类, 需要绑定在当前jar下resource目录下的META_INF/services/javax.servlet.ServletContainerInitializer文件, 文件里内容是ServletContainerInitializer实现类的全类名
3.自定义ServletContainerInitializer的实现上可以添加@HandlesTypes注解, 注解中可以传入一些class/interface, 这些class/interface的所有子类实现都会作为onStartup方法的参数
4.在onstart方法中, 我们可以向servlet容器中注册web三大组件: Listener(监听器), Filter(过滤器), Servlet, 完美替代了web.xml的作用
总结
容器启动时会扫描所有jar中的META_INF/services/javax.servlet.ServletContainerInitializer文件, 实例化文件中的类, 并调用onStartup方法(SPI机制)
2.springmvc注解版对servlet3.0规范的适配
2.1 实现
1.spring-web的jar中, 在 resource/META_INF/services/javax.servlet.ServletContainerInitializer 目录下, 有一个ServletContainerInitializer的实现类:
org.springframework.web.SpringServletContainerInitializer
2.SpringServletContainerInitializer配置了@HandlesTypes注解, 指定了WebApplicationInitializer接口
3.容器启动时, 会调用SpringServletContainerInitializer的onStartup方法, 方法的参数有两个: 一是WebApplicationInitializer的所有实现类对应的Class对象, 另一个是ServletContext
2.2 SpringServletContainerInitializer
SpringServletContainerInitializer上注解:@HandlesTypes(WebApplicationInitializer.class)
SpringServletContainerInitializer#onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
根据上述,servlet容器(tomcat)启动时调用ServletContainerInitializer实现类的onStartup方法
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<>();
// 1.获取所有的 WebApplicationInitializer 接口的实现类Class对象, 这里有5个:
// AbstractContextLoaderInitializer
// AbstractDispatcherServletInitializer
// AbstractAnnotationConfigDispatcherServletInitializer
// WebAppInitializer
// AbstractReactiveWebInitializer
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// 2.这里只有自定义的WebAppInitializer不是接口和抽象类
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
// 3.实例化 WebAppInitializer
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
// 4.调用onStartUp方法
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
2.3 WebAppInitializer
2.3.1 结构图
2.3.2 启动流程
1.调用WebAppInitializer的onStartup方法,该方法其父类AbstractDispatcherServletInitializer、AbstractContextLoaderInitializer都有实现,首先调用AbstractDispatcherServletInitializer#onStartup方法
AbstractDispatcherServletInitializer#onStartup(ServletContext servletContext)
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// 1.先调用其父类 AbstractContextLoaderInitializer 的onStartup方法, 用于初始化父Spring容器, 添加监听器等操作
super.onStartup(servletContext);
// 2.这里创建springmvc容器, 向容器中注册DispatcherServlet, 注册Filter等
registerDispatcherServlet(servletContext);
}
AbstractDispatcherServletInitializer#registerDispatcherServlet(ServletContext servletContext)
protected void registerDispatcherServlet(ServletContext servletContext) {
// 1.获取当前servletName, 这里是dispatcher
String servletName = getServletName();
Assert.hasLength(servletName, "getServletName() must not return null or empty");
// 2.创建springmvc子容器, 这里回调用getServletConfigClasses()方法, 获取springmvc的主配置, 该方法由子类 WebAppInitializer 实现, 这里返回
// WebConfig.class
WebApplicationContext servletAppContext = createServletApplicationContext();
Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null");
// 3.创建DispatcherServlet
FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null");
dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
// 4.将DispatcherServlet添加到 servletContext容器中, 这里完成了web.xml文件中<servlet>-DispatcherServlet的配置
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
if (registration == null) {
throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " +
"Check if there is another servlet registered under the same name.");
}
registration.setLoadOnStartup(1);
// 5.这里调用 getServletMappings(), 获取DispatcherServlet拦截的请求, 该方法由子类 WebAppInitializer 实现, 这里返回 "/"
registration.addMapping(getServletMappings());
registration.setAsyncSupported(isAsyncSupported());
// 6.这里我们可以实现 getServletFilters() 方法, 向servletContext中注册 Filter
Filter[] filters = getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
for (Filter filter : filters) {
registerServletFilter(servletContext, filter);
}
}
customizeRegistration(registration);
}
AbstractContextLoaderInitializer#onStartup(ServletContext servletContext)
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerContextLoaderListener(servletContext);
}
AbstractContextLoaderInitializer#registerContextLoaderListener(ServletContext servletContext)
protected void registerContextLoaderListener(ServletContext servletContext) {
// 1.初始化父spring容器, 调用createRootApplicationContext()方法时, 会调用getRootConfigClasses(), 用于获取父容器的主配置类,
// getRootConfigClasses()被子类 WebAppInitializer复写, 这里返回了RootConfig.class
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
// 2.初始化 ContextLoaderListener 监听器
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
// 3.servletContext中添加监听器 ContextLoaderListener, 这里就替代了web.xml中<listener>标签作用
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}
2.4 总结
1.spring-web的jar中, 在 resource/META_INF/services/javax.servlet.ServletContainerInitializer 目录下, 有一个ServletContainerInitializer的实现类:
org.springframework.web.SpringServletContainerInitializer
2.SpringServletContainerInitializer配置了@HandlesTypes注解, 指定了WebApplicationInitializer接口
3.容器启动时, 会调用SpringServletContainerInitializer的onStartup方法, 方法的参数有两个: 一是WebApplicationInitializer的所有实现类对应的Class对象, 另一个是ServletContext; 这里 WebApplicationInitializer的实现类只有一个: WebAppInitializer(自定义的)
4.调用其onStartup方法时会完成父spring容器的创建, 子spring容器的创建, 以及完成DispatcherServlet的创建并注册到spring容器中, 添加监听器, 过滤器等
评论