CGLIB 动态代理
参考链接:https://blog.csdn.net/yhl_jxy/article/details/80633194
参考链接:https://www.jianshu.com/p/001f866a49d7
1.CGLIB 简单介绍
CGLIB简介:CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。
CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用。
2.Demo
2.1 创建需要被代理的类
public class Student2 {
public String getName() {
System.out.println("我叫红领巾");
return "我叫红领巾";
}
public Integer getAge() {
System.out.println("14");
return 14;
}
}
2.2 生成代理类 需实现MethodInterceptor接口
public class MyProxy implements MethodInterceptor {
/**
* Enhancer.create(superClass,callback)
* superClass: 生成代理对象的父类
* callback:设置enhancer的回调对象
**/
public <T> T getProxy(Class<T> clazz){
return (T) Enhancer.create(clazz,this);
}
/**
* target:cglib生成的代理对象
* method:被代理对象方法
* args:方法入参
* methodProxy: 代理方法
**/
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("前置");
//用MethodProxy 调用父类方法。
Object returnObject = methodProxy.invokeSuper(target,args);
System.out.println("后置");
return returnObject;
}
}
2.3 生成测试类
public class ProxyTest {
public static void main(String[] args) {
// 代理类class文件存入本地磁盘方便我们反编译查看源码
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/admin");
MyProxy myProxy = new MyProxy();
Student2 student2 = myProxy.getProxy(Student2.class);
student2.getName();
}
}
2.4 运行结果
2.5 生成的代理类class文件
3. 源码解析
在Demo中通过代理类 Enhancer.create(clazz,this)方法返回被代理类
public static Object create(Class type, Callback callback) {
Enhancer e = new Enhancer();
e.setSuperclass(type);
e.setCallback(callback);
return e.create();
}
该方法就是创建一个Enhancer类通过create方法返回被代理类
public Object create() {
classOnly = false;
argumentTypes = null;
return createHelper();
}
该方法含义就是如果有必要就创建一个新类,并且用指定的回调对象创建一个新的对象实例,
使用的父类的参数的构造方法来实例化父类的部分。核心内容在createHelper()中,源码如下:
private Object createHelper() {
this.preValidate();
Object key = KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null,
ReflectUtils.getNames(this.interfaces),
this.filter == ALL_ZERO ? null : new WeakCacheKey(this.filter),
this.callbackTypes, this.useFactory,
this.interceptDuringConstruction,
this.serialVersionUID);
this.currentKey = key;
Object result = super.create(key);
return result;
}
preValidate()方法校验callbackTypes、filter是否为空,以及为空时的处理。
通过newInstance()方法创建EnhancerKey对象,作为Enhancer父类AbstractClassGenerator.create()方法
protected Object create(Object key) {
try {
ClassLoader loader = this.getClassLoader();
// 如果 data 不存在 ,在多线程环境下添加到CACHE
Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> cache = CACHE
AbstractClassGenerator.ClassLoaderData data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
if (data == null) {
Class var5 = AbstractClassGenerator.class;
synchronized(AbstractClassGenerator.class) {
cache = CACHE;
data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
if (data == null) {
Map<ClassLoader, AbstractClassGenerator.ClassLoaderData> newCache = new WeakHashMap(cache);
data = new AbstractClassGenerator.ClassLoaderData(loader);
newCache.put(loader, data);
CACHE = newCache;
}
}
}
this.key = key;
Object obj = data.get(this, this.getUseCache());
return obj instanceof Class ? this.firstInstance((Class)obj) : this.nextInstance(obj);
} catch (Error | RuntimeException var9) {
throw var9;
} catch (Exception var10) {
throw new CodeGenerationException(var10);
}
}
真正创建代理对象方法在nextInstance()方法中,该方法为抽象类AbstractClassGenerator的一个方法,签名如下:
abstract protected Object nextInstance(Object instance) throws Exception;
在子类Enhancer中实现,实现源码如下:
protected Object nextInstance(Object instance) {
EnhancerFactoryData data = (EnhancerFactoryData) instance;
if (classOnly) {
return data.generatedClass;
}
Class[] argumentTypes = this.argumentTypes;
Object[] arguments = this.arguments;
if (argumentTypes == null) {
argumentTypes = Constants.EMPTY_CLASS_ARRAY;
arguments = null;
}
return data.newInstance(argumentTypes, arguments, callbacks);
}
通过data.newInstance(argumentTypes, arguments, callbacks)方法,
第一个参数为代理对象的构成器类型,第二个为代理对象构造方法参数,第三个为对应回调对象。
最后根据这些参数,通过反射生成代理对象,源码如下:
/**
* Creates proxy instance for given argument types, and assigns the callbacks.
* Ideally, for each proxy class, just one set of argument types should be used,
* otherwise it would have to spend time on constructor lookup.
* Technically, it is a re-implementation of {@link Enhancer#createUsingReflection(Class)},
* with "cache {@link #setThreadCallbacks} and {@link #primaryConstructor}"
*
* @see #createUsingReflection(Class)
* @param argumentTypes constructor argument types
* @param arguments constructor arguments
* @param callbacks callbacks to set for the new instance
* @return newly created proxy
*/
public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) {
setThreadCallbacks(callbacks);
try {
// Explicit reference equality is added here just in case Arrays.equals does not have one
if (primaryConstructorArgTypes == argumentTypes ||
Arrays.equals(primaryConstructorArgTypes, argumentTypes)) {
// If we have relevant Constructor instance at hand, just call it
// This skips "get constructors" machinery
return ReflectUtils.newInstance(primaryConstructor, arguments);
}
// Take a slow path if observing unexpected argument types
return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments);
} finally {
// clear thread callbacks to allow them to be gc'd
setThreadCallbacks(null);
}
}
生成的代理对象的class文件进行反编译之后的代码如下
public class Student2$$EnhancerByCGLIB$$3859af2f extends Student2 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$getName$0$Method;
private static final MethodProxy CGLIB$getName$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$getAge$1$Method;
private static final MethodProxy CGLIB$getAge$1$Proxy;
private static final Method CGLIB$equals$2$Method;
private static final MethodProxy CGLIB$equals$2$Proxy;
private static final Method CGLIB$toString$3$Method;
private static final MethodProxy CGLIB$toString$3$Proxy;
private static final Method CGLIB$hashCode$4$Method;
private static final MethodProxy CGLIB$hashCode$4$Proxy;
private static final Method CGLIB$clone$5$Method;
private static final MethodProxy CGLIB$clone$5$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class clazz1 = Class.forName("com.domain.Student2$$EnhancerByCGLIB$$3859af2f");
Class clazz2;
CGLIB$equals$2$Method = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods())[0];
CGLIB$equals$2$Proxy = MethodProxy.create(clazz2, clazz1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
CGLIB$toString$3$Method = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods())[1];
CGLIB$toString$3$Proxy = MethodProxy.create(clazz2, clazz1, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
CGLIB$hashCode$4$Method = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods())[2];
CGLIB$hashCode$4$Proxy = MethodProxy.create(clazz2, clazz1, "()I", "hashCode", "CGLIB$hashCode$4");
CGLIB$clone$5$Method = ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods())[3];
CGLIB$clone$5$Proxy = MethodProxy.create(clazz2, clazz1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
ReflectUtils.findMethods(new String[] { "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (clazz2 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$getName$0$Method = ReflectUtils.findMethods(new String[] { "getName", "()Ljava/lang/String;", "getAge", "()Ljava/lang/Integer;" }, (clazz2 = Class.forName("com.domain.Student2")).getDeclaredMethods())[0];
CGLIB$getName$0$Proxy = MethodProxy.create(clazz2, clazz1, "()Ljava/lang/String;", "getName", "CGLIB$getName$0");
CGLIB$getAge$1$Method = ReflectUtils.findMethods(new String[] { "getName", "()Ljava/lang/String;", "getAge", "()Ljava/lang/Integer;" }, (clazz2 = Class.forName("com.domain.Student2")).getDeclaredMethods())[1];
CGLIB$getAge$1$Proxy = MethodProxy.create(clazz2, clazz1, "()Ljava/lang/Integer;", "getAge", "CGLIB$getAge$1");
ReflectUtils.findMethods(new String[] { "getName", "()Ljava/lang/String;", "getAge", "()Ljava/lang/Integer;" }, (clazz2 = Class.forName("com.domain.Student2")).getDeclaredMethods());
}
final String CGLIB$getName$0() { return super.getName(); }
public final String getName() {
if (this.CGLIB$CALLBACK_0 == null) {
this.CGLIB$CALLBACK_0;
CGLIB$BIND_CALLBACKS(this);
}
return (this.CGLIB$CALLBACK_0 != null) ? (String)this.CGLIB$CALLBACK_0.intercept(this, CGLIB$getName$0$Method, CGLIB$emptyArgs, CGLIB$getName$0$Proxy) : super.getName();
}
...................
...................
}
从上述代码可以看到 如果被代理类调用getName()方法,就会执行 代理类的intercept()方法
// CGLIB$getName$0$Method = ReflectUtils.findMethods(new String[] { "getName", "()Ljava/lang/String;", "getAge", "()Ljava/lang/Integer;" }, (clazz2 = Class.forName("com.domain.Student2")).getDeclaredMethods())[0];
// CGLIB$getName$0$Proxy = MethodProxy.create(clazz2, clazz1, "()Ljava/lang/String;", "getName", "CGLIB$getName$0");
clazz2 = Class.forName("com.domain.Student2"))
clazz1 = Class.forName("com.domain.Student2$$EnhancerByCGLIB$$3859af2f");
//下面看下MethodProxy.create()方法
c1: Student
c2: Student$$Enhancer
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
MethodProxy proxy = new MethodProxy();
proxy.sig1 = new Signature(name1, desc);
proxy.sig2 = new Signature(name2, desc);
proxy.createInfo = new CreateInfo(c1, c2);
return proxy;
}
this.CGLIB$CALLBACK_0.intercept(this, CGLIB$getName$0$Method, CGLIB$emptyArgs, CGLIB$getName$0$Proxy)
在MethodProxy中
对象 | 实例 |
---|---|
c1 | Student2 |
f1 | c1的fastClass,更方便调用c1的函数 |
c2 | Student2$$Enhancer,生成的代理对象的实例 |
f2 | c2的fastClass,更加方便调用c2的函数 |
在intercept()方法中,调用MethodProxy的invokeSuper()方法
public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("前置");
Object returnObject = methodProxy.invokeSuper(target,args);
System.out.println("后置");
return returnObject;
}
invokeSuper()
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
//通过下面的代码分析 可知此处调用是 Student$$Enhancer$$FastClss的invoke方法
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}
//下面是init() 方法
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对应的是 Student的FastClass
fci.f1 = helper(ci, ci.c1);
// f2对应的是 Student$$Enhancer 的FastClass
fci.f2 = helper(ci, ci.c2);
//i1i2分别是分别在Student$$FastClass和Student$$Enhancer$$FastClss中 调用方法的index.
fci.i1 = fci.f1.getIndex(this.sig1);
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
//init() 中又调用helper()方法
//根据ci得到该方法的委托类,实现类,分别生成这两个类的fastClass
private static FastClass helper(MethodProxy.CreateInfo ci, Class type) {
Generator g = new Generator();
g.setType(type);
g.setContextClass(type);
g.setClassLoader(ci.c2.getClassLoader());
g.setNamingPolicy(ci.namingPolicy);
g.setStrategy(ci.strategy);
g.setAttemptLoad(ci.attemptLoad);
return g.create();
}
通过反编译得到Student$$EnchancerFastClass的invoke()方法
public Object invoke(int paramInt, Object paramObject, Object[] paramArrayOfObject) throws InvocationTargetException {
try {
switch (paramInt) {
case 0:
return new Boolean(((Student2$$EnhancerByCGLIB$$3859af2f)paramObject).equals(paramArrayOfObject[0]));
case 1:
return ((Student2$$EnhancerByCGLIB$$3859af2f)paramObject).toString();
..........
//找到Student2$$Enhancer 的getName$0()方法。
case 17:
return ((Student2$$EnhancerByCGLIB$$3859af2f)paramObject).CGLIB$getName$0();
case 18:
return ((Student2$$EnhancerByCGLIB$$3859af2f)paramObject).CGLIB$getAge$1();
case 19:
return new Boolean(((Student2$$EnhancerByCGLIB$$3859af2f)paramObject).CGLIB$equals$2(paramArrayOfObject[0]));
case 20:
return ((Student2$$EnhancerByCGLIB$$3859af2f)paramObject).CGLIB$toString$3();
case 21:
return new Integer(((Student2$$EnhancerByCGLIB$$3859af2f)paramObject).CGLIB$hashCode$4());
case 22:
return ((Student2$$EnhancerByCGLIB$$3859af2f)paramObject).CGLIB$clone$5();
}
} catch (Throwable throwable) {
throw new InvocationTargetException(null);
}
throw new IllegalArgumentException("Cannot find matching method/constructor");
}
在Student$ E n h a n c e r 中 调 用 C G L I B Enhancer中调用CGLIB Enhancer中调用CGLIBgetName$0()调用 super. name()方法 即 Student 的getName方法();
final String CGLIB$getName$0() { return super.getName(); }
思考
思考
1.fastclass比反射快的原因
通过方法前面或者标识符index,利用switch case直接利用对象去调用函数
而反射是java.lang.reflect.Method#invoke,稍微复杂点,这个没研究过具体实现
2.MethodProxy#invoke和MethodProxy#invokeSuper什么区别,即[c1,f1]与[c2,f2]的区别
[c1,f1]对应的是 父类的class和fastclass
[c2,f2]对应的是 父类的enhanceClass和 enhanceFastClass
3.MethodProxy#init创建fastclass时,每个method在第一次调用时,都会进行
net.sf.cglib.proxy.MethodProxy#init
net.sf.cglib.proxy.MethodProxy#helper
net.sf.cglib.reflect.FastClass.Generator#create
那么为什么对应的fastclass文件只生成了一次(不是一个method调用一次就生成一次)
并且一次就有整个类的信息,而不是只有这个method相关信息呢
第一点:同一个类的fastClass只生成了一次,
net.sf.cglib.reflect.FastClass.Generator#create
net.sf.cglib.core.AbstractClassGenerator#create
里面用了缓存
第二点:一次就有整个类的信息,而不是只有这个method信息
net.sf.cglib.proxy.MethodProxy#create时就传入和class c1,c2
后来创建fastClass时
net.sf.cglib.proxy.MethodProxy#helper
调用了g.setType(type);
在fastClass生成时
net.sf.cglib.reflect.FastClass.Generator#generateClass
用到了这个之前设置好的Class type,也就直到类信息了
invokeSuper的逻辑
4.把invokeSuper改成invoke会怎么样
结论:死循环,堆栈溢出
访问Student
E
n
h
a
n
c
e
r
中
g
e
t
N
a
m
e
(
)
方
法
然
后
进
入
M
e
t
h
o
d
I
n
t
e
r
c
e
p
t
o
r
的
i
n
t
e
r
c
e
p
t
o
r
(
)
方
法
又
去
调
用
S
t
u
d
e
n
t
Enhancer中 getName()方法 然后进入MethodInterceptor的interceptor()方法 又去调用Student
Enhancer中getName()方法然后进入MethodInterceptor的interceptor()方法又去调用StudentEnhancer中 getName()方法 …
导致死循环