Spring 常用注解
问题
Spring/Spring Boot 中有哪些常用注解?它们的作用和使用场景是什么?
答案
注解分类总览
1. 组件注册注解
将类注册为 Spring Bean,本质都是 @Component 的派生注解:
| 注解 | 语义 | 典型场景 |
|---|---|---|
@Component | 通用组件 | 工具类、通用组件 |
@Service | 业务逻辑层 | Service 类 |
@Repository | 数据访问层 | DAO 类(自动转换数据库异常) |
@Controller | 表示层 | MVC Controller |
@RestController | REST 控制器 | @Controller + @ResponseBody |
@Repository 除了注册 Bean 外,还会启用异常转换——将数据库特定异常(如 SQLException)转换为 Spring 统一的 DataAccessException 体系。这样业务层不需要关心底层数据库类型。
2. 依赖注入注解
@Service
public class OrderService {
// @Autowired:按类型注入
@Autowired
private UserService userService;
// @Qualifier:指定 Bean 名称(同类型多个 Bean 时消歧)
@Autowired
@Qualifier("mysqlOrderRepository")
private OrderRepository orderRepository;
// @Value:注入配置值
@Value("${order.max-retry:3}")
private int maxRetry;
// @Resource(JSR-250):先按名称、再按类型注入
@Resource(name = "redisTemplate")
private RedisTemplate<String, Object> redisTemplate;
}
@Autowired vs @Resource:
| 对比 | @Autowired | @Resource |
|---|---|---|
| 来源 | Spring | JSR-250(JDK 标准) |
| 匹配方式 | 先按类型,再按名称 | 先按名称,再按类型 |
| 必须存在 | 默认是(required=false 可选) | 默认是 |
| 推荐 | Spring 项目首选 | 需要按名称注入时使用 |
3. 配置类注解
@Configuration // 标记为配置类(Full 模式,Bean 方法调用会被代理)
@ComponentScan("com.example") // 指定包扫描路径
@PropertySource("classpath:app.properties") // 加载额外的配置文件
@Import(RedisConfig.class) // 导入其他配置类
public class AppConfig {
// @Bean:将方法返回值注册为 Bean
@Bean
@Scope("prototype") // 指定作用域
public RestTemplate restTemplate() {
return new RestTemplate();
}
// @Bean 的 name 默认为方法名
@Bean(name = "customExecutor", initMethod = "init", destroyMethod = "cleanup")
public ThreadPoolExecutor executor() {
return new ThreadPoolExecutor(4, 8, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100));
}
}
- Full 模式(
@Configuration):配置类会被 CGLIB 代理,Bean 方法间调用会从容器中获取(保证单例) - Lite 模式(
@Component上的@Bean方法):不会被代理,Bean 方法间调用是普通 Java 调用(每次 new 新实例)
Spring Boot 推荐使用 @Configuration(proxyBeanMethods = false) 提升启动速度。
4. AOP 注解
@Aspect
@Component
public class LogAspect {
// 切点表达式
@Pointcut("execution(* com.example.service.*.*(..))")
public void servicePointcut() {}
@Before("servicePointcut()")
public void before(JoinPoint jp) { /* 前置通知 */ }
@AfterReturning(pointcut = "servicePointcut()", returning = "result")
public void afterReturning(Object result) { /* 返回通知 */ }
@AfterThrowing(pointcut = "servicePointcut()", throwing = "ex")
public void afterThrowing(Exception ex) { /* 异常通知 */ }
@After("servicePointcut()")
public void after() { /* 最终通知 */ }
// 环绕通知(功能最强)
@Around("servicePointcut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed();
log.info("耗时: {}ms", System.currentTimeMillis() - start);
return result;
}
}
5. MVC 注解
| 注解 | 作用 | 示例 |
|---|---|---|
@RequestMapping | URL 映射 | @RequestMapping("/api") |
@GetMapping | GET 请求 | @GetMapping("/{id}") |
@PostMapping | POST 请求 | @PostMapping |
@RequestBody | 请求体 → 对象 | @RequestBody UserDTO dto |
@ResponseBody | 返回值 → JSON | 方法或类级别 |
@PathVariable | URL 路径变量 | @PathVariable Long id |
@RequestParam | 查询参数 | @RequestParam String name |
@RequestHeader | 请求头 | @RequestHeader("Token") String token |
@CookieValue | Cookie 值 | @CookieValue("sid") String sid |
@Valid | 参数校验 | @Valid @RequestBody UserDTO dto |
@RestControllerAdvice | 全局异常处理 | 配合 @ExceptionHandler |
6. 事务注解
@Service
public class OrderService {
@Transactional(
propagation = Propagation.REQUIRED, // 传播行为
isolation = Isolation.READ_COMMITTED, // 隔离级别
timeout = 30, // 超时(秒)
rollbackFor = Exception.class, // 哪些异常回滚
readOnly = false // 是否只读
)
public void createOrder(Order order) {
// 事务中的操作
}
}
7. 条件与生命周期注解
// 条件注解(Spring Boot 大量使用)
@ConditionalOnProperty(name = "cache.enabled", havingValue = "true")
@ConditionalOnClass(RedisTemplate.class) // classpath 中有该类才生效
@ConditionalOnMissingBean(CacheManager.class) // 容器中没有该 Bean 才生效
@ConditionalOnBean(DataSource.class) // 容器中有该 Bean 才生效
// 生命周期回调
@Component
public class CacheWarmer {
@PostConstruct // Bean 初始化后执行
public void init() { /* 预热缓存 */ }
@PreDestroy // Bean 销毁前执行
public void cleanup() { /* 清理资源 */ }
}
8. Spring Boot 核心注解
// @SpringBootApplication = @SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScan
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
| 注解 | 作用 |
|---|---|
@SpringBootApplication | 启动类标记(组合注解) |
@EnableAutoConfiguration | 开启自动配置 |
@ConfigurationProperties | 将配置文件属性绑定到 Bean |
@ConditionalOnXxx | 条件化 Bean 注册 |
常见面试问题
Q1: @Autowired 的注入过程是怎样的?
答案:
- Spring 在创建 Bean 时,通过
AutowiredAnnotationBeanPostProcessor处理@Autowired - 先按类型(byType)在容器中查找匹配的 Bean
- 如果找到多个同类型的 Bean,再按名称(byName)匹配
- 如果还有歧义,查找
@Qualifier或@Primary标记的 Bean - 都不满足则抛出
NoUniqueBeanDefinitionException
Q2: @Autowired 和 @Resource 的区别?
答案:
@Autowired 是 Spring 注解,先按类型后按名称匹配;@Resource 是 JDK 标准注解(JSR-250),先按名称后按类型匹配。Spring 官方推荐使用构造器注入(不需要注解),也可以用 @Autowired。
Q3: @Configuration 和 @Component 有什么区别?
答案:
@Configuration 是 Full 模式,类会被 CGLIB 代理,其中的 @Bean 方法互相调用时会从 IoC 容器获取(保证单例语义)。@Component 中的 @Bean 方法是 Lite 模式,方法互调是普通 Java 方法调用,每次都会创建新实例。
Q4: @Bean 和 @Component 有什么区别?
答案:
@Component:标注在类上,通过@ComponentScan自动扫描注册@Bean:标注在方法上(配置类中),手动将方法返回值注册为 Bean
@Bean 适合注册第三方库的类(无法修改源码添加 @Component),@Component 适合注册自己写的类。
Q5: @Transactional 失效的常见场景?
答案:
- 方法非 public:Spring AOP 无法代理
- 自调用:同一个类内部方法调用,不经过代理
- 异常被 catch:事务管理器感知不到异常
- 抛出的是 checked 异常:默认只回滚 RuntimeException
- 传播行为设置不当:如
NOT_SUPPORTED会挂起事务 - 数据库引擎不支持:如 MySQL 的 MyISAM
- Bean 未被 Spring 管理:没有
@Service等注解
详细分析见 事务管理。
Q6: @PostConstruct 的执行时机?
答案:
在 Bean 的属性注入完成后、InitializingBean.afterPropertiesSet() 之前执行。完整顺序是:
构造方法 → 属性注入 → @PostConstruct → InitializingBean.afterPropertiesSet() → init-method
详细生命周期见 Bean 生命周期。
相关链接
- Spring 官方文档 - 注解
- IoC 容器与依赖注入 - @Autowired 详细流程
- AOP 面向切面编程 - AOP 注解详解
- Bean 生命周期 - @PostConstruct/@PreDestroy
- 事务管理 - @Transactional 详解
- Spring MVC - MVC 注解详解