七、SpringBoot之SpringMVC自动配置原理

SpringMvc自动配置文档

1、Spring MVC 自动配置

Spring Boot 自动配置好了SpringMVC

以下是SpringBoot对SpringMVC的默认配置:都在WebMvcAutoConfiguration.java这个类里

  • 自动配置了ViewResolver(视图解析器:根据方法的返回值得到视图对象(View),视图对象决定如何渲染,是转发还是重定向。

例如:ContentNegotiatingViewResolver:组合所有的视图解析器的;

WebMvcAutoConfiguration.java        
        @Bean //给容器中添加ContentNegotiationManager组件
        @ConditionalOnBean({ViewResolver.class})
        @ConditionalOnMissingBean(
            name = {"viewResolver"},
            value = {ContentNegotiatingViewResolver.class}
        )
        public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
            ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
            resolver.setContentNegotiationManager((ContentNegotiationManager)beanFactory.getBean(ContentNegotiationManager.class));
            resolver.setOrder(-2147483648);
            return resolver;
        }

ContentNegotiatingViewResolver.java
    @Nullable
    //解析视图
    public View resolveViewName(String viewName, Locale locale) throws Exception {
        RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
        Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
        List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
        if (requestedMediaTypes != null) {
            //获取候选视图对象
            List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
            //选择适合的视图对象,然后把这个对象返回
            View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
            if (bestView != null) {
                return bestView;
            }
        }
 
        if (this.useNotAcceptableStatusCode) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("No acceptable view found; returning 406 (Not Acceptable) status code");
            }
 
            return NOT_ACCEPTABLE_VIEW;
        } else {
            this.logger.debug("No acceptable view found; returning null");
            return null;
        }
    }

如何定制:我们可以自己给容器中添加一个视图解析器;自动的将其组合进来;
  •  
  •         @Bean
    	public ViewResolver myViewReolver(){
    	    return new MyViewResolver();
            }
    	private static class MyViewResolver implements ViewResolver{
     
                @Override
                public View resolveViewName(String viewName, Locale locale) throws Exception {
                    return null;
                }
            }
    
    自动配置了静态资源文件夹路径,webjars(前面用过)
  • 自动配置了静态首页访问(index.html)
  • 自动配置来favicon.ico图标访问
  • Converter:转换器;类型转换使用Converter
  • Formatter 格式化器;比如日期格式化转换
        //添加格式化器    
        public void addFormatters(FormatterRegistry registry) {
            //从容器中获取所有的Converter,再遍历
            Iterator var2 = this.getBeansOfType(Converter.class).iterator();
 
            while(var2.hasNext()) {
                Converter<?, ?> converter = (Converter)var2.next();
                //自己添加的格式化器转换器,我们只需要放在容器中即可
                registry.addConverter(converter);
            }
            //从容器中获取所有的GenericConverter,再遍历
 
            var2 = this.getBeansOfType(GenericConverter.class).iterator();
 
            while(var2.hasNext()) {
                GenericConverter converter = (GenericConverter)var2.next();
                registry.addConverter(converter);
            }
 
            //从容器中获取所有的Formatter,再遍历
            var2 = this.getBeansOfType(Formatter.class).iterator();
 
            while(var2.hasNext()) {
                Formatter<?> formatter = (Formatter)var2.next();
                registry.addFormatter(formatter);
            }
 
        }
  • ​HttpMessageConverter:SpringMVC用来转换Http请求和响应的;例如User转换成Json;
         //只有一个有参构造器的情况下,每一个参数的值都是要从容器中拿
        //HttpMessageConverters 是从容器中确定,获取所有的HttpMessageConverter;
        //自己给容器中添加HttpMessageConverter,只需要将自己的组件注册容器中(@Bean,@Component)
        public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider) {
            this.resourceProperties = resourceProperties;
            this.mvcProperties = mvcProperties;
            this.beanFactory = beanFactory;
            this.messageConvertersProvider = messageConvertersProvider;
            this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
        }
  • MessageCodesResolver:定义错误代码生成规则

          public MessageCodesResolver getMessageCodesResolver() {
            //从配置类中拿到一个配置,定义错误代码生成规则的配置
            if (this.mvcProperties.getMessageCodesResolverFormat() != null) {
                DefaultMessageCodesResolver resolver = new DefaultMessageCodesResolver();
                resolver.setMessageCodeFormatter(this.mvcProperties.getMessageCodesResolverFormat());
                return resolver;
            } else {
                return null;
            }
        }
  • ConfigurableWebBindingInitializer:初始化WebDataBinder;例如:请求数据与JavaBean绑定

      protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
            try {
                //从容器中拿到ConfigurableWebBindingInitializer
                //我们可以配置一个ConfigurableWebBindingInitializer添加到容器里来替换默认的;
                return (ConfigurableWebBindingInitializer)this.beanFactory.getBean(ConfigurableWebBindingInitializer.class);
            } catch (NoSuchBeanDefinitionException var2) {
                //拿不到调用父类的ConfigurableWebBindingInitializer
                return super.getConfigurableWebBindingInitializer();
            }
        }

web的所有自动场景都在org.springframework.boot.autoconfigure.web这个包里。

2、扩展SpringMVC

  • Spring以前需要写配置文件
  • SpringBoot不用写配置文件,编写一个配置类(@Configuration),是WebMvcConfigurerAdapter类型;不能标注@EnableWebMvc;

SpringBoot扩展SpringMVC既保留了所有的自动配置,也能用我们扩展的配置;

  • 原理:

​ 1.WebMvcAutoConfiguration是SpringMVC的自动配置类

​ 2.在做其他自动配置时会导入@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})

     //WebMvcAutoConfiguration.java里有一个内部类WebMvcAutoConfigurationAdapter
    //WebMvcAutoConfigurationAdapter实现WebMvcConfigurer接口,实现了接口里的方法
    @Configuration
    //在做其他自动配置时会导入@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
    @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
    @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class})
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware {
        private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);

3.容器中所有的WebMvcConfigurer都会一起起作用;

 @Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration {
 
 
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
 
    public DelegatingWebMvcConfiguration() {}
 
    @Autowired(
        required = false
    )
    //从容器中获取所有的WebMvcConfigurer,然后把WebMvcConfigurer赋值到configurers里
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }
 
    }
 
     //其中的一个参考实现,将从容器中获取所有的WebMvcConfigurer相关配置都来一起调用
     //容器中所有的WebMvcConfigurer都会一起起作用;
     //我们自己的配置类也会被调用
     protected void addViewControllers(ViewControllerRegistry registry) {
        this.configurers.addViewControllers(registry);
    }

​ 4.我们的配置类也会被调用;

​ 效果:SpringMVC的自动配置和我们的扩展配置都会起作用;

3、全面接管SpringMVC

  • @EnableWebMvc

SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己配置;所有的SpringMVC的自动配置都失效了,我们值需要在配置类中添加@EnableWebMvc即可;

 //使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
@EnableWebMvc //全面接管SpringMVC,所有的SpringMVC的自动配置都失效了
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {
 
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //super.addViewControllers(registry);
        //浏览器发送 /atguigu请求来到success页面
        registry.addViewController("/atguigu").setViewName("success");
    }
}
  • 原理:

1.@EnableWebMvc的核心

 @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({DelegatingWebMvcConfiguration.class})
public @interface EnableWebMvc {
}

2.SpringMVC自动配置类表示容器中没有WebMvcConfigurationSupport这个组件的时候,这个自动配置类才生效,@EnableWebMvc将WebMvcConfigurationSupport组件导入进来;所以所有的SpringMVC的自动配置都失效了,只导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;

 @Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

3.SpringMVC自动配置类表示容器中没有WebMvcConfigurationSupport这个组件的时候,这个自动配置类才生效

 @Configuration
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
//容器中没有这个组件的时候,这个自动配置类才生效
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {

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

模式:

  • SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户配置的,如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置的和自己默认的组合起来;
  • 在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置
  • ​ 在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值