前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >源码学习系列之SpringBoot自动配置(篇二)

源码学习系列之SpringBoot自动配置(篇二)

作者头像
SmileNicky
发布2019-11-18 14:53:25
2850
发布2019-11-18 14:53:25
举报
文章被收录于专栏:Nicky's blog

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/u014427391/article/details/103003905

源码学习系列之SpringBoot自动配置(篇二)之HttpEncodingAutoConfiguration 源码分析

继上一篇博客源码学习系列之SpringBoot自动配置(篇一)之后,本博客继续跟一下SpringBoot的自动配置源码

ok,先复习一下上一篇的内容,从前面的学习,我们知道了SpringBoot的自动配置主要是由一个选择器AutoConfigurationImportSelector,先通过选择器将自动配置的类加载到Spring容器

注意点:

  • List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);获取的候选配置的类名
  • 由SpringFactoriesLoader加载器负责加载配置类名,已经装载配置类到容器,SpringFactoriesLoader的loadSpringFactories方法读取自动配置工程的META-INF/spring.factories配置文件,加载配置类的全类名,包装成Properties对象,然后再加载到容器里
代码语言:javascript
复制
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
	/* 将spring.factories的类都装载到Spring容器*/
     public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();

        try {
        //将META-INF/spring.factories文件里配置的属性都装载到Enumeration数据结构里
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
            ArrayList result = new ArrayList();
			//遍历获取属性,然后再获取对应的配置类全类名
            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                String factoryClassNames = properties.getProperty(factoryClassName);
                result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
            }

            return result;
        } catch (IOException var8) {
            throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
        }
    }

ok,Springboot的自动配置类都在这个包里,源码很多,所以本博客只是简单跟一下源码

在这里插入图片描述
在这里插入图片描述

自动配置可以说是SpringBoot框架的一个很重要的功能,其强大的功能就是通过很多配置类实现的,当然这么多配置,可以参考SpringBoot官方的配置参考: https://docs.spring.io/spring-boot/docs/2.1.10.RELEASE/reference/html/common-application-properties.html

SpringBoot的自动配置类很多,显然不是每个配置类都生效的,比如你没引对应的jar,那对应的配置类肯定是不起效的,ok,本博客以HttpEncodingAutoConfiguration自动编码配置类为实例,记录一下SpringBoot的自动配置

先补充一些@Conditional注解的用法:详情可以参考我上篇博客SpringBoot系列之@Conditional注解用法简介

@Conditional派生注解

作用(都是判断是否符合指定的条件)

@ConditionalOnJava

系统的java版本是否符合要求

@ConditionalOnBean

有指定的Bean类

@ConditionalOnMissingBean

没有指定的bean类

@ConditionalOnExpression

符合指定的SpEL表达式

@ConditionalOnClass

有指定的类

@ConditionalOnMissingClass

没有指定的类

@ConditionalOnSingleCandidate

容器只有一个指定的bean,或者这个bean是首选bean

@ConditionalOnProperty

指定的property属性有指定的值

@ConditionalOnResource

路径下存在指定的资源

@ConditionalOnWebApplication

系统环境是web环境

@ConditionalOnNotWebApplication

系统环境不是web环境

@ConditionalOnjndi

JNDI存在指定的项

通过上篇博客的学习,我们已经知道了SpringBoot有很多自动配置类,所以本博客拿HttpEncodingAutoConfiguration类来看看

补充:

  • @Configuration proxyBeanMethods属性:默认是开启的,开启后允许其它配置类调用这个类的@bean方法,详情参看Spring官方文档:Spring官方文档
代码语言:javascript
复制
package org.springframework.boot.autoconfigure.web.servlet;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.http.HttpProperties;
import org.springframework.boot.autoconfigure.http.HttpProperties.Encoding;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.filter.CharacterEncodingFilter;

@Configuration(
    proxyBeanMethods = false
)//指定是一个配置列,关了proxyBeanMethods,其它配置类就不能调相应的@bean类
@EnableConfigurationProperties({HttpProperties.class})//让使用 @ConfigurationProperties注解的HttpProperties类生效,HttpProperties类通过ConfigurationProperties注解,将属性配置一个一个加载进来
@ConditionalOnWebApplication(
    type = Type.SERVLET
)//指定系统环境是Web环境配置才起效,并且指定类型是SERVLET
@ConditionalOnClass({CharacterEncodingFilter.class})//系统有CharacterEncodingFilter过滤器类,则配置类起效,CharacterEncodingFilter类:SpringMVC中进行乱码解决的过滤器
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)//判断配置文件是否有spring.http.encoding.enabled属性,如果没配置,也是默认为true的,因为配置了`matchIfMissing =true`
public class HttpEncodingAutoConfiguration {
	//创建一个Encoding对象
    private final Encoding properties;
	// 构造函数里通过properties.getEncoding();进行属性映射,获取默认的配置
    public HttpEncodingAutoConfiguration(HttpProperties properties) {
        this.properties = properties.getEncoding();
    }

    @Bean
    @ConditionalOnMissingBean//如果系统没有CharacterEncodingFilter类,就执行characterEncodingFilter方法
    public CharacterEncodingFilter characterEncodingFilter() {
    	//重新创建一个编码过滤器
        OrderedCharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        //设置默认的配置
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
        return filter;
    }

    @Bean
    public HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
        return new HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer(this.properties);
    }

    private static class LocaleCharsetMappingsCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
        private final Encoding properties;

        LocaleCharsetMappingsCustomizer(Encoding properties) {
            this.properties = properties;
        }

        public void customize(ConfigurableServletWebServerFactory factory) {
            if(this.properties.getMapping() != null) {
                factory.setLocaleCharsetMappings(this.properties.getMapping());
            }

        }

        public int getOrder() {
            return 0;
        }
    }
}

通过对HttpEncodingAutoConfiguration源码的学习,可以看出,其实主要是用@Conditional及其派生注解,这些注解都是要在特定情况才会起效,起效了,才会将组件加载到Spring容器里

ok,然后我们怎么知道哪些配置是起效的?在SpringBoot项目里,是可以通过配置,开启打印的,可以在application.properties加上debug=true属性就可以

控制台打印的Positive matches就表示有效的配置类

在这里插入图片描述
在这里插入图片描述

console打印的Negative matches表示不起效的配置类: 比如我的项目没有加aop的,aop自动配置类就不起效

在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/11/10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档