深入理解Spring Boot的核心机制
自动配置(Auto-Configuration)是 Spring Boot 的核心特性,它能够根据项目中的依赖自动配置 Spring 应用,极大地简化了开发工作。
当你添加 spring-boot-starter-data-jpa 依赖后,Spring Boot 会自动配置:
@SpringBootApplication 是一个组合注解,包含了三个核心注解。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration // 1. 配置类
@EnableAutoConfiguration // 2. 启用自动配置
@ComponentScan // 3. 组件扫描
public @interface SpringBootApplication {
// ...
}标记当前类为配置类,等同于 @Configuration。
@SpringBootConfiguration
public class Application {
@Bean
public MyService myService() {
return new MyService();
}
}启用自动配置机制,这是 Spring Boot 的核心。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// 排除特定的自动配置类
Class>[] exclude() default {};
String[] excludeName() default {};
}扫描当前包及子包下的组件(@Component、@Service、@Repository、@Controller)。
// 默认扫描主类所在包及子包
@SpringBootApplication
public class Application {
// 自动扫描 com.example 及其子包
}
// 自定义扫描路径
@SpringBootApplication
@ComponentScan(basePackages = {"com.example", "com.other"})
public class Application {
// ...
}Spring Boot 的自动配置通过以下步骤实现:
Spring Boot 启动时,会读取 META-INF/spring.factories 文件,加载所有的自动配置类。
# spring-boot-autoconfigure.jar 中的 spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
...每个自动配置类都使用 @Conditional 注解,只有满足条件才会生效。
@Configuration
@ConditionalOnClass(DataSource.class) // 类路径存在 DataSource
@ConditionalOnMissingBean(DataSource.class) // 容器中没有 DataSource Bean
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnProperty(name = "spring.datasource.type")
public DataSource dataSource(DataSourceProperties properties) {
// 创建数据源
return DataSourceBuilder.create()
.url(properties.getUrl())
.username(properties.getUsername())
.password(properties.getPassword())
.build();
}
}| 注解 | 说明 |
|---|---|
| @ConditionalOnClass | 类路径存在指定类时生效 |
| @ConditionalOnMissingClass | 类路径不存在指定类时生效 |
| @ConditionalOnBean | 容器中存在指定 Bean 时生效 |
| @ConditionalOnMissingBean | 容器中不存在指定 Bean 时生效 |
| @ConditionalOnProperty | 配置文件中存在指定属性时生效 |
| @ConditionalOnWebApplication | Web 应用时生效 |
我们可以创建自己的自动配置类,实现类似 Spring Boot 的自动配置功能。
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
private String name = "默认应用";
private String version = "1.0.0";
private boolean enabled = true;
// getter/setter
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getVersion() { return version; }
public void setVersion(String version) { this.version = version; }
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
}@Configuration
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyAppProperties.class)
public class MyAppAutoConfiguration {
@Autowired
private MyAppProperties properties;
@Bean
@ConditionalOnMissingBean
public MyService myService() {
MyService service = new MyService();
service.setName(properties.getName());
service.setVersion(properties.getVersion());
return service;
}
@Bean
@ConditionalOnProperty(name = "myapp.enabled", havingValue = "true")
public MyInitializer myInitializer() {
return new MyInitializer();
}
}在 resources/META-INF/spring.factories 文件中注册自动配置类:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.autoconfigure.MyAppAutoConfiguration# application.yml
myapp:
name: 我的应用
version: 2.0.0
enabled: trueSpring Boot 提供了多种方式将配置文件的值绑定到 Java 对象。
@Component
@ConfigurationProperties(prefix = "server")
public class ServerConfig {
private int port;
private String host;
private int timeout;
// getter/setter
}
// application.yml
server:
port: 8080
host: localhost
timeout: 30@Component
public class AppConfig {
@Value("${app.name}")
private String appName;
@Value("${app.version:1.0.0}") // 默认值
private String version;
@Value("${app.enabled:true}")
private boolean enabled;
}@Component
public class ConfigReader {
@Autowired
private Environment env;
public void readConfig() {
String appName = env.getProperty("app.name");
int port = env.getProperty("server.port", Integer.class, 8080);
boolean enabled = env.getProperty("app.enabled", Boolean.class, true);
}
}Spring Boot 支持为不同环境(开发、测试、生产)提供不同的配置。
application.yml # 默认配置
application-dev.yml # 开发环境
application-test.yml # 测试环境
application-prod.yml # 生产环境spring:
profiles:
active: dev # 激活开发环境
# 公共配置
app:
name: SpringBoot Demoserver:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/dev_db
username: dev_user
password: dev_pass
logging:
level:
root: DEBUGserver:
port: 80
spring:
datasource:
url: jdbc:mysql://prod-server:3306/prod_db
username: prod_user
password: ${DB_PASSWORD} # 从环境变量读取
logging:
level:
root: WARN# 方式1:配置文件
spring.profiles.active=prod
# 方式2:命令行参数
java -jar app.jar --spring.profiles.active=prod
# 方式3:环境变量
export SPRING_PROFILES_ACTIVE=prod
# 方式4:IDE 配置
-Dspring.profiles.active=prod@Configuration
public class DataSourceConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
// 开发环境数据源
return new HikariDataSource();
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
// 生产环境数据源
return new DruidDataSource();
}
}有时我们需要排除某些自动配置类。
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
RedisAutoConfiguration.class
})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}# application.yml
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
- org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration# 启动时添加参数
java -jar app.jar --debug
# 或在配置文件中
debug: true
# 输出示例:
============================
CONDITIONS EVALUATION REPORT
============================
Positive matches: # 生效的配置
-----------------
DataSourceAutoConfiguration matched:
- @ConditionalOnClass found required classes 'javax.sql.DataSource'
Negative matches: # 未生效的配置
-----------------
RedisAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'redis.clients.jedis.Jedis'