3.3 Spring Boot自动配置过程

Spring Boot内置自动配置原理是怎样的呢?这一切都在@EnableAutoConfiguration这个注解里:

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

其中的核心注解是@Import(EnableAutoConfigurationImportSelector.class),借助Enable-AutoConfigurationImportSelector、@EnableAutoConfiguration、Spring Boot应用将所有符合条件的@Configuration配置类都加载到当前Spring容器中——就像一只“八爪鱼”一样。具体的实现是使用了Spring框架中原有的一个工具类SpringFactoriesLoader。这样,@EnableAutoConfiguration就可以智能实现Bean的自动配置。

3.3.1 @EnableAutoConfiguration注解

Spring Boot中通过@EnableAutoConfiguration启用Spring应用程序上下文的自动配置,这个注解会导入一个EnableAutoConfigurationImportSelector的类,而AutoConfigurationImportSelector这个类会去读取一个spring.factories下key为EnableAutoConfiguration对应的类全限定名的值。其中的关键代码如下:

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

这个spring.factories里面配置的那些类,主要作用是告诉Spring Boot这个stareter所需要加载的那些*AutoConfiguration类,也就是你真正的要自动注册的那些Bean或功能。然后,再实现一个spring.factories指定的类,标上@Configuration注解,一个starter就定义完了。通过org.springframework.boot.autoconfigure.AutoConfigurationImportSelector里面的getCandidateConfigurations方法,获取到候选类的名字列表List<String>。

其中,loadFactoryNames的第1个参数是getSpringFactoriesLoaderFactoryClass()方法直接返回的是EnableAutoConfiguration.class,代码如下:

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

所以,getCandidateConfigurations方法里面的这段代码:

        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
                          getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());

会过滤出key为

        org.springframework.boot.autoconfigure.EnableAutoConfiguration

的全限定名对应的值。其中,SpringFactoriesLoader主要用来查询META-INF/spring. factories的properties配置中指定class对应的所有实现类。下节介绍这个文件。

提示

全限定名都使用如下命名方法:

包名.外部类名

包名.外部类名$内部类名

例如:

            org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfi
                guration

3.3.2 spring.factories文件

Spring Boot中的META-INF/spring.factories(spring-boot/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories)配置文件的完整内容可参考Spring Boot源代码工程,其中关于EnableAutoConfiguration的配置是:

        # Auto Configure
        org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
        org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAut
            oConfiguration, \
        ……
        org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

当然了,这些AutoConfiguration不是所有都会加载的,会根据AutoConfiguration上的@ConditionalOnClass等条件,再进一步判断是否加载。

3.3.3 获取候选配置类

在上面的getCandidateConfigurations方法中,我们可以看到读取spring.factories文件由SpringFactoriesLoader来完成的。SpringFactoriesLoader的实现类似于SPI(Service Provider Interface,在java.util.ServiceLoader的文档里有比较详细的介绍。Java SPI提供一种服务发现机制,为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。

SpringFactoriesLoader会加载classpath下所有JAR文件里面的META-INF/spring.factories文件。

其中加载spring.factories文件的代码在loadFactoryNames()方法里。Spring Boot自动配置的过程可以用一张图说明,如图3-3所示。

图3-3 Spring Boot Autoconfigure工作原理图