9.自动配置原理

那些属性可以在配置文件中写呢:
具体:Part X. Appendices
Appendix A. Common application properties


自动配置原理:
  1.springboot在启动时加载著配置类(@SpringBootApplication标注的类),开启了自动配置功能(@EnableAutoConfiguration)
  2.@EnableAutoConfiguration的作用:
1.@EnableAutoConfiguration标签的代码如下:
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage------------------>自动扫描启动类包下和其子包下的所有带标签的组件
    @Import({AutoConfigurationImportSelector.class})
    public @interface EnableAutoConfiguration {
         ...   
    }

2.AutoConfigurationImportSelector的代码如下:
    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        ...
        //获取候选配置
        List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
        ....
    }
3.getCandidateConfigurations的代码如下:
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        //第一个参数返回:EnableAutoConfiguration.class 
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }
4.loadFactoryNames代码如下:
    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }
5.loadSpringFactories代码如下:
    {
        ...
        Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
        ...
    }

总结:发现其底层是获取jar类路径下的:META-INF/spring.factories文件里,并通过EnableAutoConfiguration去获取要加载的全类名:

文件格式如下:
    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
    org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
    org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
    org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
    org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
    org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
    ...很多很多!
    
每一个这样的xxxAutoConfiguration都是容器的一个组件,都加到容器中,用他们来做自动配置!

springboot的精髓:

1.springboot启动时会加载大量的自动配置类(xxxAutoConfiguration)
2.我们看我们需要的功能有没有springboot默认写好的自动配置类
3.我们再来看这个自动配置类中到底配置了哪些组件(只要我们要用的组件有,就不需要再来配置了)
4.给容器中自动配置类添加组件时,会从properties类中获取某些属性值。我们就可以在配置文件中指定这些属性的值4
 
xxxAutoConfiguration:自动配置类
给容器中添加组件
xxxProperties:封装了配置文件中相关的属性
 
以HttpEncodingAutoConfiguration来理解其底层的(http编码自动设置)为例解释自动配置原理:
@Configuration( //表示这是一个配置类,跟以前编写的配置文件一样(<bean></bean>)也可以给容器中添加组件
    proxyBeanMethods = false
)
    @EnableConfigurationProperties({ServerProperties.class})//启动指定类的ConfigurationProperties功能;将配置文件中的值和ServerProperties绑定起来
    //判断当前类是不是web应用,如果是,当前配置类生效
    @ConditionalOnWebApplication(//里面是spring的@Conditional(条件判断注解),根据不同的条件,如果满足指定的条件,配置类中的配置就会生效
    type = Type.SERVLET  
)
@ConditionalOnClass({CharacterEncodingFilter.class})//判断当前项目有没有这个类:CharacterEncodingFilter;springmvc中进行乱码解决的过滤器
@ConditionalOnProperty(//判断当前项目是否存在某个配置:server.servlet.encoding.enabled; 如果不存在,判断也是成立的()matchIfMissing = true),
                        //即使我们的配置文件中不配置server.servlet.encoding.enabled=true,也是默认生效的
    prefix = "server.servlet.encoding",
    value = {"enabled"},
    matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
    //这个Encoding 类是ServerProperties的内部类,所以和springboot的appliaction.properties文件以形成了映射关系(重要!)
    private final Encoding properties;
    @Bean//给容器中添加一个组件,这个组件的某些值要从properties中获取
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));
        return filter;
}
}
根据当前不同的条件判断,决定这个配置类是否生效!!

细节
1.@Conditional派生注解(spring注解版的原生的@Conditional的作用)
作用:是必须@Conditional指定的条件必须成立,才能给容器中添加组件,配置里面的内容才能生效
@Conditional扩展注解
作用(判断是否满足当前条件)
@ConditionalOnjava
系统的java版本是否满足要求
@ConditionalOnBean
容器中存在指定的bean
@ConditionalOnMissingBean
容器中不存在指定的bean
@ConditionalOnExpression
满足SPEL表达式的
@ConditionalOnClass
系统中存在指定的类
@ConditionalOnMissingClass
系统中不存在指定的class
@ConditionalOnSingleCandidate
容器中只有一个指定的bean,或者这个bean是首选的bean
@ConditionalOnProperty
系统中指定的属性是否存在指定的值
@ConditionalOnResource
类路径下是否存在指定的资源文件
自动配置类必须在一定的条件下才能生效!
我们可以在配置文件中设置;debug=true,控制台上会输出自动配置的类!

============================
CONDITIONS EVALUATION REPORT
============================


Positive matches:(自动配置类启动的)
-----------------

   AopAutoConfiguration matched:
      - @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)

   AopAutoConfiguration.ClassProxyingConfiguration matched:
      - @ConditionalOnMissingClass did not find unwanted class 'org.aspectj.weaver.Advice' (OnClassCondition)
      - @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)
    。。。。
    
    
Negative matches:(自动配置类没有匹配上的)
-----------------

   ActiveMQAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)

   AopAutoConfiguration.AspectJAutoProxyingConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'org.aspectj.weaver.Advice' (OnClassCondition)
         ....

 

posted @ 2022-05-09 21:11  努力的达子  阅读(240)  评论(0编辑  收藏  举报