SpringMVC源码解析
配置文件
分析SpringMVC之前,首先要看一下配置文件,因为它是我们分析SpringMVC源码的入口。其实里面的重点就是配置了一个ServletContext监听器,他的作用就是监听ServletContext的启动,并且调用重写的contextInitialized方法,这里将会是源码分析的开始。然后就是配置了一个DispatchServlet类型的Servlet,这个大家都熟悉,就是SpringMVC用来处理请求分发和渲染视图的一个Servlet。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<welcome-file-list>
<welcome-file>login.do</welcome-file>
</welcome-file-list>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:dispatcher-servlet.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
WepApplicationContext的创建
当我们在web.xml里面配置某个我们实现的了ServletContextListener接口的监听器后,就会监听ServletContext的启动,在ServletContext启动的时候,就会回调重写的contextInitialized。SpringMVC正是通过这个方法,开始WebApplicationContext的创建(现在还不知道要创建的WebApplicationContext具体是什么类型)
org.springframework.web.context.ContextLoaderListener#contextInitialized
@Override
public void contextInitialized(ServletContextEvent event) {
/**
* web.xml配置文件中配置了ContextLoaderListener
* 他是ServletContextListener的实现了
* 配置了监听器,Servlet容器启动时回先执行他的contextInitialized
* 然后才回去执行load on startup的Servlet的init方法
*/
initWebApplicationContext(event.getServletContext());
}
org.springframework.web.context.ContextLoader#initWebApplicationContext
/**
* 为给定的servlet context初始化Spring的WebApplicationContext,
* 使用构成器提供的WebApplicationContext,
* 或者根据 "contextClass"
* 和 "contextConfigLocation" 两个context-params
* 创建一个新的
*/
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
...省略不重要的代码
try {
// 创建WebApplicationContext
// 存储WebApplicationContext到本地实例变量,
// 保证他在ServletContext关闭的时候也是可用的
// 当然,同时也会保存一份到servletContext中
if (this.context == null) {
// 在这里就会创建WebApplicationContext并返回
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
/*这里会手动执行WebApplicationContext的refresh方法*/
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
/* 存储WebApplicationContext到servletContext中 */
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
...省略不重要的代码
}
org.springframework.web.context.ContextLoader#createWebApplicationContext
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
/*获取WebApplicationContext的具体类型 */
Class<?> contextClass = determineContextClass(sc);
...省略不重要的代码
/*通过返回的Class对象,反射实例化WebApplicationContext并且强转成ConfigurableWebApplicationContext返回*/
return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}
这里就是确定具体的WebApplicationContext类型的地方
org.springframework.web.context.ContextLoader#determineContextClass
protected Class<?> determineContextClass(ServletContext servletContext) {
/*如果web.xml中指定了初始化参数ContextClass,就尝试获取此Class*/
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
try {
/*获取到了,则返回contextClassName对应的WebApplicationContext的Class对象*/
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load custom context class [" + contextClassName + "]", ex);
}
}
else {
/*没有指定WebApplicationContext类型,则从defaultStrategies中获取默认的,defaultStrategies就是一个Properties的对象*/
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
try {
/*返回默认的WebApplicationContext的Class对象 */
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load default context class [" + contextClassName + "]", ex);
}
}
}
可以看到首先会看看有没有在web.xml中指定初始化化参数ContextClass,这个参数需要指定具体的WebApplicationContext的完整类名,然后根据它加载对应的Class对象。但是我们一般不指定这东西,就是使用默认的,默认就会从Properties类型的对象defaultStrategies当中获取,而defaultStrategies其实是在ContextLoader的静态块中创建
private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
private static final Properties defaultStrategies;
static {
try {
/*在这里就会读取到配置文件ContextLoader.properties中默认的WebApplicationContext类型,并且保存到defaultStrategies中*/
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
}
}
可以看到这里是读取配置文件ContextLoader.properties中配置的文件
# Default WebApplicationContext implementation class for ContextLoader.
# Used as fallback when no explicit context implementation has been specified as context-param.
# Not meant to be customized by application developers.
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
可以看到,默认的类型就是XmlWebApplicationContext。通过返回XmlWebApplicationContext的Class对象,反射实例化XmlWebApplicationContext。
创建WebApplicationContext成功后,就会手动执行刷新,就是上面ContextLoader类的initWebApplicationContext中的configureAndRefreshWebApplicationContext(cwac, servletContext);。其实就是执行AbstractApplicationContext中的refresh方法,他是Spring中在ApplicationContext创建的时候,进行BeanDefinition的加载,BeanFactory创建,Bean的创建和保存等等一系列动作的入口。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
...省略不重要的代码
/* 把ServletContext设置到WebApplicationContext中 */
wac.setServletContext(sc);
...省略不重要的代码
/*执行WebApplicationContext的refresh方法,该方法继承于父类AbstractApplicationContext*/
wac.refresh();
}
DispatchServlet的初始化
然后就是DispatchServlet的创建,因为web.xml中配置了load-on-startup为1,所以Servlet容器启动后马上启动。Servlet创建后会调用init初始化方法,而DispatchServlet的init的方法在他间接继承的父类HttpServletBean中
org.springframework.web.servlet.HttpServletBean#init
/**
* 将配置参数映射到这个servlet的bean属性上,并调用子类初始化
*/
@Override
public final void init() throws ServletException {
// 从init参数设置bean属性.
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
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;
}
}
// 子类的初始化工作.
initServletBean();
}
org.springframework.web.servlet.FrameworkServlet#initServletBean
@Override
protected final void initServletBean() throws ServletException {
...省略不重要的代码
try {
/**
* 初始化WebApplicationContext, 并保存到DispatchServlet的成员变量中
* 这里之所以要这样做,是因为DispatchServlet重载类构造方法,支持通过构造方法参入一个WebApplicationContext
* 另外之前创建的WebApplicationContext,是保存到ContextLoader的成员变量和ServletContext中的
* DispatchServlet中并没有
*/
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
...省略不重要的代码
}
org.springframework.web.servlet.FrameworkServlet#initWebApplicationContext
protected WebApplicationContext initWebApplicationContext() {
/*ServletContext中获取WebApplicationContext,就是ContextLoader中创建的WebApplicationContext*/
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
// 这里要判断一次啊DispatchServlet中的成员变量webApplicationContext
// 因为DispatchServlet重载的构造,支持传入WebApplicationContext类型的参数
if (this.webApplicationContext != null) {
// 在构造器注入上下文实例,使用它
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// 上下文尚未刷新 -> 提供诸如设置父上下文、设置应用程序上下文id等服务
if (cwac.getParent() == null) {
// 如果当前的WebApplicationContext对象的parent属性为空,则赋值为rootContext
cwac.setParent(rootContext);
}
/*手动refresh当前的WebApplicationXml,和前面一样,因为是构造方法传入的,还没用refresh */
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// 在构建时没有注入上下文实例,看看是否已经在servlet上下文中注册了一个。
// 如果存在,则假定父上下文(如果有的话)已经设置,
// 并且用户已经执行了任何初始化,比如设置上下文id
// 其实就是从ServletContext找到ContextLoader创建的WebApplicationContext
wac = findWebApplicationContext();
}
if (wac == null) {
// 没有为这个servlet定义上下文实例->创建一个
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// 要么上下文不是具有刷新支持的可配置applicationcontext,
// 要么在构建时注入的上下文已经被刷新
// 在这里手动触发初始化onRefresh方法
// 会调用到DispatchServlet重写的方法
synchronized (this.onRefreshMonitor) {
// 接下来就是分析这里
onRefresh(wac);
}
}
if (this.publishContext) {
// 将WebApplicationContext作为servlet上下文属性发布。
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
org.springframework.web.servlet.DispatcherServlet#onRefresh
/**
* 这个实现调用{@link #initStrategies}。
*/
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
/**
* 初始化这个servlet使用的策略对象。
* 可以在子类中重写,以便进一步初始化策略对象。
*/
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
/* 初始化HandlerMappings */
initHandlerMappings(context);
/* 初始化HandlerAdapters */
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
/* 初始化ViewResolvers */
initViewResolvers(context);
initFlashMapManager(context);
}
可以看到,接下来就是初始化DispatchServlet中的各种组件了,比较重要的有HandlerMappings,HandlerAdapters,ViewResolvers。
DispatchServlet重要组件的初始化
org.springframework.web.servlet.DispatcherServlet#initHandlerMappings
/**
* 初始化该类使用的处理器映射。
* 如果在这个名称空间的BeanFactory中没有定义HandlerMapping bean,
* 我们默认使用BeanNameUrlHandlerMapping。
*/
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
/*detectAllHandlerMappings 默认true*/
if (this.detectAllHandlerMappings) {
// 找到所有ApplicationContext中的HandlerMapping,包括祖先ApplicationContext
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
/*保存所有的HandlerMapping*/
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// 对HandlerMapping进行排序.
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
/**
* 默然情况下,SpringMVC会加载所有实现了HandlerMapping接口的Bean,
* 但是也可以让SpringMVC只加载BeanName为handlerMapping的HandlerMapping实现类,
* 就是在web.xml配置文件中配置初始化化参数detectAllHandlerMappings为false
* 如果没有找到BeanName为handlerMapping的Bean,
* 则加载DispatcherServlet.properties配置文件中默认的handlerMappings
*/
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.
}
}
...省略不重要的代码
for (HandlerMapping mapping : this.handlerMappings) {
if (mapping.usesPathPatterns()) {
this.parseRequestPath = true;
break;
}
}
}
org.springframework.web.servlet.DispatcherServlet#initHandlerAdapters
/**
* 初始化该类使用的handleradapter。
* 如果在此名称空间的BeanFactory中没有定义HandlerAdapter bean,
* 我们默认为SimpleControllerHandlerAdapter。
*/
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
/*detectAllHandlerAdapters 默认true*/
if (this.detectAllHandlerAdapters) {
// 找到所有ApplicationContext中的HandlerAdapter,包括祖先ApplicationContext.
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
/*保存所有的HandlerAdapter*/
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// 对HandlerAdapter进行排序..
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
/**
* 如果在web.xml中初始化参数detectAllHandlerAdapters为false,
* 则只在WebApplicationContext中查找名为handlerAdapter的Bean
* 如果没有,则使用DispatcherServlet.properties配置文件中默认的的HandlerAdapter
*/
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.
}
}
...省略不重要的代码
}
org.springframework.web.servlet.DispatcherServlet#initViewResolvers
/**
* 初始化该类使用的ViewResolvers。
* 如果在BeanFactory中没有为此定义ViewResolver bean
* 名称空间,默认为InternalResourceViewResolver。
*/
private void initViewResolvers(ApplicationContext context) {
this.viewResolvers = null;
/*detectAllViewResolvers 默认true*/
if (this.detectAllViewResolvers) {
// 找到所有ApplicationContext中的ViewResolver,包括祖先ApplicationContext.
Map<String, ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
/*保存所有的ViewResolver*/
this.viewResolvers = new ArrayList<>(matchingBeans.values());
// 对ViewResolver进行排序
AnnotationAwareOrderComparator.sort(this.viewResolvers);
}
}
else {
/**
* 如果在web.xml中初始化参数detectAllViewResolvers为false,
* 则只在WebApplicationContext中查找名为viewResolver的Bean
* 如果没有,则使用DispatcherServlet.properties配置文件中默认的的ViewResolver
*/
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.
}
}
...省略不重要的代码
}
DispatchServlet的组件全部初始化完毕后,一切的准备工作就都做好了,接下来就可以正常的处理请求。在此之前先贴上spring-webmvc指定默认组件类型的properties文件DispatcherServlet.properties
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.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.function.support.RouterFunctionMapping
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.function.support.HandlerFunctionAdapter
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
DispatchServlet的处理逻辑
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Delegate POST requests to {@link #processRequest}.
* @see #doService
*/
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
可以看到,无论是get请求,或者是post请求,都调用的是processRequest方法来处理请求
org.springframework.web.servlet.FrameworkServlet#processRequest
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
...省略不重要的代码
doService(request, response);
...省略不重要的代码
}
org.springframework.web.servlet.DispatcherServlet#doService
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
/*doDispatch中就是完整的请求处理过程*/
doDispatch(request, response);
}
下面就是DispatchServlet真正处理请求的过程了,在继续往下看前,先贴一张DispatchServlet处理请求的完整流程图
然后对照代码看一下,是否流程完全一样?
org.springframework.web.servlet.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 {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
/*根据request寻找对应的mappedHandler,然后获取HandlerExecutionChain*/
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
/*如果没有找到对应的Handler,则通过response返回错误信息*/
noHandlerFound(processedRequest, response);
return;
}
/*根据当前的mappedHandler的getHandler方法返回的handler(一般就是HandlerMethod,老式用法就是Controller),寻找对应的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;
}
}
/**
* 调用拦截器链上,各拦截器的preHandle方法
* 如果其中一个返回false,
* 就执行拦截器链所有的拦截器的afterCompletion方法
* 然后返回false,然后这里就会return
* 正常情况下不进这个分支
*/
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 处理请求并返回ModelAndView对象.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
/*如果ModelAndView中没有View,则添加默认的viewName*/
applyDefaultViewName(processedRequest, mv);
/*调用各拦截器链上拦截器的postHandler方法*/
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);
}
/*处理ModelAndView到View,再渲染jsp,通过response输出页面的过程。 当然最后还会调用拦截器的afterCompletion方法 */
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);
}
}
}
}
获取mappedHandler
这里会遍历DispatchSerlet中所有的HandlerMapping,尝试通过request查找对应的handler。handler有可能有不同类型,如果我们平常的那种注解式开发的Controller,就会返回HandlerMethod。但是还用一种方式,就是我们编写的Controller类继承AbstractController,那么这里就会返回Controller。然后把handler和拦截器封装成一个HandlerExecutionChain对象
org.springframework.web.servlet.DispatcherServlet#getHandler
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
/*遍历所有的HandlerMapping,直到通过request可以获取到HandlerExecutionChain */
for (HandlerMapping mapping : this.handlerMappings) {
/*返回的是HandlerExecutionChain对象,不是想象中的一个HandlerMapping,更不是直接返回handler*/
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 根据request对象获取handler,其实就是根据url获取对应的HandlerMethod
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = obtainApplicationContext().getBean(handlerName);
}
/*把HandlerMethod封装成HandlerExecutionChain,里面包含了各个拦截器*/
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
...省略不重要的代码
return executionChain;
}
下面就是根据request中的url匹配到对应的HandlerMethode的过程
/**
* 查找给定请求的URL路径的handler.
* @param request current HTTP request
* @return the handler instance, or {@code null} if none found
*/
@Override
@Nullable
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = initLookupPath(request);
Object handler;
if (usesPathPatterns()) {
RequestPath path = ServletRequestPathUtils.getParsedRequestPath(request);
handler = lookupHandler(path, lookupPath, request);
}
else {
handler = lookupHandler(lookupPath, request);
}
if (handler == null) {
// We need to care for the default handler directly, since we need to
// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean name or resolved handler?
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
return handler;
}
然后把获取到的HandlerMethod封装成HandlerExecutionChain,其实就是添加上各种拦截器
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(request)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
返回的是一个HandlerExecutionChain 对象,然后下面就是HandlerExecutionChain 的成员变量
public class HandlerExecutionChain {
/*真正的handler,就是HandlerMethod或者Controller*/
private final Object handler;
/*存放拦截器的数组*/
@Nullable
private HandlerInterceptor[] interceptors;
/*存放拦截器的list*/
@Nullable
private List<HandlerInterceptor> interceptorList;
...
}
顺便贴一下HandlerMethod中关键的成员变量
public class HandlerMethod {
// 这个就是我们打了@Controller标签的那个类
private final Object bean;
@Nullable
private final BeanFactory beanFactory;
private final Class<?> beanType;
// 这个是他要执行的方法
private final Method method;
private final Method bridgedMethod;
// 方法参数
private final MethodParameter[] parameters;
@Nullable
private HttpStatus responseStatus;
@Nullable
private String responseStatusReason;
...
}
根据mappedHandler中的handler对象,获取HandlerAdapter
因为有不同的handler,不同的handler会有不同的接口,所有需要HandlerAdapter去做适配,这里用到的就是设计模式中的适配器模式。拿到了返回的HandlerExecutionChain 对象之后,就会通过里面的handler,获取HandlerAdapter。
org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
/*遍历所有的HandlerAdapter,直到该HandlerAdapter的supports方法返回true*/
for (HandlerAdapter adapter : this.handlerAdapters) {
/*如果adapter的supports方法返回true,代表就是要找的handler*/
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
如果handler的类型是HandlerMethoded的话
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports
@Override
public final boolean supports(Object handler) {
return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}
或者handler的类型是老式用法的继承Controller
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter#supports
@Override
public boolean supports(Object handler) {
/*当前handler对象时Controller类型,就返回*/
return (handler instanceof Controller);
}
处理请求并返回ModelAndView对象
先贴一行DispatchServlet中走到的当前的步骤
org.springframework.web.servlet.DispatcherServlet#doDispatch
// 处理请求并返回ModelAndView对象
// ha就是上面寻找到的HandlerAdapter,mappedHandler.getHandler()返回的是HandlerMethod或者Controller.
// 下面就只分析HandlerMethod的了
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
下面就是处理请求返回ModelAndView的过程了
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ModelAndView mav; // 要返回的ModelAndView
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) {
// 执行HandlerMethod中的方法,返回ModelAndView
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// 执行HandlerMethod中的方法,返回ModelAndView
mav = invokeHandlerMethod(request, response, handlerMethod);
}
}
else {
// 执行HandlerMethod中的方法,返回ModelAndView
mav = invokeHandlerMethod(request, response, handlerMethod);
}
...省略不重要的代码
return mav;
}
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
/*封装请求参数webRequest*/
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
/*根据当前的HandlerMethod创建HandlerMethod的间接子类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);
/*ModelAndViewContainer 意思就是ModelAndView的容器*/
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
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);
}
/*执行请求处理*/
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
// 获取并返回ModelAndView
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
/*执行请求处理,继续点进去*/
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
...省略不重要代码
}
org.springframework.web.method.support.InvocableHandlerMethod#invokeForRequest
@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
/*获取方法的参数*/
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Arguments: " + Arrays.toString(args));
}
/*里面是真的要执行了*/
return doInvoke(args);
}
org.springframework.web.method.support.InvocableHandlerMethod#doInvoke
@Nullable
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
/*利用反射的方式执行方法,就是method.invoke(object, args)*/
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
...省略不重要代码
}
catch (InvocationTargetException ex) {
...省略不重要代码
}
}
请求已经处理完了,还有一步返回ModelAndView
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getModelAndView
@Nullable
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
}
/*从ModelAndViewContainer中获取ModelMap*/
ModelMap model = mavContainer.getModel();
/*创建ModelAndView*/
ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
...
/*返回ModelAndView*/
return mav;
}
viewResolver通过viewName获取view
现在已经处理完请求,返回了ModelAndView,回到DispatcServlet的doDispatch方法中,进行下一步的分析。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
/*处理ModelAndView到View,再渲染jsp,通过response输出页面的过程 */
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
...
}
org.springframework.web.servlet.DispatcherServlet#processDispatchResult
/**
* 处理handler选择和handler调用的结果,该结果要么是ModelAndView,要么是要解析到ModelAndView的异常。
*/
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);
}
}
// 处理器是否返回一个要渲染的view?
if (mv != null && !mv.wasCleared()) {
/*viewResolver通过ModelAndView获取View,进行渲染*/
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
...省略不重要的代码
if (mappedHandler != null) {
// 调用该Handler上所有拦截器链中的afterCompletion方法
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
在render方法中就会开始进行,里面将会遍历viewResolvers,尝试通过ModelAndView获取View对象。然后通过View对象的render方法,进行渲染工作。
org.springframework.web.servlet.DispatcherServlet#render
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
/*通过ModelAndView获取viewName*/
String viewName = mv.getViewName();
if (viewName != null) {
// ModelAndView中包含viewName,则尝试通过viewResolver解析
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// 不需要查找:ModelAndView对象包含实际的视图对象。
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// 委托给view对象进行渲染。
if (logger.isTraceEnabled()) {
logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
/*视图渲染(jsp),然后通过response返回渲染的页面*/
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}
这里就会遍历所有的viewResolver,都尝试获取View,如果获取到了就返回。
org.springframework.web.servlet.DispatcherServlet#resolveViewName
@Nullable
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
/*遍历所有的viewResolver*/
for (ViewResolver viewResolver : this.viewResolvers) {
/*尝试通过viewResolver解析viewName,看是否能返回view*/
View view = viewResolver.resolveViewName(viewName, locale);
/*获取都view不为空,则返回*/
if (view != null) {
return view;
}
}
}
return null;
}
这里会判断一下是否有缓存,有的话就尝试从缓存中取,没有的话直接创建
org.springframework.web.servlet.view.AbstractCachingViewResolver#resolveViewName
@Override
@Nullable
public View resolveViewName(String viewName, Locale locale) throws Exception {
if (!isCache()) {
/*不存在缓存的情况下直接创建view*/
return createView(viewName, locale);
}
else {
/*否则先尝试从缓存中取*/
Object cacheKey = getCacheKey(viewName, locale);
View view = this.viewAccessCache.get(cacheKey);
if (view == null) {
synchronized (this.viewCreationCache) {
view = this.viewCreationCache.get(cacheKey);
if (view == null) {
// Ask the subclass to create the View object.
view = createView(viewName, locale);
if (view == null && this.cacheUnresolved) {
view = UNRESOLVED_VIEW;
}
if (view != null && this.cacheFilter.filter(view, viewName, locale)) {
this.viewAccessCache.put(cacheKey, view);
this.viewCreationCache.put(cacheKey, view);
}
}
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace(formatKey(cacheKey) + "served from cache");
}
}
return (view != UNRESOLVED_VIEW ? view : null);
}
}
我们直接看createView方法,因为当前viewResolver默认的类型是InternalResourceViewResolver,在上面的DispatcherServlet.properties中可以看到。而InternalResourceViewResolver又继承了UrlBasedViewResolver,createView方法在UrlBasedViewResolver中重写了,所以这里首先会调用类UrlBasedViewResolver的createView方法
org.springframework.web.servlet.view.UrlBasedViewResolver#createView
@Override
protected View createView(String viewName, Locale locale) throws Exception {
// 如果这个解析器不支持处理给定的view,
// 返回null以传递给链中的下一个解析器
if (!canHandle(viewName, locale)) {
return null;
}
// "redirect:" 前缀,重定向的处理。
if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
RedirectView view = new RedirectView(redirectUrl,
isRedirectContextRelative(), isRedirectHttp10Compatible());
String[] hosts = getRedirectHosts();
if (hosts != null) {
view.setHosts(hosts);
}
return applyLifecycleMethods(REDIRECT_URL_PREFIX, view);
}
// "forward:" 前缀,内部转发的处理。
if (viewName.startsWith(FORWARD_URL_PREFIX)) {
String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
InternalResourceView view = new InternalResourceView(forwardUrl);
return applyLifecycleMethods(FORWARD_URL_PREFIX, view);
}
// 否则回到超类实现:调用loadView.
return super.createView(viewName, locale);
}
org.springframework.web.servlet.view.AbstractCachingViewResolver#createView
这里除了处理重定向和转发的处理,剩下的就是回调父类AbstractCachingViewResolver的createView方法,然后里面又会调用loadView方法。
@Nullable
protected View createView(String viewName, Locale locale) throws Exception {
return loadView(viewName, locale);
}
UrlBasedViewResolver重写了loadView方法,所以又会回到UrlBasedViewResolver中,这里就会真正的创建View并返回
org.springframework.web.servlet.view.UrlBasedViewResolver#loadView
@Override
protected View loadView(String viewName, Locale locale) throws Exception {
/* 通过viewName获取View的子类AbstractUrlBasedView */
AbstractUrlBasedView view = buildView(viewName);
/* 执行bean的初始化回调方法initializeBean */
View result = applyLifecycleMethods(viewName, view);
// 返回view
return (view.checkResource(locale) ? result : null);
}
buildView方法会调用InternalResourceViewResolver的buildView,然后又会调用父类UrlBasedViewResolver的buildView方法
org.springframework.web.servlet.view.InternalResourceViewResolver#buildView
@Override
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
/*调用UrlBasedViewResolver的buildView方法*/
InternalResourceView view = (InternalResourceView) super.buildView(viewName);
if (this.alwaysInclude != null) {
view.setAlwaysInclude(this.alwaysInclude);
}
view.setPreventDispatchLoop(true);
return view;
}
buildView方法中会反射实例化一个AbstractUrlBasedView对象,然后对他进行一推的属性设置
org.springframework.web.servlet.view.UrlBasedViewResolver#buildView
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
Class<?> viewClass = getViewClass();
Assert.state(viewClass != null, "No view class");
AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass);
/*添加前缀以及后缀*/
view.setUrl(getPrefix() + viewName + getSuffix());
view.setAttributesMap(getAttributesMap());
String contentType = getContentType();
if (contentType != null) {
view.setContentType(contentType);
}
String requestContextAttribute = getRequestContextAttribute();
if (requestContextAttribute != null) {
view.setRequestContextAttribute(requestContextAttribute);
}
Boolean exposePathVariables = getExposePathVariables();
if (exposePathVariables != null) {
view.setExposePathVariables(exposePathVariables);
}
Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();
if (exposeContextBeansAsAttributes != null) {
view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);
}
String[] exposedContextBeanNames = getExposedContextBeanNames();
if (exposedContextBeanNames != null) {
view.setExposedContextBeanNames(exposedContextBeanNames);
}
return view;
}
最后就会返回这个view,然后调用他的render方法
view的渲染
先回到DispatchServlet的render方法,看看我们接下来要看的代码
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
/*视图渲染(jsp),然后通过response返回渲染的页面*/
view.render(mv.getModelInternal(), request, response);
}
org.springframework.web.servlet.view.AbstractView#render
/**
* 根据指定的模型准备视图,如有必要,将其与静态属性和RequestContext属性合并。
* 委托renderMergedOutputModel进行实际的渲染。
* @see #renderMergedOutputModel
*/
@Override
public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("View " + formatViewName() +
", model " + (model != null ? model : Collections.emptyMap()) +
(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
}
/*mergedModel 可以理解为就是jsp中我们可以获取通过JSTL获取到的数据:如${users}*/
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
/*进行实际的渲染,并通过response输出*/
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel
@Override
protected void renderMergedOutputModel(
Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
// 将model object公开为请求属性.
exposeModelAsRequestAttributes(model, request);
// 公开helpers作为请求属性, 如果有.
exposeHelpers(request);
// 确定请求dispatcher的路径。
String dispatcherPath = prepareForRendering(request, response);
// 获取目标资源(通常是一个JSP)的RequestDispatcher。
RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
if (rd == null) {
throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
"]: Check that the corresponding file exists within your web application archive!");
}
// 如果已经包含或响应已经提交,则执行include,否则执行forward。
if (useInclude(request, response)) {
response.setContentType(getContentType());
if (logger.isDebugEnabled()) {
logger.debug("Including [" + getUrl() + "]");
}
rd.include(request, response);
}
else {
//注意:转发的资源应该决定content type本身。
if (logger.isDebugEnabled()) {
logger.debug("Forwarding to [" + getUrl() + "]");
}
rd.forward(request, response);
}
}
rd会转发到一个Servlet中,专门进行jsp的解析,最后把拼装成的html交给response输出到客户端浏览器。
到此为止,源码分析就结束了。
Java配置注册的DispatchServlet
在最开始的时候有说道,DispatchServlet是支持构造器实例化的,并且通过构造器参数的方式传递ApplicationContext。但是上面并没有体现,这里补充一下。
在SpringMVC的官方文档中,有这么一段代码示例
public class MyWebApplicationInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletCxt) {
// Load Spring web application configuration
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
ac.register(AppConfig.class);
ac.refresh();
// Create and register the DispatcherServlet
DispatcherServlet servlet = new DispatcherServlet(ac);
ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/app/*");
}
}
意思就是我们实现一个WebApplicationInitializer 接口的实现类,然后重写onStartup。我们在里面创建AnnotationConfigWebApplicationContext,并且制定扫描的配置类如AppConfig.class,调用它的refresh刷新方法,然后new一个DispatcherServlet,把AnnotationConfigWebApplicationContext 传递进去,然后再把DispatchServlet注册到ServletContext 中,然后还有指定指定LoadOnStartup为1,该Servelt接受请求的路径。至此,代码方式的配置就结束了,完全跟web.xml中配置的一模一样。
但问题是他为什么会生效呢?
其实这里涉及到Servlet3.0以后提供的新功能
首先tomcat在启动的时候,会扫描ClassPath路径下有没有META-INF/services/javax.servlet.ServletContainerInitializer这样一个配置文件,以下是spring-web的该配置文件的内容
org.springframework.web.SpringServletContainerInitializer
tomcat扫描到后就是去查看这个类,是否实现了ServletContainerInitializer接口,如果是,就会调用里面重写的onStartup方法。并且tomcat会传递一个Set<Class<?>>类型的集合,里面都是Class对象。而具体传递的Class,由实现了ServletContainerInitializer接口的实现类上的注解@HandlesTypes决定,这个也是Tomcat定的一个规范。
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer
可以看到SpringServletContainerInitializer 实现了ServletContainerInitializer,并且@HandlesTypes的值为WebApplicationInitializer.class,tomcat就会扫描所有类型为WebApplicationInitializer的Class,传递给onStartup方法
org.springframework.web.SpringServletContainerInitializer#onStartup
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<>();
if (webAppInitializerClasses != null) {
// 遍历所有实现了WebApplicationInitializer接口的Class对象
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
// 反射实例化后,添加到initializers
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);
for (WebApplicationInitializer initializer : initializers) {
// 遍历所有的WebApplicationInitializer 对象,调用他的onStartup,并且把ServletContext 对象传递进去
initializer.onStartup(servletContext);
}
}
最后就是调用到Spring官网文档上的那段代码