Spring 注解使用详解
Spring 的注解体系覆盖了从 Bean 注册、依赖注入、AOP、事务到 Web 开发的方方面面。注解把配置信息直接写在代码上,让开发和维护都更直观。本文按功能分类,逐一说明常用注解的用法、适用场景和底层机制。
一、注解生效的底层机制
Spring 处理注解主要依赖两个扩展点:
BeanPostProcessor:在 Bean 初始化前后介入,处理@Autowired、@Value、@PostConstruct等注解。AutowiredAnnotationBeanPostProcessor负责依赖注入,CommonAnnotationBeanPostProcessor负责@Resource、@PostConstruct、@PreDestroy。BeanFactoryPostProcessor:在 Bean 实例化之前介入,处理@ComponentScan、@Configuration、@Bean等注解。ConfigurationClassPostProcessor负责解析配置类,生成 BeanDefinition。
注解本身不会“自动生效”,是这些后置处理器在容器启动时扫描并执行对应逻辑。
二、声明 Bean 的注解
1. @Component 及其派生注解
| 注解 | 语义 | 特殊功能 |
|---|---|---|
@Component | 通用组件 | 无 |
@Service | 业务层 | 无(语义清晰) |
@Repository | 数据访问层 | 异常转换 |
@Controller | Web 控制层 | 视图解析 |
@RestController | REST 控制器 | 直接返回 JSON |
@Configuration | 配置类 | CGLIB 代理 |
@ServicepublicclassUserService{@AutowiredprivateUserDaouserDao;}@RepositorypublicclassUserDaoImplimplementsUserDao{@AutowiredprivateJdbcTemplatejdbcTemplate;}Bean 名称默认是类名首字母小写,也可以显式指定:@Service("userService")。
2. @Bean
标注在@Configuration类的方法上,把返回值注册为 Bean。适合第三方类或需要复杂初始化逻辑的对象。
@ConfigurationpublicclassAppConfig{@BeanpublicDataSourcedataSource(){HikariDataSourceds=newHikariDataSource();ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");returnds;}@BeanpublicJdbcTemplatejdbcTemplate(DataSourcedataSource){returnnewJdbcTemplate(dataSource);}}@Bean方法参数会自动从容器注入。@Bean(initMethod = "init", destroyMethod = "cleanup")可以指定初始化和销毁方法。
三、依赖注入注解
1. @Autowired
按类型自动注入,可以标注在字段、构造方法、Setter 方法上。
// 构造器注入(推荐)@ServicepublicclassUserService{privatefinalUserDaouserDao;publicUserService(UserDaouserDao){this.userDao=userDao;}}// 字段注入@ServicepublicclassUserService{@AutowiredprivateUserDaouserDao;}required = false允许依赖为 null。构造器注入是 Spring 官方推荐的方式,保证依赖不可变且完全就绪。
2. @Qualifier
同类型有多个 Bean 时,按名称指定:
@ServicepublicclassOrderService{@Autowired@Qualifier("aliPayService")privatePaymentServicepaymentService;}3. @Primary
同类型多 Bean 时,标记首选:
@Service@PrimarypublicclassAliPayServiceimplementsPaymentService{}@Qualifier优先级高于@Primary。
4. @Value
注入简单类型和配置值:
@ComponentpublicclassAppConfig{@Value("${app.name}")privateStringappName;@Value("${app.timeout:30}")privateinttimeout;}5. @Resource
JSR-250 标准,默认按名称注入:
@ServicepublicclassUserService{@Resource(name="userDaoImpl")privateUserDaouserDao;}与@Autowired的区别:@Autowired默认按类型,@Resource默认按名称;@Autowired支持required = false和构造器注入,@Resource不支持。
四、配置与扫描注解
1. @ComponentScan
指定扫描包路径:
@Configuration@ComponentScan("com.example")publicclassAppConfig{}2. @Import
导入其他配置类:
@Configuration@Import({DatabaseConfig.class,RedisConfig.class})publicclassAppConfig{}3. @PropertySource
加载自定义 properties 文件:
@Configuration@PropertySource("classpath:custom.properties")publicclassAppConfig{@Value("${custom.value}")privateStringvalue;}4. @ConfigurationProperties
批量绑定配置到对象:
@Component@ConfigurationProperties(prefix="app")@Getter@SetterpublicclassAppProperties{privateStringname;privateinttimeout;privateList<String>servers;}五、条件化与 Profile 注解
1. @Conditional
根据条件决定是否注册 Bean:
@Bean@Conditional(WindowsCondition.class)publicFileServicewindowsFileService(){returnnewWindowsFileService();}2. Spring Boot 条件注解
| 注解 | 条件 |
|---|---|
@ConditionalOnClass | classpath 存在指定类 |
@ConditionalOnMissingBean | 容器中不存在指定 Bean |
@ConditionalOnProperty | 配置属性满足条件 |
@ConditionalOnWebApplication | 是 Web 应用 |
@Bean@ConditionalOnMissingBeanpublicObjectMapperobjectMapper(){returnnewObjectMapper();}3. @Profile
按环境激活:
@Configuration@Profile("dev")publicclassDevConfig{}@Configuration@Profile("prod")publicclassProdConfig{}六、AOP 注解
1. 开启 AOP
@Configuration@EnableAspectJAutoProxypublicclassAopConfig{}Spring Boot 中引入spring-boot-starter-aop后自动生效。
2. 定义切面
@Aspect@ComponentpublicclassLoggingAspect{@Pointcut("execution(* com.example.service.*.*(..))")publicvoidserviceLayer(){}@Before("serviceLayer()")publicvoidbefore(JoinPointjp){System.out.println("执行前:"+jp.getSignature().getName());}@AfterReturning(pointcut="serviceLayer()",returning="result")publicvoidafterReturning(JoinPointjp,Objectresult){System.out.println("返回:"+result);}@AfterThrowing(pointcut="serviceLayer()",throwing="ex")publicvoidafterThrowing(JoinPointjp,Exceptionex){System.out.println("异常:"+ex.getMessage());}@Around("serviceLayer()")publicObjectaround(ProceedingJoinPointpjp)throwsThrowable{longstart=System.currentTimeMillis();Objectresult=pjp.proceed();System.out.println("耗时:"+(System.currentTimeMillis()-start)+"ms");returnresult;}}七、事务注解
@ServicepublicclassOrderService{@Transactional(rollbackFor=Exception.class,propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED,timeout=30)publicvoidcreateOrder(Orderorder){orderDao.save(order);inventoryDao.decrease(order.getProductId(),order.getQuantity());}}需要@EnableTransactionManagement(Spring Boot 自动配置)。注意@Transactional在同一个类内部调用不生效,必须通过代理调用。
八、Web 注解
1. 请求映射
@RestController@RequestMapping("/api/users")publicclassUserController{@GetMapping("/{id}")publicUsergetUser(@PathVariableLongid){returnuserService.getById(id);}@PostMappingpublicUsercreate(@RequestBody@ValidUseruser){returnuserService.save(user);}@GetMappingpublicList<User>list(@RequestParam(required=false)Stringname){returnuserService.findByName(name);}}2. 全局异常处理
@RestControllerAdvicepublicclassGlobalExceptionHandler{@ExceptionHandler(BusinessException.class)publicResponseEntity<ErrorResponse>handleBusiness(BusinessExceptione){returnResponseEntity.badRequest().body(newErrorResponse(e.getMessage()));}}九、测试注解
@SpringBootTestclassUserServiceTest{@AutowiredprivateUserServiceuserService;@MockBeanprivateUserDaouserDao;@TestvoidtestGetUser(){when(userDao.findById(1L)).thenReturn(newUser(1L,"张三"));Useruser=userService.getById(1L);assertEquals("张三",user.getName());}}常用测试注解:@SpringBootTest、@WebMvcTest、@DataJpaTest、@MybatisTest、@MockBean、@SpyBean、@TestPropertySource。
十、其他常用注解
| 注解 | 作用 |
|---|---|
@Async | 异步执行方法,需@EnableAsync |
@Scheduled | 定时任务,需@EnableScheduling |
@Cacheable | 缓存方法结果,需@EnableCaching |
@CacheEvict | 清除缓存 |
@EventListener | 事件监听 |
@Order | 控制 Bean 加载顺序 |
@Lazy | 延迟初始化 |
@Scope | 指定作用域 |
@AsyncpublicCompletableFuture<String>sendEmail(Stringto){...}@Scheduled(cron="0 0 2 * * ?")publicvoiddailyReport(){...}@Cacheable(value="users",key="#id")publicUsergetUser(Longid){...}十一、注解使用最佳实践
- 按层选择语义注解:Controller 用
@RestController,Service 用@Service,Dao 用@Repository。 - 优先使用构造器注入,保证依赖不可变和完整。
- 第三方类无法加注解时,用
@Configuration+@Bean注册。 - 多环境配置用
@Profile,避免运行时 if-else。 - 提供默认实现时用
@ConditionalOnMissingBean,允许用户覆盖。 - 事务注解放在 Service 层,注意内部调用失效问题。
- AOP 切面只处理真正的横切关注点,避免滥用导致调试困难。
- 测试中使用
@MockBean隔离外部依赖,用切片测试代替完整@SpringBootTest提升速度。
十二、总结
| 分类 | 核心注解 |
|---|---|
| 声明 Bean | @Component、@Service、@Repository、@Controller、@RestController、@Configuration、@Bean |
| 依赖注入 | @Autowired、@Qualifier、@Primary、@Value、@Resource |
| 配置与扫描 | @ComponentScan、@Import、@PropertySource、@ConfigurationProperties |
| 条件与 Profile | @Conditional、@ConditionalOnXxx、@Profile |
| AOP | @Aspect、@Pointcut、@Before、@After、@Around |
| 事务 | @Transactional |
| Web | @RequestMapping、@GetMapping、@PostMapping、@RequestParam、@PathVariable、@RequestBody、@RestControllerAdvice |
| 测试 | @SpringBootTest、@MockBean、@WebMvcTest |
| 其他 | @Async、@Scheduled、@Cacheable、@EventListener |
Spring 注解体系庞大但逻辑清晰:声明 Bean 靠@Component系列和@Bean,注入依赖靠@Autowired系列,扩展功能靠@EnableXxx和条件注解。掌握这些注解的语义、生效机制和适用场景,就能在开发中灵活组合,写出简洁且易维护的 Spring 应用。