cglib创建代理对象
还是从一个的小demo开始
例子
-
被代理的类
public class Bean{ public String sayHello(String name) { return "Bean.sayHello"; } private String privateSayHello(String name){ return "Bean.privateSayHello"; } public String lipu1(){ return "lipu"; } private String privateLipu1(){ return "privateLipu1"; } public String jump(){ return "jump"; } private String privateJump(){ return "privateJump"; } public String hhhh(){ return "hhhh"; } private String privateHhhh(){ return "hhhh"; } public String dadada(){ return "dadada"; } private String privateDadada(){ return "privateDadada"; } public String lululu(){ return "lululu"; } private String privateLululu(){ return "privateLululu"; }}
-
主测试类
public class SampleTest { public static void main(String[] args) { // 保存生成的class的路径,对应的代码在DebuggingClassWriter#DEBUG_LOCATION_PROPERTY字段,toByteArray方法 System.getProperties().setProperty("cglib.debugLocation","C:\\Users\\Administrator\\Desktop\\temp"); Enhancer enhancer = new Enhancer(); final Bean bean = new Bean(); enhancer.setSuperclass(Bean.class); // 下面的这些都是Callback,这些Callback是通过CallbackFilter来指定的。 Dispatcher dispatcher = new Dispatcher() { @Override public Object loadObject() throws Exception { System.out.println("SampleTest.loadObject"); return bean; } }; MethodInterceptor methodInterceptor = new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("SampleTest.intercept"); return "SampleTest.intercept"; } }; InvocationHandler invocationHandler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("SampleTest.invoke"); return "SampleTest.invoke"; } }; LazyLoader lazyLoader = new LazyLoader() { @Override public Object loadObject() throws Exception { System.out.println("SampleTest.loadObject"); return bean; } }; FixedValue fixedValue = new FixedValue() { @Override public Object loadObject() throws Exception { System.out.println("SampleTest.loadObject"); return bean; } }; ProxyRefDispatcher proxyRefDispatcher = new ProxyRefDispatcher() { @Override public Object loadObject(Object proxy) throws Exception { return bean; } }; Callback[] callbacks = { dispatcher, methodInterceptor, invocationHandler, lazyLoader, fixedValue, NoOp.INSTANCE, proxyRefDispatcher }; // 通过方法的名字来指定那个callback起作用 CallbackFilter callbackFilter = new CallbackFilter() { @Override public int accept(Method method) { System.out.println("SampleTest.accept:" + method.getName()); switch (method.getName()){ case "sayHello": return 0; case "lipu1": return 1; case "jump": return 2; case "hhhh": return 3; case "dadada": return 4; case "lululu": // 如果是 NoOp.INSTANCE表示不需要代理,在生成的代理类里面没有操作,也就是代理类不会重写父类的方法 return 5; case "sasasasa": return 6; } return 0; } }; enhancer.setCallbacks(callbacks); enhancer.setCallbackFilter(callbackFilter); Bean o = (Bean) enhancer.create(); String test = o.sayHello("test"); System.out.println(test); } }
概念解释
这里只是将正常使用的时候的两种常见的类型做解释,其余和Cglib有比较重要的概念在之后说
Callback
先看类图
关于各个的实现类的功能,已经在各个类的注释上说清楚了。可能有的意思还是不太懂,在本文的最后一节里面,贴出了生成的代理类,对比代理类,看看不同的Callback的子类的作用,就很清晰了。
子类解释
- MethodInterceptor:回调,可以通过MethodProxy调用父类,或者同一个类型的Bean的同名方法
- NoOp:什么都不做
- LazyLoader:懒加载,但是加载过之后,就不加载了。
- Dispatcher:做分派,每次都会调用。通过它返回的Bean来做同名方法的调用
- InvocationHandler:这就和JDK的一样,和MethodInterceptor不一样的是,它没有MethodProxy
- FixedValue:固定值。
CallbackFilter
在生成代理类的时候,代理类会重写父类的方法,在重写父类方法的时候,会通过它来判断要用哪个Callback。
accept
方法返回的是Callback数组中的下标。在构建代理类的时候,就会使用Callback数组对应下标中的Callback。
public interface CallbackFilter {
int accept(Method method);
boolean equals(Object o);
}
在生成代理类的时候,代理类会重写父类的方法,在重写父类方法的时候,会通过它来判断要用哪个Callback。对应于(Enhancer#emitMethods,在这个方法里面有int index = filter.accept(actualMethod);
代码)
如果传递的Callback多于一个,并且没有指定CallbackFilter的话,就会报错,如果CallBack就一个,它会给一个默认的CallbackFilter,总是返回0。(Enhancer#preValidate做判断,并且给默认值。)
这是和JDK-Proxy不同的一点,在JDK-Proxy是不能支持多个InvocationHandler,但是Cglib是可以的
这篇文章不具体的分析CGLIB创建代理对象的操作。旨在说清楚Callback子接口的作用,还有CallBackFilter。还有生成的代理类长什么样?
代理类
代理类的创建和生成是在内存里面的,不过可以通过配置,让生成的类保存起来,便于观察。通过下面的代码开启
System.getProperties().setProperty("cglib.debugLocation","C:\\Users\\Administrator\\Desktop\\temp");
在运行上面的例子之后,就会在指定的文件夹下面生成几个class文件
将生成的文件直接拖入Idea,idea会反编译。便于我们观察
代码比较多,详细的解释写在注释里面,这里会对这个类来做一些简单的说明:
-
在代理类里面保留callback子接口的引用关系,在不同的方法里面用不同的callback。
-
private方法是不能被代理对象重写的, 可以看到上面例子里面private开头的方法,都没有被重写。
-
如果给一个方法指定的callback类型是
NoOp.INSTANCE
,那这个方法可能是不会被代理类重写的(可以看到,上面例子中lululu方法并没有被重写),这里说可能的意思是NoOp也有NoOpGenerator,具体的代码逻辑在NoOpGenerator#generate。它要求满足下面才可以重写。
看这个代码逻辑,有两个问题,
- Method有区分,OriginalMethod和Method有什么区别?
- OriginalMethod为public,代理的方法为Public是什么样的场景?
具体在后面分析
- 所有通过Enhancer生成的代理类都实现了
Factory
接口
通过这个接口可以很快的创建代理类(很快的意思是,如果要创建一个和当前代理类在同样的方法用同样的callback类型,但是行为不一样,创建起来比较快,因为直接new 对象就好了,但是如果要通过Enhancer来做的,就比较慢了,快就快在这里了,如果用Enhancer来做,起码要在内存里面编织字节码,这一点就比较慢了)只要指定Callback就可以创建代理类,可以动态的修改Callback(也就是可以动态的修改行为),还可以获取Callback。
-
equals
,toString
,hashCode
,clone
也会走callbackFilter的逻辑,但是这里要注意了,对于protected修饰的方法,不同的CallbackGenerator有不同的要求DispatcherGenerator:不支持重写(DispatcherGenerator#generate方法里面有
if (!TypeUtils.isProtected(method.getModifiers()))
判断)FixedValueGenerator:支持(FixedValueGenerator#generate方法里面没有类似上面的判断)
InvocationHandlerGenerator:支持(InvocationHandlerGenerator#generate,没有类似上面的判断)
LazyLoaderGenerator:不支持(LazyLoaderGenerator#generate,
TypeUtils.isProtected(method.getModifiers())
)MethodInterceptorGenerator:支持(MethodInterceptorGenerator#generate)
NoOpGenerator:不支持(NoOpGenerator#generate)
-
MethodInterceptor 应用的方法比较特殊,和普通的不一样
- 属性中多了一个MethodProxy的引用,并且还多了一个以CGLIB开头,中间是方法名字,后面是Proxy结尾的方法,在这个方法里面直接调用了父类的方法。
-
多的这个方法有什么用?创建的MethodProxy有什么用?
创建的MethodProxy是要通过MethodInterceptor传递的,我们在日常用的时候可以直接调用MethodProxy的invokeSuper,来调用父类(被代理的类)的方法。
这个操作就会调用到多出来的这个方法(对比到上图中就是GLIB$lipu1$2方法)。首先调用super肯定不能直接调用到lipu1方法。如果调用到,就陷入到循环里面了。这就像在JDK-proxy的时候,在InvocationHandler里面通过第一个参数(proxy)来做调用会导致栈溢出,因为陷入到无限套娃里面了。
所以,就得单独搞一个方法,不要走MethodInterceptor的拦截操作。就不会有栈溢出的问题了。
此外,MethodProxy还有别的作用,可以通过MethodProxy来调用指定对象的目标方法(对应的就是invoke(Object,Object[]))方法。在利用MethodProxy做调用的时候,这个过程还会生成两个代理类。通过这两代理类做调用。
-
MethodProxy解释
方法和属性都在上面展示了,这里说几个问题
-
代理对象中的MethodProxy赋值操作
具体的代码在MethodInterceptorGenerator#generate里面。会在代理类里面静态的引用,在静态代码块里面会通过
MethodProxy#create(Class c1, Class c2, String desc, String name1, String name2)
来创建。方法的参数从左到右为,被代理类对象,代理类对象,方法签名(方法参数,返回值等等),属于被代理对象方法签名一样的方法名称,属于代理对象方法签名一样的方法名称。现在看起来有点模糊,在之后的文章里面会详细的解释清楚的。
-
在通过MethodProxy来调用方法的时候,也会创建动态的创建两个类。
具体的代码在
MethodProxy#
helper方里面。在每次调用MethodProxy的invoke或者invokeSuper的时候,都会调用init方法,init方法里面会调用到helper方法。在这里面会创建一个类。private static FastClass helper(CreateInfo ci, Class type) { FastClass.Generator g = new FastClass.Generator(); g.setType(type); g.setClassLoader(ci.c2.getClassLoader()); g.setNamingPolicy(ci.namingPolicy); g.setStrategy(ci.strategy); g.setAttemptLoad(ci.attemptLoad); return g.create(); }
这个Generator是FastClass的内部类,也是继承了AbstractClassGenerator,可以生成类。
-
-
代理类中方法名字生成的逻辑在哪里,class文件的命名是什么样的规则?
- NamingPolicy接口,用来生成class文件的名字,DefaultNamingPolicy是它的默认的实现类。
- 方法名字生成逻辑和代码生成逻辑
主要在CallbackGenerator的实现类里面,通过不同的实现类,来生成不同类型的代码。在这里面会通过Context来获取字段的信息。
- 静态方法名字生成逻辑
生成的代理类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package net.sf.cglib.samples.simple;
import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Dispatcher;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.FixedValue;
import net.sf.cglib.proxy.InvocationHandler;
import net.sf.cglib.proxy.LazyLoader;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.NoOp;
import net.sf.cglib.proxy.ProxyRefDispatcher;
import net.sf.cglib.proxy.UndeclaredThrowableException;
// 生成的代理类会继承要代理的类,并且实现Factory接口
public class Bean$$EnhancerByCGLIB$$d79f67a6 extends Bean implements Factory {
// 标志位,表示是否初始化过,默认值是false
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
// 利用ThreadLocal来存储Callback[]
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
// Callback[]
private static final Callback[] CGLIB$STATIC_CALLBACKS;
// 下面的这几个属性都是在创建代理对象的时候,通过Enhancer传递进来的Callback
// 传递进来的dispatch
private Dispatcher CGLIB$CALLBACK_0;
//传递进来的MethodInterceptor
private MethodInterceptor CGLIB$CALLBACK_1;
// InvocationHandler
private InvocationHandler CGLIB$CALLBACK_2;
private LazyLoader CGLIB$CALLBACK_3;
private FixedValue CGLIB$CALLBACK_4;
private NoOp CGLIB$CALLBACK_5;
private ProxyRefDispatcher CGLIB$CALLBACK_6;
// LazyLoader的引用的返回值的引用
private static Object CGLIB$CALLBACK_FILTER;
//liupu1方法的引用,而且这个引用是属于Bean对象的
private static final Method CGLIB$lipu1$2$Method;
//MethodProxy对象,可以看下面的CGLIB$STATICHOOK1方法,va1是Bean的class对象,var0是当前代理对象的class对象。
// ()Ljava/lang/String;是方法的签名,lipu1和CGLIB$lipu1$2是不同的类对象的不同方法名字。
private static final MethodProxy CGLIB$lipu1$2$Proxy;
// 空参数对象,这就一个默认值
private static final Object[] CGLIB$emptyArgs;
// bean对象的jump方法引用
private static final Method CGLIB$jump$5;
// lazyLoader加载引用关系
private Object CGLIB$LAZY_LOADER_3;
static void CGLIB$STATICHOOK1() {
// 赋值
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("net.sf.cglib.samples.simple.Bean$$EnhancerByCGLIB$$d79f67a6");
Class var1;
CGLIB$lipu1$2$Method = ReflectUtils.findMethods(new String[]{"lipu1", "()Ljava/lang/String;"}, (var1 = Class.forName("net.sf.cglib.samples.simple.Bean")).getDeclaredMethods())[0];
CGLIB$lipu1$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "lipu1", "CGLIB$lipu1$2");
CGLIB$jump$5 = Class.forName("net.sf.cglib.samples.simple.Bean").getDeclaredMethod("jump");
}
//sayHello用的callback是Dispatcher,
public final String sayHello(String var1) {
// 每个变量都是关联好的,在什么方法用什么callback都是确定好的,
Dispatcher var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return ((Bean)var10000.loadObject()).sayHello(var1);
}
//
public final boolean equals(Object var1) {
Dispatcher var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000.loadObject().equals(var1);
}
public final String toString() {
Dispatcher var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000.loadObject().toString();
}
public final int hashCode() {
Dispatcher var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000.loadObject().hashCode();
}
// 要注意这个方法,这是 MethodProxy CGLIB$lipu1$2$Proxy属性里面的,在通过MethodProxy.invokeSuper的时候会调用到这个方法
final String CGLIB$lipu1$2() {
return super.lipu1();
}
// lipu1用的是methodInterceptor,在调用的时候会将CGLIB$lipu1$2$Proxy传递过去,并且,因为这个方法没有入参,
public final String lipu1() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_1;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$lipu1$2$Method, CGLIB$emptyArgs, CGLIB$lipu1$2$Proxy) : super.lipu1();
}
//静态方法,获取MethodProxy,通过方法的签名,这个签名对象有俩个字段,名字描述
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -286557062:
if (var10000.equals("lipu1()Ljava/lang/String;")) {
return CGLIB$lipu1$2$Proxy;
}
}
return null;
}
// 用的是invocationHandler
public final String jump() {
try {
InvocationHandler var10000 = this.CGLIB$CALLBACK_2;
// 这是做初始化操作的
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_2;
}
return (String)var10000.invoke(this, CGLIB$jump$5, new Object[0]);
} catch (Error | RuntimeException var1) {
throw var1;
} catch (Throwable var2) {
throw new UndeclaredThrowableException(var2);
}
}
// 用的是lazyLoader
public final String hhhh() {
// 它调用的是CGLIB$LOAD_PRIVATE_3方法,然后再调用hhh方法
//CGLIB$LOAD_PRIVATE_3在下面方法声明,在它里面会先看是否调用过,没有调用过,才会调用loadObject,。通过loadObject返回的对象来
// 调用hhh方法
return ((Bean)this.CGLIB$LOAD_PRIVATE_3()).hhhh();
}
private final synchronized Object CGLIB$LOAD_PRIVATE_3() {
Object var10000 = this.CGLIB$LAZY_LOADER_3;
if (var10000 == null) {
LazyLoader var10001 = this.CGLIB$CALLBACK_3;
if (var10001 == null) {
CGLIB$BIND_CALLBACKS(this);
var10001 = this.CGLIB$CALLBACK_3;
}
var10000 = this.CGLIB$LAZY_LOADER_3 = var10001.loadObject();
}
return var10000;
}
// 用的是fixedValue,这个比较重要,直接返回loadObject方法返回的值。
public final String dadada() {
FixedValue var10000 = this.CGLIB$CALLBACK_4;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_4;
}
return (String)var10000.loadObject();
}
// proxyRefDispatcher 在调用的时候,会将代理对象传递过去,还是和之前一样,做调用
public final String sasasasa() {
ProxyRefDispatcher var10000 = this.CGLIB$CALLBACK_6;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_6;
}
return ((Bean)var10000.loadObject(this)).sasasasa();
}
// 构造方法
public Bean$$EnhancerByCGLIB$$d79f67a6() {
CGLIB$BIND_CALLBACKS(this);
}
//给ThreadLoacal设置callBack[]
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
// 改变callback[],注意,看这个名字有一个static,上面的名字里面有一个Thread
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
CGLIB$STATIC_CALLBACKS = var0;
}
// 私有静态方法,用这个方法来给CGLIB$CALLBACK_6这些赋值,首先会从ThreadLocal中获取值,再回从静态的callback[]里面获取值
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
Bean$$EnhancerByCGLIB$$d79f67a6 var1 = (Bean$$EnhancerByCGLIB$$d79f67a6)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;
}
}
// 赋值
Callback[] var10001 = (Callback[])var10000;
var1.CGLIB$CALLBACK_6 = (ProxyRefDispatcher)((Callback[])var10000)[6];
var1.CGLIB$CALLBACK_5 = (NoOp)var10001[5];
var1.CGLIB$CALLBACK_4 = (FixedValue)var10001[4];
var1.CGLIB$CALLBACK_3 = (LazyLoader)var10001[3];
var1.CGLIB$CALLBACK_2 = (InvocationHandler)var10001[2];
var1.CGLIB$CALLBACK_1 = (MethodInterceptor)var10001[1];
var1.CGLIB$CALLBACK_0 = (Dispatcher)var10001[0];
}
}
// 这个方法是Factory接口的方法,所有通过Enhancer生成的代理类都实现了这个接口,利用这个接口就可以快速的创建实例,
// 改变callback,获取callback
public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
Bean$$EnhancerByCGLIB$$d79f67a6 var10000 = new Bean$$EnhancerByCGLIB$$d79f67a6();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
throw new IllegalStateException("More than one callback object required");
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
Bean$$EnhancerByCGLIB$$d79f67a6 var10000 = new Bean$$EnhancerByCGLIB$$d79f67a6;
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);
Object var10000;
switch(var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
case 1:
var10000 = this.CGLIB$CALLBACK_1;
break;
case 2:
var10000 = this.CGLIB$CALLBACK_2;
break;
case 3:
var10000 = this.CGLIB$CALLBACK_3;
break;
case 4:
var10000 = this.CGLIB$CALLBACK_4;
break;
case 5:
var10000 = this.CGLIB$CALLBACK_5;
break;
case 6:
var10000 = this.CGLIB$CALLBACK_6;
break;
default:
var10000 = null;
}
return (Callback)var10000;
}
public void setCallback(int var1, Callback var2) {
switch(var1) {
case 0:
this.CGLIB$CALLBACK_0 = (Dispatcher)var2;
break;
case 1:
this.CGLIB$CALLBACK_1 = (MethodInterceptor)var2;
break;
case 2:
this.CGLIB$CALLBACK_2 = (InvocationHandler)var2;
break;
case 3:
this.CGLIB$CALLBACK_3 = (LazyLoader)var2;
break;
case 4:
this.CGLIB$CALLBACK_4 = (FixedValue)var2;
break;
case 5:
this.CGLIB$CALLBACK_5 = (NoOp)var2;
break;
case 6:
this.CGLIB$CALLBACK_6 = (ProxyRefDispatcher)var2;
}
}
public Callback[] getCallbacks() {
CGLIB$BIND_CALLBACKS(this);
return new Callback[]{this.CGLIB$CALLBACK_0, this.CGLIB$CALLBACK_1, this.CGLIB$CALLBACK_2, this.CGLIB$CALLBACK_3, this.CGLIB$CALLBACK_4, this.CGLIB$CALLBACK_5, this.CGLIB$CALLBACK_6};
}
public void setCallbacks(Callback[] var1) {
this.CGLIB$CALLBACK_0 = (Dispatcher)var1[0];
this.CGLIB$CALLBACK_1 = (MethodInterceptor)var1[1];
this.CGLIB$CALLBACK_2 = (InvocationHandler)var1[2];
this.CGLIB$CALLBACK_3 = (LazyLoader)var1[3];
this.CGLIB$CALLBACK_4 = (FixedValue)var1[4];
this.CGLIB$CALLBACK_5 = (NoOp)var1[5];
this.CGLIB$CALLBACK_6 = (ProxyRefDispatcher)var1[6];
}
static {
CGLIB$STATICHOOK1();
}
}
到此,结束了。
关于博客这件事,我是把它当做我的笔记,里面有很多的内容反映了我思考的过程,因为思维有限,不免有些内容有出入,如果有问题,欢迎指出。一同探讨。谢谢