代理专栏总结
该专栏围绕 Java 代理、Spring AOP 及 @Transactional 注解展开,系统梳理了相关概念、原理及应用场景,以下是核心知识点总结:
一、Java 代理机制
1. 静态代理
- 定义:代理类与目标类实现相同接口,代理类持有目标类实例,通过代理类间接调用目标方法。
- 核心特点:
- 代理类在方法执行前后可添加额外逻辑(如性能监控、日志记录)。
- 适用于需要对目标类功能进行扩展的场景。
- 需手动编写代理类,灵活性较低。
2. 动态代理
- 定义:在程序运行时动态生成代理类,无需提前编译,通过反射机制实现功能扩展。
- 核心思想:解耦业务逻辑与增强逻辑,不修改目标对象代码。
- 分类及实现:
- JDK 动态代理:
- 基于接口实现,代理类必须实现目标接口。
- 通过
Proxy.newProxyInstance
生成代理类,步骤包括参数检查、字节码生成、类加载。
- CGLIB 动态代理:
- 基于类继承实现,无需接口,适用于代理普通类。
- 通过字节码生成技术创建子类作为代理类。
- ByteBuddy:
- 无需实现固定接口(如
InvocationHandler
),通过注解自动匹配拦截逻辑。 - 参数包括代理对象(
@This
)、被拦截方法(@Origin
)、方法参数(@AllArguments
)。
- 无需实现固定接口(如
- JDK 动态代理:
- 性能对比:
- JDK 代理:便捷但受限(仅支持接口)。
- CGLIB:功能强大但发展缓慢,部分场景性能优于 JDK 代理。
- ByteBuddy:动态性更强,适合复杂场景。
二、Spring AOP 核心概念
1. 基本原理
- 基于动态代理实现(默认使用 JDK 代理,可配置为 CGLIB)。
- 关键术语:
- 连接点(Join Point):程序执行中的具体点(如方法调用)。
- 切入点(Pointcut):通过表达式(如
execution
)定义匹配的连接点集合。- 示例:
@Pointcut("execution(* org.derek.controller.*.*(..))")
匹配指定包下的所有方法。
- 示例:
- 通知(Advice):在切入点处执行的增强逻辑,类型包括:
@Before
(前置通知)、@After
(后置通知,无论是否异常)、@AfterReturning
(正常返回后)、@AfterThrowing
(异常抛出时)、@Around
(环绕通知)。
2. 常用注解与配置
- 启用 AOP 需引入依赖:
spring-boot-starter-aop
。 - 通过注解定义切面(
@Aspect
)、通知类型及切入点表达式。
三、@Transactional 注解详解
1. 实现原理
- 基于 Spring AOP 机制,通过代理拦截方法,在方法执行前后添加事务管理逻辑(开启、提交、回滚)。
- 默认使用
Spring AOP(mode=Proxy,proxyTargetClass=false)
,即 JDK 代理(需接口),可配置为 CGLIB 代理(proxyTargetClass=true
)。
2. 功能与作用
- 声明事务边界:
- 开启事务:方法执行前创建新事务或加入现有事务。
- 提交事务:方法正常执行完成后提交。
- 回滚事务:方法抛出异常时根据配置回滚(默认仅回滚
RuntimeException
及其子类)。
- 使用场景:主要用于服务层(
@Service
)方法,实现数据库操作的原子性。
3. 异常不回滚常见原因
- 未抛出受检异常(Checked Exception),需显式配置
@Transactional(rollbackFor = Exception.class)
。 - 异常被内部捕获且未重新抛出。
- 方法非 public(Spring 默认仅拦截 public 方法)。
- 代理对象调用失效(如同一类内方法调用,未通过代理对象触发)。
- 事务传播机制配置不当(如
Propagation.NOT_SUPPORTED
不支持事务)。
四、知识关联与扩展
- 代理与 AOP 的关系:Spring AOP 通过动态代理实现,代理是 AOP 的底层技术支撑。
- 事务管理与 AOP 的结合:
@Transactional
本质是 AOP 切面,通过拦截方法实现声明式事务控制。 - 动态代理选型建议:
- 有接口时优先使用 JDK 代理。
- 无接口时使用 CGLIB 或 ByteBuddy。
- 复杂场景(如字节码操作)可考虑 ByteBuddy。
通过以上知识点,可系统理解 Java 代理机制、Spring AOP 的核心原理及事务管理的实际应用,帮助排查开发中常见的事务不回滚等问题。