SpringMVC 源码解析
SpringMVC
在WEB-INF的web.xml中配置Servlet和Listener。
其中核心就是ContextLoaderListener和DispatcherServlet类
配置SpringMVC
1 |
|
ContextLoaderListener
继承关系
ServletContextListener是ServletContext生命周期的监听类,有contextInitialized和contextDestroyed方法。1
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {}
先解析父类ContextLoader。
ContextLoader
继承关系
1 | public class ContextLoader {} |
成员变量
1 | public static final String CONTEXT_ID_PARAM = "contextId"; |
构造器
1 | public ContextLoader() { |
initWebApplicationContext方法
1 | public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { |
createWebApplicationContext() 创建上下文
不在初始参数中设置则默认为WebApplicationContext1
2
3
4
5
6
7
8protected 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
22protected 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 | protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) { |
成员变量
无
构造器
1 | public ContextLoaderListener() { |
contextInitialized方法
详见initWebApplicationContext解析1
2
3
4
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
contextDestroyed方法
1 |
|
DispatcherServlet
1 初始化
1.1 继承关系
1 | public class DispatcherServlet extends FrameworkServlet { |
DispatcherServlet本质是实现了Servlet接口。
DispatcherServlet 构造器
无参构造器1
2
3
4public DispatcherServlet() {
super();
setDispatchOptionsRequest(true);
}
有参构造器1
2
3
4public DispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
setDispatchOptionsRequest(true);
}
setDispatchOptionsRequest设置成true使DispatcherServlet支持处理OPTIONS请求方式。1
2
3public void setDispatchOptionsRequest(boolean dispatchOptionsRequest) {
this.dispatchOptionsRequest = dispatchOptionsRequest;
}
由此可以猜测初始化的流程在父类中执行。
父类FrameworkServlet构造器
1 | public FrameworkServlet() { |
可以看到FrameworkSeervlet的构造器也没有执行初始化流程,那么应该在向上追溯HttpServletBean类的构造器。
HttpServletBean 构造器
实际发现HttpServletBean使用的是默认构造器,可以知道初始化流程不在构造器中执行。
仔细思考HttpServletBean是实现Servlet的,Servlet接口有个专门的初始化方法init()。
1.2 HttpServletBean init方法
1 |
|
initServletBean()由继承HttpServletBean的类实现,执行子类需要执行的初始化流程。具体查看FrameworkServlet类的initServletBean方法。
FrameworkServlet.initServletBean
1 |
|
根据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
101protected 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 | private void initHandlerMappings(ApplicationContext context) { |
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.Class1
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
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;
}
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);
}
调用逻辑是
BeanFactoryUtils.beansOfTypeIncludingAncestors->DefaultListableBeanFactory.getBeansOfType->DefaultListableBeanFactory.getBeanNamesForType->DefaultListableBeanFactory.doGetBeanNamesForType
doGetBeanNamesForType方法中实际就是循环判断所有由spring管理的bean中是否有匹配对应class的bean,然后返回。通过加断点调试可以获取返回的所有HandlerMapping类:
- org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
- org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
- org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
可以猜测url与类的映射关系就是在这些HandlerMapping类的初始化的时候完成的,接下来我们探究这些HandlerMapping类的初始化过程。探究之前先看一下执行HandlerMapping的基类:AbstractHandlerMethodMapping
1.4.2 AbstractHandlerMethodMapping基本信息
1 | public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean { |
这里核心就是将url与执行的类的方法的映射关系存储在mappingRegistry中,通过HandlerMapping就能获得需要执行的类的方法。接下来看mappingRegistry类。
mappingRegistry
1 | class MappingRegistry { |
可以看到有两种映射方式,一是常用的url映射;另一种是名称例如UC#add,名称的方式通常用在动态模板中。
拦截器初始化
抽象类ApplicationObjectSupport提供getApplicationContext()方法,可以方便的获取到ApplicationContext。而AbstractHandlerMethodMapping继承了AbstractHandlerMapping,AbstractHandlerMapping继承了WebApplicationObjectSupport,WebApplicationObjectSupport继承了ApplicationObjectSupport。
继承了ApplicationObjectSupport的类只要实现 protected void initApplicationContext() throws BeansException 即可从上下文中获取bean。
1 | public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered { |
1.4.3 RequestMappingHandlerMapping初始化
RequestMappingHandlerMapping的父类是AbstractHandlerMethodMapping,实现了InitializingBean接口的,所有在bean初始化时会调用afterPropertiesSet方法。1
2
3
4
5
6
7
8
9
10
11
12
13
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
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
44protected 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>() {
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
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
31protected void detectHandlerMethods(final Object handler) {
//...省略
//这里key是方法,T是封装了@RequestMapping信息的类
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
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.register1
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 | protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { |
以上看以看到doService方法中大概做了什么事情,核心的还是doDispathcer()方法,接下来就解析这个方法。
2.2 doDispatcher()
1 | protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { |
2.1.1 根据请求查找执行方法(Handler) getHandler
1 | protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { |
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
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
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 | protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { |
2.1.2 根据执行方法查找运行适配器(HandlerAdapter) getHandlerAdapter
遍历HandlerAdapter集合,根据HandlerAdapter的supports方法判断是否支持。这些集合是DispatcherServlet在初始化时从上下文中获取的。1
2
3
4
5
6
7
8
9
10
11
12protected 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
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
((Servlet) handler).service(request, response);
return null;
}
AbstractHandlerMethodAdapter
1 | public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered { |
把具体执行的部分单独拿了出来。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
65protected 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
50public 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
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
43private 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
29protected 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
30public 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
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 返回处理
RequestResponseBodyMethodProcessor1
2
3
4
5
6
7
8
9
10
11
12
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);
}
视图返回
ViewMethodReturnValueHandler1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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());
}
}
视图名称返回
ViewNameMethodReturnValueHandler1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
52protected 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 | private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, |
视图渲染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
45protected 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
32protected 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);
}
}
}
// 省略
}