0%

SpringBoot 自动配置原理分析

Spring Boot 自动配置(Auto Configuration)是 Spring Boot 提供的一种核心机制,它能够根据项目中引入的依赖和配置,自动配置 Spring 应用中常用的 Bean,从而极大简化开发者的配置工作。Spring 框架本身功能强大,但配置繁琐,需要大量 XML 或 Java 配置代码。Spring Boot 的自动配置通过“约定优于配置”的理念,帮开发者自动完成这些配置,使开发变得更简单、更快速。

问题背景:没有自动配置的“旧时代”

在 SpringBoot 没有出现之前,如果我们要搭建一个同时需要 Web 服务和数据库访问的 Spring 项目,我们需要手动繁琐的 XML 配置或 Java 配置类,包括配置以下 Bean:

  • 配置 DispatcherServlet 来处理 Web 请求。
  • 配置视图解析器(View Resolver),比如 Thymeleaf 或 JSP。
  • 配置数据源(DataSource),提供数据库的 URL、用户名、密码等信息。
  • 配置一个 JdbcTemplateSqlSessionFactory (MyBatis) 或 EntityManagerFactory (JPA) 来执行数据库操作。
  • 配置事务管理器(TransactionManager)。
  • 启用注解驱动,扫描 @Controller, @Service, @Repository 等组件。

这个过程非常繁琐、容易出错,而且大部分项目的这些配置都大同小异,充满了“样板代码”。

Spring Boot 自动配置

Spring Boot 的核心思想是“约定优于配置”。它认为,对于大多数应用场景,很多配置都可以是标准化的,它会自动帮你完成这些配置。现在,我们看看用 Spring Boot 如何实创建一个 Web + 数据库应用。

添加“启动器” (Starters)

我们只需要在 Maven 的 pom.xml 文件中添加两个依赖:

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

创建主启动类

1
2
3
4
5
6
7
8
9
10
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);
}
}

在配置文件中提供信息

src/main/resources/application.properties 文件中,如果我们用的是像 MySQL 这样的外部数据库,可以配置连接信息。

1
2
3
4
# 如果使用 MySQL,可以这样配置 
# spring.datasource.url=jdbc:mysql://localhost:3306/mydb
# spring.datasource.username=root
# spring.datasource.password=password

这样以后,应用程序已经:

  • 内置了一个 Tomcat 服务器,可以处理 HTTP 请求。
  • 配置好了 Spring MVC 的核心组件 DispatcherServlet
  • 在 IoC 容器中创建并配置好了一个 DataSource (数据源)。
  • 基于这个 DataSource,创建并配置好了一个 JdbcTemplate

现在可以直接在你的代码里注入并使用它们了,SpringBoot 已经为我们配置好了 Web 应用和数据库相关的组件了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

private final JdbcTemplate jdbcTemplate;

@Autowired
public MyController(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

@GetMapping("/count")
public String countUsers() {
// 直接使用,无需任何手动配置!
Integer count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users", Integer.class);
return "Total users: " + count;
}
}

自动配置的工作原理

核心入口:@SpringBootApplication,这个注解其实是一个复合注解,其中最重要的一个是 @EnableAutoConfiguration

1
2
3
4
5
6
7
8
@SpringBootApplication
// SpringBootApplication 是一个复合注解,等价于
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
//EnableAutoConfiguration 也是一个复合注解:
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)

@EnableAutoConfiguration 是自动配置的总开关,它告诉 Spring Boot:“请根据我添加的依赖(classpath 上的 jar 包),来猜测我需要哪些配置,并自动完成它们”,可以通过源码分析:

1
2
3
4
5
6
7
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;
}



工作流程分析:

  1. 依赖触发 (Classpath Scanning)

    • Spring Boot 启动时,@EnableAutoConfiguration 会扫描项目的类路径 (classpath)
    • 它发现你引入了 spring-boot-starter-web,这个 starter 包含了 tomcat-embed-core.jarspring-webmvc.jar。它会从 classpath 中扫描所有的 META-INF/spring.factories 文件,加载其中配置的 org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的类(即所有自动配置类)
  2. 条件注解 (@ConditionalOn) : Spring Boot 内部有大量的 *AutoConfiguration 类(比如 RedisAutoConfiguration, WebMvcAutoConfiguration等)。这些类并非无条件生效,而是被大量的条件注解所控制。我们以 RedisAutoConfiguration 为例:Spring Boot 针对 Redis 的自动配置类 RedisAutoConfiguration。它负责在你的 Spring Boot 应用中,当你引入了 Redis 相关的依赖后,自动为你配置好 RedisTemplate 和 StringRedisTemplate 等核心 Redis 组件,而无需你手动编写这些 Bean 的定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Configuration(proxyBeanMethods = false)
//只有当 RedisOperations 类存在于应用的 classpath 中时,
// RedisAutoConfiguration 这个自动配置类才会生效,
// RedisOperations 是 Spring Data Redis 模块中的一个核心接口,
// 当你引入 spring-boot-starter-data-redis 依赖时,这个类就会被
// 引入,从而满足这个条件。如果这个类不存在,说明你的项目可能不打算
// 使用 Spring Data Redis
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
return template;
}

@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}

}

总结一下这个流程:

  • 你添加依赖 (pom.xml) -> 触发了类路径变化
  • Spring Boot 启动 -> @EnableAutoConfiguration 生效。
  • 扫描类路径 -> 发现 RedisOperations.class 等。
  • 激活对应的自动配置类 (RedisAutoConfiguration),因为 @ConditionalOnClass 条件满足了。
  • 检查 IoC 容器 -> 发现你没有自己提供 RedisTemplateStringRedisTemplate 的 Bean。
  • 执行自动配置 -> 因为 @ConditionalOnMissingBean 条件满足了,Spring Boot 自动帮你创建了 RedisTemplateStringRedisTemplate 的实例,并放入了容器。
  • 你可以直接 @Autowired 使用

自动配置的灵活性:如何覆盖

Spring Boot 的自动配置非常智能,它总会优先采用用户自定义的配置。如果你不满意它自动配置的 RedisTemplate,你只需要在你的配置类中自己定义一个 RedisTemplate Bean 即可,Spring Boot 的 @ConditionalOnMissingBean 就会确保你的定义优先。这就是“约定优于配置”的体现——它提供默认约定,但也允许你随时轻松覆盖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
public class BaseRedisConfig {

@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisSerializer<Object> serializer = redisSerializer();
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(serializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(serializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}

总结

SpringBoot 自动配置 本质上是 Spring Boot 基于你项目中的依赖,通过条件化配置@ConditionalOn)的机制,智能地、自动地将常用框架的 Bean 创建并装配到 Spring IoC 容器中的过程。它极大地简化了初始搭建和开发过程,让开发者可以更专注于业务逻辑,而不是繁琐的底层配置。其核心是启动器 (Starters)条件注解的协同工作。