一、Spring Boot 自动配置原理深度解析
1.1 自动配置的核心机制
Spring Boot 的自动配置基于条件化配置和 Spring Factories 加载机制,理解这一机制是进行高级定制的基础。
核心流程:
-
@SpringBootApplication→@EnableAutoConfiguration -
EnableAutoConfigurationImportSelector扫描所有 jar 包的META-INF/spring.factories -
加载
org.springframework.boot.autoconfigure.EnableAutoConfiguration指定的配置类 -
根据条件注解决定是否启用这些配置类
条件注解的高级应用
java
@Configuration
@ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(prefix = "spring.datasource", name = "url")
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class CustomDataSourceAutoConfiguration {
@Bean
@ConditionalOnSingleCandidate(DataSource.class)
public DataSourceDecorator dataSourceDecorator(DataSource dataSource) {
return new DataSourceDecorator(dataSource);
}
}
1.2 自定义自动配置类
创建企业级 Starter 的关键在于编写自定义的自动配置类:
java
@Configuration
@ConditionalOnClass(RedisConnectionFactory.class)
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class CacheAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public CacheManager cacheManager(
RedisConnectionFactory connectionFactory,
CacheProperties properties) {
RedisCacheManager.RedisCacheManagerBuilder builder =
RedisCacheManager.builder(connectionFactory);
if (properties.getEnableStatistics()) {
builder.enableStatistics();
}
return builder
.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(properties.getDefaultTtl()))
.build();
}
}
@ConfigurationProperties(prefix = "app.cache")
public class CacheProperties {
private Duration defaultTtl = Duration.ofMinutes(30);
private boolean enableStatistics = true;
private String keyPrefix = "app:cache:";
// getters and setters
}
二、组件注册的 5 种高级方式
2.1 @Configuration + @Bean(配置类注册)
这是 Spring Boot 推荐的注册方式,替代传统的 XML 配置。
java
@Configuration
public class AdvancedBeanConfig {
@Bean
@ConditionalOnProperty(prefix = "cache", name = "type", havingValue = "redis")
public CacheManager redisCacheManager() {
return new RedisCacheManager();
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public PrototypeBean prototypeBean() {
return new PrototypeBean();
}
@Bean(initMethod = "init", destroyMethod = "cleanup")
public LifecycleBean lifecycleBean() {
return new LifecycleBean();
}
}
2.2 @Import 注解(导入式注册)
java
// 1. 导入普通类(自动注册为 Bean)
@Configuration
@Import({ServiceA.class, ServiceB.class}) // ServiceA 和 ServiceB 会被注册为 Bean
public class ImportConfig {
}
// 2. 导入配置类
@Configuration
public class DatabaseConfig {
@Bean
public DataSource dataSource() {
return new HikariDataSource();
}
}
@Configuration
@Import(DatabaseConfig.class) // 导入其他配置类
public class AppConfig {
}
// 3. 实现 ImportSelector(动态选择导入)
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 根据条件动态返回要导入的类
List<String> imports = new ArrayList<>();
if (isFeatureEnabled("cache")) {
imports.add("com.example.CacheConfig");
}
if (isFeatureEnabled("security")) {
imports.add("com.example.SecurityConfig");
}
return imports.toArray(new String[0]);
}
}
// 4. 实现 ImportBeanDefinitionRegistrar(编程式注册)
public class MyBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
// 编程式注册 Bean
RootBeanDefinition beanDefinition = new RootBeanDefinition(CustomBean.class);
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
beanDefinition.setLazyInit(false);
// 设置属性值
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("name", "custom-bean");
beanDefinition.setPropertyValues(propertyValues);
// 注册 Bean
registry.registerBeanDefinition("customBean", beanDefinition);
// 批量注册
registerBatchBeans(registry);
}
private void registerBatchBeans(BeanDefinitionRegistry registry) {
List<Class<?>> beanClasses = scanBeanClasses();
for (Class<?> beanClass : beanClasses) {
GenericBeanDefinition definition = new GenericBeanDefinition();
definition.setBeanClass(beanClass);
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
registry.registerBeanDefinition(
StringUtils.uncapitalize(beanClass.getSimpleName()),
definition
);
}
}
}
// 5. 使用自定义注解 + @Import
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({MyImportSelector.class, MyBeanDefinitionRegistrar.class})
public @interface EnableMyFeatures {
String[] features() default {};
boolean enableCache() default false;
}
// 主应用类使用
@SpringBootApplication
@EnableMyFeatures(features = {"feature1", "feature2"}, enableCache = true)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2.3 @Conditional 系列注解(条件化注册)
java
// 1. 自定义条件注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnFeatureEnabledCondition.class)
public @interface ConditionalOnFeature {
String value();
boolean required() default true;
}
// 2. 实现 Condition 接口
public class OnFeatureEnabledCondition implements Condition {
@Override
public boolean matches(ConditionContext context,
AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(
ConditionalOnFeature.class.getName()
);
if (attributes != null) {
String feature = (String) attributes.get("value");
boolean required = (boolean) attributes.get("required");
// 检查功能是否启用
Environment env = context.getEnvironment();
String enabled = env.getProperty("features." + feature);
if (required) {
return "true".equalsIgnoreCase(enabled);
} else {
return enabled == null || "true".equalsIgnoreCase(enabled);
}
}
return false;
}
}
// 3. 使用条件注解
@Configuration
public class ConditionalConfig {
// 根据配置文件决定是否注册
@Bean
@ConditionalOnProperty(prefix = "cache", name = "enabled", havingValue = "true")
public CacheManager cacheManager() {
return new CacheManager();
}
// 根据类路径是否存在
@Bean
@ConditionalOnClass(name = "redis.clients.jedis.Jedis")
public RedisTemplate<?, ?> redisTemplate() {
return new RedisTemplate<>();
}
// 根据 Bean 是否存在
@Bean
@ConditionalOnBean(DataSource.class)
@ConditionalOnMissingBean(JdbcTemplate.class)
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
// 根据表达式
@Bean
@ConditionalOnExpression(
"#{environment['spring.profiles.active'] == 'prod'}"
)
public ProductionBean productionBean() {
return new ProductionBean();
}
// 自定义条件注解
@Bean
@ConditionalOnFeature("advanced-logging")
public AdvancedLogger advancedLogger() {
return new AdvancedLogger();
}
// 组合条件
@Bean
@ConditionalOnWebApplication
@ConditionalOnClass(Servlet.class)
@ConditionalOnProperty(prefix = "server", name = "ssl.enabled")
public SslConfig sslConfig() {
return new SslConfig();
}
}
// 4. 条件组合
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(AllConditions.class)
public @interface ConditionalOnAll {
Class<? extends Condition>[] value();
}
public class AllConditions implements Condition {
@Override
public boolean matches(ConditionContext context,
AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(
ConditionalOnAll.class.getName()
);
if (attributes != null) {
Class<? extends Condition>[] conditionClasses =
(Class<? extends Condition>[]) attributes.get("value");
for (Class<? extends Condition> conditionClass : conditionClasses) {
Condition condition = BeanUtils.instantiateClass(conditionClass);
if (!condition.matches(context, metadata)) {
return false;
}
}
}
return true;
}
}
三、高级配置管理策略
3.1 配置文件优先级深度解析
Spring Boot 的配置加载遵循明确的优先级规则:

3.2 @PropertySource 精确应用

@PropertySource通常与@ConfigurationProperties结合使用
-
@PropertySource :作用是将指定的配置文件(如
custom.properties)加载到 Spring 的Environment中 ,让配置文件中的属性可以被@Value或@ConfigurationProperties读取。它本身不负责属性与 JavaBean 的绑定,只是 "把配置文件内容导入 Spring 环境" 的工具。 -
@ConfigurationProperties :作用是将 Spring 环境中的配置属性(不管是全局配置文件还是
@PropertySource加载的文件)批量绑定到 JavaBean 的字段上,是 "属性绑定" 的核心注解。
3.2.1 二者结合使用场景
java
#步骤 1:创建自定义配置文件
# src/main/resources/custom-user.properties
user.name=王五
user.age=22
user.hobbies=篮球,足球
user.address.city=北京
user.address.street=某某路
步骤 2:绑定到 JavaBean
@Component
@PropertySource("classpath:custom-user.properties") // 加载自定义文件
@ConfigurationProperties(prefix = "user") // 批量绑定该文件中的user前缀属性
public class User {
private String name;
private Integer age;
private List<String> hobbies;
private Map<String, String> address;
// getter/setter
}
3.2.2 二者区别
|--------|---------------------------------------|---------------------------------------|
| 维度 | @PropertySource | @ConfigurationProperties |
| 核心职责 | 加载指定的配置文件到 Spring 环境 | 将配置文件中的属性批量绑定到 JavaBean |
| 作用对象 | 配置类(@Configuration 标注的类) | JavaBean(需是 Spring 容器组件) |
| 配置文件类型 | 仅支持.properties(不支持.yml) | 支持.properties和.yml |
| 配置文件路径 | 需手动指定(如classpath:custom.properties) | 自动读取全局配置文件(application.properties/yml |
| 属性绑定方式 | 不直接绑定,需配合@Value使用 | 批量绑定(按前缀匹配) |
| 数据校验支持 | 不支持 | 支持(配合@Validated+JSR380 注解) |
3.3 @ImportResource 的现代化应用
虽然 Spring Boot 推荐使用 Java Config,但在迁移旧系统时仍需导入 XML 配置:
java
@Configuration
// 条件化导入 XML 配置
@ConditionalOnProperty(name = "legacy.enabled", havingValue = "true")
@ImportResource({
"classpath:META-INF/spring/legacy-services.xml",
"classpath:META-INF/spring/legacy-dao.xml"
})
public class LegacyIntegrationConfig {
@Bean
public BridgeService bridgeService(
@Qualifier("legacyService") Object legacyService) {
// 将 XML 中定义的 Bean 与新的 Java Config Bean 桥接
return new BridgeService(legacyService);
}
}
3.4 多环境配置策略
java
# application.yml
spring:
profiles:
active: @activatedProperties@ # Maven/Gradle 属性替换
config:
import:
- optional:file:./config/
- optional:file:./config/${spring.profiles.active}/
# 多文档块配置
---
spring:
config:
activate:
on-profile: "dev"
datasource:
url: jdbc:h2:mem:testdb
h2:
console:
enabled: true
---
spring:
config:
activate:
on-profile: "prod"
datasource:
url: ${DB_URL}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
hikari:
maximum-pool-size: 20
四、静态资源高级管理
4.1 默认静态资源位置与优先级
Spring Boot 自动从以下位置查找静态资源(优先级从高到低):
-
classpath:/META-INF/resources/ -
classpath:/resources/ -
classpath:/static/ -
classpath:/public/
访问方式: 直接通过 /资源名 访问,无需目录前缀。
4.2 自定义静态资源配置
java
# application.yml
spring:
web:
resources:
# 1. 添加自定义静态资源位置
static-locations:
- classpath:/custom-static/
- file:/opt/uploads/
- classpath:/META-INF/resources/
- classpath:/resources/
- classpath:/static/
- classpath:/public/
# 2. 缓存控制(生产环境)
cache:
period: 3600 # 缓存1小时
cachecontrol:
max-age: 1h
must-revalidate: true
# 3. 链式配置
chain:
enabled: true
strategy:
content:
enabled: true
paths: /**
compressed: true # 启用gzip压缩