Spring boot自动配置原理

Spring boot自动配置原理

自动配置,顾名思义就是不需要开发者自己去配置应用程序,而是只要满足springboot实现自动配置的条件即可。具体来说就是Springboot根据开发者添加的jar包依赖项来自动配置springboot程序的。

1.环境

spring-boot 1.5.9.RELEASE

2.配置类注册到IOC容器的流程图

Spring boot自动配置原理

3.从代码开始分析

3.1、启动类
@SpringBootApplication
public class SpringbootLearnApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootLearnApplication.class, args);
    }
}
3.2、@SpringBootApplication注解
//省略部分注解
@SpringBootConfiguration//表示这是SpringBoot的配置类
@EnableAutoConfiguration//这个注解的作用就是让SpringBoot开启自动配置
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)//开启组件扫描
public @interface SpringBootApplication

@SpringBootApplication是一个组合注解,其中@EnableAutoConfiguration开启了自动配置功能。

3.3、@EnableAutoConfiguration注解
//省略部分注解
@AutoConfigurationPackage//添加该注解的类所在的package作为自动配置package进行管理
@Import({EnableAutoConfigurationImportSelector.class})//利用EnableAutoConfigurationImportSelector给容器中导入一些组件
public @interface EnableAutoConfiguration

EnableAutoConfigurationImportSelector类继承AutoConfigurationImportSelector类,查看AutoConfigurationImportSelector类源代码

 public String[] selectImports(AnnotationMetadata annotationMetadata) {
         .... 
        //获取候选的配置
         List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
         ....       
    }

getCandidateConfigurations方法

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        ....
    }
3.4、SpringFactoriesLoader类的loadFactoryNames方法

SpringFactoriesLoader类的loadFactoryNames方法,扫描所有jar包类路径下 META-INF/spring.factories 把扫描到的这些文件的内容包装成properties对象 从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();

        try {
            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);
        }
    }
3.5、spring.factories在spring-test-autoconfigure下的示例
# AutoConfigureCache auto-configuration imports
org.springframework.boot.test.autoconfigure.core.AutoConfigureCache=\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration

# AutoConfigureDataJpa auto-configuration imports
org.springframework.boot.test.autoconfigure.orm.jpa.AutoConfigureDataJpa=\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
    .......

4.HttpEncodingAutoConfiguration自动配置过程

4.1、HttpEncodingAutoConfiguration
@Configuration //配置类,可以给容器中添加组件
@EnableConfigurationProperties({HttpEncodingProperties.class})//启动指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;并把HttpEncodingProperties加入到ioc容器中
@ConditionalOnWebApplication//当Spring服务为web时,才使注解的类生效
@ConditionalOnClass({CharacterEncodingFilter.class})//判断当前项目有没有这个类
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)//判断配置文件中是否存在某个配置spring.http.encoding.enabled;如果不存在,判断也是成立的,即使在配置文件中不配置spring.http.encoding.enabled=true,配置也是生效的
public class HttpEncodingAutoConfiguration {
    
    //HttpEncoding的配置类,其中字段已经和配置文件映射了
    private final HttpEncodingProperties properties;

    //当前构造函数参数的值,会从容器中获取
    public HttpEncodingAutoConfiguration(HttpEncodingProperties properties)     {
        this.properties = properties;
    }

    @Bean//给容器中添加一个组件CharacterEncodingFilter
    @ConditionalOnMissingBean({CharacterEncodingFilter.class})//判断容器有没有这个组件
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());       filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST)); filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
        return filter;
    }

HttpEncodingAutoConfiguration会根据当前不同的条件判断,决定这个配置类是否生效,如果这个配置类生效,会给容器中添加各种组件;这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;

4.2 、HttpEncodingProperties
@ConfigurationProperties(prefix = "spring.http.encoding")////从配置文件中获取指定的值和bean的属性进行绑定
public class HttpEncodingProperties {

    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    private Charset charset = DEFAULT_CHARSET;

    private Boolean force;

    private Boolean forceRequest;

    private Boolean forceResponse;

    private Map<Locale, Charset> mapping;

    public Charset getCharset() {
        return this.charset;
    }
    .....
}
4.3、总结
  • SpringBoot启动会加载大量的自动配置类;给容器中自动配置添加组件的时候,会从propeties类中获取配置文件中指定这些属性的值
  • xxxxAutoConfigurartion:⾃动配置类给容器中添加组件;
  • xxxxProperties:封装配置文件中相关属性;
小技巧:
在配置文件中配置:debug=true,可以在控制台打印自动配置报告。
上一篇:Python实现分发数据块到多台服务器上


下一篇:分享我用Qt开发的应用程序【二】在Qt应用程序中使用字体图标fontawesome