Spring Boot自动配置的底层实现机制

Spring Boot框架的自动装配能力由@EnableAutoConfiguration注解触发。深入探索该注解的源码实现,可以发现其核心依赖于一个关键的工厂加载方法:

org.springframework.core.io.support.SpringFactoriesLoader.loadFactoryNames(Class<?>, ClassLoader)

该方法的实现逻辑如下:

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    try {
        // 定位所有包含spring.factories文件的资源位置
        Enumeration<URL> urls = (classLoader != null ?
                classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                classLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));

        List<String> result = new ArrayList<>();
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            // 加载每个文件中的配置属性
            Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
            String factoryClassNames = properties.getProperty(factoryClassName);
            // 解析逗号分隔的类名列表
            result.addAll(Arrays.asList(
                    StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
        }
        return result;
    } catch (IOException ex) {
        throw new IllegalArgumentException("无法从[" + FACTORIES_RESOURCE_LOCATION +
                "]位置加载[" + factoryClass.getName() + "]工厂类", ex);
    }
}

该方法会扫描整个类路径下所有JAR包中特定位置的配置文件:

/**
 * 工厂配置文件的存储位置
 * <p>该文件可能在多个JAR包中存在</p>
 */
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

在Spring Boot的自动配置模块(例如spring-boot-autoconfigure-1.5.6.RELEASE.jar)中,我们可以找到这个配置文件,其中定义了大量的自动配置类:

# 自动配置类注册表
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.CloudAutoConfiguration,\
...

以数据源自动配置的实现为例,其关键注解结构为:


@Configuration
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@EnableConfigurationProperties(DataSourceProperties.class)
@Import({Registrar.class, DataSourcePoolMetadataProvidersConfiguration.class})
public class DataSourceAutoConfiguration {
    // 配置实现细节
}

这里体现了自动配置的两个核心要素:@Configuration表明这是一个配置类,@ConditionalOnClass则根据类路径中是否存在特定类来决定是否激活该配置。

实现自定义的自动配置模块

掌握了自动配置的基本原理后,我们可以创建自己的自动配置功能。下面是一个完整的实现示例:

第一步:构建配置功能类

public class ConfigurationReader implements EnvironmentAware {

    private final Logger log = LoggerFactory.getLogger(getClass());
    private Environment environment;

    public String readString(String propertyKey) {
        return environment.getProperty(propertyKey);
    }

    public Long readLong(String propertyKey) {
        String value = readString(propertyKey);
        try {
            return Long.parseLong(value);
        } catch (NumberFormatException e) {
            log.warn("数值转换异常,键值对: {} = {}", propertyKey, value);
            return 0L;
        }
    }

    public Integer readInteger(String propertyKey) {
        return readLong(propertyKey).intValue();
    }

    @Override
    public void setEnvironment(Environment env) {
        this.environment = env;
    }
}

第二步:创建自动配置类

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.PropertyResolver;

@Configuration
@ConditionalOnClass(PropertyResolver.class)
public class ConfigurationReaderAutoConfig {

    @Bean
    public ConfigurationReader configurationReader() {
        return new ConfigurationReader();
    }
}

第三步:注册自动配置

在项目资源目录创建META-INF/spring.factories文件,添加配置:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.config.ConfigurationReaderAutoConfig

完成以上三步,自定义的自动配置模块即可生效。

查看自动配置状态信息

了解哪些自动配置类被加载或排除,有多种方式可以查看详细报告:

  1. Maven插件方式:使用spring-boot:run时在环境变量中添加debug=true
  2. JAR运行方式:执行命令时添加--debug参数
  3. IDE配置方式:在虚拟机参数中添加-Ddebug
  4. 配置文件方式:在application.propertiesapplication.yml中设置debug: true
  5. 监控端点方式:集成Actuator后访问/actuator/conditions端点

应用启动时将显示详细的自动配置报告:

=========================
自动配置分析报告
=========================

已激活的配置:
-------------

   AopAutoConfiguration 已激活:
      - 检测到必需的类: 'org.springframework.context.annotation.EnableAspectJAutoProxy', 
        'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice' (类条件检查)
      - 属性条件 spring.aop.auto=true 匹配成功 (属性条件检查)
   
   ...
   
   ConfigurationReaderAutoConfig 已激活:
      - 检测到必需的类: 'org.springframework.core.env.PropertyResolver' (类条件检查)

   ErrorMvcAutoConfiguration 已激活:
      - 检测到必需的类: 'javax.servlet.Servlet', 'org.springframework.web.servlet.DispatcherServlet' 
        (类条件检查)
      - 检测到Web应用环境: StandardServletEnvironment (Web应用条件检查)

未激活的配置:
-------------

   ActiveMQAutoConfiguration:
      未激活原因:
         - 未找到必需的类: 'javax.jms.ConnectionFactory', 
           'org.apache.activemq.ActiveMQConnectionFactory' (类条件检查)

   BatchAutoConfiguration:
      未激活原因:
         - 未找到必需的类: 'org.springframework.batch.core.launch.JobLauncher' (类条件检查)
   
   ...

报告明确分为两部分:

  • 已激活的配置:满足所有条件并成功加载的自动配置类
  • 未激活的配置:因某些条件不满足而被跳过的自动配置类

从输出中可以看到,我们自定义的ConfigurationReaderAutoConfig已被成功识别并启用。