一句话总结
Spring Boot 注解分四大类:1)组件注册(@Component/@Service/@Repository/@Controller、@Configuration/@Bean、@Import);2)依赖注入(@Autowired/@Qualifier/@Resource/@Value);3)条件装配(@ConditionalOnClass/@ConditionalOnMissingBean/@ConditionalOnProperty);4)配置绑定(@ConfigurationProperties/@EnableConfigurationProperties)。核心区别:@Component 是通用组件,@Service/@Repository/@Controller 是语义化特化(功能相同,但 @Repository 额外支持异常转换)。
初级理解
组件注册注解
| 注解 | 作用 | 特殊能力 |
| @Component | 通用组件,注册为 Bean | — |
| @Service | 业务层组件 | 语义标识 |
| @Repository | 数据访问层组件 | 异常转换(将 JDBC 异常转为 Spring DataAccessException) |
| @Controller | 控制器组件 | 处理 Web 请求 |
| @Configuration | 配置类 | 配合 @Bean 创建 Bean,CGLIB 增强保证单例 |
# @Configuration + @Bean
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
return new HikariDataSource();
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource ds) {
return new JdbcTemplate(ds); // ds 来自上面的 @Bean 方法
}
}
# @Configuration 类会被 CGLIB 代理
# 多次调用 dataSource() 返回同一个实例(单例)
中级深入
@Conditional 条件注解
| 注解 | 条件 |
| @ConditionalOnClass | classpath 存在指定类 |
| @ConditionalOnMissingClass | classpath 不存在指定类 |
| @ConditionalOnBean | 容器中存在指定 Bean |
| @ConditionalOnMissingBean | 容器中不存在指定 Bean |
| @ConditionalOnProperty | 配置项有指定值 |
| @ConditionalOnExpression | SpEL 表达式为 true |
| @ConditionalOnJava | Java 版本满足条件 |
| @ConditionalOnWebApplication | 是 Web 应用 |
# 条件注解实战
@Configuration
public class CacheConfig {
@Bean
@ConditionalOnClass(RedisConnectionFactory.class)
@ConditionalOnMissingBean(CacheManager.class)
@ConditionalOnProperty(name = "spring.cache.type", havingValue = "redis")
public CacheManager redisCacheManager() {
// 三个条件同时满足才创建
// 1. classpath 有 Redis
// 2. 用户没自定义 CacheManager
// 3. 配置了 spring.cache.type=redis
}
}
高级拓展
@ConfigurationProperties vs @Value
# @Value:单个属性注入
@Component
public class AppConfig {
@Value("${app.name}")
private String name;
@Value("${app.timeout:3000}") // 默认值
private int timeout;
}
# @ConfigurationProperties:批量属性绑定(推荐)
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
private int timeout = 3000; // 默认值
private List<String> servers;
private Map<String, String> config;
// getter/setter
}
# 对比
# @Value:逐个注入,支持 SpEL,不支持复杂类型
# @ConfigurationProperties:批量注入,支持 List/Map,支持 JSR303 校验
@Import 的三种用法
# 1. 导入普通类
@Import(UserService.class)
# 2. 导入配置类
@Import(AppConfig.class)
# 3. 导入 ImportSelector(自动配置的核心)
@Import(AutoConfigurationImportSelector.class)
# 4. 导入 ImportBeanDefinitionRegistrar
@Import(MyBeanRegistrar.class)
# 可以编程式注册 BeanDefinition
实战场景
场景:多环境配置切换
# 使用 @Profile 切换环境
@Configuration
public class DataSourceConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
return new HikariDataSource(); // 开发环境
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
return new HikariDataSource(); // 生产环境
}
}
# 激活 Profile
# application.yml
spring:
profiles:
active: dev
# 或命令行
# java -jar app.jar --spring.profiles.active=prod
面试模拟
面试官:@Component 和 @Bean 有什么区别?
你:@Component 用在类上,通过类路径扫描自动注册;@Bean 用在方法上,手动声明 Bean,通常配合 @Configuration 使用。@Component 适合自己写的类,@Bean 适合第三方库的类(无法加 @Component)。
面试官:@Configuration 和 @Component 有什么区别?
你:@Configuration 是 @Component 的特化。区别在于 @Configuration 类会被 CGLIB 代理,保证 @Bean 方法内部调用时返回的是同一个单例实例。@Component 类中的 @Bean 方法不会被代理,内部调用会创建新实例。