代理
代理模式
代理模式是一种结构型设计模式,概念为通过一个代理对象来控制对原始对象的访问,代理对象通常表现出的行为与原始对象一致(实现同一接口)以便于可以在使用原始对象的地方代替原始对象。使用代理模式一般用来保护以及增强原始对象。
静态代理与动态代理
编译期间就确定好了代理类与被代理类为静态代理,其中代理类与被代理类会实现同一个接口,代理类持有被代理类,代理类可以调用被代理类方法并添加逻辑。
动态代理的代理类是运行期间动态生成的,其他地方与静态代理相同。很显然在被代理类很多时使用动态代理可以节省代码且方便修改逻辑。
静态代理一般来说效率稍高,但是代码冗余大,不便于修改。
动态代理一般使用 jdk 动态代理和 cglib 动态代理。
jdk 动态代理
jdk 动态代理是基于实现接口的方式,代理类是动态生成的和被代理类实现同一接口且持有被代理类实例的类。
很显然 jdk 动态代理是代理不了接口中没有的方法的。
jdk 动态代理基于反射,代理类与被代理类是委托关系,使用 Proxy 生成字节码文件。
涉及到以下几个类和接口
InvocationHandler 接口
动态代理类需要实现这个接口且持有被代理类实例,通过代理对象调用一个方法时,这个方法的调用会被转发由这个接口的 invoke 方法来进行调用
java
// InvocationHandler 唯一的接口
Object invoke(Object proxy, Method method, Object[] args)throws Throwable
参数说明:
- proxy - 被代理类实例
- method - 被代理类的某个方法的 Method 对象
- args - 调用被代理类某个方法时需要的参数列表
Proxy 类
Proxy 这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,用的最多的就是 newProxyInstance 方法:
java
//得到一个动态的代理对象
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
参数说明:
- loader - 一个 ClassLoader 对象,定义了由哪个 ClassLoader 对象来对生成的代理对象进行加载
- interfaces - 一个接口对象的数组,表示代理对象需要实现的接口
- h - 一个 InvocationHandler 对象,表示代理对象调用方法时需要关联的 InvocationHandler 对象
动态生成的类
只会生成一个类,这是其反编译后的代码示例
java
//继承了java.lang.reflect.Proxy,实现了被代理类的接口
public 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) {
//使用父类的构造方法
super(var1);
}
...
public final void deal() {
try {
//调用InvocationHandler的invoke方法
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
...
static {
try {
//Object的equals方法
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
//Object的toString方法
m2 = Class.forName("java.lang.Object").getMethod("toString");
//被代理类的接口中的方法,如果接口中有多个方法会往后延
m3 = Class.forName("动态代理.jdk动态代理.Subject").getMethod("deal");
//Object的hashCode方法
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
其调用关系为
调用方 -> 动态生成的代理类的对应方法 -> 拦截器的 invoke 方法 -> 被代理类的对应方法
cglib 动态代理
cglib 动态代理是基于继承的方式,代理类是动态生成的继承了被代理类的类,使用重写方法的方式实现增强。
由于 cglib 动态代理是基于继承的,因此代理不了私有方法、final 方法、静态方法和构造方法,以及被声明为 final 的类。
cglib 动态代理基于FastClass方法索引,第一次调用需要生成 Class 对象较慢,代理类与被代理类是继承关系,使用ASM框架生成字节码文件。
MethodInterceptor
拦截器需要实现的接口,通过代理对象调用一个方法时,这个方法的调用会被转发由这个接口的 intercept 方法来进行调用
java
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable
参数说明:
- o - 代理类
- method - 被代理的方法
- args - 调用时的参数
- methodProxy - 方法的代理类
FastClass
索引类,其中有两个主要的方法
- getIndex - 获取目标的编号;索引类记录了目标方法与编号之间的对应关系,传递方法签名信息并返回对应编号
- invoke - 根据方法编号,调用目标方法;三个参数分别代表
- index - 方法编号
- target - 目标对象
- args - 方法执行所需参数
java
//代理类的FastClass
public class RealSubject$$FastClassByCGLIB$$b86fb30b extends FastClass {
public RealSubject$$FastClassByCGLIB$$b86fb30b(Class var1) {
super(var1);
}
//根据方法的签名获取对应的索引
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case 1540437897:
if (var10000.equals("deal()V")) {
return 0;
}
break;
...
}
return -1;
}
...
//根据方法索引调用被索引类的对应方法
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
RealSubject var10000 = (RealSubject)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
var10000.deal();
return null;
...
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
...
}
MethodProxy
在代理类初始化时被创建
java
public class RealSubject$$EnhancerByCGLIB$$679604bd extends RealSubject implements Factory {
...
private static Method CGLIB$deal$0$Method;
private static MethodProxy CGLIB$deal$0$Proxy;
...
static void CGLIB$STATICHOOK1() throws ClassNotFoundException {
...
CGLIB$deal$0$Method = ReflectUtils.findMethods(new String[]{"deal", "()V"}, (var1 = Class.forName("动态代理.cglib动态代理.RealSubject")).getDeclaredMethods())[0];
//关联了代理的方法与被代理的方法
CGLIB$deal$0$Proxy = MethodProxy.create(var1, var0, "()V", "deal", "CGLIB$deal$0");
}
static {
try {
CGLIB$STATICHOOK1();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
在 invoke 或者 invokeSuper 方法调用时被初始化
java
public class MethodProxy {
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
//初始化
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
} catch (IllegalArgumentException var5) {
if (this.fastClassInfo.i1 < 0) {
throw new IllegalArgumentException("Protected method: " + this.sig1);
} else {
throw var5;
}
}
}
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
//初始化
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}
private void init() {
//如果没有初始化的话
if (this.fastClassInfo == null) {
synchronized(this.initLock) {
if (this.fastClassInfo == null) {
MethodProxy.CreateInfo ci = this.createInfo;
MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
//获取代理类和被代理类的索引类,其中f1是被代理类的索引类,f2是代理类的索引类
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
//类似的,i1是被代理方法的索引值,i2是代理类的索引值
fci.i1 = fci.f1.getIndex(this.sig1);
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
}
动态生成的类
会生成三个类,分别是代理类、代理类的索引类、被代理类的索引类
java
//动态生成的代理类
public class RealSubject$$EnhancerByCGLIB$$679604bd extends RealSubject implements Factory {
...
//直接调用被代理方法的方法
final void CGLIB$deal$0() {
super.deal();
}
//重写的被代理类的方法
public final void deal() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
try {
//调用拦截器的intercept方法
var10000.intercept(this, CGLIB$deal$0$Method, CGLIB$emptyArgs, CGLIB$deal$0$Proxy);
} catch (Throwable e) {
e.printStackTrace();
}
} else {
super.deal();
}
}
...
}
//代理类的FastClass
public class RealSubject$$EnhancerByCGLIB$$679604bd$$FastClassByCGLIB$$d3b917bf extends FastClass {
...
}
//代理类的FastClass
public class RealSubject$$FastClassByCGLIB$$b86fb30b extends FastClass {
}
其调用关系为
调用方 -> 动态生成的代理类的对应方法的重载 -> 自定义的拦截器的 intercept 方法 -> 代理类索引类的 invoke 方法 -> 动态生成的代理类的直接调用父类对应方法的实现 -> 被代理类
调用方 代理类 拦截器 MethodProxy 代理类索引类 被代理类 业务方法() 1. intercept() 2. 前置拦截 3. invokeSuper() 4. getIndex() 5. 返回方法索引 6. invoke() 7. CGLIB业务方法?() 8. 业务方法 9. 返回 10. 返回 11. 返回 12. 返回 13. 后置拦截 14. 返回 15. 返回 调用方 代理类 拦截器 MethodProxy 代理类索引类 被代理类