Spring Boot自动配置原理

springboot的自动配置是她的核心之一,为我们简化配置文件起到了主要作用。本文就简单的探索下springboot的自动配置原理,欢迎大家评论与探讨。

1、SpringBoot启动的时候会加载主配置类,开启了自动配置功能 @EnableAutoConfiguration

这里不妨点开这个注解,看看其内部实现:

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

2、@EnableAutoConfiguration 作用:

利用EnableAutoConfigurationImportSelector给容器中导入一些组件
点开这个导入选择器可以查看selectImports()方法的内容;

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, 	      annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

这里面主要涉及到了两个方法

1.AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader):
public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
        return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
 }
//继续看loadMetadata()方法
public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
        return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
    }

    static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
        try {
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources(path) : ClassLoader.getSystemResources(path);
            Properties properties = new Properties();

            while(urls.hasMoreElements()) {
                properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource((URL)urls.nextElement())));
            }

            return loadMetadata(properties);
        } catch (IOException var4) {
            throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", var4);
        }
    }
    
    static AutoConfigurationMetadata loadMetadata(Properties properties) {
        return new AutoConfigurationMetadataLoader.PropertiesAutoConfigurationMetadata(properties);
    }

从源码可以看出该方法是为了扫描所有jar包类路径下 META‐INF/spring-autoconfigure-metadata.properties,并获取文件中的值将其封装为AutoConfigurationMetadata对象返回,这个文件中记录了相关配置类的加载条件,符合条件的配置类才会被允许加载。
若不满足,则该类是会从自动配置类列表中排除,这样能加快springboot的启动速度。spring官方文档(https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html)对该文件的作用描述如下:

Spring Boot uses an annotation processor to collect the conditions on auto-configurations in a metadata file (META-INF/spring-autoconfigure-metadata.properties). If that file is present, it is used to eagerly filter auto-configurations that do not match, which will improve startup time.

然后根据匹配结果,将真正满足配置条件的配置类放入list集合中 boolean[] skip记录了对应的候选自动配置类是否需要跳过,true-不满足条件,需要跳过,false-满足条件,不需要跳过。

2.getAutoConfigurationEntry,

我们来看看这个方法的实现:

protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);     //去重
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);  //排序
            this.checkExcludedClasses(configurations, exclusions);    
            configurations.removeAll(exclusions);             //去除排除项
            configurations = this.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

该方法将第一步的AutoConfigurationMetadata的对象作为参数,核心就是返回一个configurations ,而这个是通过getCandidateConfigurations方法得到的,下面看看这个方法的实现:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        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;
    }
 protected Class<?> getSpringFactoriesLoaderFactoryClass() {
      return EnableAutoConfiguration.class;
 }

我们可以看到这个方法调用了SpringFactoriesLoader.loadFactoryNames的静态方法:

public final class SpringFactoriesLoader {
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
	public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
        String factoryClassName = factoryClass.getName();
        return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
    }
}

可以看到,方法2就是扫描META-INF/spring.factories(spring-boot-autoconfigure-1.5.9.RELEASE-sources.jar)文件并获取自动配置类key=EnableAutoConfiguration.class的配置就这样找到对应的要加载的配置类。

总的来说,归为以下几点:

1、读取META-INF/spring-autoconfigure-metadata.properties文件中的配置类的条件;

2、获取需要排除的自动配置类;

3、读取spring-boot-autoconfigure.RELEASE.jar中的META-INF/spring.factories文件内容,作为候选自动配置类;

4、对候选自动配置类进行去重、排序、去除所有排除项;

5、利用META-INF/spring-autoconfigure-metadata.properties文件的配置对META-INF/spring.factories经历第四步处理后的候选自动配置类进行过滤,去除不满足加载条件的类,得到最终的自动配置类供SpringBoot加载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值