java详细介绍一下Spring Boot框架的自动配置原理

71 阅读5分钟

Spring Boot 的自动配置(Auto-configuration)是其最核心的特性之一,它通过“约定优于配置”的理念,自动推断并配置 Spring 应用所需的组件,极大地减少了开发者的手动配置工作。下面我们来深入拆解其实现原理。

核心思想

自动配置的核心思想是:Spring Boot 会根据你项目中添加的依赖(JAR 包)和配置,自动判断并创建所需的 Bean,注册到 Spring 容器中。

例如,当你在 ​​pom.xml​​ 中添加了 ​​spring-boot-starter-web​​ 依赖,Spring Boot 就会自动配置 Tomcat 服务器、DispatcherServlet、Jackson 等 Web 开发必需的组件。

关键技术与组件

实现自动配置主要依赖以下几个关键技术:

  1. ​ @EnableAutoConfiguration​​ 注解
  2. Spring Factories 机制
  3. 条件注解(Conditional Annotations)
  4. ​ @ConfigurationProperties​​ 注解
1. ​​@EnableAutoConfiguration​​ 注解

这个注解是开启自动配置的“总开关”。在 Spring Boot 应用的启动类上,你通常会看到:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

而 ​​@SpringBootApplication​​ 是一个复合注解,它包含了 ​​@EnableAutoConfiguration​​。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration // <-- 关键注解
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    // ...
}

​@EnableAutoConfiguration​​ 的作用是:告诉 Spring Boot 去“尝试”根据 classpath 下的依赖和配置来自动配置 Spring 应用上下文。

2. Spring Factories 机制

这是 Spring Boot 实现自动配置的核心加载机制。它是一种基于 SPI(Service Provider Interface)的扩展方式。

工作原理如下:

  1. Spring Boot 启动时,​​@EnableAutoConfiguration​​ 会触发 ​​AutoConfigurationImportSelector​​ 这个类。
  2. ​AutoConfigurationImportSelector​​ 的核心方法 ​​selectImports()​​ 会去扫描所有在 ​​META-INF/spring.factories​​ 文件中注册的自动配置类。
  3. 它并不仅仅扫描你自己项目的 ​​classpath​​,而是会扫描所有引入依赖(JAR 包)中的 ​​META-INF/spring.factories​​ 文件。

举个例子:

在 ​​spring-boot-autoconfigure-xxx.jar​​ 这个核心自动配置包中,就有一个 ​​META-INF/spring.factories​​ 文件,其中包含了大量的自动配置类:

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

# 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.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration,\
org.springframework.boot.autoconfigure.netty.NettyAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\
org.springframework.boot.autoconfigure.r2dbc.R2dbcTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.r2dbc.R2dbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

# ... 其他配置

​AutoConfigurationImportSelector​​ 会读取这个文件中的 ​​org.springframework.boot.autoconfigure.EnableAutoConfiguration​​ 列表,这个列表里的每一个类都是一个候选的自动配置类。

3. 条件注解(Conditional Annotations)

扫描到的自动配置类并不会全部都被应用。Spring Boot 使用条件注解来精确控制某个配置类在什么情况下才会生效。

这是实现“智能推断”的关键。最常用的条件注解都位于 ​​org.springframework.boot.autoconfigure.condition​​ 包下:

  • ​@ConditionalOnClass​​:只有当 classpath 下存在指定的类时,才启用该配置。
  • 例:​​@ConditionalOnClass({DispatcherServlet.class})​​ 表示只有项目里引入了 Spring MVC 的 ​​DispatcherServlet​​ 类(即添加了 Web 依赖),这个 Web 相关的自动配置才会生效。
  • ​@ConditionalOnMissingClass​​:与上面相反,当 classpath 下不存在指定的类时才启用。
  • ​@ConditionalOnBean​​:只有当 Spring 容器中已经存在指定类型的 Bean 时才启用。
  • 例:​​@ConditionalOnBean(DataSource.class)​​ 表示只有当数据源 Bean 已经被创建后,依赖它的 JdbcTemplate 配置才会生效。
  • ​@ConditionalOnMissingBean​​:当 Spring 容器中不存在指定类型的 Bean 时才启用。这允许用户通过手动定义一个同名 Bean 来覆盖 Spring Boot 的默认配置。
  • 例:如果你自己定义了一个 ​​RestTemplate​​ 的 Bean,那么 Spring Boot 自动配置的 ​​RestTemplate​​ 就不会生效。
  • ​@ConditionalOnProperty​​:根据配置文件(​​application.properties​​ 或 ​​application.yml​​)中的属性值来判断是否启用。
  • 例:​​@ConditionalOnProperty(prefix = "spring.datasource", name = "url")​​ 表示只有当配置了 ​​spring.datasource.url​​ 属性时,数据源自动配置才会生效。
  • ​@ConditionalOnWebApplication​​:只有当应用是一个 Web 应用时才启用。
  • ​@ConditionalOnNotWebApplication​​:只有当应用不是 Web 应用时才启用。

一个实际的自动配置类示例 (​WebMvcAutoConfiguration​​):

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET) // 1. 仅在 Servlet Web 应用中生效
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) // 2. 仅在 classpath 下有这些类时生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class) // 3. 如果用户自己提供了 WebMvcConfigurationSupport,这个自动配置就失效
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
        ValidationAutoConfiguration.class }) // 4. 在这些自动配置之后执行
public class WebMvcAutoConfiguration {
    // ... 内部定义了大量的 Bean,如 RequestMappingHandlerMapping, RequestMappingHandlerAdapter 等
}
4. ​​@ConfigurationProperties​​ 注解

自动配置类通常需要读取外部配置来定制化 Bean 的行为。​​@ConfigurationProperties​​ 注解就是用来将 ​​application.properties​​ 或 ​​application.yml​​ 中的属性绑定到一个 Java Bean 上。

工作流程:

  1. 创建一个配置属性类,并使用 @ConfigurationProperties 注解。
@ConfigurationProperties(prefix = "spring.datasource")
public class DataSourceProperties {
    private String url;
    private String username;
    private String password;
    private String driverClassName;
    // ... getters and setters
}
  1. 在自动配置类中,通过 @EnableConfigurationProperties 或直接使用 @Autowired 将这个配置属性类注入,并用来配置 Bean。
@Configuration
@EnableConfigurationProperties(DataSourceProperties.class) // 启用配置属性绑定
public class DataSourceAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public DataSource dataSource(DataSourceProperties properties) {
        // 使用 properties 对象中的 url, username, password 等来创建 DataSource Bean
        return DataSourceBuilder.create()
                .url(properties.getUrl())
                .username(properties.getUsername())
                .password(properties.getPassword())
                .driverClassName(properties.getDriverClassName())
                .build();
    }
}
  1. 这样,开发者就可以在 application.properties 中轻松配置数据源:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

整体流程总结

Spring Boot 自动配置的完整流程可以概括为以下几个步骤:

  1. 启动应用:执行 ​​SpringApplication.run(...)​​。
  2. 启用自动配置:​​@EnableAutoConfiguration​​ 被激活。
  3. 扫描候选配置:​​AutoConfigurationImportSelector​​ 扫描所有 ​​classpath​​ 下 ​​META-INF/spring.factories​​ 文件,收集所有 ​​EnableAutoConfiguration​​ 对应的配置类。
  4. 筛选有效配置:Spring 容器根据每个候选配置类上的条件注解(如 ​​@ConditionalOnClass​​, ​​@ConditionalOnProperty​​ 等)进行判断,筛选出当前环境下真正需要生效的配置类。
  5. 注入配置属性:对生效的配置类,Spring Boot 会通过 ​​@ConfigurationProperties​​ 将外部配置(如 ​​application.yml​​)绑定到对应的属性类上。
  6. 注册 Bean 到容器:执行筛选后配置类中的 ​​@Bean​​ 方法,将创建好的组件(如 ​​DataSource​​, ​​DispatcherServlet​​)注册到 Spring 容器中。
  7. 应用启动完成:所有必要的 Bean 都已就绪,应用启动成功。

通过这套机制,Spring Boot 实现了高度的自动化和灵活性,让开发者能够“开箱即用”,同时又保留了在需要时进行手动干预和定制的能力。