美文网首页
SpringBoot 自动配置跟踪记录

SpringBoot 自动配置跟踪记录

作者: 浅笑丨无痕 | 来源:发表于2019-07-19 23:40 被阅读0次

SpringBoot 自动配置跟踪记录

从启动流程解析中可以看到,@SpringBootApplication注解中包含了@EnableAutoConfiguration,先看看这个注解的源码。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    
    Class<?>[] exclude() default {};
    
    String[] excludeName() default {};
}

@AutoConfigurationPackage

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}

可以看到,这个注解引入另一个类AutoConfigurationPackages.Registrar,功能是从主程序类所在的包路径(包括子包)下的所有组件注册到 Spring IOC 容器中。

再看 @Import(AutoConfigurationImportSelector.class)

引入类AutoConfigurationImportSelector,看看核心方法selectImports(),

public String[] selectImports(AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return NO_IMPORTS;
    }
    // 1.得到注解信息
    AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
        .loadMetadata(this.beanClassLoader);
    // 2.对注解信息进行处理
    AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
                                                                              annotationMetadata);
    return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

看getAutoConfigurationEntry()

protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
                                                           AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    // 获取注解中的属性
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // 从注解数据中获取候选配置列表
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // 去重
    configurations = removeDuplicates(configurations);
    // 排除不需要的信息
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    configurations.removeAll(exclusions);
    configurations = filter(configurations, autoConfigurationMetadata);
    // 触发自动配置类引入完成的事件
    fireAutoConfigurationImportEvents(configurations, exclusions);
    // 创建 AutoConfigurationEntry 对象并返回
    return new AutoConfigurationEntry(configurations, exclusions);
}

getCandidateConfigurations()是比较关键的方法,主要是从注解数据中获取候选配置列表

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
                                                                         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;
}

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
    return EnableAutoConfiguration.class;
}

可以看到,调用的SpringFactoriesLoader.loadFactoryNames()方法,从 (所有jar下)META-INF/spring.factories 加载的指定类型为 EnableAutoConfiguration 类。

随便找到一个jar的spring.factories的文件,可以看到有很多自动配置的key-value属性:


image.png

点击其中一个配置类看看RedisAutoConfiguration,

@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
    public RedisAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"}
    )
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

这里就放着redis相关配置。

从这里就可以得出,Springboot 在启动的时候会AutoConfigurationImportSelector去寻找jar包下面的META-INF/spring.factories文件,通过这些文件找到这些配置类的位置,并去加载其中的配置。当然这些配置类也不是全部加载到容器中,而是通过@ConditionalOnxxx的注解来判断是否满足条件,从而达到根据条件来加载对应类的功能。

以上只是大概的流程。

相关文章

网友评论

      本文标题:SpringBoot 自动配置跟踪记录

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