美文网首页Spring
SpringBoot-Web自动配置

SpringBoot-Web自动配置

作者: elijah777 | 来源:发表于2019-07-13 10:39 被阅读0次

    spring-boot-web

    一、在项目中使用thymeleaf

    spring-boot-starter-thymeleaf会自动包含spring-boot-starter-web

    ThymeleafPropertiese类

    import java.nio.charset.Charset;
    import java.nio.charset.StandardCharsets;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    @ConfigurationProperties(
            prefix = "spring.thymeleaf"
    )
    public class ThymeleafProperties {
        private static final Charset DEFAULT_ENCODING;
    
        /**
         * 前缀设置,springboot默认是模板防止在classpath:/templates/下
         */
        public static final String DEFAULT_PREFIX = "classpath:/templates/";
    
        /**
         * 后缀设置
         */
        public static final String DEFAULT_SUFFIX = ".html";
        private boolean checkTemplate = true;
        private boolean checkTemplateLocation = true;
        private String prefix = "classpath:/templates/";
        private String suffix = ".html";
        /**
         * 模板模式设置
         */
        private String mode = "HTML";
        /**
         * 模板的编码设置,默认是UTF_8
         */
        private Charset encoding;
        private boolean cache;
        private Integer templateResolverOrder;
        private String[] viewNames;
        private String[] excludedViewNames;
        private boolean enableSpringElCompiler;
        private boolean renderHiddenMarkersBeforeCheckboxes;
        private boolean enabled;
        static {
            DEFAULT_ENCODING = StandardCharsets.UTF_8;
        }
    
        //  .......
    }
    
    
    

    二、Web相关配置

    spring-boot提供相关自动配置

    源码查看WebMvcAutoConfiguration 和 WebMvcProperties 的源码

    public class WebMvcAutoConfiguration {
    
    
     @Bean
            @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;
            }
            
            
            @Bean
            @ConditionalOnBean({View.class})
            @ConditionalOnMissingBean
            public BeanNameViewResolver beanNameViewResolver() {
                BeanNameViewResolver resolver = new BeanNameViewResolver();
                resolver.setOrder(2147483637);
                return resolver;
            }
            
            
        }
    
    1、自动配置的viewResolver
    a)、ContentNegotiatingViewResolver

    ContentNegotiatingViewResolver是spring提供的特殊ViewResolve,ContentNegotiatingViewResolver不是自己处理View,而是代理给不同的ViewResolve来处理不同的View,所以它有最高优先级

    package org.springframework.web.servlet.view;
    
    public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered, InitializingBean {
        // .....
    }
    
    b)、BeanNameViewResolver

    在控制器(@Controller)中的一个方法的返回值的字符串(视图名,return “index”;)会根据BeanNameViewResolve 去查找Bean的名称为返回字符串的View来渲染视图。

    package org.springframework.web.servlet.view;
    
    public class BeanNameViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered {
         // .....
    }
    

    定义BeanNameViewResolve的Bean:

    @Bean
            @ConditionalOnBean({View.class})
            @ConditionalOnMissingBean
            public BeanNameViewResolver beanNameViewResolver() {
                BeanNameViewResolver resolver = new BeanNameViewResolver();
                resolver.setOrder(2147483637);
                return resolver;
            }
            
    

    定义一个View的Bean,名称为jsonView:

    @Bean
    public MappingJackson2JsonView  JsonView() {
        MappingJackson2JsonView JsonView = new MappingJackson2JsonView();
        return JsonView;
    }
    

    在控制器中,返回值为字符串json,它会找bean的名称为jsonView的视图来渲染:

     @RequestMapping(value = "/json", produces = {MediaType.APPLICATION_JSON_VALUE})
        public String json(Model model) {
            Person person = new Person("aa", 11);
            model.addAttribute("single", person);
            return "jsonView";
        }
        
    
    c)、InternalResourceViewResolver

    这是极为常用的ViewResolve,主要通过设置前缀、后缀,以及控制器中方法来返回视图名的字符串,以得到实际页面:

     @Bean
            @ConditionalOnMissingBean
            public InternalResourceViewResolver defaultViewResolver() {
                InternalResourceViewResolver resolver = new InternalResourceViewResolver();
                resolver.setPrefix(this.mvcProperties.getView().getPrefix());
                resolver.setSuffix(this.mvcProperties.getView().getSuffix());
                return resolver;
            }
            
    
    package org.springframework.web.servlet.view;
    
    public class InternalResourceViewResolver extends UrlBasedViewResolver {}
    
    
    2、自动配置的静态资源

    在自动配置类的addResourceHandlers方法中定义了以下静态资源的自动配置。

    WebMvcAutoConfiguration类中方法

    public void addResourceHandlers(ResourceHandlerRegistry registry) {
                if (!this.resourceProperties.isAddMappings()) {
                    logger.debug("Default resource handling disabled");
                } else {
                    Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
                    CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
                    if (!registry.hasMappingForPattern("/webjars/**")) {
                        this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                    }
    
                    String staticPathPattern = this.mvcProperties.getStaticPathPattern();
                    if (!registry.hasMappingForPattern(staticPathPattern)) {
                        this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                    }
    
                }
            }
            
    

    类路径文件和webjars

    3、自动配置的Formatter和Converter

    关于自动配置Formatter和Converter,

    WebMvcAutoConfiguration类中方法

    public void addFormatters(FormatterRegistry registry) {
                Iterator var2 = this.getBeansOfType(Converter.class).iterator();
    
                while(var2.hasNext()) {
                    Converter<?, ?> converter = (Converter)var2.next();
                    registry.addConverter(converter);
                }
    
                var2 = this.getBeansOfType(GenericConverter.class).iterator();
    
                while(var2.hasNext()) {
                    GenericConverter converter = (GenericConverter)var2.next();
                    registry.addConverter(converter);
                }
    
                var2 = this.getBeansOfType(Formatter.class).iterator();
    
                while(var2.hasNext()) {
                    Formatter<?> formatter = (Formatter)var2.next();
                    registry.addFormatter(formatter);
                }
    
            }
    
    
    

    可以看出定义了Converter、GenericConverter和Formatter接口实现类的Bean,这个Bean会自动注册到Spring MVC中。

    4、自动配置的HttpMessageConverters

    在WebMvcAutoConfiguration中注册了MessageConverters

     public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
                this.messageConvertersProvider.ifAvailable((customConverters) -> {
                    converters.addAll(customConverters.getConverters());
                });
            }
            
    

    如果要新增自定义的HttpMessageConverter,则只需定义一个HttpMessageConverter的Bean,然后在此Bean中注册自定义HttpMessageConvertter即可。

    @Bean
    publie HttpMessageConverter constomConverters() {
        HttpMessageConverter<?> constomConverter1 = new ConstomConverter1();
        HttpMessageConverter<?> constomConverter2 = new ConstomConverter2();
        return new HttpMessageConverters(constomConverter1, constomConverter2);
    }
    

    思考一下

    对于Web在印象中的成长,从最初的Servlet、JSP,到Struts2,JSF和SpringMVC,每一次都是巨大的飞跃,记得上学期间用JSP写的项目,代码真是一摞摞的,写着写着自己都找不到了,后来用了SSH框架,立马不一样,代码看起来清晰一些了,但是配置文件对一些,自己还是菜菜的,写的也是很乱,用了SpringMVC的注解之后,感觉到编码很愉快,也很清晰,到目前的springboot,自动配置更是省下了很多配置,但底层的原理没有变,读读源码依旧是头蒙蒙的,不仅要学习新的技术,也不能忘记老的基础。

    2019/07/13 上午于成都

    相关文章

      网友评论

        本文标题:SpringBoot-Web自动配置

        本文链接:https://www.haomeiwen.com/subject/jalpkctx.html