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、自动注册了 ConverterGenericConverterFormatter

  • 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的所有自动场景;

MVC配置官网文档

如果你想保留Spring Boot MVC特性,并且你只想添加额外的MVC配置(如:拦截器,格式化器,视图控制器等),你可以添加你自己的类型为WebMvcConfigurerAdapter@Configuration类,但使用 @EnableWebMvc

如果你想提供RequestMappingHandlerMappingRequestMappingHandlerAdapterExceptionHandlerExceptionResolver的自定义实例,你可以声明一个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)@EnableWebMvcWebMvcConfigurationSupport组件导入进来;

5)导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;

4.如何修改SpringBoot的默认配置

模式:

​ 1)、SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来;

​ 2)、在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置

​ 3)、在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置

posted @   Lz_蚂蚱  阅读(91)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起