✒️ 作者 - Lex 📝 博客 - 掘金 📚 源码地址 - github
JDK动态代理是一种在运行时生成代理类的机制,它基于接口实现,通过在代理类中重定向方法调用到实际对象,并提供了InvocationHandler接口来实现代理对象方法调用的处理逻辑,适用于AOP、远程方法调用等场景,能够在不修改原始类的情况下实现横切关注点的统一管理,提供更灵活和可维护的代码结构。
代理对象生成
接口实现
方法重定向
横切关注点的统一管理
AOP的实现
使用 JDK 动态代理的基本流程。首先,创建目标对象 MyService
的实例,然后获取目标对象的类信息。接着,通过调用 Proxy.newProxyInstance
方法创建代理对象,传入目标对象的类加载器、实现的接口以及调用处理器。最后,通过代理对象调用方法,实际上会调用 MyInvocationHandler
中的 invoke
方法来处理方法调用,并在方法执行前后添加额外的逻辑。
public class JdkProxyDemo {
public static void main(String[] args) {
// 创建目标对象
MyService target = new MyServiceImpl();
// 获取目标对象的类对象
Class clz = target.getClass();
// 创建代理对象,并指定目标对象的类加载器、实现的接口以及调用处理器
MyService proxyObject = (MyService) Proxy.newProxyInstance(clz.getClassLoader(), clz.getInterfaces(), new MyInvocationHandler(target));
// 打印代理对象的类信息
System.out.println("ProxyObject = " + proxyObject.getClass());
// 通过代理对象调用方法,实际上会调用 MyInvocationHandler 中的 invoke 方法
proxyObject.doSomething();
}
}
实现了 InvocationHandler
接口,定义了一个名为 MyInvocationHandler
的类。该类包含一个私有属性 target
,用于存储目标对象。构造函数接收一个目标对象作为参数,并将其存储在 target
属性中。在 invoke
方法中,会在目标方法执行前打印 "Before method execution",然后通过反射调用目标对象的方法,并获取方法的返回结果。最后,在目标方法执行后打印 "After method execution",并返回方法的结果。
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before method execution");
Object result = method.invoke(target, args);
System.out.println("After method execution");
return result;
}
}
定义了一个接口 MyService
,其中包含一个抽象方法 doSomething()
。然后,定义了一个实现了 MyService
接口的类 MyServiceImpl
,并实现了 doSomething()
方法。
public interface MyService {
void doSomething();
}
public class MyServiceImpl implements MyService {
@Override
public void doSomething() {
System.out.println("hello world");
}
}
运行结果,成功使用了 JDK 动态代理。首先打印了代理对象的类信息,确认了代理对象确实是由 $Proxy0
类生成的。接着,打印了 "Before method execution",表示方法执行前的逻辑已经被执行。然后调用了目标对象的 doSomething()
方法,输出了 "hello world"。最后打印了 "After method execution",表示方法执行后的逻辑也被执行了。这表明 JDK 动态代理成功地代理了目标对象的方法,并在方法执行前后执行了额外的逻辑。
ProxyObject = class com.sun.proxy.$Proxy0
Before method execution
hello world
After method execution
这段代码是通过 Arthas 工具反编译得到的结果。它是一个代理类,位于 com.sun.proxy
包下,命名为 $Proxy0
。该类继承自 Proxy
类,并实现了 MyService
接口。在 doSomething
方法中,通过 InvocationHandler
对象的 invoke
方法调用了目标对象的 doSomething
方法。在静态代码块中,获取了 java.lang.Object
类中的 equals
、hashCode
和 toString
方法,以及 MyService
接口中的 doSomething
方法的 Method
对象。
package com.sun.proxy;
import com.xcs.spring.MyService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements MyService {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler invocationHandler) {
super(invocationHandler);
}
public final void doSomething() {
try {
this.h.invoke(this, m3, null);
return;
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
// ... [toString代码部分省略以简化]
// ... [hashCode代码部分省略以简化]
// ... [equals代码部分省略以简化]
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.xcs.spring.MyService").getMethod("doSomething", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException noSuchMethodException) {
throw new NoSuchMethodError(noSuchMethodException.getMessage());
}
catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
}
代理对象的类型限制
无法代理 final 类和方法
无法代理静态方法
性能开销
泛型的处理
调用堆栈的可读性
InvocationHandler
,可能会增加调用堆栈的深度,降低代码的可读性和调试的便利性。此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。