Spring 通过动态代理(JDK 或 CGLIB)为特定注解提供功能增强。以下是触发代理的核心注解及其实现机制:
一、事务管理相关
注解 | 代理机制 | 作用与场景 | 注意事项 |
---|---|---|---|
@Transactional | JDK 动态代理或 CGLIB(默认优先 JDK) | 声明式事务管理,标注在类或方法上,控制事务的提交、回滚和传播行为。 | - 需通过代理调用,同类方法直接调用会导致事务失效。 - 默认仅对 RuntimeException 回滚,需显式配置其他异常。 |
@EnableTransactionManagement | 无直接代理,启用事务管理支持 | 配合 @Transactional 使用,启用基于代理的事务管理。 | 需与 @Configuration 类结合使用。 |
示例:
java">@Service
public class OrderService {@Transactionalpublic void createOrder(Order order) {// 数据库操作(代理拦截事务)}
}
二、异步任务相关
注解 | 代理机制 | 作用与场景 | 注意事项 |
---|---|---|---|
@Async | JDK 动态代理或 CGLIB(默认优先 JDK) | 标注方法或类,异步执行任务(通过线程池)。 | - 同类调用需通过代理触发异步逻辑(如 AopContext.currentProxy() )。- 需启用 @EnableAsync 。 |
@EnableAsync | 无直接代理,启用异步支持 | 配合 @Async 使用,激活异步代理生成。 | 可配置线程池参数。 |
示例:
java">@Service
public class TaskService {@Asyncpublic void processTask() {// 异步执行(代理拦截并提交到线程池)}
}
三、缓存相关
注解 | 代理机制 | 作用与场景 | 注意事项 |
---|---|---|---|
@Cacheable | JDK 动态代理或 CGLIB(默认优先 JDK) | 标注方法,缓存方法返回值(根据 Key 匹配缓存)。 | - 同类调用需通过代理触发缓存逻辑。 - 需启用 @EnableCaching 。 |
@CachePut | 同上 | 更新缓存数据(无论缓存是否存在)。 | 需与 @Cacheable 配合使用。 |
@CacheEvict | 同上 | 清除指定缓存条目。 | 可配置 allEntries 清空所有缓存。 |
@EnableCaching | 无直接代理,启用缓存支持 | 激活缓存代理生成。 | 需配置缓存管理器(如 Redis)。 |
示例:
java">@Service
public class UserService {@Cacheable(value = "users", key = "#userId")public User getUser(String userId) {// 数据库查询(代理拦截并缓存结果)}
}
四、AOP 切面相关
注解 | 代理机制 | 作用与场景 | 注意事项 |
---|---|---|---|
@Aspect | JDK 动态代理或 CGLIB(默认优先 JDK) | 定义切面类,包含通知(@Before 、@Around 等)和切入点(@Pointcut )。 | - 需启用 @EnableAspectJAutoProxy 。- 同类调用需通过代理触发切面逻辑。 |
@EnableAspectJAutoProxy | 无直接代理,启用 AspectJ 自动代理 | 激活 AOP 代理生成,可配置 proxyTargetClass=true 强制使用 CGLIB。 | 通常与 @Configuration 类结合使用。 |
示例:
java">@Aspect
@Component
public class LogAspect {@Before("execution(* com.xiaolingting.service.*.*(..))")public void logBefore(JoinPoint joinPoint) {// 日志记录(代理拦截方法调用)}
}
五、配置类代理
注解 | 代理机制 | 作用与场景 | 注意事项 |
---|---|---|---|
@Configuration | CGLIB 代理(Full 模式) | 标注配置类,声明 @Bean 方法,通过代理拦截 @Bean 方法调用,确保单例依赖正确注入。 | - 无此注解时为 Lite 模式(无代理,直接调用)。 - 需避免在 @Bean 方法中直接调用其他 @Bean 方法。 |
@Bean | 依赖 @Configuration 的代理机制 | 声明 Bean 实例化逻辑。 | 在 @Configuration 类中通过代理保证单例。 |
示例:
java">@Configuration
public class AppConfig {@Beanpublic UserService userService() {return new UserServiceImpl(orderService()); // 代理确保单例}@Beanpublic OrderService orderService() {return new OrderServiceImpl();}
}
六、安全相关
注解 | 代理机制 | 作用与场景 | 注意事项 |
---|---|---|---|
@PreAuthorize | JDK 动态代理或 CGLIB(默认优先 JDK) | 方法级权限控制(需 Spring Security 支持)。 | - 需启用 @EnableGlobalMethodSecurity(prePostEnabled = true) 。 |
@Secured | 同上 | 基于角色的权限控制。 | 需显式启用 @EnableGlobalMethodSecurity(securedEnabled = true) 。 |
示例:
java">@Service
public class AdminService {@PreAuthorize("hasRole('ADMIN')")public void deleteUser(String userId) {// 仅管理员可调用(代理拦截权限校验)}
}
七、重试机制
注解 | 代理机制 | 作用与场景 | 注意事项 |
---|---|---|---|
@Retryable | JDK 动态代理或 CGLIB(默认优先 JDK) | 标注方法,在抛出指定异常时重试(需 Spring Retry 支持)。 | - 需启用 @EnableRetry 。- 可配置重试次数和退避策略。 |
示例:
java">@Service
@EnableRetry
public class PaymentService {@Retryable(value = PaymentException.class, maxAttempts = 3)public void processPayment() {// 支付失败时自动重试(代理拦截重试逻辑)}
}
总结
Spring 代理机制通过动态生成代理对象,为以下场景提供功能增强:
- 事务管理:
@Transactional
。 - 异步任务:
@Async
。 - 缓存控制:
@Cacheable
、@CachePut
、@CacheEvict
。 - AOP 切面:
@Aspect
及相关通知注解。 - 配置类单例:
@Configuration
+@Bean
。 - 安全控制:
@PreAuthorize
、@Secured
。 - 重试机制:
@Retryable
。
核心注意事项:
- 代理触发条件:需确保目标类被 Spring 管理(如
@Component
扫描或手动注册)。 - 同类调用问题:通过
AopContext.currentProxy()
或重构代码解决。 - 代理类型选择:优先 JDK 动态代理(接口实现),强制 CGLIB 需配置
proxyTargetClass=true
。