关于java:SpringBoot进阶之道自动装配

3次阅读

共计 5573 个字符,预计需要花费 14 分钟才能阅读完成。

SpringBoot 的主动拆卸是拆箱即用的根底,也是为服务化的前提。

一、主动拆卸的过程

1.1 @SpringBootApplication

后面一章我解说过了《SpringBoot 进阶之道 -@SpringBootApplication》。咱们晓得 @SpringBootApplication 蕴含了 @SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan。

1.2 @EnableAutoConfiguration

在上一章我解说过《SpringBoot 进阶之道 -@Enable 模块驱动》,这种 @Enabelxx 的注解是开启某一项性能的注解,其原理是借助 @Import,将所有合乎主动配置条件的 bean 定义加载到 IOC 容器。具体的能够去看看。

那么 @EnableAutoConfiguration 这个注解会开启 springboot 主动拆卸性能。直白的说,Spring 会试图在你的 classpath 下找到所有配置的 Bean 而后进行拆卸。咱们以 springboot2.x 源码为例:

@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 {};}

从源码咱们得悉,要害是 @Import({AutoConfigurationImportSelector.class}),借助 AutoConfigurationImportSelector,@EnableAutoConfiguration 能够帮忙 springboot 利用将所有符合条件的 @Configuration 配置都加载到以后 SpringBoot 创立并应用的 ioc 容器。那么我为什么这么说呢?咱们看下 AutoConfigurationImportSelector 源码:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    ...
    public AutoConfigurationImportSelector() {}
}

该类实现了 DeferredImportSelector 接口,而 DeferredImportSelector 是继承了 ImportSelector:

public interface ImportSelector {String[] selectImports(AnnotationMetadata var1);
}

ImportSelector 接口次要是为了导入 @Configuration 的配置项,而 DeferredImportSelector 是延期导入,当所有的 @Configuration 都解决过后才会执行。
咱们看看 AutoConfigurationImportSelector 实现的 selectImports 办法:

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 判断是否进行主动拆卸
        if (!this.isEnabled(annotationMetadata)) {return NO_IMPORTS;} else {
            // 1 加载 META-INF/spring-autoconfigure-metadata.properties 文件
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
    }

    protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {
            // 2 获取注解的属性及其值(PS:注解指的是 @EnableAutoConfiguration 注解)AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            //3. 在 classpath 下所有的 META-INF/spring.factories 文件中查找 org.springframework.boot.autoconfigure.EnableAutoConfiguration 的值,并将其封装到一个 List 中返回
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            //4. 对上一步返回的 List 中的元素去重、排序
            configurations = this.removeDuplicates(configurations);
            //5. 根据第 2 步中获取的属性值排除一些特定的类
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            //6. 对上一步中所失去的 List 进行过滤,过滤的根据是条件匹配。这里用到的过滤器是
            //org.springframework.boot.autoconfigure.condition.OnClassCondition 最终返回的是一个 ConditionOutcome[] 数组。//(PS:很多类都是依赖于其它的类的,当有某个类时才会拆卸,所以这次过滤的就是依据是否有某个
            //class 进而决定是否拆卸的。这些类所依赖的类都写在 META-INF/spring-autoconfigure-metadata.properties 文件里)this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }
     ....
    public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {return loadMetadata(classLoader, "META-INF/spring-autoconfigure-metadata.properties");
    }
}

从下面的源码得悉,该办法先判断是否进行主动拆卸,而后从 META-INF/spring-autoconfigure-metadata.properties 读取元数据与元数据的相干属性,而后调用 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;
}

这个时候咱们看到个 Spring 框架原有的一个工具类 SpringFactoriesLoader,其次要的工作是从指定的 META-INF/spring.factories 加载配置,即依据 @EnableAutoConfiguration 的残缺类名 ”org.springframework.boot.autoconfigure.EnableAutoConfiguration” 作为查找的 Key,获取对应的配置,通过反射失去对应的一组 @Configuration 类。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,\
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
....

总结:主动拆卸就是利用 SpringFactoriesLoader 从 classpath 中搜寻所有的 META-INF/spring.factories 配置文件,并将其中 org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的配置项通过反射实例化为标注了 @Configuration 的 JavaConfig 模式的配置类,而后汇总并加载到 ioc 容器。所以,以前咱们须要本人配置的货色,主动配置类都帮咱们实现了,是不是很嗨~~~

正文完
 0