SpringBoot16-@Configuration 类
一、@Configuration 类的执行时机
@Configuration 注解的类会在 Spring Boot 启动时自动加载,但不是"执行整个类",而是:
1. 类本身会被实例化(构造方法)
@Configuration
public class MyConfig {// 构造方法会在启动时执行public MyConfig() {System.out.println("MyConfig 被实例化了");}
}
输出:项目启动时会打印 MyConfig 被实例化了
2. @Bean 方法会被调用
@Configuration
public class MyConfig {@Beanpublic UserService userService() {System.out.println("创建 UserService Bean");return new UserService();}@Beanpublic OrderService orderService() {System.out.println("创建 OrderService Bean");return new OrderService();}
}
输出:启动时会打印:
创建 UserService Bean
创建 OrderService Bean
3. 普通方法不会自动执行
@Configuration
public class MyConfig {// ❌ 这个方法不会自动执行public void normalMethod() {System.out.println("这不会被执行");}// ✅ 只有 @Bean 方法才会执行@Beanpublic String myBean() {System.out.println("这会被执行");return "hello";}
}
完整的执行流程示例
@Configuration
public class MyConfig {// 1. 构造方法最先执行public MyConfig() {System.out.println("1. MyConfig 构造方法执行");}// 2. @Bean 方法会执行@Beanpublic UserService userService() {System.out.println("2. 创建 UserService");return new UserService();}// 3. 普通方法不会执行public void test() {System.out.println("3. 这不会执行");}// 4. @PostConstruct 会在构造方法后执行@PostConstructpublic void init() {System.out.println("4. @PostConstruct 执行");}
}
启动时输出:
1. MyConfig 构造方法执行
4. @PostConstruct 执行
2. 创建 UserService
4、特殊的配置类方法
(1)implements WebMvcConfigurer 的方法
@Configuration
public class WebConfig implements WebMvcConfigurer {// ✅ 这个方法会在启动时自动执行@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {System.out.println("配置静态资源映射");registry.addResourceHandler("/upload/**").addResourceLocations("file:D:/upload/");}// ✅ 这个方法也会自动执行@Overridepublic void addInterceptors(InterceptorRegistry registry) {System.out.println("配置拦截器");registry.addInterceptor(new MyInterceptor());}
}
为什么会执行? 因为 Spring MVC 在启动时会主动调用这些配置方法。
(2)其他自动执行的配置
@Configuration
public class SecurityConfig {// ✅ Spring Security 会自动调用@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {System.out.println("配置 Spring Security");http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated());return http.build();}
}
5、验证是否被加载
方法1:使用构造方法
@Configuration
public class TestConfig {public TestConfig() {System.out.println("===== TestConfig 已加载 =====");}
}
方法2:使用 @PostConstruct
@Configuration
public class TestConfig {@PostConstructpublic void init() {System.out.println("===== TestConfig 初始化完成 =====");}
}
方法3:使用 ApplicationRunner
@Configuration
public class StartupConfig {@Beanpublic ApplicationRunner runner() {return args -> {System.out.println("===== 应用启动完成 =====");};}
}
6、加载顺序控制
(1)使用 @Order 控制顺序
@Configuration
@Order(1)
public class FirstConfig {public FirstConfig() {System.out.println("第一个加载");}
}@Configuration
@Order(2)
public class SecondConfig {public SecondConfig() {System.out.println("第二个加载");}
}
控制不同的@Configuration类
(2)使用 @DependsOn 控制依赖
@Configuration
public class DatabaseConfig {@Beanpublic DataSource dataSource() {System.out.println("创建数据源");return new DataSource();}
}@Configuration
@DependsOn("dataSource")
public class ServiceConfig {@Beanpublic UserService userService(DataSource dataSource) {System.out.println("创建 UserService(依赖数据源)");return new UserService(dataSource);}
}
7、条件加载
(1)只在特定条件下加载@Conditional
@Configuration
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true")
public class FeatureConfig {public FeatureConfig() {System.out.println("功能已启用,加载配置");}
}
# application.yml
feature:enabled: true # 改为 false 则不加载
(2)根据环境加载@Profile
@Configuration
@Profile("dev")
public class DevConfig {public DevConfig() {System.out.println("开发环境配置");}
}@Configuration
@Profile("prod")
public class ProdConfig {public ProdConfig() {System.out.println("生产环境配置");}
}
8、完整示例:监控配置类加载
@Configuration
@Slf4j
public class WebConfig implements WebMvcConfigurer {// 1. 构造方法public WebConfig() {log.info("========================================");log.info("WebConfig 开始加载");log.info("========================================");}// 2. 初始化方法@PostConstructpublic void init() {log.info("WebConfig 初始化完成");}// 3. 配置静态资源(自动执行)@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {log.info("开始配置静态资源映射");registry.addResourceHandler("/upload/**").addResourceLocations("file:D:/upload/");log.info("静态资源映射配置完成");}// 4. Bean 创建@Beanpublic MyService myService() {log.info("创建 MyService Bean");return new MyService();}
}
启动日志:
WebConfig 开始加载
WebConfig 初始化完成
开始配置静态资源映射
静态资源映射配置完成
创建 MyService Bean
9、总结
| 会自动执行 | 不会自动执行 |
|---|---|
| 构造方法 | 普通方法 |
| @Bean 方法 | 没有注解的方法 |
| @PostConstruct 方法 | - |
| WebMvcConfigurer 的重写方法 | - |
关键点:
@Configuration类在启动时会被实例化- 只有特定方法会自动执行(@Bean、配置接口的方法等)
- 普通方法不会执行,除非手动调用
- 可以用构造方法或 @PostConstruct 验证类是否加载
二、@Configuration 类和 spring.factories文件
2-1、@Configuration 类的自动扫描
大多数情况:自动扫描(不需要注册)
只要 @Configuration 类在主启动类的包或子包下,Spring Boot 会自动扫描并加载。
com.example.myapp
├── MyApplication.java # 主启动类
├── config
│ ├── WebConfig.java # ✅ 自动扫描
│ └── SecurityConfig.java # ✅ 自动扫描
├── controller
│ └── UserController.java # ✅ 自动扫描
└── service└── UserService.java # ✅ 自动扫描
@SpringBootApplication // 包含 @ComponentScan
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}
原理:
@SpringBootApplication包含了@ComponentScan,会扫描当前包及子包下所有带@Component、@Configuration、@Service等注解的类。
示例:普通配置类(无需注册)
package com.example.myapp.config;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/upload/**").addResourceLocations("file:D:/upload/");}
}
启动时会自动加载 ✅ 不需要在任何文件中注册
2-2、spring.factories 的使用场景
spring.factories 只在特定场景下需要:
场景1:自动配置类(Auto-Configuration)
当你开发一个 starter 或需要自动配置时才需要。
my-spring-boot-starter
├── src/main/java
│ └── com.example.starter
│ └── MyAutoConfiguration.java
└── src/main/resources└── META-INF└── spring.factories # ⚠️ 这里才需要
spring.factories:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.starter.MyAutoConfiguration
@Configuration
@ConditionalOnClass(SomeClass.class)
public class MyAutoConfiguration {@Beanpublic MyService myService() {return new MyService();}
}
场景2:外部包的配置类
如果配置类在主启动类包之外,有两种解决方案:
方案A:使用 @Import(推荐)
@SpringBootApplication
@Import(ExternalConfig.class) // 导入外部配置
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}
方案B:使用 @ComponentScan 指定包
@SpringBootApplication
@ComponentScan(basePackages = {"com.example.myapp", // 主包"com.external.config" // 外部包
})
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}
方案C:使用 spring.factories
META-INF/spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.external.config.ExternalConfig
2-3、对比:什么时候需要注册
| 场景 | 是否需要注册 | 注册方式 |
|---|---|---|
| 项目内的配置类(同包或子包) | ❌ 不需要 | 自动扫描 |
| 自定义 Starter 的自动配置 | ✅ 需要 | spring.factories |
| 外部 jar 包的配置类 | ✅ 需要 | spring.factories 或 @Import/@ComponetScan |
| 第三方库的配置 | ✅ 需要 | spring.factories(由第三方提供) |
2-4、完整示例对比
示例1:普通项目配置(不需要 spring.factories)
my-project
├── src/main/java
│ └── com.example.myapp
│ ├── MyApplication.java
│ ├── config
│ │ ├── WebConfig.java # ✅ 自动加载
│ │ ├── SecurityConfig.java # ✅ 自动加载
│ │ └── DatabaseConfig.java # ✅ 自动加载
│ ├── controller
│ └── service
└── src/main/resources├── application.yml└── 无需 spring.factories ❌
示例2:开发 Starter(需要 spring.factories)
my-redis-starter
├── src/main/java
│ └── com.example.redis
│ ├── RedisAutoConfiguration.java
│ └── RedisTemplate.java
└── src/main/resources└── META-INF└── spring.factories # ✅ 必须有
spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.redis.RedisAutoConfiguration
使用方只需要引入依赖:
<dependency><groupId>com.example</groupId><artifactId>my-redis-starter</artifactId>
</dependency>
自动配置就会生效,无需手动 @Import。
2-5、验证是否自动加载
方法1:启动日志
@Configuration
@Slf4j
public class WebConfig implements WebMvcConfigurer {public WebConfig() {log.info("========================================");log.info("WebConfig 已自动加载(无需注册)");log.info("========================================");}
}
启动项目,看到日志就说明自动加载了。
方法2:使用 @Autowired 测试
@RestController
public class TestController {@Autowiredprivate ApplicationContext context;@GetMapping("/test")public String test() {// 检查 Bean 是否存在boolean exists = context.containsBean("webConfig");return "WebConfig exists: " + exists;}
}
2-6、spring.factories 的完整格式
如果你真的需要用 spring.factories:
位置:src/main/resources/META-INF/spring.factories
# 自动配置类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.config.MyAutoConfiguration,\
com.example.config.AnotherAutoConfiguration# 应用监听器
org.springframework.context.ApplicationListener=\
com.example.listener.MyApplicationListener# 环境后置处理器
org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.processor.MyEnvironmentPostProcessor
2-7、常见误区
❌ 误区1:所有配置类都要注册
// 错误认知:需要在 spring.factories 注册
@Configuration
public class WebConfig {// ...
}
正确:项目内的配置类自动扫描,无需注册。
❌ 误区2:@Component 类需要注册
// 错误认知:需要在 spring.factories 注册
@Service
public class UserService {// ...
}
正确:@Service、@Component、@Controller 等都会自动扫描。
✅ 正确认知
- 99% 的情况:不需要
spring.factories - 只有开发 starter 或外部库:才需要
spring.factories
2-8、总结
项目结构:
├── 主启动类
├── 同包或子包
│ └── @Configuration 类 → ✅ 自动扫描,无需注册
│
├── 外部包(其他项目)
│ └── @Configuration 类 → ⚠️ 需要 @Import 或 spring.factories
│
└── 自定义 Starter└── 自动配置类 → ✅ 必须用 spring.factories
记住:
- 普通项目的配置类 → 不需要 spring.factories
- 开发 Starter 或库 → 才需要 spring.factories
