来源:https://www.jianshu.com/p/992dfcecff34
github:https://github.com/imhuster/DynamicProxy/blob/master/src/main/java/com/iqts/MyProxy.java
实现:动态生成的代理类的字节码(内存中 []byte),原理是继承Proxy 类,实现被代理类的所有接口生成动态代理类。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
final class $Proxy0 extends Proxy implements Subject {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void doOperation() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("proxy.jdk.Subject").getMethod("doOperation");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
除了实现了被代理类所有接口中的方法外,JDK 动态代理还重写了 Object 类中的 hashCode
、equals
、toString
三个方法。(注意在 invoke 方法中在代理类上调用它们会递归)
继承的 Proxy 类拥有 InvocationHandler
字段,通过代理类的构造器初始化;
重写的方法中,都会转向调用 super.h.invoke
问题:
动态生成的代理类需要继承 Proxy 类,而 Java 中只能单继承的限制使得被代理类必须实现接口才能实现动态代理
如果被代理的类没有实现接口就无法实现动态代理,这时候我们就需要使用第三方工具。
CGLib 可以在运行期扩展 Java 类及实现Java接口、提供方法的拦截,因此被众多 AOP 框架使用。CGLib 包的底层是通过使用字节码处理框架 ASM 来转换字节码并生成新的类。
原理:CGLib 是通过继承被代理类实现动态代理的,这也就要求被代理的类不能是 final 类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package proxy.cglib;
...
public class RealSubject$$EnhancerByCGLIB$$5fe030cf extends RealSubject implements Factory {
private MethodInterceptor CGLIB$CALLBACK_0;
private static final Method CGLIB$doOperation$0$Method;
private static final MethodProxy CGLIB$doOperation$0$Proxy;
...
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("proxy.cglib.RealSubject$$EnhancerByCGLIB$$5fe030cf");
Class var1;
CGLIB$doOperation$0$Method = ReflectUtils.findMethods(new String[]{"doOperation", "()V"}, (var1 = Class.forName("proxy.cglib.RealSubject")).getDeclaredMethods())[0];
CGLIB$doOperation$0$Proxy = MethodProxy.create(var1, var0, "()V", "doOperation", "CGLIB$doOperation$0");
...
}
final void CGLIB$doOperation$0() {
super.doOperation();
}
public final void doOperation() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$doOperation$0$Method, CGLIB$emptyArgs, CGLIB$doOperation$0$Proxy);
} else {
super.doOperation();
}
}
......
static {
CGLIB$STATICHOOK1();
}
}
CGLib 不仅重写了 Object 类的 hashCode
、equals
、toString
方法,还重写了 clone 方法。
代理的方法都对应两个具体的方法,例如 CGLIB$doOperation$0
和 doOperation
,后者是对被代理对象的重写方法,前者是调用父类的方法。因此在实现 MethodInterceptor
接口的 intercept 方法中:
methodProxy.invoke()
是对 doOperation
方法的调用(对于代理对象,就调用该重写方法,因此需要注意递归调用)methodProxy.invokeSuper()
是对 CGLIB$doOperation$0
方法的调用(必须是代理对象,该方法仅调用父类的 doOperation
方法,即目标对象的方法)。由于是继承实现,final 方法是不会代理的,只会调用父类的 final 方法。
CGLib 可以直接生成接口的代理对象,代理对重新接口中的方法,类似 JDK 动态代理;
^26a5aa
CGLib 可以实现 MethodInterceptor 接口与 InvocationHandler 接口(CGLib包中),使用 InvocationHandler 方式与 JDK 方式类似,并且代理的方法只对应一个具体的方法(代理类对父类的重写方法-同名)。
本文链接: Java动态代理
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
发布日期: 2022-11-11
最新构建: 2024-12-26
欢迎任何与文章内容相关并保持尊重的评论😊 !