Spring Boot-Spring MVC自动装配原理
说明
在非Spring Boot项目中我们要使用Spring MVC 要做很多繁琐的配置,配置DispatcherServlet、配置RequestMapping 配置RequestMappingAdapter
当我们使用Spring Boot项目只需要引入以下依赖就完成了整个自动Spring MVC的装配实现开箱即用
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${spring.boot.version}</version> </dependency>
完成自动装配的核心依赖在
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>2.0.5.RELEASE</version> <scope>compile</scope> </dependency>
我们查看依赖数
这个包里面汇集了常用框架的spring boot的自动装配的整合方案,关于我们Spring MVC的自动装配在web下的servlet包下的org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
我们来跟一下源码看看是如何完成自动装配的吧这个类里面有一系列的Spring MVC组件初始化我们主要关注
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration
EnableWebMvcConfiguration类主要继承了spring-webmvc提供的WebMvcConfigurationSupport 来与spring 整合
RequestMappingHandlerAdapter组件自动装配
主要解释WebMvcConfigurer完成自定义配置原理 这里举例了一个例子,后续更多自定义配置都是围绕WebMvcConfigurer
<1>
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration#requestMappingHandlerAdapter
@Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { //<1-1>交给父类方法进行初始化 RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(); adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect()); return adapter; }
<1-1>
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerAdapter
@Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { // <1-1-1>创建 RequestMappingHandlerAdapter 实例 RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter(); //<1-1-2>设置内容协商管理器 adapter.setContentNegotiationManager(mvcContentNegotiationManager()); // 设置消息转换器 adapter.setMessageConverters(getMessageConverters()); // 设置 Web 绑定初始化器 adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer()); // 设置自定义参数解析器 adapter.setCustomArgumentResolvers(getArgumentResolvers()); // 设置自定义返回值处理器 adapter.setCustomReturnValueHandlers(getReturnValueHandlers()); // 如果存在 Jackson 依赖,则设置 JSON 视图处理建议 if (jackson2Present) { adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice())); adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice())); } // 创建并配置异步支持配置器 AsyncSupportConfigurer configurer = new AsyncSupportConfigurer(); configureAsyncSupport(configurer); // 如果配置了任务执行器,则设置到 adapter 中 if (configurer.getTaskExecutor() != null) { adapter.setTaskExecutor(configurer.getTaskExecutor()); } // 如果配置了超时时间,则设置到 adapter 中 if (configurer.getTimeout() != null) { adapter.setAsyncRequestTimeout(configurer.getTimeout()); } // 设置可调用拦截器 adapter.setCallableInterceptors(configurer.getCallableInterceptors()); // 设置延迟结果拦截器 adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors()); // 返回配置好的 RequestMappingHandlerAdapter 实例 return adapter; }
<1-1-1>
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#createRequestMappingHandlerAdapter
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() { return new RequestMappingHandlerAdapter(); }
<1-1-2>
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#mvcContentNegotiationManager
@Bean public ContentNegotiationManager mvcContentNegotiationManager() { if (this.contentNegotiationManager == null) { ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(this.servletContext); configurer.mediaTypes(getDefaultMediaTypes()); //<1-1-2-1>交给子类DelegatingWebMvcConfiguration 也就是WebMvcConfigurationSupport的父类 configureContentNegotiation(configurer); this.contentNegotiationManager = configurer.buildContentNegotiationManager(); } return this.contentNegotiationManager; }
<1-1-2-1>
WebMvcConfigurer 就是我们使用spring boot进行自定义配置原理
@Autowired( required = false ) public void setConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.configurers.addWebMvcConfigurers(configurers); } } //委托给 WebMvcConfigurer 进行自定义配置 protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) { this.configurers.configureContentNegotiation(configurer); }
RequestMappingHandlerMapping自定装配
<1>
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
@Bean @Primary public RequestMappingHandlerMapping requestMappingHandlerMapping() { //<1-1>委托给父类处理 return super.requestMappingHandlerMapping(); }
<1-1>
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#requestMappingHandlerMapping
@Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { // 创建 RequestMappingHandlerMapping 实例 RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping(); // 设置映射顺序 mapping.setOrder(0); //<1-1-1>设置拦截器 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); } // 获取 URL 路径帮助器 UrlPathHelper pathHelper = configurer.getUrlPathHelper(); if (pathHelper != null) { // 设置 URL 路径帮助器 mapping.setUrlPathHelper(pathHelper); } // 获取路径匹配器 PathMatcher pathMatcher = configurer.getPathMatcher(); if (pathMatcher != null) { // 设置路径匹配器 mapping.setPathMatcher(pathMatcher); } // 返回配置好的 RequestMappingHandlerMapping 实例 return mapping; }
<1-1-1>
org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#getInterceptors
protected final Object[] getInterceptors() { if (this.interceptors == null) { //初始化InterceptorRegistry InterceptorRegistry registry = new InterceptorRegistry(); //<1-1-1-1>交给子类进行自定义设置 addInterceptors(registry); registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService())); registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider())); //获取自定义设置的拦截器 this.interceptors = registry.getInterceptors(); } return this.interceptors.toArray(); }
<1-1-1-1>
@Autowired( required = false ) public void setConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.configurers.addWebMvcConfigurers(configurers); } } protected void addInterceptors(InterceptorRegistry registry) {
//调用WebMvcConfigurer完成拦截器注入 this.configurers.addInterceptors(registry); }
来看看我们要自定义拦截器如何做的WebMvcConfigurer 最终形成了闭环
@Configuration public class WebConfig implements WebMvcConfigurer { private final Logger logger = LoggerFactory.getLogger(WebConfig.class); @Autowired private LoginAuthenticationFilter loginAuthenticationFilter; @Autowired private AuthorizationInterceptor authorizationInterceptor; @Autowired private LogHandlerInterceptor logHandlerInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authorizationInterceptor).addPathPatterns("/**"); registry.addInterceptor(logHandlerInterceptor).addPathPatterns("/**"); } }
总结
知道了Spring Boot整合Spring MVC的入口点,并且举例了围绕WebMvcConfigurer进行的初始化,后续我们对相关其他配置初始化可以跟这里源码