在前面SpringMVC源码解读部分,我们都是通过xml配置文件去处理例如HandlerMapping、HanlderAdapter、ViewResolver、HandlerMethodArgumentResolver接口。但如今我们一般是直接用注解扫描处理这些的注入,要注入关于SpringMVC的Bean,我们可以直接通过@EnableWebMvc注解来处理注入一些默认需要的接口。只需要在SpringMVC的配置文件中加上扫描的内容就可以了,例如:
<context:component-scan base-package="web" />
我们只需要加入扫描这个标签就可以了,然后将EnableWebMvc注解的类放到这个包下面。
例如我们创建一个类,加上注解:
@Configuration @EnableWebMvc public class WebEnableConfig }
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(DelegatingWebMvcConfiguration.class) public @interface EnableWebMvc { }
可以看到这里是引入了DelegatingWebMvcConfiguration。
@Configuration public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
其继承与WebMvcConfigurationSupport,这个我们就很熟悉了。这里主要就是通过WebMvcConfigurationSupport注入这些Bean。
1、WebMvcConfigurationSupport
public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
下面我们来看下其是怎样注入这些接口实现Bean的。
1、RequestMappingHandlerMapping
@Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping(); mapping.setOrder(0); mapping.setInterceptors(getInterceptors()); mapping.setContentNegotiationManager(mvcContentNegotiationManager()); mapping.setCorsConfigurations(getCorsConfigurations()); ............ return mapping; } protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() { return new RequestMappingHandlerMapping(); }
可以看到这就是RequestMappingHandlerMapping的注入。其会获取设置Interceptor:
protected final Object[] getInterceptors() { if (this.interceptors == null) { InterceptorRegistry registry = new InterceptorRegistry(); addInterceptors(registry); registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService())); registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider())); this.interceptors = registry.getInterceptors(); } return this.interceptors.toArray(); } protected void addInterceptors(InterceptorRegistry registry) { }
所以我们一般继承WebMvcConfigurationSupport,然后重写其的addInterceptors来注入我们自定义的Interceptor,然后在创建HandlerMapping的时候。,就是这样将其设置到HandlerMapping中的。
2、BeanNameUrlHandlerMapping
@Bean public BeanNameUrlHandlerMapping beanNameHandlerMapping() { BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping(); mapping.setOrder(2); mapping.setInterceptors(getInterceptors()); mapping.setCorsConfigurations(getCorsConfigurations()); return mapping; }
类似的BeanNameUrlHandlerMapping也是对应的这种设置。
下面我们来看下HandlerAdapter
3、RequestMappingHandlerAdapter
@Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter(); .......... adapter.setMessageConverters(getMessageConverters()); adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer()); adapter.setCustomArgumentResolvers(c()); adapter.setCustomReturnValueHandlers(getReturnValueHandlers()); ........ ......... return adapter; }
然后这里的几个get方法也是与前面getInterceptors类似。不过getMessageConverters方法,是注入HttpMessageConverter,这个接口的作用在前面梳理过。其会有一些默认的,也是在个getMessageConverters方法中调用的:
protected final List<HttpMessageConverter<?>> getMessageConverters() { if (this.messageConverters == null) { this.messageConverters = new ArrayList<>(); configureMessageConverters(this.messageConverters); if (this.messageConverters.isEmpty()) { addDefaultHttpMessageConverters(this.messageConverters); } extendMessageConverters(this.messageConverters); } return this.messageConverters; } protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) { } protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { } protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { }
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) { ........... messageConverters.add(new ResourceHttpMessageConverter()); ......... if (romePresent) { messageConverters.add(new AtomFeedHttpMessageConverter()); messageConverters.add(new RssChannelHttpMessageConverter()); } ......... if (jackson2SmilePresent) { Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile(); if (this.applicationContext != null) { builder.applicationContext(this.applicationContext); } messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build())); } ........ } private static final boolean jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", WebMvcConfigurationSupport.class.getClassLoader());
这些以Present结尾的例如jackson2SmilePresent,就是根据当前加载的所有class中有没有SmileFactory接口,代表有加入这个包,这个与SpringBoot的应用包就默认注入一些类,并进行默认配置。
4、HttpRequestHandlerAdapter等
@Bean public HttpRequestHandlerAdapter httpRequestHandlerAdapter() { return new HttpRequestHandlerAdapter(); } @Bean public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() { return new SimpleControllerHandlerAdapter(); }
这里主要是引出其的处理流程,梳理通过WebMvcConfigurationSupport注入与SpringMVC处理相关的接口。具体整个又引入那些,这里就不再一一列举了。