独家揭秘动态代理两大巨头JDK和CGLIB的奥秘
2023-02-09 00:12:11
动态代理:超越传统,赋予代码新功能
在软件开发的浩瀚世界中,我们时常遇到这样的场景:迫切需要为现有代码添加额外功能,却苦于无法直接修改源代码。此时,动态代理技术如同一位隐形英雄,悄然登场,为我们带来了解决之道。
何谓动态代理
动态代理是一种面向切面编程(AOP)的技术,允许我们在不触碰原始代码的情况下,为类或接口添加附加功能。它如同一位幕后操手,在方法调用时悄然介入,执行我们预先定义的功能,而不影响原有代码的正常运作。
JDK动态代理:灵活多变的帮手
Java SE 中的 JDK 动态代理是业界常用的动态代理实现。它利用 Java 反射机制来创建代理对象,专精于代理接口,而非类。
JDK动态代理的工作原理
JDK动态代理的工作流程十分简洁:
- 创建一个
InvocationHandler
接口的实现类,负责在方法调用时执行预定义的功能。 - 借助
Proxy
类的newProxyInstance()
方法,传入代理类的类加载器、实现的接口列表和InvocationHandler
实现,生成代理对象。 - 通过代理对象调用目标类或接口的方法时,代理对象会将方法调用转发给
InvocationHandler
的实现类,从而触发预定义功能的执行。
JDK动态代理的优缺点
JDK动态代理的优点不容忽视:
- 使用简单,只需实现
InvocationHandler
接口即可。 - 性能优异,代理对象通过运行时动态生成,无需修改字节码。
然而,它的不足也显而易见:
- 只能代理接口,对于类无能为力。
- 代理类只能继承自
InvocationHandler
接口,限制了代理功能的扩展。
CGLIB动态代理:万能的魔术师
CGLIB动态代理脱颖而出,因为它既能代理接口,也能代理类。它利用 ASM 字节码生成框架,为代理对象注入新的生命。
CGLIB动态代理的工作原理
CGLIB动态代理的工作机制同样清晰明了:
- 创建一个
MethodInterceptor
接口的实现类,在方法调用时负责执行预定义的功能。 - 通过
Enhancer
类的create()
方法,传入目标类的类型和MethodInterceptor
实现,生成代理对象。 - 代理对象接收方法调用时,会将调用转发给
MethodInterceptor
的实现类,进而执行预定义功能。
CGLIB动态代理的优缺点
CGLIB动态代理拥有诸多优势:
- 代理能力全面,可同时代理接口和类。
- 代理类可以继承自任意类,扩展功能不受限。
然而,它也不无缺憾:
- 性能略逊于 JDK 动态代理,代理对象通过字节码生成产生。
- 使用稍显复杂,需要创建
MethodInterceptor
的实现类。
JDK与CGLIB动态代理的对比
让我们将 JDK 和 CGLIB 动态代理置于显微镜下,一探究竟:
特性 | JDK动态代理 | CGLIB动态代理 |
---|---|---|
代理类型 | 接口 | 接口或类 |
代理类继承 | InvocationHandler |
任意类 |
性能 | 优异 | 稍差 |
使用难度 | 简单 | 稍复杂 |
代码示例
JDK动态代理
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
interface TargetInterface {
void doSomething();
}
class TargetClass implements TargetInterface {
@Override
public void doSomething() {
System.out.println("TargetClass.doSomething() called");
}
}
class LoggingInvocationHandler implements InvocationHandler {
private final TargetInterface target;
public LoggingInvocationHandler(TargetInterface target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("LoggingInvocationHandler.invoke() called");
Object result = method.invoke(target, args);
System.out.println("LoggingInvocationHandler.invoke() completed");
return result;
}
}
public class DynamicProxyExample {
public static void main(String[] args) {
TargetInterface target = new TargetClass();
LoggingInvocationHandler invocationHandler = new LoggingInvocationHandler(target);
TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
TargetClass.class.getClassLoader(),
new Class[]{TargetInterface.class},
invocationHandler
);
proxy.doSomething();
}
}
CGLIB动态代理
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
class TargetClass {
public void doSomething() {
System.out.println("TargetClass.doSomething() called");
}
}
class LoggingMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("LoggingMethodInterceptor.intercept() called");
Object result = proxy.invokeSuper(obj, args);
System.out.println("LoggingMethodInterceptor.intercept() completed");
return result;
}
}
public class DynamicProxyExample {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TargetClass.class);
enhancer.setCallback(new LoggingMethodInterceptor());
TargetClass proxy = (TargetClass) enhancer.create();
proxy.doSomething();
}
}
结论
动态代理技术为软件开发开辟了一条崭新的道路,让开发者在不修改源代码的前提下,为类或接口注入新的活力。JDK动态代理和CGLIB动态代理各具特色,根据不同的需求,选择合适的代理技术,可以有效提升开发效率,增强代码的灵活性和可维护性。
常见问题解答
-
动态代理有什么实际应用场景?
- 日志记录
- 性能监控
- 事务管理
- 权限控制
-
JDK动态代理和CGLIB动态代理有什么区别?
- JDK动态代理只能代理接口,而CGLIB动态代理既能代理接口,也能代理类。
-
为什么需要使用动态代理?
- 在不修改源代码的情况下,为代码添加额外功能。
-
动态代理的缺点是什么?
- JDK动态代理无法代理类,CGLIB动态代理性能略差于JDK动态代理。
-
如何选择合适的动态代理实现?
- 如果需要代理接口,并且追求高性能,则选择JDK动态代理;如果需要代理类,或者需要代理类继承自特定的类,则选择CGLIB动态代理。