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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步