CGLIB动态代理源码分析
CGLIB是一个开源项目,可以在运行期间扩展Java类,实现Java接口等待。底层是字节码处理框架ASM,来转换字节码和生成新的类。
理论上也可直接ASM来生成代码,但是操作比较复杂。
CGLIB动态代理使用
先导入依赖:
<dependencies>
<dependency>
<groupId>org.sonatype.sisu.inject</groupId>
<artifactId>cglib</artifactId>
<version>3.1.1</version>
</dependency>
</dependencies>
被代理的类:
public class Target {
public void f() {
System.out.println("Target f()");
}
public void g() {
System.out.println("Target g()");
}
}
拦截器:
public class Interceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代理前---------");
// 为啥要invokeSuper
Object result = methodProxy.invokeSuper(o,objects);
System.out.println("代理后---------");
return result;
}
}
这里有个invokeSuper
,为什么不用invoke
呢?分析代理类时说。
测试类:
public class Test {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,
"./");
//实例化一个增强器,cglib的一个class generator
Enhancer enhancer = new Enhancer();
//设置目标类
enhancer.setSuperclass(Target.class);
//设置拦截对象
//可以设置多个,不是一个方法可以被拦截多次
//而是目标类中不同的方法可以被不同的拦截器拦截
enhancer.setCallback(new Interceptor());
//生成代理类,返回实例
Target target = (Target) enhancer.create();
target.f();
target.g();
//结果:
//CGLIB debugging enabled, writing to './'
//代理前---------
//Target f()
//代理后---------
//代理前---------
//Target g()
//代理后---------
}
}
使用步骤
- 创建
Enhancer
实例 setSuperClass
方法设置目标类setCallback
方法设置拦截对象create
生成代理类
CGLIB动态代理源码解析
代理类分析
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package cn.orzlinux.cglibTest;
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.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class Target$$EnhancerByCGLIB$$557584f8 extends Target implements Factory {
private boolean CGLIB$BOUND;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static final Method CGLIB$g$0$Method;
private static final MethodProxy CGLIB$g$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$f$1$Method;
private static final MethodProxy CGLIB$f$1$Proxy;
//...
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("cn.orzlinux.cglibTest.Target$$EnhancerByCGLIB$$557584f8");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$finalize$2$Method = var10000[0];
CGLIB$finalize$2$Proxy = MethodProxy.create(var1, var0, "()V", "finalize", "CGLIB$finalize$2");
CGLIB$equals$3$Method = var10000[1];
CGLIB$equals$3$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$3");
CGLIB$toString$4$Method = var10000[2];
CGLIB$toString$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$4");
CGLIB$hashCode$5$Method = var10000[3];
CGLIB$hashCode$5$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$5");
CGLIB$clone$6$Method = var10000[4];
CGLIB$clone$6$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$6");
var10000 = ReflectUtils.findMethods(new String[]{"g", "()V", "f", "()V"}, (var1 = Class.forName("cn.orzlinux.cglibTest.Target")).getDeclaredMethods());
//被代理类方法对象
CGLIB$g$0$Method = var10000[0];
//初始化代理类方法对象
CGLIB$g$0$Proxy = MethodProxy.create(var1, var0, "()V", "g", "CGLIB$g$0");
CGLIB$f$1$Method = var10000[1];
CGLIB$f$1$Proxy = MethodProxy.create(var1, var0, "()V", "f", "CGLIB$f$1");
}
// 目标类的g方法
final void CGLIB$g$0() {
super.g();
}
public final void g() {
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$g$0$Method, CGLIB$emptyArgs, CGLIB$g$0$Proxy);
} else {
super.g();
}
}
//。。。finalize toString...方法省略
}
代理类继承了目标类Target:
public class Target$$EnhancerByCGLIB$$557584f8 extends Target implements Factory
对于Target中的非private方法,代理类生成两个方法:
//被代理类的g方法
final void CGLIB$g$0() {
super.g();
}
//代理类的g()方法,override
public final void g() {
//获取拦截对象
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
//拦截器对象的intecept方法
var10000.intercept(this, CGLIB$g$0$Method, CGLIB$emptyArgs, CGLIB$g$0$Proxy);
} else {
super.g();
}
}
拦截器对象何时获得?
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
Target$$EnhancerByCGLIB$$557584f8 var1 = (Target$$EnhancerByCGLIB$$557584f8)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
//ThreadLocal里获取,何时赋值?
//都是在newInstance里设置的,因为代理类实现了Factory接口
//Factory接口有newInstance方法,所以并不是这里设置的,要看Enhancer
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];
}
}
Enhancer
public class Enhancer extends AbstractClassGenerator
{
//...
public Object create() {
classOnly = false;
argumentTypes = null;
return createHelper();
}
private Object createHelper() {
validate();
if (superclass != null) {
setNamePrefix(superclass.getName());
} else if (interfaces != null) {
setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName());
}
// KEY_FACTORY.newInstance生成一个代理对象,保存了用户设置的代理信息
// create创建代理对象
return super.create(KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
ReflectUtils.getNames(interfaces),
filter,
callbackTypes,
useFactory,
interceptDuringConstruction,
serialVersionUID));
}
}
create跳转几次到达:
private Object createUsingReflection(Class type) {
setThreadCallbacks(type, callbacks);
try{
if (argumentTypes != null) {
return ReflectUtils.newInstance(type, argumentTypes, arguments);
} else {
return ReflectUtils.newInstance(type);
}
}finally{
// clear thread callbacks to allow them to be gc'd
setThreadCallbacks(type, null);
}
}
发现设置了callback。
MethodProxy
对照拦截器代码:
public class Interceptor implements MethodInterceptor {
@Override
//o: 被代理对象
//method:要调用的方法
//objects: 方法参数
//methodProxy 方法代理, 源自:
//CGLIB$g$0$Proxy = MethodProxy.create(var1, var0, "()V", "g", "CGLIB$g$0");
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代理前---------");
// 为啥要invokeSuper
Object result = methodProxy.invokeSuper(o,objects);
System.out.println("代理后---------");
return result;
}
}
invoke()和invokeSuper()
为什么有MethodProxy
?代理的是被代理对象的方法和代理对象的方法。
invoke
:g()
也就是代理类的方法。
invokeSuper
: CGLIB$g$0
也就是被代理类的方法。
public class Interceptor implements MethodInterceptor {
private final Target target = new Target();
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代理前---------");
// 为啥要invokeSuper
//Object result = methodProxy.invokeSuper(o,objects);
//1.ok
//methodProxy.invokeSuper(target,objects);
//2. error
//methodProxy.invokeSuper(target,objects); //error
// > Target cannot be cast to Target$$EnhancerByCGLIB$$55...
//3. error
//methodProxy.invoke(o,objects);
// 栈溢出,一直循环调用
methodProxy.invokeSuper(o,objects);
System.out.println("代理后---------");
return null;
}
}
MethodProxy对象创建
CGLIB$f$1$Proxy = MethodProxy.create(var1, var0, "()V", "f", "CGLIB$f$1");
()V
是void的意思,返回参数,最后两个参数是函数的两个名字,代表调用代理类函数和被代理类函数。
源码:
// c1是被代理类class
// c2是代理类class
// desc被代理方法返回值类型
// name1 被代理方法名,如test
// name2代理类中的CGLIB$test$0方法
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
MethodProxy proxy = new MethodProxy();
proxy.sig1 = new Signature(name1, desc); //被代理方法签名:void test()
// Signature:
//public class Signature {
// private String name;
// private String desc;
// // ...
//}
proxy.sig2 = new Signature(name2, desc);
proxy.createInfo = new CreateInfo(c1, c2); //存放被代理类和代理类信息
return proxy;
}
创建好MethodProxy对象之后,就可以在g()方法里面调用了:
//拦截器对象的intecept方法
var10000.intercept(this, CGLIB$g$0$Method, CGLIB$emptyArgs, CGLIB$g$0$Proxy);
而在自定义拦截其中,用invokeSuper进行被代理类的调用。
public class Interceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代理前---------");
methodProxy.invokeSuper(o,objects);
System.out.println("代理后---------");
return null;
}
}
invokeSuper
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
init();
FastClassInfo fci = fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException e) {
//...
}
}
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) {
//...
}
}
这里代码比较相似,不同的就是f1,f2,i1,i2。这个是因为代理方法里面是对应的两个方法。
private void init()
{
//双重校验单例模式
if (fastClassInfo == null)
{
synchronized (initLock)
{
if (fastClassInfo == null)
{
CreateInfo ci = createInfo;
FastClassInfo fci = new FastClassInfo();
//被代理类的FastClass代理类
fci.f1 = helper(ci, ci.c1);
//代理类的FastClass代理类
fci.f2 = helper(ci, ci.c2);
//预先生成方法对应的下表,调用时利用下标
//找到方法,性能高
fci.i1 = fci.f1.getIndex(sig1);
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}
生成的class有三个文件:
FastClass的invoke
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
//var1000是调用方法对应的类,没有用反射,而是直接调用
//所以会稍快一些
Target var10000 = (Target)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
var10000.g();
return null;
case 1:
var10000.f();
return null;
case 2:
var10000.wait();
return null;
case 3:
...
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
CGLIB和JDK动态代理区别
Spring 中的动态代理,如果代理对象有接口,就用 JDK 动态代理,否则就是 Cglib 动态代理。
区别:
- jdk动态代理:是根据接口生成代理类,这个继承Proxy类,在这个代理类的构造函数里把handler给代理类,代理类在调用方法的时候,用的是handler,handler手里又有一个原对象实例,调用的时候用反射进行调用。
- cglib动态代理:利用ASM框架,来生成目标对象的子类,在这个代理类的方法里调用拦截器,拦截器传入的是方法代理,而不是方法,运行的时候也不是用反射,而是直接调用的对象。
一个刁钻的问题:为什么还要用JDK动态代理?
在调用次数少的时候jdk好像相对效率高些。