SpringMvc加载机制

Web容器启动时会调用ServletContainerInitializeronStartup方法,以Tomcat容器为例,其调用实际是在StandardContext容器的startInternal()方法中被调用的,且可在该接口的实现类上标注@HandlesTypes注解,该注解配置的接口的实现类都会被传递到onStartup方法的入参中,并通过反射调用生成对象,Spring MVC中通过SpringServletContainerInitializer实现了ServletContainerInitializer接口,并在该类上通过@HandlesTypes注解导入了WebApplicationInitializer

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
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
// 容器启动的时会调用该方法,且传入@HandlesTypes(WebApplicationInitializer.class)
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<>();
if (webAppInitializerClasses != null) { // 传入的webAppInitializerClasses类的所有子类
for (Class<?> waiClass : webAppInitializerClasses) { //进行循环敢兴趣的类
// 判断类不是接口,不是抽象类
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {// 通过反射调用创建类的实例,然后加入到initializers
initializers.add((WebApplicationInitializer) ReflectionUtils.accessibleConstructor(waiClass).newInstance());
} catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
// 若WebApplicationInitializer的实现类实现了Orderd接口或者是标注了@Order注解,会进行排序
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext); // 依次循环调用类的实例的onStartup方法
}
}
}

最终会调用AbstractDispatcherServletInitializer抽象类的onStartup方法,该方法会先调用超类的onStartup方法创建rootAppContext,且将rootAppContext设置到ContextLoaderListener,并将创建的ContextLoaderListener设置到ServletContext中,在Tomcat的StandardContext容器调用listenerStart()方法中调用ContextLoaderListenercontextInitialized方法;然后创建webAppContext,并将其设置到新创建的DispatcherServlet中。

创建AnnotationConfigWebApplicationContext上下文仅仅调用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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
registerDispatcherServlet(servletContext);
}
protected void registerDispatcherServlet(ServletContext servletContext) {
String servletName = getServletName();
Assert.hasLength(servletName, "getServletName() must not return null or empty");
WebApplicationContext servletAppContext = createServletApplicationContext();
Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null");

FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null");
dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());

ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
if (registration == null) {
throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " + "Check if there is another servlet registered under the same name.");
}
registration.setLoadOnStartup(1);
registration.addMapping(getServletMappings());
registration.setAsyncSupported(isAsyncSupported());

Filter[] filters = getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
for (Filter filter : filters) {
registerServletFilter(servletContext, filter);
}
}
customizeRegistration(registration);
}
}
public abstract class AbstractContextLoaderInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
registerContextLoaderListener(servletContext);
}
protected void registerContextLoaderListener(ServletContext servletContext) {
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
servletContext.addListener(listener);
}
}
}
public abstract class AbstractAnnotationConfigDispatcherServletInitializer extends AbstractDispatcherServletInitializer {
protected WebApplicationContext createRootApplicationContext() {
Class<?>[] configClasses = getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(configClasses);
return context;
}
else {
return null;
}
}
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
Class<?>[] configClasses = getServletConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
context.register(configClasses);
}
return context;
}
}

故可通过继承AbstractAnnotationConfigDispatcherServletInitializer重写getRootConfigClassesgetServletConfigClasses方法来自定义设置Root容器的配置类和Web容器的配置类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ElevenStarterInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebAppConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
1
2
3
4
5
6
7
@Configuration
@ComponentScan(basePackages = "com.eleven.icode.imvc", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {RestController.class, Controller.class}),
@ComponentScan.Filter(type = ASSIGNABLE_TYPE, value = WebAppConfig.class),
})
public class RootConfig {
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
@ComponentScan(basePackages = {"com.eleven.icode.imvc"}, includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {RestController.class, Controller.class})
}, useDefaultFilters = false)
@EnableWebMvc
public class WebAppConfig implements WebMvcConfigurer {
@Bean
public ElevenInterceptor tulingInterceptor() {
return new ElevenInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tulingInterceptor()).addPathPatterns("/*");
}
@Bean
public InternalResourceViewResolver internalResourceViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setSuffix(".jsp");
viewResolver.setPrefix("/");
return viewResolver;
}
}

ContextLoaderListener实现了ServletContextListener接口,该接口是在Servlet API中定义的,提供了与Servlet生命周期结合的回调contextInitializedcontextDestroyed。这里只是去启动Root容器。通过注解方式在创建ContextLoaderListener就已将context传递进来了,这里不需要再创建了,只有通过xml方式的context才为空,需要在这里创建根容器对象。

当Root容器初始化完成后会将其保存到ServletContext应用上下文对象中,方便在Web容器实例化过程从ServletContext取出来设置为父容器。

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
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
}
public class ContextLoader {
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!");
}
try {
if (this.context == null) { // 通过注解方式在外面就已经传递进来了,通过xml方式context为空,需要在这里创建根容器对象
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
// 强制转化成ConfigurableWebApplicationContext
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
// 判断ConfigurableWebApplicationContext配置上下文版本的是不是激活了
if (!cwac.isActive()) { // 没有激活
if (cwac.getParent() == null) { // 若此时ConfigurableWebApplicationContext对象的父容器为空
ApplicationContext parent = loadParentContext(servletContext); // 为Root Context加载我们的父容器
cwac.setParent(parent); // parent == null
}
configureAndRefreshWebApplicationContext(cwac, servletContext); // 配置和刷新根容器对象
}
}
// 把Spring上下文保存到应用上下文对象中,方便在Spring web上下文对象实例化过程会从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);
}
return this.context;
} catch (RuntimeException ex) {
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
} catch (Error err) {
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
String idParam = sc.getInitParameter(CONTEXT_ID_PARAM); // 去ServletContext获取contextId
if (idParam != null) {
wac.setId(idParam); // 若web.xml配置了该参数就设置到容器中
} else { //若没有配置,就使用默认的
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
wac.setServletContext(sc); // 把当前工程的应用上下文设置到spring上下文中
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) { // 把配置文件的路径保存到上下文中
wac.setConfigLocation(configLocationParam);
}
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
customizeContext(sc, wac); // 定制spring上下文对象
wac.refresh(); // 会触发IOC根容器的刷新
}
}

对于Web容器的初始化工作是在DispatcherServlet的超类FrameworkServlet中的initServletBean()方法中完成的,该方法是Servlet的init方法中被调用。首先将之前初始化好的Root容器设置到当前Web容器中,然后将Web容器进行初始化。

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
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
protected final void initServletBean() throws ServletException {
try {
this.webApplicationContext = initWebApplicationContext();
initFrameworkServlet();
} catch (ServletException | RuntimeException ex) {
throw ex;
}
}
protected WebApplicationContext initWebApplicationContext() {
// 从ServletContext对象中获取到Spring Root上下文对象,在Spring根容器上下文创建成功后放入到ServletContext对象中
WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) { // webApplicationContext对象是在创建DispatcherServlet对象时,存放进来的一个springmvc web的上下文对象
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) { // 判断是否激活
if (cwac.getParent() == null) { // 设置父的上下文对象
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac); // 作为SpringMvc上下文刷新
}
}
}
if (wac == null) {
wac = findWebApplicationContext();
}
if (wac == null) {
wac = createWebApplicationContext(rootContext);
}

if (!this.refreshEventReceived) {
synchronized (this.onRefreshMonitor) {
onRefresh(wac);
}
}
if (this.publishContext) {
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
if (this.contextId != null) {
wac.setId(this.contextId);
} else {
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()));
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
}
postProcessWebApplicationContext(wac);
applyInitializers(wac);
wac.refresh();
}
}

启动Web容器与启动Root容器基本类似,唯一比较大的区别是在Web容器启动前添加了一个ContextRefreshListener监听器,在容器启动完成时会进行调用,初始化Spring MVC九大组件。

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
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
FrameworkServlet.this.onApplicationEvent(event);
}
}
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
public void onApplicationEvent(ContextRefreshedEvent event) {
this.refreshEventReceived = true;
synchronized (this.onRefreshMonitor) {
onRefresh(event.getApplicationContext());
}
}
}
public class DispatcherServlet extends FrameworkServlet {
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context); // 初始化用于文件上传下载的解析器对象
initLocaleResolver(context); // 初始化用于处理国际化资源的解析器对象
initThemeResolver(context); // 主题解析器对象初始化
initHandlerMappings(context); // 初始化HandlerMapping
initHandlerAdapters(context); // 初始化HandlerAdapters
initHandlerExceptionResolvers(context); // 初始化处理器异常解析器对象
initRequestToViewNameTranslator(context);
initViewResolvers(context); // 初始化给DispatcherSerlvet的ViewResolvers处理器
initFlashMapManager(context);
}
}

@EnableWebMvc注解中导入了DelegatingWebMvcConfiguration配置类,该类的超类WebMvcConfigurationSupport中导入了很多Mvc请求处理相关的Bean。这里会导入一系列处理器映射器其中比较常用和重要的是RequestMappingHandlerMappingBeanNameUrlHandlerMapping,前者是使用注解@Controller和@RequestMapping时默认映射策略,后者是XML方式通过在web.xml中配置的方式注册Bean默认映射策略。且RequestMappingHandlerMapping的Order为0,而BeanNameUrlHandlerMapping的Order为1。

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
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
mapping.setInterceptors(getInterceptors());
mapping.setContentNegotiationManager(mvcContentNegotiationManager());
mapping.setCorsConfigurations(getCorsConfigurations());

PathMatchConfigurer configurer = getPathMatchConfigurer();

Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
if (useSuffixPatternMatch != null) {
mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
}
Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
if (useRegisteredSuffixPatternMatch != null) {
mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
}
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
if (useTrailingSlashMatch != null) {
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
}

UrlPathHelper pathHelper = configurer.getUrlPathHelper();
if (pathHelper != null) {
mapping.setUrlPathHelper(pathHelper);
}
PathMatcher pathMatcher = configurer.getPathMatcher();
if (pathMatcher != null) {
mapping.setPathMatcher(pathMatcher);
}
return mapping;
}
public BeanNameUrlHandlerMapping beanNameHandlerMapping() {
BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
mapping.setOrder(2);
mapping.setInterceptors(getInterceptors());
mapping.setCorsConfigurations(getCorsConfigurations());
return mapping;
}
}

RequestMappingHandlerMapping实现了InitializingBean接口,在初始化时会调用afterPropertiesSet方法来进行初始化操作,该方法会调用父类AbstractHandlerMethodMappingafterPropertiesSet方法来把Controller中的RequestMapping注解的路径方法进行一一映射保存

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
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping implements MatchableHandlerMapping, EmbeddedValueResolverAware {
public void afterPropertiesSet() {
// 构建RequestMappingInfo.BuilderConfiguration静态类部类对象
this.config = new RequestMappingInfo.BuilderConfiguration();
// 调用当前父类AbstractHandlerMapping.getUrlPathHelper()获取UrlPathHelper对象
this.config.setUrlPathHelper(getUrlPathHelper());
// 调用父类的AbstractHandlerMapping.getPathMatcher()的ant匹配器对象
this.config.setPathMatcher(getPathMatcher());
this.config.setSuffixPatternMatch(this.useSuffixPatternMatch); // 设置前缀匹配
this.config.setTrailingSlashMatch(this.useTrailingSlashMatch); // 末尾不带/的匹配
this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
// 设置内容协商管理器,一个请求路径返回多种数据格式
this.config.setContentNegotiationManager(getContentNegotiationManager());
// 调用父类AbstractHandlerMethodMapping#afterPropertiesSet()方法来处理器路径和控制器映射
super.afterPropertiesSet();
}
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
}
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
// 去web容器中获取出所有组件的beanNames获取出来
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) : obtainApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try { // 通过beanName去web容器中获取beanType即class对象
beanType = obtainApplicationContext().getType(beanName);
} // 通过Class对象判断是不是一个controller对象判断类上面有没有@Controller||@RequestMapping注解
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName); // 探测我们的处理器方法对象
}
}
}
handlerMethodsInitialized(getHandlerMethods()); // 空方法
}
}

Controller中标注的@RequestMapping的方法对象做为key,配置的路径作为value设置到Map对象中,最终将把method和path的映射关系保存到MappingRegistry对象中。

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
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
protected void detectHandlerMethods(Object handler) {
// 判断传入handler是不是beanName,若是则通过beanName从web容器中获取beanName对应的bean的class对象,否则直接获取handler的class对象
Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
// 获取目标的class对象,防止class对象被cglib增强的
Class<?> userType = ClassUtils.getUserClass(handlerType);
// 把Controller中标注的@RequestMapping的方法对象做为key,配置的路径作为value设置到Map对象中
// 使用lambda表达式,把getMappingForMethod(method,userType)方法注入到MethodIntrospector.MetadataLookup接口中的inspect方法中,真正调用inspect()方法时会调用getMappingForMethod方法
Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> {
try {
return getMappingForMethod(method, userType);
} catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex);
}
});
// 循环上一步解析的map,把method---path 的映射关系保存到MappingRegistry对象中
methods.forEach((method, mapping) -> {
// 解析map中的key(method)对象,获取method对象是不是一个可执行的method对象
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
// 把映射关系保存到MappingRegistry中
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
class MappingRegistry {
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock(); // 加写锁,写操作有且只有一个线程能操作
try {
// 根据controller对象和被调用的method对象来创建HandlerMethod
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
assertUniqueMethodMapping(handlerMethod, mapping); // 判断处理器映射是否唯一
// 把url,和handlerMethod保存到mappingLookup map中mappingLookup<RequestMappingInfo,HandlerMethod>
this.mappingLookup.put(mapping, handlerMethod);
// 从RequestMappingInfo中解析出直接的url,@RequestMapping(value = {"/tuling","/angle"}) urlLookUp(tuling,RequestMappingInfo) urlLookUp(angle,RequestMappingInfo)
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
}
String name = null;
// 策略模式:生成name{ElevenController}TC#方法名===>TC#testEleven Map<String, List<HandlerMethod>>
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
addMappingName(name, handlerMethod);
}
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
this.corsLookup.put(handlerMethod, corsConfig);
}
// 映射表注册MappingRegistration对象
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
} finally {
this.readWriteLock.writeLock().unlock(); // 释放锁对象
}
}
}
}
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping implements MatchableHandlerMapping, EmbeddedValueResolverAware {
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
//解析method方法上的@ReuqestMapping注解,解析出对应的RequestMappingInfo对象
RequestMappingInfo info = createRequestMappingInfo(method);
//方法级别上的RequestMapping注解不为空
if (info != null) {
// 创建类级别的RequestMappingInfo对象
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) { // 若Controller类上也标注了@RequestMapping
info = typeInfo.combine(info); // 把类级别的RequestMappingInfo和方法级别的RequestMappingInfo连接起来
}
}
return info;
}
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
// 从element对象上找出request注解
RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
// 获取@RequestMapping注解上的各个条件
RequestCondition<?> condition = (element instanceof Class ? getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
// 判断requestMapping注解是否为空,不为空则真正的创建createRequestMappingInfo(requestMapping,condition)
return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}
protected RequestMappingInfo createRequestMappingInfo(RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
RequestMappingInfo.Builder builder = RequestMappingInfo
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path())) //构建路径
.methods(requestMapping.method()) //构建方法(get还是post等)
.params(requestMapping.params())//参数 对应http request parameter
.headers(requestMapping.headers())//头部
.consumes(requestMapping.consumes())//request的提交内容类型content type,如application/json, text/html
.produces(requestMapping.produces())//指定返回的内容类型的content type,仅当request请求头中的(Accept)类型中包含该指定类型才返回
.mappingName(requestMapping.name());
if (customCondition != null) {
builder.customCondition(customCondition);
}
return builder.options(this.config).build(); // 真正的构建RequestMappingInfo对象
}
}

BeanNameUrlHandlerMappingApplicationContextAware的子类,对于映射关系的解析是在其加载完毕后通过调用Aware接口的setApplicationContext方法触发调用initApplicationContext()方法从而进行映射关系的解析。

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
public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
protected String[] determineUrlsForHandler(String beanName) {
List<String> urls = new ArrayList<>();
if (beanName.startsWith("/")) {
urls.add(beanName);
}
String[] aliases = obtainApplicationContext().getAliases(beanName);
for (String alias : aliases) {
if (alias.startsWith("/")) {
urls.add(alias);
}
}
return StringUtils.toStringArray(urls);
}
}
public abstract class AbstractDetectingUrlHandlerMapping extends AbstractUrlHandlerMapping {
public void initApplicationContext() throws ApplicationContextException {
super.initApplicationContext();
detectHandlers();
}
protected void detectHandlers() throws BeansException {
ApplicationContext applicationContext = obtainApplicationContext();
String[] beanNames = (this.detectHandlersInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) : applicationContext.getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
String[] urls = determineUrlsForHandler(beanName);
if (!ObjectUtils.isEmpty(urls)) {
registerHandler(urls, beanName);
}
}
}
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
for (String urlPath : urlPaths) {
registerHandler(urlPath, beanName);
}
}
protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
Object resolvedHandler = handler;
if (!this.lazyInitHandlers && handler instanceof String) {
String handlerName = (String) handler;
ApplicationContext applicationContext = obtainApplicationContext();
if (applicationContext.isSingleton(handlerName)) {
resolvedHandler = applicationContext.getBean(handlerName);
}
}
Object mappedHandler = this.handlerMap.get(urlPath);
if (mappedHandler != null) {
if (mappedHandler != resolvedHandler) {
throw new IllegalStateException("Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath + "]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
}
} else {
if (urlPath.equals("/")) {
setRootHandler(resolvedHandler);
} else if (urlPath.equals("/*")) {
setDefaultHandler(resolvedHandler);
} else {
this.handlerMap.put(urlPath, resolvedHandler);
}
}
}
}

WebMvcConfigurationSupport中也会导入一系列处理器适配器RequestMappingHandlerAdapterHttpRequestHandlerAdapterSimpleControllerHandlerAdapter

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 class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setContentNegotiationManager(mvcContentNegotiationManager());
adapter.setMessageConverters(getMessageConverters());
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
adapter.setCustomArgumentResolvers(getArgumentResolvers());
adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

if (jackson2Present) {
adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
}

AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
configureAsyncSupport(configurer);
if (configurer.getTaskExecutor() != null) {
adapter.setTaskExecutor(configurer.getTaskExecutor());
}
if (configurer.getTimeout() != null) {
adapter.setAsyncRequestTimeout(configurer.getTimeout());
}
adapter.setCallableInterceptors(configurer.getCallableInterceptors());
adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());
return adapter;
}
@Bean
public HttpRequestHandlerAdapter httpRequestHandlerAdapter() {
return new HttpRequestHandlerAdapter();
}
@Bean
public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() {
return new SimpleControllerHandlerAdapter();
}
}

RequestMappingHandlerAdapter实现了InitializingBean接口,在初始化时会调用afterPropertiesSet方法来进行初始化操作,主要是解析标注了@ControllerAdvice@InitBinder@ModelAttribute等注解的类和方法,并将解析后的数据放入缓存中。以及添加一系列的参数解析器标注@InitBinder注解方法的参数解析器返回值解析器

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
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean {
public static final MethodFilter INIT_BINDER_METHODS = method -> (AnnotationUtils.findAnnotation(method, InitBinder.class) != null);
public static final MethodFilter MODEL_ATTRIBUTE_METHODS = method -> (AnnotationUtils.findAnnotation(method, RequestMapping.class) == null && AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null);
public void afterPropertiesSet() {
initControllerAdviceCache(); // 实例化标注了@ControllerAdvice等组件
if (this.argumentResolvers == null) { // 加入容器中各种参数解析器对象
List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.initBinderArgumentResolvers == null) { // 解析@InitBinder注解标注的方法的参数解析器对象
List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
}
if (this.returnValueHandlers == null) { // 返回值解析器对象
List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
}
}
private void initControllerAdviceCache() {
if (getApplicationContext() == null) {
return;
}
// 传入web上下文对象,查找容器中标注了@ControllerAdvice组件的bean
List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
AnnotationAwareOrderComparator.sort(adviceBeans); // 排序
List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();
for (ControllerAdviceBean adviceBean : adviceBeans) { // 循环所有的@ControllerAdvice的集合
Class<?> beanType = adviceBean.getBeanType(); // 获取bean的class类型
if (beanType == null) {
throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
}
// 获取class类中所有标注了@ModelAttribute注解
Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
if (!attrMethods.isEmpty()) { // 标注了@ModelAttribute标注的方法不为空
this.modelAttributeAdviceCache.put(adviceBean, attrMethods); // 加入到缓存中
}
// 查找全局的@InitBinder注解标标注的方法
Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
if (!binderMethods.isEmpty()) { // 不为空加入到缓存中
this.initBinderAdviceCache.put(adviceBean, binderMethods);
}
boolean isRequestBodyAdvice = RequestBodyAdvice.class.isAssignableFrom(beanType);
boolean isResponseBodyAdvice = ResponseBodyAdvice.class.isAssignableFrom(beanType);
if (isRequestBodyAdvice || isResponseBodyAdvice) {
requestResponseBodyAdviceBeans.add(adviceBean);
}
}
if (!requestResponseBodyAdviceBeans.isEmpty()) {
this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
}
}
}
public class ControllerAdviceBean implements Ordered {
public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext applicationContext) {
List<ControllerAdviceBean> beans = new ArrayList<>();
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class)) {
if (applicationContext.findAnnotationOnBean(name, ControllerAdvice.class) != null) {
// 若组件上标注了@ControllerAdvice,则加入到集合中返回
beans.add(new ControllerAdviceBean(name, applicationContext));
}
}
return beans;
}
}