前言
什么是代理?
为其他对象提供一个代理以控制对某个对象的访问。代理类主要负责为委托的目标对象(真实对象)的操作预处理、操作过滤、传递消息给委托类,代理类不现实具体服务,而是利用目标对象来完成服务,并将执行结果封装处理。
听起来比较绕,其实就是方法调用的时候不直接使用原有的类,而是使用一个代理类来执行,这个代理类可以在原有的类方法上执行更多的操作。
也可以说 代理是提供一种“一个类对另外一个类的控制权。”
静态代理
知道了代理 就是“一个类控制另外一个类”,增强被代理的类的功能
那么怎么进行代理?很简单就能想到创建一个代理类,然后用这个代理类持有被代理的类,调用时调用代理类的方法,代理类的被调用的方法中对请求进行过处理,然后再转发到被代理的类的真正的方法。
创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。
也就是说 代理对象 = 增强代码 + 目标对象(原对象)
接口:
public interface IDo {
void doAction();
}
被代理类:
public class Do implements IDo {
@Override
public void doAction() {
System.out.println("Hello World!");
}
}
代理类:
public class TheProxy implements IDo {
private IDo do= new Do();
@Override
public void doAction() {
System.out.println("Before invoke doAction" );
do.doAction();
System.out.println("After invoke doAction");
}
}
是不是很简单呢
复合优先于继承法则,复合类就是代理了代理类的方法。复合类通过持有一个代理类的引用,代理了代理类的方法,对被代理的类的功能进行了增强。
但是静态代理有个缺陷 那就是需要手动为每一个目标类编写对应的代理类
为什么需要动态代理?
如果现在有几个需求:在项目现有所有类的方法前后打印日志或者记录方法的调用时间
显然一个个的修改已有的代码是个费力不讨好的办法,那么肯定想到了使用代理的方法
不修改原有的代码,而是通过代理去执行增强的功能。
能使用静态代理吗?静态代理需要为手动为每一个目标类编写对应的代理类 当你的代码中的类数量很大时,这几乎是个不可能的任务。
所以,我们的需求其实是:如何少写或者不写代理类,却能完成代理功能?
此时就 需要动态代理了。
常见的动态代理场景
Spring的AOP 面向切面编程 通过动态代理实现对切面(也就是被代理类的方法)的增强
有些框架,比如Feign,Retrofit 可以在用户完全不写实现类,只需定义接口的情况下,还能调用接口中的方法,这就是通过动态代理在调用过程中动态的生成了被代理类
使用
JDK的原生动态代理机制
通过静态代理我们可知,代理的关键是创建代理类以代理目标对象的方法。那么动态代理的关键就是怎么自动化的,可控的创建需要的代理对象。
对象的创建
对象的创建,第一个就会想到使用new关键字+构造函数创建 A a=new A()
非常的容易,但是在给若干个未知类动态的创建代理类对象的时候,显然就不能使用new关键字去创造了,那么怎么办呢?
自然就想到创建对象的另一个方法,使用反射去创建对象。不写代理类,直接得到代理Class对象,然后根据它创建代理实例。
Class对象包含了一个类的所有信息,比如构造器、方法、字段等。如果我们不写代理类,这些信息从哪获取呢?JDK的原生动态代理机制要求代理类和目标对象实现相同的接口。之所以实现相同接口,是为了尽可能保证代理对象的内部结构和目标对象一致,这样我们对代理对象的操作最终都可以转移到目标对象身上,代理对象只需专注于增强代码的编写。
接口拥有代理对象和目标对象共同的方法信息。所以,我们可以从接口那得到理应由代理类提供的信息。
动态代理
JDK提供了java.lang.reflect.InvocationHandler
接口和 java.lang.reflect.Proxy
类,这两个类相互配合,入口是Proxy。
Proxy有一个静态方法
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
传入一个类加载器,一组接口,返回一个实现了所有传入接口的类,这个类就可以作为目标对象的代理类,因为它实现了所有和目标对象相同的接口。
先定义一个接口
public interface Developer {
void code();
void debug();
void comment() ;
}
再定义一个实现类
public class PhpDeveloper implements Developer {
@Override
public void code() {
System.out.println("dev php code");
}
@Override
public void debug() {
System.out.println("debug php code");
}
@Override
public void comment() {
System.out.println("PHP是世界上最好的语言!");
}
}
现在我们通过Proxy.getProxyClass
来代理这个PHPDeveloper对象
public class JavaReflect {
//主方法
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
JavaReflect reflect = new JavaReflect();
reflect.enCode();
}
public void enCode() throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
Developer phpDeveloper = new PhpDeveloper();
//反射从字节码生成Class
Class delegateDeveloperClass=Proxy.getProxyClass
(phpDeveloper.getClass().getClassLoader(),Developer.class);
//调用构造方法从Class创建对象 注意这里是使用了InvocationHandler接口创建自己的调用处理器 所以下面的构造方法需要传入一个InvocationHandler对象
Constructor<Developer> constructor=delegateDeveloperClass
.getConstructor(InvocationHandler.class);
//生成代理对象 传入一个InvocationHandler对象 InvocationHandler对象实际持有目标对象的引用
Developer phpDeveloperProxy=
constructor.newInstance(new InvocationHandler() {
//方法调用 每次调用代理对象的方法 实际上就是通过此方法桥接到目标对象的方法
@Override
public Object invoke
(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println(method.getName());
//执行目标对象的方法
return method.invoke(phpDeveloper ,args);
}
});
phpDeveloperProxy.code();
phpDeveloperProxy.debug();
phpDeveloperProxy.comment();
}
}
结果
code
dev php code
debug
debug php code
comment
PHP是世界上最好的语言!
到这里已经实现了动态代理,根据传入的对象自动生成一个代理类,执行代理方法。
无论现在系统有多少类,只要你把实例传进来,getProxy()都能给你返回对应的代理对象。
当然这个方法还是有点麻烦,需要创建类,获取构造方法,再从类构造方法创建对象,最后调用代理对象。所以JDK已经提供了一个更方便的方法Proxy.newProxyInstance()
而Proxy.getProxyClass
已经在JDK11被标记为@废弃
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
- loder,选用的类加载器。因为代理的是目标对象,所以一般都会用加载目标对象的类加载器。
- interfaces,被代理的类所实现的接口,这个接口可以是多个。
- h,调用处理器 用来绑定代理类的方法。
InvocationHandler调用处理器,作用就是,当代理对象的原本方法被调用的时候,会绑定执行一个方法,这个方法就是InvocationHandler里面定义的内容,同时会替代原本方法的结果返回。
new InvocationHandler() {
//方法调用 每次调用代理对象的方法 实际上就是通过此方法桥接到目标对象的方法
@Override
public Object invoke
(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println(method.getName());
//执行目标对象的方法
return method.invoke(phpDeveloper ,args);
}
}
InvocationHandler接收三个参数
- proxy,代理后的实例对象。
- method,对象被调用方法。
- args,调用时的参数。
使用Proxy.newProxyInstance()
进行动态代理
public void enCode() {
Developer developerProxy=(Developer) JavaReflect
.getProxy(new PhpDeveloper());
developerProxy.code();
developerProxy.debug();
developerProxy.comment();
}
private static Object getProxy(final Object target) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
(proxy, method, args) ->
{
System.out.println("方法前置处理");
Object object=method.invoke(target,args);
System.out.println("方法后置处理");
return object;
});
}
到这里,也明白了为什么使用JDK动态代理,被代理的目标对象必须实现接口,因为只有实现了接口,代理类才知道目标对象调用的方法,接口中没有的方法,代理类就无法执行。那有没有代理没有实现接口的类的办法呢?也是有的,就是使用cglib库代理。
使用CGLib进行动态代理
前面说了,有没有代理没有实现接口的类的办法呢?也是有的,就是使用CGLib库实现代理。因为JDK动态代理是基于接口的方式;而CGLib动态代理是代理类去继承目标类,然后重写其中目标类的方法啊,这样去保证代理类拥有目标类的同名方法的,需要生成代理类,所以叫Code Generation Library(代码生成库)。
正是由于CGLib可以代理未实现接口的类,所以功能显然比JDK动态代理要强大,所以很多地方都会用到这个库去实现代理。
CGLib的使用
和JDK动态代理不同,作为一个外部库,CGLib需要引入依赖。
使用Gradle引入CGLib 3.3依赖
dependencies {
implementation group: 'cglib', name: 'cglib', version: '3.3.0'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
编写一个目标类,作为被代理的对象
作为CGLib的代理目标对象,不需要实现接口
public class JavaDeveloper {
public void code() {
System.out.println("dev javacode");
}
public void debug() {
System.out.println("debug java code");
}
public void comment() {
System.out.println("Java是一种主流的,有些啰嗦和臃肿的语言.");
}
}
编写一个本地拦截器LocalMethodInterceptor
实现对目标对象的方法调用时拦截 并进行增强
这个的作用就等于JDK动态代理的InvocationHandler
public class LocalMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("进入本地拦截器 前置处理");
Object result = proxy.invokeSuper(obj, args);
System.out.println("退出本地拦截器 后置处理");
return result;
}
}
进行动态代理
/*
DebuggingClassWriter 这个类时用来生成代理类的
所以设置其属性以指定生成动态代理类的存放目录
*/
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, ".\\build\\classes");
//创建Enhancer对象,类似于JDK动态代理的Proxy类
Enhancer enhancer = new Enhancer();
//设置目标类的字节码文件
enhancer.setSuperclass(JavaDeveloper.class);
//设置回调函数
enhancer.setCallback(new LocalMethodInterceptor());
//这里的creat方法就是正式创建代理类
JavaDeveloper proxyDev = (JavaDeveloper)enhancer.create();
//调用代理类的方法
proxyDev.code();
proxyDev.debug();
proxyDev.comment();
结果
进入本地拦截器 前置处理
dev java code
退出本地拦截器 后置处理
进入本地拦截器 前置处理
debug java code
退出本地拦截器 后置处理
进入本地拦截器 前置处理
Java是一种主流的,有些啰嗦和臃肿的语言.
退出本地拦截器 后置处理
到这里就完成对一个目标对象的静态代理了,可以看出,不是很复杂。
只要传入一个目标对象的类属性,设置好要增强的拦截器,就可以对一个类进行动态增强了。
原理解析
生成代理类时,CGLib底层使用了ASM字节码生成库来操作字节码,ASM编织完字节码后,CGLib上层使用字节码来生成新的类。ASM使用类似SAX的解析器来实现高性能的生成字节码,一般情况下我们不需要去直接使用ASM,因为使用它需要对Java字节码的格式足够的了解。
在Java 8之前的JDK动态代理,使用反射的方式去生成代理类,性能相比CGLib有些差距,但是Java 8以来,JDK也改用编织字节码的方式来生成代理类,两者的性能已经所差无几。所以使用CGLib更看重的是其提供了对未实现接口的类代理功能。
查看一下设置的代码生成目录,可以找到生成的代理类
可以看到生成了三个相关代理类
一个是代理类 JavaDeveloper$$EnhancerByCGLIB$$e3631778
带有增强(Enhance)标志的是代理类
剩下两个一个是代理类的FastClass 另一个是目标对象的FastClass
FastClass是快速访问方法类 可以理解为代理方法的索引 详情后面再解释
打开代理类 JavaDeveloper$$EnhancerByCGLIB$$e3631778.class
Idea有反编译机制 可以直接看到源码
public class JavaDeveloper$$EnhancerByCGLIB$$e3631778 extends JavaDeveloper implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$debug$0$Method;
private static final MethodProxy CGLIB$debug$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$comment$1$Method;
private static final MethodProxy CGLIB$comment$1$Proxy;
private static final Method CGLIB$code$2$Method;
private static final MethodProxy CGLIB$code$2$Proxy;
private static final Method CGLIB$equals$3$Method;
private static final MethodProxy CGLIB$equals$3$Proxy;
private static final Method CGLIB$toString$4$Method;
private static final MethodProxy CGLIB$toString$4$Proxy;
private static final Method CGLIB$hashCode$5$Method;
private static final MethodProxy CGLIB$hashCode$5$Proxy;
private static final Method CGLIB$clone$6$Method;
private static final MethodProxy CGLIB$clone$6$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("or.g.dyj.kotlin.learn.JavaDeveloper$$EnhancerByCGLIB$$e3631778");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"debug", "()V", "comment", "()V", "code", "()V"}, (var1 = Class.forName("or.g.dyj.kotlin.learn.JavaDeveloper")).getDeclaredMethods());
CGLIB$debug$0$Method = var10000[0];
CGLIB$debug$0$Proxy = MethodProxy.create(var1, var0, "()V", "debug", "CGLIB$debug$0");
CGLIB$comment$1$Method = var10000[1];
CGLIB$comment$1$Proxy = MethodProxy.create(var1, var0, "()V", "comment", "CGLIB$comment$1");
CGLIB$code$2$Method = var10000[2];
CGLIB$code$2$Proxy = MethodProxy.create(var1, var0, "()V", "code", "CGLIB$code$2");
var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$3$Method = var10000[0];
CGLIB$equals$3$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$3");
CGLIB$toString$4$Method = var10000[1];
CGLIB$toString$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$4");
CGLIB$hashCode$5$Method = var10000[2];
CGLIB$hashCode$5$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$5");
CGLIB$clone$6$Method = var10000[3];
CGLIB$clone$6$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$6");
}
final void CGLIB$debug$0() {
super.debug();
}
public final void debug() {
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$debug$0$Method, CGLIB$emptyArgs, CGLIB$debug$0$Proxy);
} else {
super.debug();
}
}
final void CGLIB$comment$1() {
super.comment();
}
public final void comment() {
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$comment$1$Method, CGLIB$emptyArgs, CGLIB$comment$1$Proxy);
} else {
super.comment();
}
}
final void CGLIB$code$2() {
super.code();
}
public final void code() {
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$code$2$Method, CGLIB$emptyArgs, CGLIB$code$2$Proxy);
} else {
super.code();
}
}
final boolean CGLIB$equals$3(Object var1) {
return super.equals(var1);
}
public final boolean equals(Object var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var2 = var10000.intercept(this, CGLIB$equals$3$Method, new Object[]{var1}, CGLIB$equals$3$Proxy);
return var2 == null ? false : (Boolean)var2;
} else {
return super.equals(var1);
}
}
final String CGLIB$toString$4() {
return super.toString();
}
public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$4$Method, CGLIB$emptyArgs, CGLIB$toString$4$Proxy) : super.toString();
}
final int CGLIB$hashCode$5() {
return super.hashCode();
}
public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$hashCode$5$Method, CGLIB$emptyArgs, CGLIB$hashCode$5$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.hashCode();
}
}
final Object CGLIB$clone$6() throws CloneNotSupportedException {
return super.clone();
}
protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? var10000.intercept(this, CGLIB$clone$6$Method, CGLIB$emptyArgs, CGLIB$clone$6$Proxy) : super.clone();
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$6$Proxy;
}
break;
case 547749954:
if (var10000.equals("debug()V")) {
return CGLIB$debug$0$Proxy;
}
break;
case 899095734:
if (var10000.equals("comment()V")) {
return CGLIB$comment$1$Proxy;
}
break;
case 941787752:
if (var10000.equals("code()V")) {
return CGLIB$code$2$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$3$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$4$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$5$Proxy;
}
}
return null;
}
public JavaDeveloper$$EnhancerByCGLIB$$e3631778() {
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
JavaDeveloper$$EnhancerByCGLIB$$e3631778 var1 = (JavaDeveloper$$EnhancerByCGLIB$$e3631778)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
JavaDeveloper$$EnhancerByCGLIB$$e3631778 var10000 = new JavaDeveloper$$EnhancerByCGLIB$$e3631778();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
JavaDeveloper$$EnhancerByCGLIB$$e3631778 var10000 = new JavaDeveloper$$EnhancerByCGLIB$$e3631778();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
JavaDeveloper$$EnhancerByCGLIB$$e3631778 var10000 = new JavaDeveloper$$EnhancerByCGLIB$$e3631778;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}
public Callback getCallback(int var1) {
CGLIB$BIND_CALLBACKS(this);
MethodInterceptor var10000;
switch(var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
default:
var10000 = null;
}
return var10000;
}
public void setCallback(int var1, Callback var2) {
switch(var1) {
case 0:
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
default:
}
}
public Callback[] getCallbacks() {
CGLIB$BIND_CALLBACKS(this);
return new Callback[]{this.CGLIB$CALLBACK_0};
}
public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
}
static {
CGLIB$STATICHOOK1();
}
}
以code()方法为例,发现代理类中有code()
方法,还有CGLIB$code$2$Proxy
这个代理方法
CGLIB$code$2$Proxy
这个代理方法代理了什么呢?
是由MethodProxy方法代理创建的CGLIB$code$2()
这个方法的索引(为什么这样创建后面再说)
而CGLIB$code$2()
方法就是调用的super.code()
代理类继承了目标对象,所以super.code()
调用的就是JavaDeveloper.code()
方法
CGLIB$code$2$Proxy = MethodProxy.create(var1, var0, "()V", "code", "CGLIB$code$2");
final void CGLIB$code$2() {
super.code();
}
三个方法代理索引 可以看出是按照字母顺序排列 命令原理就是 CGLIB$方法名$排序号$Proxy
这么个模式
这样一看是不是就很清楚了,这种奇怪的名字也不难理解了
private static final MethodProxy CGLIB$debug$0$Proxy;
private static final MethodProxy CGLIB$comment$1$Proxy;
private static final MethodProxy CGLIB$code$2$Proxy;
方法代理索引CGLIB$xxx$2$Proxy
,方法引用CGLIB$xxx$数字
都是这样命名的。
看一下code方法的详情
public final void code() {
//方法拦截器的引用
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$code$2$Method, CGLIB$emptyArgs, CGLIB$code$2$Proxy);
} else {
super.code();
}
}
存在方法拦截器的情况下 代理类会调用方法拦截器去执行目标对象的方法,向拦截器传入三个参数
分别是代理类方法,执行时的入参,代理的目标对象的方法。
看了以上这些后,可以发现代理类中主要有这几部分:
- 1.重写的父类方法 就是目标对象的真实方法
- 2.
CGLIB$debug$0
,CGLIB$comment$1
,CGLIB$code$2
这种目标对象方法的引用 - 3.
CGLIB$debug$0$Proxy
,CGLIB$comment$1Proxy
,CGLIB$code$2Proxy
这种目标对象方法的索引 - 4.Interceptor() 拦截器方法,
- 5.newInstance和get/setCallback方法
这样子代理类已经解析完毕了
那FastClass快速方法类是干什么的?竟然还有两个。
这其实是CGLib的一种索引机制,称为FastClass机制。
为什么要用这种机制呢?因为相比直接使用反射来调用方法,性能较差,
所以CGLib库选择了FastClass机制来实现高性能的代理调用。
我们从一开始梳理下调用链
首先找到调用部分
JavaDeveloper proxyDev = (JavaDeveloper)enhancer.create();
//调用代理类的方法
proxyDev.code();
从前面知识可知 proxyDev 就是代理类 继承了JavaDeveloper类
可以看到proxyDevd的实际类型就是生成的代理类 JavaDeveloper$$EnhancerByCGLIB$$e3631778
之前解读过代理类的源码 知道执行代理的方法时 如果存在拦截器 则先执行拦截器
就是之前写的拦截器切面增强方法
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("进入本地拦截器 前置处理");
//proxy.invokeSuper中调用了FastClass的索引方法
Object result = proxy.invokeSuper(obj, args);
System.out.println("退出本地拦截器 后置处理");
return result;
}
刚才的代码生成中,生成了两个FastClass类
目标对象的FastClass JavaDeveloper$$FastClassByCGLIB$$987a353c
代理类的FastClass JavaDeveloper$$EnhancerByCGLIB$$e3631778$$FastClassByCGLIB$$b4a5b8bc
但是 在代理类中却找不到调用的地方 那么是在哪里调用的呢?
回到本地方法拦截器中的代理执行语句
Object result = proxy.invokeSuper(obj, args);
调用的是MethodProxy的invokeSuper方法
此时就能找到 实际调用FastClass的地方了
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
在此处打断点,执行一下,执行时的FastClass是 JavaDeveloper$$EnhancerByCGLIB$$e3631778$$FastClassByCGLIB$$b4a5b8bc
那这个FastClass是在init()
方法中被赋值的
我们看一下init()
方法
private void init()
{
/**
这里使用个带锁的双重检测单例法
*/
if (fastClassInfo == null)
{
synchronized (initLock)
{
if (fastClassInfo == null)
{
CreateInfo ci = createInfo;
FastClassInfo fci = new FastClassInfo();
fc1就是目标对象FastClass fc2就是代理对象的FastClass
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
这里就是通过索引获取真实调用的方法 sig1="code()V" sig2="CGLIB$code$2()V"
所以fci.i1就是目标对象方法的索引 fci.i2 就是代理对象方法的索引
fci.i1 = fci.f1.getIndex(sig1);
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}
我们看下代理对象的获取索引方法
Signature var1就是方法签名 code方法传入的方法签名是code()V
public int getIndex(Signature var1) {
String var10000 = var1.toString();
传入签名方法进行散列 然后根据散列值去匹配索引 code方法的索引是15
switch(var10000.hashCode()) {
case -2128373160:
if (var10000.equals("CGLIB$debug$1()V")) {
return 10;
}
break;
case -2071771415:
if (var10000.equals("CGLIB$clone$6()Ljava/lang/Object;")) {
return 8;
}
break;
case -2055565910:
if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 4;
}
break;
case -1663710620:
if (var10000.equals("CGLIB$equals$3(Ljava/lang/Object;)Z")) {
return 13;
}
break;
case -1606711239:
if (var10000.equals("CGLIB$code$0()V")) {
return 6;
}
break;
case -1457535688:
if (var10000.equals("CGLIB$STATICHOOK1()V")) {
return 9;
}
break;
case -1411783143:
if (var10000.equals("CGLIB$hashCode$5()I")) {
return 7;
}
break;
case -894172689:
if (var10000.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 20;
}
break;
case -623122092:
if (var10000.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) {
return 14;
}
break;
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return 19;
}
break;
case -419626537:
if (var10000.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) {
return 0;
}
break;
case 547749954:
if (var10000.equals("debug()V")) {
return 23;
}
break;
case 560567118:
if (var10000.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) {
return 3;
}
break;
case 811063227:
if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 21;
}
break;
case 899095734:
if (var10000.equals("comment()V")) {
return 24;
}
break;
case 941787752:
if (var10000.equals("code()V")) {
return 15;
}
break;
case 973717575:
if (var10000.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) {
return 1;
}
break;
case 1221173700:
if (var10000.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 22;
}
break;
case 1230699260:
if (var10000.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) {
return 2;
}
break;
case 1506978155:
if (var10000.equals("CGLIB$comment$2()V")) {
return 11;
}
break;
case 1584330438:
if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 5;
}
break;
case 1729170762:
if (var10000.equals("CGLIB$toString$4()Ljava/lang/String;")) {
return 12;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return 16;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return 17;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return 18;
}
}
return -1;
}
此时fci.i2=23 然后执行invoke()
方法下面 我们来看下代理类的FastClass 的invoke方法是什么
应该是code()
方法
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
e3631778 var10000 = (e3631778)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
return new Boolean(var10000.equals(var3[0]));
case 1:
return var10000.toString();
case 2:
return new Integer(var10000.hashCode());
case 3:
return var10000.clone();
case 4:
return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
case 5:
return var10000.newInstance((Callback[])var3[0]);
case 6:
return var10000.newInstance((Callback)var3[0]);
case 7:
var10000.debug();
return null;
case 8:
var10000.comment();
return null;
case 9:
var10000.code();
return null;
case 10:
var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
return null;
case 11:
e3631778.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
return null;
case 12:
e3631778.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
return null;
case 13:
var10000.setCallbacks((Callback[])var3[0]);
return null;
case 14:
return var10000.getCallbacks();
case 15:
return var10000.getCallback(((Number)var3[0]).intValue());
case 16:
return var10000.CGLIB$toString$4();
case 17:
var10000.CGLIB$comment$1();
return null;
case 18:
e3631778.CGLIB$STATICHOOK1();
return null;
case 19:
return new Boolean(var10000.CGLIB$equals$3(var3[0]));
case 20:
var10000.CGLIB$debug$0();
return null;
case 21:
return new Integer(var10000.CGLIB$hashCode$5());
case 22:
return var10000.CGLIB$clone$6();
case 23:
var10000.CGLIB$code$2();
return null;
case 24:
return e3631778.CGLIB$findMethodProxy((Signature)var3[0]);
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
上面说 fc.i2=23 ,那么此时执行的就是case 23;也就是var10000.CGLIB$code$2()
;
var10000就是代理类e36178,所以此时就在执行代理类的CGLIB$code$2()
方法
上面说过 CGLIB$code$2()
方法就是调用的super.code()
代理类继承了目标对象,所以super.code()调用的就是JavaDeveloper.code()方法
此时就调用到了目标对象的方法
综上,就是这样一个调用链
我们调用代理类门面的代理方法,比如proxyDev.code()
实际执行的是代理类JavaDeveloper$$EnhancerByCGLIB$$e3631778.code()
方法
而JavaDeveloper$$EnhancerByCGLIB$$e3631778.code()
方法又通过调用
本地拦截器LocalMethodInterceptor
执行方法增强,本地方法拦截器通过方法代理
MethodProxy.invokeSuper()
方法去匹配真正要执行的目标对象方法
而目标对象方法的引用保持在代理类JavaDeveloper$$EnhancerByCGLIB$$e3631778.code()
中
通过向FastClass对象JavaDeveloper$$EnhancerByCGLIB$$e3631778$$FastClassByCGLIB$$b4a5b8bc
传入hash索引 匹配到真正的目标对象方法