警告
本文最后更新于 2020-12-15,文中内容可能已过时。
spring源码系列文章,示例代码的中文注释,均是 copy 自 https://gitee.com/wlizhi/spring-framework 。
链接中源码是作者从 github 下载,并以自身理解对核心流程及主要节点做了详细的中文注释。
@EnableWebMvc的声明
@EnableWebMvc 的声明源码如下:
1
2
3
4
5
6
7
8
9
|
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
// 这里支持了激活mvc各种组件功能,其中父类中有很多@Bean注解的方法,创建了许多可能需要的组件,
// 比如RequestMappingHandlerMapping就是在这时候生成的URL-对象方法的映射,
// RequestMappingHandlerMapping实现了InitializingBean,afterPropertiesSet方法中初始化了映射关系
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
|
在 @EnableWebMvc 声明处,使用 @Import 注解导入了一个类,这个类是 DelegatingWebMvcConfiguration,这是一个配置类,使用了注解 @Configuration 标注。
DelegatingWebMvcConfiguration 中的配置聚合
在 DelegatingWebMvcConfiguration 中,聚合了项目中所有的 WebMvcConfigurer 实现类实例。在这个类中,有很多 @Bean 注解标注的方法,来完成一些 mvc 组件的注册。
而对这些组件的注册的一些配置,会通过调用 DelegatingWebMvcConfiguration 的一些回调方法来完成,这些回调方法中,遍历了搜集到的 WebMvcConfigurer,将对应的方法进行依次调用。
在 DelegatingWebMvcConfiguration 中,聚合 WebMvcConfigurer 实例的源码如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
// 这个类合成了容器中所有实例化的 WebMvcConfigurer
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
/** 将容器中所有实例化的 WebMvcConfigurer 根据类型注入到方法参数,将其封装起来,之后所有的配置方法中,
* 会遍历这里搜集到的所有的实例,依次进行配置。 */
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
}
|
在 DelegatingWebMvcConfiguration 中,声明了一个成员变量 configurers,这个类是 WebMvcConfigurerComposite,同时它也是一个 WebMvcConfigurer 的实现。
在 setConfigurers() 中,注入了子容器中所有的 WebMvcConfigurer 实例,并将其封装到 configurers 中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
class WebMvcConfigurerComposite implements WebMvcConfigurer {
private final List<WebMvcConfigurer> delegates = new ArrayList<>();
public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.delegates.addAll(configurers);
}
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.configureViewResolvers(registry);
}
}
// 省略一系列方法实现...
}
|
通过 addWebMvcConfigurers() 方法,将所有的实现类,封装到成员 delegates 中。
WebMvcConfigurerComposite 本身并不提供任何组件的配置,而是通过搜集容器中注入的 WebMvcConfigurer 实例,调用各个配置方法时,通过遍历这些实例,依次调用其同名方法来进行配置。
比如 configureViewResolvers(),它会遍历所有封装的实例,依次调用这些实例的 configureViewResolvers(),来进行组件的配置。
DelegatingWebMvcConfiguration 中的组件注册
在 DelegatingWebMvcConfiguration 继承了 WebMvcConfigurationSupport,在这个类中,通过 @Bean的方式,完成了很多 mvc 相关组件的注册。
主要成员
DelegatingWebMvcConfiguration 的主要成员变量如下:
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 class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
/** spring容器的上下文对象 */
@Nullable
private ApplicationContext applicationContext;
/** servlet 上下文对象 */
@Nullable
private ServletContext servletContext;
/** springmvc 拦截器封装 */
@Nullable
private List<Object> interceptors;
/** 帮助配置HandlerMappings路径匹配类的封装 */
@Nullable
private PathMatchConfigurer pathMatchConfigurer;
/** 内容协商机制 */
@Nullable
private ContentNegotiationManager contentNegotiationManager;
/** 方法的参数处理 */
@Nullable
private List<HandlerMethodArgumentResolver> argumentResolvers;
/** 方法的返回值处理 */
@Nullable
private List<HandlerMethodReturnValueHandler> returnValueHandlers;
/** 消息转换器 */
@Nullable
private List<HttpMessageConverter<?>> messageConverters;
/** cors 跨域相关 */
@Nullable
private Map<String, CorsConfiguration> corsConfigurations;
}
|
这里面封装了上下文对象、拦截器、方法参数处理、返回值处理、消息转换器等实例。
注册 RequestMappingHandlerMapping
通过 @Bean,注册了 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
|
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
// RequestMappingHandlerMapping 实现了 InitializingBean,所以它在实例化后,会调用 afterPropertiesSet() 进行初始化。
// 创建 RequestMappingHandlerMapping。
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
mapping.setOrder(0);
// getInterceptors()中调用了钩子方法,可通过 WebMvcConfigurer进行扩展
mapping.setInterceptors(getInterceptors());
mapping.setContentNegotiationManager(mvcContentNegotiationManager());
// getCorsConfigurations() 调用了钩子犯法
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);
}
Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
if (pathPrefixes != null) {
mapping.setPathPrefixes(pathPrefixes);
}
return mapping;
}
}
|
在创建 RequestMappingHandlerMapping 的过程中,调用了 getInterceptors()、getCorsConfigurations() 等的回调方法。
getInterceptors() 源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
protected final Object[] getInterceptors() {
if (this.interceptors == null) {
InterceptorRegistry registry = new InterceptorRegistry();
// 钩子方法,如果我们定义了一个WebMvcConfigurer,它就会回调到对应实现的方法中。
// 遍历所有注册到容器中的WebMvcConfigurer,依次进行添加操作
addInterceptors(registry);
registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService()));
registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider()));
this.interceptors = registry.getInterceptors();
}
return this.interceptors.toArray();
}
}
|
这里调用了 addInterceptors():
1
2
3
4
5
6
7
8
9
|
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
// 这个类合成了容器中所有实例化的 WebMvcConfigurer
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Override
protected void addInterceptors(InterceptorRegistry registry) {
// 遍历,依次进行添加操作。
this.configurers.addInterceptors(registry);
}
}
|
可以看到,在 addInterceptors() 中,就遍历了 DelegatingWebMvcConfiguration 中封装的所有的 WebMvcConfigurer 实例的 addInterceptors()。依次调用对 RequestMappingHandlerMapping 实例进行相关配置。
getCorsConfigurations() 源码:
1
2
3
4
5
6
7
8
9
10
|
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
protected final Map<String, CorsConfiguration> getCorsConfigurations() {
if (this.corsConfigurations == null) {
CorsRegistry registry = new CorsRegistry();
addCorsMappings(registry);// 这里遍历了DelegatingWebMvcConfiguration中封装的 WebMvcConfigurer,依次将对应方法调用
this.corsConfigurations = registry.getCorsConfigurations();
}
return this.corsConfigurations;
}
}
|
同样的,这里调用了 addCorsMappings(),进入源码:
1
2
3
4
5
6
7
8
|
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
// 这个类合成了容器中所有实例化的 WebMvcConfigurer
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Override
protected void addCorsMappings(CorsRegistry registry) {
this.configurers.addCorsMappings(registry);
}
}
|
同样遍历了 WebMvcConfigurer 实例,依次调用同名的配置方法。
注册 RequestMappingHandlerAdapter
源码如下:
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
|
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public RequestMappingHandlerAdapter 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;
}
}
|
创建 RequestMappingHandlerAdapter,并对其进行一些设置,这些设置大多都是通过遍历并依次回调前面封装的 WebMvcConfigurer 对应方法进行的。
RequestMappingHandlerMapping 和 RequestMappingHandlerAdapter 都实现了接口 InitializingBean,那么在他们通过 @Bean 将自身实例注入到容器中时,也会调用 afterPropertiesSet() 做一些事情,具体做了什么,在后面文章中列举。
异常处理器 HandlerExceptionResolver
源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
@Bean
public HandlerExceptionResolver handlerExceptionResolver() {
// 全局异常处理器的创建注册
List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<>();
// 钩子方法,遍历依次回调封装的 WebMvcConfigurer
configureHandlerExceptionResolvers(exceptionResolvers);
if (exceptionResolvers.isEmpty()) {
// 如果没有定义,则添加默认的异常处理器
addDefaultHandlerExceptionResolvers(exceptionResolvers);
}
extendHandlerExceptionResolvers(exceptionResolvers);
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
composite.setOrder(0);
composite.setExceptionResolvers(exceptionResolvers);
return composite;
}
}
|
这里通过 @Bean 向容器中注入了异常处理器 HandlerExceptionResolver,如果在 WebMvcConfigurer 实现类中,配置了异常处理类,就会加载。否则就会使用默认的异常处理类 ExceptionHandlerExceptionResolver。
在 ExceptionHandlerExceptionResolver 中定义了@ControllerAdvice的支持,在 getExceptionHandlerMethod() 中,通过创建 ExceptionHandlerMethodResolver 对 @HandlerException 进行了支持。
其他
在 WebMvcConfigurationSupport 中,还有很多其他的组件注册。不再列举。