SpringMVC

在WEB-INF的web.xml中配置Servlet和Listener。

其中核心就是ContextLoaderListener和DispatcherServlet类

配置SpringMVC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<!-- 配置web.xml,使其具有springmvc特性,主要配置两处,一个是ContextLoaderListener,一个是DispatcherServlet -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
<!-- 配置ContextLoaderListener表示,该工程要以spring的方式启动。启动时会默认在/WEB-INF目录下查找applicationContext.xml作为spring容器的配置文件,该文件里可以初始化一些bean -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- spring mvc 配置 -->
<!-- 配置DispatcherServlet表示,该工程将采用springmvc的方式。启动时也会默认在/WEB-INF目录下查找XXX-servlet.xml作为配置文件,
XXX就是DispatcherServlet的名字,该文件中将配置两项重要的mvc特性:HandlerMapping,负责为DispatcherServlet这个前端控制器的请求查找Controller;
ViewResolver,负责为DispatcherServlet查找ModelAndView的视图解析器。
此处使用指定的配置文件spring-mvc.xml -->
<servlet>
<servlet-name>contacts</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!--<param-value>/WEB-INF/classes/spring-mvc-servlet.xml</param-value>-->
<param-value>classpath*:/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>contacts</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
</web-app>

ContextLoaderListener

继承关系

ServletContextListener是ServletContext生命周期的监听类,有contextInitialized和contextDestroyed方法。

1
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {}

先解析父类ContextLoader。

ContextLoader

继承关系
1
public class ContextLoader {}
成员变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static final String CONTEXT_ID_PARAM = "contextId";
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
public static final String CONTEXT_CLASS_PARAM = "contextClass";
public static final String CONTEXT_INITIALIZER_CLASSES_PARAM = "contextInitializerClasses";
public static final String GLOBAL_INITIALIZER_CLASSES_PARAM = "globalInitializerClasses";
private static final String INIT_PARAM_DELIMITERS = ",; \t\n";
private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
private static final Properties defaultStrategies;
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
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());
}
}

private static final Map<ClassLoader, WebApplicationContext> currentContextPerThread =
new ConcurrentHashMap<>(1);
@Nullable
private static volatile WebApplicationContext currentContext;
@Nullable
private WebApplicationContext context;
private final List<ApplicationContextInitializer<ConfigurableApplicationContext>> contextInitializers =
new ArrayList<>();
构造器
1
2
3
4
5
public ContextLoader() {
}
public ContextLoader(WebApplicationContext context) {
this.context = context;
}
initWebApplicationContext方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
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!");
}

servletContext.log("Initializing Spring root WebApplicationContext");
Log logger = LogFactory.getLog(ContextLoader.class);
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.
// spring上下文创建
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
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 ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
// 设置上下文到ServletContext中
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}

if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");
}

return this.context;
}
catch (RuntimeException | Error ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
}
createWebApplicationContext() 创建上下文

不在初始参数中设置则默认为WebApplicationContext

1
2
3
4
5
6
7
8
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
Class<?> contextClass = determineContextClass(sc);
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}

determineContextClass 上线文类反射

可以在ServletContext初始化参数中配置Spring上下文的实现类型,默认为WebApplicationContext。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected Class<?> determineContextClass(ServletContext servletContext) {
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
try {
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load custom context class [" + contextClassName + "]", ex);
}
}
else {
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
try {
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load default context class [" + contextClassName + "]", ex);
}
}
}

configureAndRefreshWebApplicationContext() 配置上下文
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
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
String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
if (idParam != null) {
wac.setId(idParam);
}
else {
// Generate default id...
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(sc.getContextPath()));
}
}

wac.setServletContext(sc);
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) { //配置文件地址
wac.setConfigLocation(configLocationParam);
}

// 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) {
// 保存ServletContext初始化参数到Spring上下文
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}

customizeContext(sc, wac); // 加载传入的类
wac.refresh(); // 加载
}

成员变量

构造器

1
2
3
4
5
public ContextLoaderListener() {
}
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}

contextInitialized方法

详见initWebApplicationContext解析

1
2
3
4
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}

contextDestroyed方法

1
2
3
4
5
@Override
public void contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}

DispatcherServlet

1 初始化

1.1 继承关系

1
2
3
4
5
6
7
8
9
public class DispatcherServlet extends FrameworkServlet {
//省略
}
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
//省略
}
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware {
//省略
}

DispatcherServlet本质是实现了Servlet接口。
DispatcherServlet 构造器
无参构造器

1
2
3
4
public DispatcherServlet() {
super();
setDispatchOptionsRequest(true);
}

有参构造器

1
2
3
4
public DispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
setDispatchOptionsRequest(true);
}

setDispatchOptionsRequest设置成true使DispatcherServlet支持处理OPTIONS请求方式。

1
2
3
public void setDispatchOptionsRequest(boolean dispatchOptionsRequest) {
this.dispatchOptionsRequest = dispatchOptionsRequest;
}

由此可以猜测初始化的流程在父类中执行。
父类FrameworkServlet构造器

1
2
3
4
5
public FrameworkServlet() {
}
public FrameworkServlet(WebApplicationContext webApplicationContext) {
this.webApplicationContext = webApplicationContext;
}

可以看到FrameworkSeervlet的构造器也没有执行初始化流程,那么应该在向上追溯HttpServletBean类的构造器。

HttpServletBean 构造器

实际发现HttpServletBean使用的是默认构造器,可以知道初始化流程不在构造器中执行。

仔细思考HttpServletBean是实现Servlet的,Servlet接口有个专门的初始化方法init()。

1.2 HttpServletBean init方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Override
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
// Set bean properties from init parameters.
//设置Servlet初始化参数
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
//封装Wrapper
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
//设置资源加载器
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
//ResourceEditor类用于将配置文件转化为Resource资源对象,同时PropertyResolver来处理${..}配置引用
//Environment extends PropertyResolver
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
//初始化wrapper,目前是个空实现
initBeanWrapper(bw);
//将Servlet初始化参数设置进去
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}

// 让子类实现,执行子类想要执行的初始化流程。
initServletBean();

if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}

initServletBean()由继承HttpServletBean的类实现,执行子类需要执行的初始化流程。具体查看FrameworkServlet类的initServletBean方法。

FrameworkServlet.initServletBean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@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 {
//核心方法,初始化上下文,web.xml中配置了ContextLoadListener会在初始时生成上下文并设置到ServletContext中
this.webApplicationContext = initWebApplicationContext();
//预留给子类的初始化方法,当前为空方法
initFrameworkServlet();
}
catch (ServletException | 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");
}
}

根据initServletBean中的内容可以看到上下文初始化方法,接下来查看initWebApplicationContext方法。

FrameworkServlet.initWebApplicationContext

这里主要处理如果在构造器时传入一个上下文,同时ContextLoaderListener初始时也会自动生成一个上下文,这样要将自动生成的上下文作为传入的上下文的父容器,确保传入的上下文能够获取初始上下文的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
protected WebApplicationContext initWebApplicationContext() {
//从ServletContext中取出上下文
//servletContext.getAttribute(attrName);
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
// this.webApplicationContext 是构造器中注入的
// 优先使用构造器中传入的上下文
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
//上下的active状态是在refresh()中的prepareRefresh阶段
//this.active.set(true);
//active不是true说明还没refresh
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
//设置ServletContext,ServletConfig,Namespace,contextId,ApplicationListener...
//并执行上下文的refresh()
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
//从ServletContext中获取上下文
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
//新建一个默认上下文,默认类型是XmlWebApplicationContext
//新建完同样会执行configureAndRefreshWebApplicationContext方法将其初始化
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.
//上下文已经refresh了,执行onRefresh方法,实际是有DispatcherServlet实现了该方法,处理了url映射等的初始化。
onRefresh(wac);
}

if (this.publishContext) {
// Publish the context as a servlet context attribute.
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;
}
//初始化上下文,并执行上下文的refresh方法
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 {
// Generate default id...
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
}
}

wac.setServletContext(getServletContext());
wac.setServletConfig(getServletConfig());
wac.setNamespace(getNamespace());
//委托模式
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);
//执行配置在Servlet初始化参数中的初始化器
//从参数中获取所有绑定的初始化类,然后执行它们的initialize方法
applyInitializers(wac);
//IOC容器定位加载注册的核心方法
wac.refresh();
}

1.3 DispatcherServlet初始化 onRefresh()

onRefresh方法中依赖IOC容器(上下文)初始需求的对象,例如文件上传解析器、主题解析器、路径映射处理器集合、处理执行器集合等,具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}

接下来主要查看url映射关系加载的代码。

1.4 url 映射关系加载(HandleMapping)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
//全部加载
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<HandlerMapping>(matchingBeans.values());
//做排序处理
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");
}
}
}

detectAllHandlerMappings 默认值为true,所以可以看到默认是加载所有映射。其中核心代码是
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);

这里使用了 BeanFactoryUtils 来获取需要的所有HandlerMapping。接下来解析一下BeanFactoryUtils的beansOfTypeIncludingAncestors方法。

1.4.1 HandlerMapping获取

这里泛型T是HandlerMapping。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
*Map<String, HandlerMapping> matchingBeans =
*BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
*true 包含非单例类,
*返回值:<beanName, 对应的bean>
**/
public static <T> Map<String, T> beansOfTypeIncludingAncestors(
ListableBeanFactory lbf, Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException {

Assert.notNull(lbf, "ListableBeanFactory must not be null");
Map<String, T> result = new LinkedHashMap<String, T>(4);
result.putAll(lbf.getBeansOfType(type, includeNonSingletons, allowEagerInit));
if (lbf instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
Map<String, T> parentResult = beansOfTypeIncludingAncestors(
(ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
for (Map.Entry<String, T> entry : parentResult.entrySet()) {
String beanName = entry.getKey();
if (!result.containsKey(beanName) && !hbf.containsLocalBean(beanName)) {
result.put(beanName, entry.getValue());
}
}
}
}
return result;
}

其中调用 DefaultListableBeanFactory#getBeansOfType(java.lang.Class, boolean, boolean) 方法查询上下文中的bean。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
@Override
public <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException {

String[] beanNames = getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
Map<String, T> result = new LinkedHashMap<String, T>(beanNames.length);
for (String beanName : beanNames) {
try {
result.put(beanName, getBean(beanName, type));
}
catch (BeanCreationException ex) {
Throwable rootCause = ex.getMostSpecificCause();
if (rootCause instanceof BeanCurrentlyInCreationException) {
BeanCreationException bce = (BeanCreationException) rootCause;
if (isCurrentlyInCreation(bce.getBeanName())) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Ignoring match to currently created bean '" + beanName + "': " +
ex.getMessage());
}
onSuppressedException(ex);
// Ignore: indicates a circular reference when autowiring constructors.
// We want to find matches other than the currently created bean itself.
continue;
}
}
throw ex;
}
}
return result;
}
@Override
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
}
Map<Class<?>, String[]> cache =
(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
String[] resolvedBeanNames = cache.get(type);
if (resolvedBeanNames != null) {
return resolvedBeanNames;
}
resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
cache.put(type, resolvedBeanNames);
}
return resolvedBeanNames;
}
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
List<String> result = new ArrayList<String>();
// Check all bean definitions.
for (String beanName : this.beanDefinitionNames) {
// Only consider bean as eligible if the bean name
// is not defined as alias for some other bean.
if (!isAlias(beanName)) {
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
if (!mbd.isAbstract() && (allowEagerInit ||
((mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading())) &&
!requiresEagerInitForType(mbd.getFactoryBeanName()))) {
// In case of FactoryBean, match object created by FactoryBean.
boolean isFactoryBean = isFactoryBean(beanName, mbd);
boolean matchFound = (allowEagerInit || !isFactoryBean || containsSingleton(beanName)) &&
(includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type);
if (!matchFound && isFactoryBean) {
// In case of FactoryBean, try to match FactoryBean instance itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type);
}
if (matchFound) {
result.add(beanName);
}
}
}
catch (CannotLoadBeanClassException ex) {
if (allowEagerInit) {
throw ex;
}
// Probably contains a placeholder: let's ignore it for type matching purposes.
if (this.logger.isDebugEnabled()) {
this.logger.debug("Ignoring bean class loading failure for bean '" + beanName + "'", ex);
}
onSuppressedException(ex);
}
catch (BeanDefinitionStoreException ex) {
if (allowEagerInit) {
throw ex;
}
// Probably contains a placeholder: let's ignore it for type matching purposes.
if (this.logger.isDebugEnabled()) {
this.logger.debug("Ignoring unresolvable metadata in bean definition '" + beanName + "'", ex);
}
onSuppressedException(ex);
}
}
}

// Check manually registered singletons too.
for (String beanName : this.manualSingletonNames) {
try {
// In case of FactoryBean, match object created by FactoryBean.
if (isFactoryBean(beanName)) {
if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
result.add(beanName);
// Match found for this bean: do not match FactoryBean itself anymore.
continue;
}
// In case of FactoryBean, try to match FactoryBean itself next.
beanName = FACTORY_BEAN_PREFIX + beanName;
}
// Match raw bean instance (might be raw FactoryBean).
if (isTypeMatch(beanName, type)) {
result.add(beanName);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Shouldn't happen - probably a result of circular reference resolution...
if (logger.isDebugEnabled()) {
logger.debug("Failed to check manually registered singleton with name '" + beanName + "'", ex);
}
}
}

return StringUtils.toStringArray(result);
}

调用逻辑是

  1. BeanFactoryUtils.beansOfTypeIncludingAncestors ->
  2. DefaultListableBeanFactory.getBeansOfType ->
  3. DefaultListableBeanFactory.getBeanNamesForType ->
  4. DefaultListableBeanFactory.doGetBeanNamesForType

doGetBeanNamesForType方法中实际就是循环判断所有由spring管理的bean中是否有匹配对应class的bean,然后返回。通过加断点调试可以获取返回的所有HandlerMapping类:

  1. org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
    1. org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
    2. org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

可以猜测url与类的映射关系就是在这些HandlerMapping类的初始化的时候完成的,接下来我们探究这些HandlerMapping类的初始化过程。探究之前先看一下执行HandlerMapping的基类:AbstractHandlerMethodMapping

1.4.2 AbstractHandlerMethodMapping基本信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
//HandlerMapping类名称生成器
private HandlerMethodMappingNamingStrategy<T> namingStrategy;
//核心,保存url与HandlerMappingInfo(具体执行的类和方法)
private final MappingRegistry mappingRegistry = new MappingRegistry();
private static final CorsConfiguration ALLOW_CORS_CONFIG = new CorsConfiguration();
static {
ALLOW_CORS_CONFIG.addAllowedOrigin("*");
ALLOW_CORS_CONFIG.addAllowedMethod("*");
ALLOW_CORS_CONFIG.addAllowedHeader("*");
ALLOW_CORS_CONFIG.setAllowCredentials(true);
}
//... 省略
}

这里核心就是将url与执行的类的方法的映射关系存储在mappingRegistry中,通过HandlerMapping就能获得需要执行的类的方法。接下来看mappingRegistry类。

mappingRegistry
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MappingRegistry {
private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>();
//T 是AbstractHandlerMethodMapping<T>,HandlerMethod是具体执行的类的方法信息
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>();
//url映射,通过查找执行的类方法
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>();
//名称映射,名称是AbstractHandlerMethodMapping类中的属性namingStrategy生成的
private final Map<String, List<HandlerMethod>> nameLookup =
new ConcurrentHashMap<String, List<HandlerMethod>>();
//cors访问控制,通常是处理跨域
private final Map<HandlerMethod, CorsConfiguration> corsLookup =
new ConcurrentHashMap<HandlerMethod, CorsConfiguration>();
//...省略
}

可以看到有两种映射方式,一是常用的url映射;另一种是名称例如UC#add,名称的方式通常用在动态模板中。

拦截器初始化

抽象类ApplicationObjectSupport提供getApplicationContext()方法,可以方便的获取到ApplicationContext。而AbstractHandlerMethodMapping继承了AbstractHandlerMapping,AbstractHandlerMapping继承了WebApplicationObjectSupport,WebApplicationObjectSupport继承了ApplicationObjectSupport。

继承了ApplicationObjectSupport的类只要实现 protected void initApplicationContext() throws BeansException 即可从上下文中获取bean。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered {
@Override
protected void initApplicationContext() throws BeansException {
//留给子类添加拦截器的入口
extendInterceptors(this.interceptors);
//获取拦截器
detectMappedInterceptors(this.adaptedInterceptors);
initInterceptors();
}
//从上下文中获取拦截器
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
getApplicationContext(), MappedInterceptor.class, true, false).values());
}
}
1.4.3 RequestMappingHandlerMapping初始化

RequestMappingHandlerMapping的父类是AbstractHandlerMethodMapping,实现了InitializingBean接口的,所有在bean初始化时会调用afterPropertiesSet方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void afterPropertiesSet() {
//这里都是配置了一下工具类,例如url解析工具、路径匹配工具、路径前缀匹配工具。
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());
//核心在父类中执行
super.afterPropertiesSet();
}

接下来查看父类中的afterPropertiesSet方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Override
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
//获得BeanFactory中所有的类(查找了继承Object的类)
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
//直接循环遍历
for (String beanName : beanNames) {
//排除scopedTarget.开头的类
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
//查询bean的class类型
try {
beanType = getApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
//这里是核心,isHandler在这个类中是抽象方法由子类去实现,这里要看RequestMappingHandlerMapping的实现
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
protected abstract boolean isHandler(Class<?> beanType);

在上面的initHandlerMethods方法中可以看见通过isHandler方法判断是不是需要解析的类,而isHandler的实现是交由子类即RequestMappingHandlerMapping来实现。

1
2
3
4
5
6
@Override
protected boolean isHandler(Class<?> beanType) {
//这里是判断类有没有使用@Controller或@RequestMapping注解的
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

RequestMappingHandlerMapping是判断类是否有@Controller或者@RequestMapping注解来判断的。
接下来回到initHandlerMethods方法中继续解析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
protected void initHandlerMethods() {
//...省略其他代码
if (beanType != null && isHandler(beanType)) {
//处理映射的核心方法
detectHandlerMethods(beanName);
}
}
}
handlerMethodsInitialized(getHandlerMethods());
}
//查找映射关系
//handler是被判断为可以解析映射关系的类(例如使用@RequestMapping注解的类)
protected void detectHandlerMethods(final Object handler) {
//解析handler类型
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
//去除动态代理,获得被代理的类本身
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//遍历这个类都所有方法,映射是url映射到具体的方法上的
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
//这里是具体解析这个类的方法
//实际是交由子类去实现的,这里也就是RequestMappingHandlerMapping类实现的
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
});

if (logger.isDebugEnabled()) {
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
}
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
registerHandlerMethod(handler, invocableMethod, mapping);
}
}

根据上文我们接下来解析RequestMappingHandlerMapping类的getMappingForMethod方法实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
//这里根据方法是否有@RequestMapping注解生成RequestMappingInfo
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
//解析类本身的映射,例如在类上加上注解@RequestMapping("/a")这个时候就要把类上配置的路径加上方法上的路径才是真正的路径
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
//这一步会处理类上的@RequestMapping,把类上的url与方法上的url拼接在一起,生成真正的路径。
info = typeInfo.combine(info);
}
}
return info;
}
//判断方法是否有@ReequestMapping注解,如果有这个注解就解析并生成RequestMappingInfo类
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
//这里判断了是否有@RequestMapping注解
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
//处理RequestCondition
RequestCondition<?> condition = (element instanceof Class<?> ?
getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
//根据是否有@RequestMapping注解来生成RequestMappingInfo
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
//RequestMappingInfo类中记录了@RequestMapping注解的参数信息和这个方法的信息
protected RequestMappingInfo createRequestMappingInfo(
RequestMapping requestMapping, RequestCondition<?> customCondition) {

return RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
.methods(requestMapping.method())
.params(requestMapping.params())
.headers(requestMapping.headers())
.consumes(requestMapping.consumes())
.produces(requestMapping.produces())
.mappingName(requestMapping.name())
.customCondition(customCondition)
.options(this.config)
.build();
}

现在映射关系获取了,但是还有存储到RequestMappingHandlerMapping类中。回到AbstractHandlerMethodMapping.detectHandlerMethods方法中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
protected void detectHandlerMethods(final Object handler) {
//...省略
//这里key是方法,T是封装了@RequestMapping信息的类
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
});
//...省略
//循环解析
for (Map.Entry<Method, T> entry : methods.entrySet()) {
//校验这个方法是在这个类上的,保证可以访问
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
//存放到this.mappingRegistry
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
//注册到mappingRegistry中
//AbstractHandlerMethodMapping.MappingRegistry 内部类
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}

最后看一下注册的过程,AbstractHandlerMethodMapping.MappingRegistry.register

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//handler是类型(Class)
//T是RequestMappingInfo 记录了url信息
public void register(T mapping, Object handler, Method method) {
//加写锁
this.readWriteLock.writeLock().lock();
try {
//将类和方法封装成HandlerMethod
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
//判断唯一性
assertUniqueMethodMapping(handlerMethod, mapping);

if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
}
//保存到mappingLookup mapping中有url信息
this.mappingLookup.put(mapping, handlerMethod);
//获取访问路径
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
//保存到路径映射集合中
this.urlLookup.add(url, mapping);
}
//设置了名称 类名中的大写字母#method
//例如:UserController.add 就是 UC#add
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
//访问配置(处理跨域请求配置/请求头),由子类实现即RequestMappingHandlerMapping
//RequestMappingHandlerMapping中是通过方法/类有没有@CrossOrigin注解来处理的
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
//保存映射信息
this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));
}
finally {
this.readWriteLock.writeLock().unlock();
}
}
//获取访问路径TODO
private List<String> getDirectUrls(T mapping) {
List<String> urls = new ArrayList<String>(1);
for (String path : getMappingPathPatterns(mapping)) {
if (!getPathMatcher().isPattern(path)) {
urls.add(path);
}
}
return urls;
}

2 请求处理

因为DispatcherServlet继承了HttpServlet,请求会到doService方法中执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}

// Make framework objects available to handlers and view objects.
// 设置request属性用于框架访问执行方法和视图
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的作用是在redirect中传递参数,取是从session中取的
//redirect过程会产生一个新的request,但是参数不变,所以需要保存参数
//
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
//设置FlashMap和管理器
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

try {
//这里是执行的核心
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);
}
}
}
}

以上看以看到doService方法中大概做了什么事情,核心的还是doDispathcer()方法,接下来就解析这个方法。

2.2 doDispatcher()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
// 配置异步管理器用于Servlet 3.0的异步支持
// Servlet的异步需要提供线程池,异步管理器中就有线程池
// request中已经有了就取出,没有就新建一个
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {
//视图和异常
ModelAndView mv = null;
Exception dispatchException = null;

try {
// 判断是否是文件上传,借助了multipartResolver文件上传解析器判断
// 如果是文件上传的请求,则将request封装成能够处理文件上传的SevrvletRequest
processedRequest = checkMultipart(request);
// 是否包装成文件上传的Request,判断是否是文件上传
multipartRequestParsed = (processedRequest != request);

// Determine handler for the current request.
// 根据Request,实际就是url去获取对应的执行方法
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
// 没有对应的Handler就执行默认的
noHandlerFound(processedRequest, response);
return;
}

// Determine handler adapter for the current request.
// 适配器用于执行具体的Handler
// 因为url对应的类不一定都是使用RequestMapping方式的普通方法,所以springMVC通过适配器去统一执行
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;
}
}
// 执行拦截器的前置方法 applyPreHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

// Actually invoke the handler.
// 执行url对应的具体那个类的方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//没有视图就设置默认视图
applyDefaultViewName(processedRequest, mv);
// 执行拦截器的后置方法
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
// 不管成功还是失败都执行applyAfterConcurrentHandlingStarted
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
2.1.1 根据请求查找执行方法(Handler) getHandler
1
2
3
4
5
6
7
8
9
10
11
12
13
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}

HandlerExecutionChain 是委托HandlerMapping的getHandler,AbstractHandlerMapping类中实现了该方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 查找 handler
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
// 如果只是bean名称就获取bean对象
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
// 加上拦截器,生成执行链
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// 设置跨域访问控制
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}

查找handler

getHandlerInternal方法不同的HandlerMapping中有不同的实现,这里查看了AbstractHandlerMethodMapping的实现,RequestMappingHandlerMapping是继承该抽象类的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 获得url路径
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
this.mappingRegistry.acquireReadLock();
try {
// 根据url查找handlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
// createWithResolvedBean处理是bean名称的情况,是bean名称则到上下文中获取对应的对象
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
/**
* 根据url查找HandlerMethod
**/
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
// 从mappingRegistry成员变量urlLookup集合中查出所有的RequestMappingInfo
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
//找不到
if (matches.isEmpty()) {
// No choice but to go through all mappings...
// RequestMappingHandlerMapping是根据请求参数生成一个新对象
// 由各个HandlerMapping 实现
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}

if (!matches.isEmpty()) {
// 比较器用于排序
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
lookupPath + "] : " + matches);
}
Match bestMatch = matches.get(0);
// 一条路径匹配了多个方法
if (matches.size() > 1) {
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();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
// request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath);
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
// handlerMethod.createWithResolvedBean()
public class HandlerMethod {
public HandlerMethod createWithResolvedBean() {
// url
Object handler = this.bean;
if (this.bean instanceof String) {
String beanName = (String) this.bean;
handler = this.beanFactory.getBean(beanName);
}
return new HandlerMethod(this, handler);
}

//... 省略
}

查找拦截器,生成执行链
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
//获取url
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
//添加拦截器,只有url匹配的拦截器才添加
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
2.1.2 根据执行方法查找运行适配器(HandlerAdapter) getHandlerAdapter

遍历HandlerAdapter集合,根据HandlerAdapter的supports方法判断是否支持。这些集合是DispatcherServlet在初始化时从上下文中获取的。

1
2
3
4
5
6
7
8
9
10
11
12
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
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");
}

HandlerAdapter适配器,Handler是url对应具体执行的类或方法,Handler可以是多种实现的例如是Servlet,是@Controller注解的pojo,是@RequestMapping注解的pojo等,HandlerAdapter适配器给这些不同的实现提供了一个统一的执行方式。即:HandlerAdapter.handle

2.1.3 通过适配器(HandlerAdapter)执行

HandlerAdapter有各种实现,选择来解析

SimpleServletHandlerAdapter

SimpleServletHandlerAdapter 就是处理Servlet实现的类,很简单直接执行service方法就行了。

1
2
3
4
5
6
7
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {

((Servlet) handler).service(request, response);
return null;
}

AbstractHandlerMethodAdapter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
//... 省略
@Override
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 子类实现
return handleInternal(request, response, (HandlerMethod) handler);
}
}
// 实现类
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
//... 省略

@Override
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 返回的模型和视图
ModelAndView mav;
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 {
//执行
mav = invokeHandlerMethod(request, response, handlerMethod);
}
// 缓存处理
if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
}
else {
prepareResponse(response);
}
}

return mav;
}
}

把具体执行的部分单独拿了出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//包装了request和response
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
// 处理@InitBinder,用于请求参数类型转换
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
// 处理@ModelAttribute和@SessionAttribute 用于向Model(ModelAndVie中的Model)中设置属性
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// ServletInvocableHandlerMethod 是HandlerMethod的子类
// 相比HandlerMethod增加了参数解析,返回值处理等功能,最重要的是新增了方法的执行功能
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
// 设置参数解析器
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
// 设置返回值处理器
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
invocableMethod.setDataBinderFactory(binderFactory);
// 设置参数名称查找器
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// ModelAndViewContainer主要是用来返回Model对象的,在ModelAndViewContainer中有defaultModel和redirectModel,defaultModel是默认使用的Model,
// 后者用于传递redirect时的参数,我们在处理中使用了Model或ModelMap时,ArgumentResolver会传入defaultModel,它是BindingAwareModelMap类型,既继承了ModelMap又实现了Model接口,所以在处理器中使用Model或者ModelMap其实使用的是同一个对象,
// Map参数传入的也是这个对象。处理器中RedirectAttributes类型的参数ArgumentResolver会传入redirectModel,
// 它实际上是RedirectAttributeModelMap类型。
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
// 处理redict的Model
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 执行@ModelAttribute和@SessionAttribute,保存属性到Model
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
// Servlet 3.0 异步处理,WebAsyncManager提供了异步需要的一些工具
// AsyncWebRequest 提供了一下异步状态查询的方法
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
// 线程池
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
// Callable拦截器
asyncManager.registerCallableInterceptors(this.callableInterceptors);
// DeferredResult处理过程拦截器,在start async前,超时后/异步处理完成后/网络超时后触发拦截
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
//判断是否有异步执行结果
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
if (logger.isDebugEnabled()) {
logger.debug("Found concurrent result value [" + result + "]");
}
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
// 开始执行
invocableMethod.invokeAndHandle(webRequest, mavContainer);
// 判断当前请求是否是异步请求
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}

return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}

执行 ServletInvocableHandlerMethod.invokeAndHandle

查看ServletInvocableHandlerMethod类的invokeAndHandle方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//这里是开始调用 controller 方法
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 设置响应状态,如果发生异常是不会执行这一步,会继续往上抛
setResponseStatus(webRequest);

if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}

mavContainer.setRequestHandled(false);
try {
// 处理返回值,是视图还是JSON还是其他,这部分内容放在最后返回值处理
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
/**
* 执行controller方法
**/
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 获取方法所需参数
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
if (logger.isTraceEnabled()) {
logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"' with arguments " + Arrays.toString(args));
}
// 反射执行方法
Object returnValue = doInvoke(args);
if (logger.isTraceEnabled()) {
logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
"] returned [" + returnValue + "]");
}
return returnValue;
}

获取controller方法所需的参数。
查找某个参数值的逻辑:

  1. 先委托参数名查找器获取参数名
  2. 从外部提供的参数清单中查找值(竟然是根据类型判断的)
  3. 如果没有直接提供,使用参数解析器创建
  4. 如果还是没有获得,直接报错
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
    Object... providedArgs) throws Exception {
    // MethodParameter记录了参数的信息,例如下标、类型等
    MethodParameter[] parameters = getMethodParameters();
    Object[] args = new Object[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
    MethodParameter parameter = parameters[i];
    parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
    // 从providedArgs中获取参数,providedArgs是null
    args[i] = resolveProvidedArgument(parameter, providedArgs);
    if (args[i] != null) {
    continue;
    }
    // 判断是否支持,是否能取到变量
    // argumentResolvers类中保存了所有的参数解析器
    // 通过遍历这些解析,哪个解析器能提供参数就使用哪个解析器
    // 有多种的参数解析器,例如请求参数的,路径变量的,Servlet参数的
    if (this.argumentResolvers.supportsParameter(parameter)) {
    try {
    // 根据支持的解析器提供参数,有可以解析的解析器就允许参数为null
    args[i] = this.argumentResolvers.resolveArgument(
    parameter, mavContainer, request, this.dataBinderFactory);
    continue;
    }
    catch (Exception ex) {
    if (logger.isDebugEnabled()) {
    logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
    }
    throw ex;
    }
    }
    // 获取不到就报错
    if (args[i] == null) {
    throw new IllegalStateException("Could not resolve method parameter at index " +
    parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
    ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
    }
    }
    return args;
    }
    public MethodParameter[] getMethodParameters() {
    return this.parameters;
    }

执行controller方法,很简单反射执行Method就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
protected Object doInvoke(Object... args) throws Exception {
ReflectionUtils.makeAccessible(getBridgedMethod());
try {
// Method 的反射执行
return getBridgedMethod().invoke(getBean(), args);
}
catch (IllegalArgumentException ex) {
assertTargetBean(getBridgedMethod(), getBean(), args);
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
throw new IllegalStateException(getInvocationErrorMessage(text, args), ex);
}
catch (InvocationTargetException ex) {
// Unwrap for HandlerExceptionResolvers ...
Throwable targetException = ex.getTargetException();
if (targetException instanceof RuntimeException) {
throw (RuntimeException) targetException;
}
else if (targetException instanceof Error) {
throw (Error) targetException;
}
else if (targetException instanceof Exception) {
throw (Exception) targetException;
}
else {
String text = getInvocationErrorMessage("Failed to invoke handler method", args);
throw new IllegalStateException(text, targetException);
}
}
}

2.1.4 返回值处理

在上一小节看到执行controller的方法,并产生了返回值,于是可以接下去看看。
查看ServletInvocableHandlerMethod类的invokeAndHandle方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
//这里是开始调用 controller 方法
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
// 设置响应状态,如果发生异常是不会执行这一步,会继续往上抛
setResponseStatus(webRequest);

if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
}
else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}

mavContainer.setRequestHandled(false);
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}

this.returnValueHandlers.handleReturnValue 这里对方法的返回值进行了处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
// 这里选择一个处理返回值的处理器
// 不同的返回有不同的处理器,像ResponseBody、视图等
// ResponseBody很好判断有没有注解就可以,其他的都是native方法不方便查看
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
boolean isAsyncValue = isAsyncReturnValue(value, returnType);
for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
continue;
}
if (handler.supportsReturnType(returnType)) {
return handler;
}
}
return null;
}

@ResponseBody 返回处理

RequestResponseBodyMethodProcessor

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

// Try even with null return value. ResponseBodyAdvice could get involved.
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

视图返回

ViewMethodReturnValueHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

if (returnValue == null) {
return;
}
else if (returnValue instanceof View){
View view = (View) returnValue;
mavContainer.setView(view);
if (view instanceof SmartView) {
if (((SmartView) view).isRedirectView()) {
mavContainer.setRedirectModelScenario(true);
}
}
}
else {
// should not happen
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}

视图名称返回

ViewNameMethodReturnValueHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

if (returnValue instanceof CharSequence) {
String viewName = returnValue.toString();
mavContainer.setViewName(viewName);
if (isRedirectViewName(viewName)) {
mavContainer.setRedirectModelScenario(true);
}
}
else if (returnValue != null){
// should not happen
throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}

返回值处理完,我们回到DispatcherServlet的doDispatcher方法中继续执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
try{
// 省略之前执行的内容

// 这里执行了方法,并返回了ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 异步请求直接返回
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 没返回设置默认视图
applyDefaultViewName(processedRequest, mv);
// 拦截器后置方法执行
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) {
// 执行拦截器的完成方法 afterCompletion
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
// 执行拦截器的完成方法 afterCompletion
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
// 异步
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
// 执行异步拦截器的afterConcurrentHandlingStarted方法
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// 清理文件上传缓存
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, 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);
}
}

// 有视图返回就渲染
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}

if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
// 执行afterCompletion
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}

视图渲染

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
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.resolveLocale(request);
response.setLocale(locale);

View view;
// 视图引用
if (mv.isReference()) {
// 根据视图名称获取视图
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
// 返回的就是视图
else {
// No need to lookup: the ModelAndView object contains the actual View object.
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() + "'");
}
}

// Delegate to the View object for rendering.
if (logger.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
// 执行视图渲染
// HtmlResourceView 就是把文件流输出到Response FileCopyUtils.copy(this.resource.getInputStream(), response.getOutputStream());
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
getServletName() + "'", ex);
}
throw ex;
}
}

总结点

DispatcherServlet构造时如果传入一个容器,父子容器的处理?

DispatcherServlet允许在构造时传入一个Spring容器,同时ContextLoaderListener在初始时会自动构造一个Spring容器,这个时候DispatcherServlet初始过程会设置父子容器:

HttpServletBean.init() -> FrameworkServlet.initWebApplicationContext() -> FrameworkServlet.initServletBean
FrameworkServlet.initWebApplicationContext

会将ContextLoaderListener初始的容器作为DispatcherServlet中传入的容器的父容器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
protected WebApplicationContext initWebApplicationContext() {
//从ServletContext中取出上下文
//servletContext.getAttribute(attrName);
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
// this.webApplicationContext 是构造器中注入的
// 优先使用构造器中传入的上下文
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
//上下的active状态是在refresh()中的prepareRefresh阶段
//this.active.set(true);
//active不是true说明还没refresh
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
//设置ServletContext,ServletConfig,Namespace,contextId,ApplicationListener...
//并执行上下文的refresh()
configureAndRefreshWebApplicationContext(cwac);
}
}
}
// 省略
}