Spring框架的核心幼稚之一是通过注解驱动简化配置,实现组件解耦和功能扩展,注解本质就是元数据标记,Spring容器通过注解解析器识别这些标记,完成组件注册、依赖注入、事务管理等核心功能。
一、组件注册注解:将Bean纳入Spring容器管理
核心作用是告诉Spring容器,哪些类需要被实例化并纳入管理,替代传统XML中的<bean>标签
1.核心组件注解(Spring Context层)
|-----------------|----------------------------------|---------------------------------------------------------------------------------|
| 注解 | 使用场景 | 核心特点 |
| @Component | 通过组件注解,标记普通java类为Spring Bean | 没有特定的语义,适用于任何层 |
| @Service | 标记业务逻辑层(Service)租 | 语义化注解,底层与@Component完全一致 |
| @Repository | 标记数据访问层(DAO) 组件 | 除语义化外,额外支持 Spring 的「持久化异常转换」需配合 PersistenceExceptionTranslationPostProcessor) |
| @Controller | 标记Spring MVC 控制器(Controller) 组件 | 语义化注解,支持 Spring MVC 的请求映射(@RequestMapping 等),底层基于 @Component |
| @RestController | 标记RESTful 风格控制器(Spring 4.0+) | 组合注解 = @Controller + @ResponseBody,默认所有方法返回 JSON/XML 而非视图 |
关键细节:
- 这些注解默认通过「类路径扫描」生效,需在配置类中添加
@ComponentScan指定扫描包(如@ComponentScan("com.example"))。 - Bean 的默认名称:类名首字母小写(如
UserService→userService),可通过注解 value 属性自定义(如@Service("myUserService"))。
2.配置类相关注册注解
| 注解 | 作用场景 | 核心原理 |
|---|---|---|
@Configuration |
标记类为配置类,替代传统 XML 配置文件 | 被标记的类会被 Spring 代理(CGLIB),确保 @Bean 方法单例(多次调用返回同一实例) |
@Bean |
用于配置类的方法上,手动注册 Bean(适用于第三方类,无法加 @Component) |
方法返回值作为 Bean 实例,默认名称为方法名,可通过 @Bean("beanName") 自定义 |
@Import |
快速导入 Bean 或配置类(无需扫描) | 支持 3 种类型:普通类(直接注册为 Bean)、ImportSelector 实现类(动态导入)、ImportBeanDefinitionRegistrar 实现类(手动注册 BeanDefinition) |
@Conditional |
条件化注册 Bean(Spring 4.0+) | 配合 Condition 接口,满足条件时才注册 Bean(如 @Conditional(OnClassCondition.class) 检查类是否存在) |
示例:@Bean 注册第三方组件
@Configuration
public class ThirdPartyConfig {
// 注册 RedisTemplate(第三方类,无法加 @Component)
@Bean("myRedisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
return template;
}
}
二、依赖注入注解:解决 Bean 之间的依赖关系
核心作用是让 Spring 容器自动将依赖的 Bean 注入到目标组件中,替代传统 XML 中的 <property> 或构造器注入。
1. 核心注入注解
| 注解 | 注入方式 | 适用场景与注意事项 |
|---|---|---|
@Autowired |
Spring 自带注解,按类型(byType) 注入 | 1. 优先匹配类型一致的 Bean,若存在多个同类型 Bean,需配合 @Qualifier 指定名称;2. 默认要求依赖必须存在(可通过 required = false 允许空值);3. 支持构造器、字段、setter 方法注入 |
@Qualifier |
配合 @Autowired,按名称(byName) 注入 |
解决同类型多 Bean 冲突(如 @Autowired @Qualifier("userServiceV2")) |
@Resource |
JDK 原生注解(JSR-250),按名称优先注入 | 1. 先按名称匹配,名称不存在则按类型匹配;2. 支持字段、setter 方法注入,不支持构造器注入;3. 无需配合其他注解,直接指定名称(@Resource(name = "userDao")) |
@Value |
注入基本类型 / 字符串值,支持 SpEL 表达式 | 1. 注入配置文件值(如 @Value("${app.name}"),需配合 @PropertySource 加载配置文件);2. 注入常量(如 @Value("10"))或 SpEL 表达式(如 @Value("#{T(java.lang.Math).random()}) |
注入方式优先级(Spring 推荐):
- 构造器注入 :强制依赖初始化,避免空指针,且组件不可变(final 字段),Spring 4.3+ 支持无
@Autowired的构造器注入(仅一个构造器时); - setter 注入:适用于可选依赖;
- 字段注入:代码简洁,但可读性差,且无法注入 final 字段,不推荐大量使用。
示例:构造器注入(推荐)
@Service
public class UserService {
private final UserDao userDao;
private final OrderService orderService;
// Spring 4.3+ 无需 @Autowired(仅一个构造器)
public UserService(UserDao userDao, @Qualifier("orderServiceV2") OrderService orderService) {
this.userDao = userDao;
this.orderService = orderService;
}
}
2. 配置文件加载注解
| 注解 | 作用场景 | 示例 |
|---|---|---|
@PropertySource |
加载外部 properties 配置文件(Spring 3.1+) | @PropertySource("classpath:application.properties")(加载类路径下的配置文件) |
@PropertySources |
加载多个 properties 文件(Spring 4.0+) | @PropertySources({@PropertySource("a.properties"), @PropertySource("b.properties")}) |
三、Bean 生命周期注解:控制 Bean 的创建与销毁
Spring Bean 的生命周期:实例化 → 属性注入 → 初始化 → 销毁,注解用于干预初始化和销毁阶段。
| 注解 | 作用时机 | 核心特点 |
|---|---|---|
@PostConstruct |
JDK 原生注解(JSR-250),Bean 初始化完成后执行(属性注入后) | 1. 无参数、无返回值的非静态方法;2. 执行时机:BeanPostProcessor.postProcessAfterInitialization 之前 |
@PreDestroy |
JDK 原生注解(JSR-250),Bean 销毁前执行(容器关闭时) | 1. 无参数、无返回值的非静态方法;2. 仅适用于单例 Bean(原型 Bean 容器不管理销毁) |
@Bean(initMethod = "init", destroyMethod = "destroy") |
配置类中 @Bean 方法指定初始化 / 销毁方法 |
适用于第三方类(无法加 @PostConstruct),如 @Bean(initMethod = "start", destroyMethod = "stop") |
执行顺序:
构造器 → @Autowired(属性注入) → @PostConstruct(初始化) → 业务逻辑 → @PreDestroy(销毁)
四、AOP 与事务注解:面向切面编程与事务管理
1. AOP 核心注解(Spring AOP)
AOP 用于分离核心业务与横切逻辑(如日志、权限、异常处理),Spring AOP 基于动态代理实现。
| 注解 | 作用场景 | 核心说明 |
|---|---|---|
@Aspect |
标记类为切面类(包含通知和切入点) | 需配合 @EnableAspectJAutoProxy(Spring 4.0+)开启 AOP 自动代理 |
@Pointcut |
定义切入点表达式(指定哪些方法需要被增强) | 常用表达式:- execution(方法匹配):execution(* com.example.service.*.*(..))(匹配 service 层所有方法);- @annotation(注解匹配):@annotation(com.example.annotation.Log)(匹配加了 @Log 注解的方法) |
@Before |
前置通知:目标方法执行前执行 | |
@AfterReturning |
返回通知:目标方法正常返回后执行(异常时不执行) | 可通过 returning 参数获取返回值:@AfterReturning(pointcut = "pc()", returning = "result") |
@AfterThrowing |
异常通知:目标方法抛出异常后执行 | 可通过 throwing 参数获取异常对象:@AfterThrowing(pointcut = "pc()", throwing = "e") |
@After |
最终通知:目标方法执行后执行(无论正常 / 异常,类似 finally) | |
@Around |
环绕通知:包裹目标方法,可控制目标方法的执行(最强大) | 需通过 ProceedingJoinPoint 调用 proceed() 执行目标方法,可修改参数、返回值或异常 |
示例:日志切面
@Aspect
@Component
public class LogAspect {
// 切入点:匹配 service 层所有方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void servicePointcut() {}
// 环绕通知:记录方法执行时间
@Around("servicePointcut()")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed(); // 执行目标方法
long time = System.currentTimeMillis() - start;
System.out.println(joinPoint.getSignature() + " 执行时间:" + time + "ms");
return result;
}
}
// 启动类开启 AOP
@SpringBootApplication
@EnableAspectJAutoProxy
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2. 事务管理注解(Spring Transaction)
基于 AOP 实现声明式事务,替代传统 XML 中的 <tx:advice> 配置。
| 注解 | 作用场景 | 核心属性与注意事项 |
|---|---|---|
@Transactional |
标记方法 / 类需要事务管理(声明式事务) | 1. 作用范围 :类上(所有方法生效)、方法上(覆盖类上配置);2. 核心属性:- propagation:事务传播行为(如 REQUIRED 【默认】、REQUIRES_NEW);- isolation:事务隔离级别(如 READ_COMMITTED 【默认】);- rollbackFor:指定触发回滚的异常(如 rollbackFor = Exception.class,默认仅运行时异常回滚);- readOnly:是否只读事务(查询方法设为 true,优化性能);3. 需配合 @EnableTransactionManagement 开启事务管理(Spring Boot 自动开启) |
关键注意事项:
@Transactional仅对public 方法生效(Spring AOP 动态代理限制);- 内部方法调用(如
A.methodA()调用本类@Transactional methodB())不会触发事务(代理对象未介入),需通过AopContext.currentProxy()获取代理对象调用。
五、注解使用核心原则
- 语义化优先 :如 Service 层用
@Service,DAO 层用@Repository,而非全用@Component,提升代码可读性; - 依赖注入推荐构造器注入:避免空指针,支持不可变对象(final 字段);
- 事务注解注意作用范围:仅 public 方法生效,避免内部调用;
- 配置类避免组件扫描冲突 :
@Configuration配合@Bean注册第三方组件,@ComponentScan扫描自定义组件; - AOP 切面类需加
@Component:确保切面类被 Spring 容器管理,否则@Aspect不生效。