SpringAOP动态代理:JDK与CGLib深度解析
好的,我们来深入解析 Spring AOP 的核心原理之一:动态代理,并重点对比 JDK 动态代理 和 CGLib 动态代理 的实现方式、区别以及实战应用。
核心概念:动态代理与 AOP
Spring AOP (Aspect-Oriented Programming) 的核心目标是将横切关注点(如日志记录、事务管理、安全检查等)从核心业务逻辑中分离出来。为了实现这种非侵入式的增强,Spring 主要依赖于 动态代理 技术。
- 动态代理:在程序运行时动态地创建一个实现特定接口或继承特定类的代理对象。当通过这个代理对象调用目标方法时,代理对象可以在调用目标方法的前后插入额外的逻辑(Advice - 增强)。
- AOP 中的角色:
- 目标对象 (Target Object):包含核心业务逻辑的需要被增强的对象。
- 代理对象 (Proxy Object):由 AOP 框架创建的对象,它包裹了目标对象,并负责在调用目标方法前后执行增强逻辑。
- 连接点 (Joinpoint):程序执行过程中的一个点,例如方法调用或异常抛出。在 Spring AOP 中,主要指方法调用。
- 切点 (Pointcut):一个表达式,用于匹配哪些连接点需要被增强。
- 增强 (Advice):在特定连接点执行的动作(如前置通知、后置通知、环绕通知等)。
- 切面 (Aspect):切点和增强的结合。
Spring AOP 在底层使用两种动态代理技术来创建这些代理对象:JDK 动态代理 和 CGLib 动态代理。
1. JDK 动态代理
原理: JDK 动态代理是 Java 标准库 (java.lang.reflect 包) 提供的功能。它要求目标对象必须实现至少一个接口。代理对象在运行时动态生成,它会实现目标对象所实现的接口。
实现机制:
- 核心类是
java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler。 Proxy.newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h)方法用于创建代理对象。loader: 类加载器。interfaces: 目标对象实现的接口列表。h: 实现了InvocationHandler接口的对象,它定义了代理对象拦截方法调用的逻辑。
- 当通过代理对象调用接口方法时,这个调用会被转发给
InvocationHandler的invoke方法:public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 前置增强逻辑 (Before Advice) Object result = method.invoke(target, args); // 调用目标对象的方法 // 后置增强逻辑 (After Advice) return result; }http://my.tv.sohu.com/us/442338213/699359606.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTYwNi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359615.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTYxNS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359712.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTcxMi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359631.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTYzMS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359809.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTgwOS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359725.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTcyNS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359820.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTgyMC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359824.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTgyNC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359921.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTkyMS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359923.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTkyMy5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359832.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTgzMi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359663.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTY2My5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359845.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTg0NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359752.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTc1Mi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359849.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTg0OS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359939.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTkzOS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359676.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTY3Ni5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359859.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTg1OS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359683.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTY4My5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359775.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTc3NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359973.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTk3My5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359790.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTc5MC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360205.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDIwNS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360103.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDEwMy5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360026.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDAyNi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360000.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDAwMC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360035.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDAzNS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360125.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDEyNS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360042.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDA0Mi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360136.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDEzNi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360142.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDE0Mi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360056.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDA1Ni5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360060.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDA2MC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360065.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDA2NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360162.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDE2Mi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360353.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDM1My5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360272.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDI3Mi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360179.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDE3OS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360275.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDI3NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360279.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDI3OS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360185.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDE4NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360187.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDE4Ny5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360190.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDE5MC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360375.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDM3NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360378.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDM3OC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360293.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDI5My5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360295.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDI5NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360410.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDQxMC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360611.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDYxMS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360421.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDQyMS5zaHRtbA==.html
proxy: 代理对象本身(通常用不到)。method: 被调用的目标方法。args: 方法参数。target: 目标对象(需要在自定义的InvocationHandler实现中持有其引用)。
特点:
- 优点:基于 Java 标准库,无需额外依赖。
- 优点:生成的代理对象是接口类型,符合面向接口编程的原则。
- 缺点:只能代理实现了接口的类。
- 缺点:通过反射调用方法,性能略低于 CGLib(但通常可接受)。
实战示例:
// 1. 定义业务接口
public interface UserService {
void saveUser(User user);
User getUserById(int id);
}
// 2. 实现业务接口 (目标对象)
public class UserServiceImpl implements UserService {
@Override
public void saveUser(User user) { /* 业务逻辑 */ }
@Override
public User getUserById(int id) { /* 业务逻辑 */ return new User(); }
}
// 3. 实现 InvocationHandler (定义增强逻辑)
public class LoggingHandler implements InvocationHandler {
private final Object target; // 目标对象
public LoggingHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method: " + method.getName());
Object result = method.invoke(target, args); // 调用目标方法
System.out.println("After method: " + method.getName());
return result;
}
}
// 4. 创建代理对象并使用
public class Main {
public static void main(String[] args) {
UserService target = new UserServiceImpl(); // 目标对象
// 创建代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new LoggingHandler(target)
);
// 通过代理调用方法,增强逻辑会被执行
proxy.saveUser(new User());
proxy.getUserById(1);
}
}
2. CGLib 动态代理
原理: CGLib (Code Generation Library) 是一个强大的高性能代码生成库。它通过在运行时动态生成目标类的子类来实现代理。因此,它不需要目标类实现任何接口。
实现机制:
- 核心类是
net.sf.cglib.proxy.Enhancer和net.sf.cglib.proxy.MethodInterceptor。 Enhancer用于创建代理对象:Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); // 设置目标类为父类 enhancer.setCallback(new MyMethodInterceptor()); // 设置回调(拦截器) Object proxy = enhancer.create(); // 创建代理对象http://my.tv.sohu.com/us/442338213/699359606.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTYwNi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359615.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTYxNS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359712.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTcxMi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359631.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTYzMS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359809.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTgwOS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359725.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTcyNS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359820.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTgyMC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359824.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTgyNC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359921.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTkyMS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359923.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTkyMy5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359832.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTgzMi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359663.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTY2My5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359845.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTg0NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359752.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTc1Mi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359849.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTg0OS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359939.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTkzOS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359676.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTY3Ni5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359859.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTg1OS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359683.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTY4My5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359775.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTc3NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359973.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTk3My5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699359790.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM1OTc5MC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360205.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDIwNS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360103.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDEwMy5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360026.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDAyNi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360000.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDAwMC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360035.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDAzNS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360125.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDEyNS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360042.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDA0Mi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360136.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDEzNi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360142.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDE0Mi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360056.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDA1Ni5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360060.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDA2MC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360065.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDA2NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360162.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDE2Mi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360353.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDM1My5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360272.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDI3Mi5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360179.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDE3OS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360275.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDI3NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360279.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDI3OS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360185.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDE4NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360187.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDE4Ny5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360190.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDE5MC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360375.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDM3NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360378.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDM3OC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360293.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDI5My5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360295.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDI5NS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360410.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDQxMC5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360611.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDYxMS5zaHRtbA==.html
http://my.tv.sohu.com/us/442338213/699360421.shtml
https://tv.sohu.com/v/dXMvNDQyMzM4MjEzLzY5OTM2MDQyMS5zaHRtbA==.html
MethodInterceptor接口定义了拦截方法:public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 前置增强逻辑 (Before Advice) Object result = proxy.invokeSuper(obj, args); // 调用父类(目标类)的方法 // 后置增强逻辑 (After Advice) return result; }obj: 代理对象本身(通常用不到)。method: 被调用的目标方法。args: 方法参数。proxy: 用于快速调用父类(目标类)方法的工具。
特点:
- 优点:可以代理没有实现接口的普通类。
- 优点:通常认为其生成的代理对象在方法调用上比 JDK 代理(基于反射)性能更高,因为它使用了 FastClass 机制直接调用方法。
- 缺点:需要额外引入 CGLib 库 (Spring Core 已包含)。
- 缺点:无法代理
final方法(因为子类无法覆盖),也无法代理final类(因为无法继承)。 - 缺点:代理对象类型是目标类的子类类型。
实战示例:
// 0. 引入 CGLib 依赖 (通常由 Spring 提供)
// 1. 目标类 (无需实现接口)
public class OrderService {
public void createOrder(Order order) { /* 业务逻辑 */ }
public Order getOrder(String id) { /* 业务逻辑 */ return new Order(); }
}
// 2. 实现 MethodInterceptor (定义增强逻辑)
public class TransactionInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Start transaction for: " + method.getName());
Object result = proxy.invokeSuper(obj, args); // 调用父类(目标类)方法
System.out.println("Commit transaction for: " + method.getName());
return result;
}
}
// 3. 创建代理对象并使用
public class Main {
public static void main(String[] args) {
// 创建增强器
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OrderService.class); // 设置目标类为父类
enhancer.setCallback(new TransactionInterceptor()); // 设置拦截器
// 创建代理对象
OrderService proxy = (OrderService) enhancer.create();
// 通过代理调用方法,增强逻辑会被执行
proxy.createOrder(new Order());
proxy.getOrder("123");
}
}
3. JDK 代理 vs CGLib 代理 对比总结
| 特性 | JDK 动态代理 | CGLib 动态代理 |
|---|---|---|
| 依赖 | Java 标准库 (java.lang.reflect) | 需要 CGLib 库 |
| 代理对象类型 | 实现目标接口 | 目标类的子类 |
| 目标要求 | 必须实现至少一个接口 | 可以是普通类 (非 final) |
final 方法 | 可以代理 | 无法代理 (子类不能覆盖) |
final 类 | 如果实现了接口则可以代理 | 无法代理 (不能继承) |
| 性能 (创建) | 相对较快 | 相对较慢 (需要生成字节码) |
| 性能 (调用) | 较慢 (反射调用) | 较快 (FastClass 机制) |
| Spring 默认选择 | 目标有接口时优先使用 | 目标无接口时使用 |
4. Spring AOP 如何选择?
Spring AOP 内部自动根据目标对象的情况选择合适的代理方式:
- 如果目标对象实现了接口(一个或多个):默认使用 JDK 动态代理。
- 如果目标对象没有实现任何接口:则必须使用 CGLib 动态代理。
- 强制使用 CGLib:可以通过配置 (如
@EnableAspectJAutoProxy(proxyTargetClass = true)) 强制 Spring AOP 对所有目标都使用 CGLib 代理,即使目标实现了接口。
核心价值:
无论底层使用哪种代理技术,Spring AOP 都向开发者提供了一个统一的、声明式的 AOP 编程模型(主要通过 @Aspect, @Before, @After, @Around 等注解)。开发者只需关注切面的定义和增强逻辑的编写,无需直接处理复杂的代理创建过程,大大简化了 AOP 的应用。
理解 JDK 和 CGLib 动态代理的原理,有助于深入掌握 Spring AOP 的工作机制,并在需要时进行更底层的调试或定制。











