返回
动态代理与JDK的那些事儿
后端
2024-02-19 04:23:04
前言
在Java开发中,动态代理是一种非常重要的技术,它允许我们动态地创建代理对象,并赋予其与原对象相同的接口和行为。动态代理的应用场景非常广泛,比如:
- 日志记录: 可以使用动态代理来记录对象方法的调用。
- 性能监控: 可以使用动态代理来监控对象方法的执行时间。
- 安全: 可以使用动态代理来对对象方法进行访问控制。
- 事务: 可以使用动态代理来对对象方法进行事务管理。
基于JDK的动态代理
Java中基于JDK的动态代理,主要利用java.lang.reflect包下的Proxy类。Proxy类的newProxyInstance方法可以创建一个新的代理对象,该代理对象继承了java.lang.reflect.InvocationHandler接口。InvocationHandler接口有一个invoke方法,该方法会在代理对象的方法被调用时触发。
以下是一个基于JDK的动态代理的例子:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxyExample {
public static void main(String[] args) {
// 创建一个目标对象
Foo target = new Foo();
// 创建一个InvocationHandler对象
InvocationHandler handler = new MyInvocationHandler(target);
// 创建一个代理对象
Foo proxy = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[]{Foo.class}, handler);
// 调用代理对象的方法
proxy.foo();
}
// 定义一个接口
interface Foo {
void foo();
}
// 定义一个目标对象
static class FooImpl implements Foo {
@Override
public void foo() {
System.out.println("FooImpl.foo()");
}
}
// 定义一个InvocationHandler对象
static class MyInvocationHandler implements InvocationHandler {
private final Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("MyInvocationHandler.invoke()");
return method.invoke(target, args);
}
}
}
基于CGLIB的动态代理
Java中基于CGLIB的动态代理,主要利用CGLIB库。CGLIB是一个开源的Java库,它提供了动态创建类的功能。使用CGLIB可以动态地创建代理类,该代理类继承了目标类的所有方法。
以下是一个基于CGLIB的动态代理的例子:
import net.sf.cglib.proxy.Enhancer;
public class CglibProxyExample {
public static void main(String[] args) {
// 创建一个目标对象
Foo target = new Foo();
// 创建一个代理对象
Foo proxy = (Foo) Enhancer.create(Foo.class, new MyMethodInterceptor());
// 调用代理对象的方法
proxy.foo();
}
// 定义一个接口
interface Foo {
void foo();
}
// 定义一个目标对象
static class FooImpl implements Foo {
@Override
public void foo() {
System.out.println("FooImpl.foo()");
}
}
// 定义一个MethodInterceptor对象
static class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("MyMethodInterceptor.intercept()");
return method.invoke(obj, args);
}
}
}
基于JDK的动态代理与基于CGLIB的动态代理的对比
基于JDK的动态代理与基于CGLIB的动态代理各有优缺点。
基于JDK的动态代理的优点:
- 简单易用。
- 不需要修改目标类的代码。
基于JDK的动态代理的缺点:
- 只能代理实现了接口的类。
- 性能开销较大。
基于CGLIB的动态代理的优点:
- 可以代理任何类,包括没有实现接口的类。
- 性能开销较小。
基于CGLIB的动态代理的缺点:
- 需要修改目标类的字节码。
- 可能导致目标类的安全性降低。
结论
动态代理是一种非常重要的技术,它可以帮助我们动态地创建代理对象,并赋予其与原对象相同的接口和行为。Java中基于JDK的动态代理和基于CGLIB的动态代理都是非常常用的动态代理实现方式,它们各有优缺点。在实际开发中,我们可以根据具体情况选择合适的动态代理实现方式。