SpringMVC自动配置原理
SpringMVC自动配置原理
1.Spring MVC auto-configuration
Spring Boot 自动配置好了SpringMVC,以下是SpringBoot对SpringMVC的默认配置:(WebMvcAutoConfiguration)
1、ContentNegotiatingViewResolver 和 BeanNameViewResolver
-
自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染)
-
ContentNegotiatingViewResolver:组合所有的视图解析器的;
-
如何定制:我们可以自己给容器中添加一个视图解析器;自动的将其组合进来;
public class WebMvcAutoConfiguration {
@Bean
@ConditionalOnBean(View.class)
@ConditionalOnMissingBean
public BeanNameViewResolver beanNameViewResolver() {
BeanNameViewResolver resolver = new BeanNameViewResolver();
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
return resolver;
}
@Bean
@ConditionalOnBean(ViewResolver.class)
@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(
beanFactory.getBean(ContentNegotiationManager.class));
// ContentNegotiatingViewResolver uses all the other view resolvers to locate
// a view so it should have a high precedence
resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
return resolver;
}
}
2、支持提供静态资源,包括对webjar
的支持,静态资源文件夹路径webjars
、静态index.html
首页访问和favicon.ico 图像显示。
public class WebMvcAutoConfiguration {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Integer cachePeriod = this.resourceProperties.getCachePeriod();
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(
registry.addResourceHandler("/webjars/**")
.addResourceLocations(
"classpath:/META-INF/resources/webjars/")
.setCachePeriod(cachePeriod));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(
registry.addResourceHandler(staticPathPattern)
.addResourceLocations(
this.resourceProperties.getStaticLocations())
.setCachePeriod(cachePeriod));
}
}
}
3、自动注册了 Converter
、GenericConverter
、Formatter
-
Converter:转换器; 类型转换使用Converter;
-
Formatter
格式化器; "2017.12.17"格式化成Date
;自己自定义添加的格式化器转换器,我们只需要放在容器中即可
@Bean
@ConditionalOnProperty(prefix = "spring.mvc", name = "date-format") //在文件中配置日期格式化的规则
public Formatter<Date> dateFormatter() {
return new DateFormatter(this.mvcProperties.getDateFormat()); //日期格式化组件
}
4、Http消息转换器HttpMessageConverters
-
HttpMessageConverter:SpringMVC用来转换Http请求和响应的;User---转换为---> Json;
-
HttpMessageConverters
是从容器中确定;获取所有的HttpMessageConverter;
如果你需要添加或自定义转换器,你可以使用Spring Boot的HttpMessageConverters类,如下所示:
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;
@Configuration
public class MyConfiguration {
@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = ...
HttpMessageConverter<?> another = ...
return new HttpMessageConverters(additional, another);
}
}
上下文中出现的任何HttpMessageConverter bean都被添加到转换器列表中。您也可以用相同的方法重写默认转换器。
5、定义错误代码生成规则 MessageCodesResolver
6、web数据绑定器 ConfigurableWebBindingInitializer
我们可以配置一个ConfigurableWebBindingInitializer来替换默认的;(添加到容器)
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
@Override
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
try {
return this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
}
catch (NoSuchBeanDefinitionException ex) {
return super.getConfigurableWebBindingInitializer();
}
}
}
public class ConfigurableWebBindingInitializer implements WebBindingInitializer {
// 初始化WebDataBinder数据绑定器
@Override
public void initBinder(WebDataBinder binder, WebRequest request) {
binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
if (this.directFieldAccess) {
binder.initDirectFieldAccess();
}
if (this.messageCodesResolver != null) {
binder.setMessageCodesResolver(this.messageCodesResolver);
}
if (this.bindingErrorProcessor != null) {
binder.setBindingErrorProcessor(this.bindingErrorProcessor);
}
if (this.validator != null && binder.getTarget() != null &&
this.validator.supports(binder.getTarget().getClass())) {
binder.setValidator(this.validator);
}
if (this.conversionService != null) {
binder.setConversionService(this.conversionService);
}
if (this.propertyEditorRegistrars != null) {
for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
propertyEditorRegistrar.registerCustomEditors(binder);
}
}
}
}
在包org.springframework.boot.autoconfigure.web下是web的所有自动场景;
如果你想保留Spring Boot MVC特性,并且你只想添加额外的MVC配置(如:拦截器,格式化器,视图控制器等),你可以添加你自己的类型为WebMvcConfigurerAdapter
的@Configuration
类,但不使用 @EnableWebMvc
。
如果你想提供RequestMappingHandlerMapping
,RequestMappingHandlerAdapter
或ExceptionHandlerExceptionResolver
的自定义实例,你可以声明一个WebMvcRegistrationsAdapter
实例来提供这样的组件。
如果你想完全控制Spring MVC,你可以添加你自己的@Configuration
注释与@EnableWebMvc
。
2.扩展SpringMVC
编写一个@Configuration
注解类,并且类型要为WebMvcConfigurer
(实现WebMvcConfigurer接口),还 不能 标注@EnableWebMvc注解
既保留了所有的自动配置,也能用我们扩展的配置
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
// 因为类型要求为WebMvcConfigurer,所以我们实现其接口
// 可以使用自定义类扩展MVC的功能
// 如果我们要扩展springmvc,官方推荐这样做
@Configuration
public class MySpringMvcConfig implements WebMvcConfigurer {
// 视图跳转
@Override
public void addViewControllers(ViewControllerRegistry registry){
// 浏览器发送/temp请求跳转到test视图页面
registry.addViewController("/temp").setViewName("test");
}
}
各种配置都是这么扩展 在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置
原理:
1)WebMvcAutoConfiguration是SpringMVC的自动配置类
2)在做其他自动配置时会导入;@Import(EnableWebMvcConfiguration.class)
public class WebMvcAutoConfiguration {
@Configuration
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {
}
}
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
}
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
//从容器中获取所有的WebMvcConfigurer
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
}
class WebMvcConfigurerComposite implements WebMvcConfigurer {
private final List<WebMvcConfigurer> delegates = new ArrayList<WebMvcConfigurer>();
// 以视图解析为例:将所有的WebMvcConfigurer相关配置都来一起调用
@Override
public void addViewControllers(ViewControllerRegistry registry) {
for (WebMvcConfigurer delegate : this.delegates) {
delegate.addViewControllers(registry);
}
}
}
3)容器中所有的WebMvcConfigurer都会一起起作用;
4)我们的配置类也会被调用;
效果:SpringMVC的自动配置和我们的扩展配置都会起作用;
3.全面接管SpringMVC
使用@EnableWebMvc注解,SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己配置;所有的SpringMVC的自动配置都失效了
我们需要在配置类中添加@EnableWebMvc即可
//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// super.addViewControllers(registry);
//浏览器发送 /hguo 请求来到 视图名success页面
registry.addViewController("/hguo").setViewName("success");
}
}
原理:
为什么@EnableWebMvc自动配置就失效了;
1)查看注解@EnableWebMvc可以看到@Import(DelegatingWebMvcConfiguration.class)引入了这个组件
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
2)DelegatingWebMvcConfiguration
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {}
3)而在WebMvcAutoConfiguration
自动配置类中有注解@ConditionalOnMissingBean
对容器中组件进行判断
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
//@ConditionalOnMissingBean判断容器中没有WebMvcConfigurationSupport这个组件的时候,这个自动配置类才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
4)@EnableWebMvc
将WebMvcConfigurationSupport
组件导入进来;
5)导入的WebMvcConfigurationSupport
只是SpringMVC最基本的功能;
4.如何修改SpringBoot的默认配置
模式:
1)、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来;
2)、在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置
3)、在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置
本文来自博客园,作者:Lz_蚂蚱,转载请注明原文链接:https://www.cnblogs.com/leizia/p/16686941.html