一、 环境搭建
火车站实体类
public class TrainStation {
public void sell() {
System.out.println("卖票");
}
动态代理工厂
public class ProxyFactory{
private TrainStation trainStation = new TrainStation();
// 通过Cglib 获得代理对象
public Sell getSell1() {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\ideaPro\\cloud-demo\\gateway\\target\\classes\\cn\\itcast\\gateway");
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(trainStation.getClass());
enhancer.setCallback(this);
//是否开启缓存
// enhancer.setUseCache(false);
Object o = enhancer.create();
return (Sell) o;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("!!!!!!!!!!!");
Object invoke = methodProxy.invokeSuper(o, objects);
return invoke;
}
}
主函数
public class Client {
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();
Sell sell1 = proxyFactory.getSell1();
sell1.sell();
}
}
二、查看代理类的字节码文件
第一步
第二步: 在代理类工厂添加这句话
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,
"D:\\ideaPro\\cloud-demo\\gateway\\target\\classes\\cn\\itcast\\gateway");
最终显示样式
三、动态代理源码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package DEMO;
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 TrainStation$$EnhancerByCGLIB$$5e21b681 extends TrainStation 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$sell$0$Method;
private static final MethodProxy CGLIB$sell$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("DEMO.TrainStation$$EnhancerByCGLIB$$5e21b681");
Class var1;
CGLIB$sell$0$Method = ReflectUtils.findMethods(new String[]{"sell", "()V"}, (var1 = Class.forName("DEMO.TrainStation")).getDeclaredMethods())[0];
CGLIB$sell$0$Proxy = MethodProxy.create(var1, var0, "()V", "sell", "CGLIB$sell$0");
Method[] 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$1$Method = var10000[0];
CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = var10000[1];
CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = var10000[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = var10000[3];
CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
}
final void CGLIB$sell$0() {
super.sell();
}
public final void sell() {
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$sell$0$Method, CGLIB$emptyArgs, CGLIB$sell$0$Proxy);
} else {
super.sell();
}
}
final boolean CGLIB$equals$1(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$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
return var2 == null ? false : (Boolean)var2;
} else {
return super.equals(var1);
}
}
final String CGLIB$toString$2() {
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$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
}
final int CGLIB$hashCode$3() {
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$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.hashCode();
}
}
final Object CGLIB$clone$4() 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$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$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$4$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$1$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$2$Proxy;
}
break;
case 1978249955:
if (var10000.equals("sell()V")) {
return CGLIB$sell$0$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$3$Proxy;
}
}
return null;
}
public TrainStation$$EnhancerByCGLIB$$5e21b681() {
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) {
TrainStation$$EnhancerByCGLIB$$5e21b681 var1 = (TrainStation$$EnhancerByCGLIB$$5e21b681)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);
TrainStation$$EnhancerByCGLIB$$5e21b681 var10000 = new TrainStation$$EnhancerByCGLIB$$5e21b681();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
TrainStation$$EnhancerByCGLIB$$5e21b681 var10000 = new TrainStation$$EnhancerByCGLIB$$5e21b681();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}
public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
TrainStation$$EnhancerByCGLIB$$5e21b681 var10000 = new TrainStation$$EnhancerByCGLIB$$5e21b681;
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();
}
}
四、代理类源码分析
通过代理工厂,生成代理类,代理类调用被增强的方法( Sell() )
我们从sell()方法入手开始分析源码
动态生成的代理类中sell方法源码
public class TrainStation$$EnhancerByCGLIB$$5e21b681 extends
TrainStation implements Factory {
public final void sell() {
//通过查看源码发现 该方法拦截器并没有被赋值 ,所以为空
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
//进入改方法 拿到方法拦截器
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
/*通过方法拦截器调用我们增强的方法
参数说明:
this:动态代理对象
CGLIB$sell$0$Method: 就是 Sell的方法类 在这里被赋值
CGLIB$sell$0$Method = ReflectUtils.findMethods(new String[]{"sell", "()V"}, (var1 = Class.forName("DEMO.TrainStation")).getDeclaredMethods())[0];
CGLIB$emptyArgs:方法中的参数
CGLIB$sell$0$Proxy: 代理方法类 在这里被创建 具体作用下面介绍
CGLIB$sell$0$Proxy = MethodProxy.create(var1, var0, "()V", "sell", "CGLIB$sell$0");
*/
var10000.intercept(this, CGLIB$sell$0$Method, CGLIB$emptyArgs, CGLIB$sell$0$Proxy);
} else {
super.sell();
}
}
}
通过这段代码可以看的出来 ,只要能拿到这个CGLIB$CALLBACK_0方法拦截器就可以调用我们的增强方法 ,所以目前问题就是我们如何得到这个方法拦截器
CGLIB$BIND_CALLBACKS方法拦截器的具体源码
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
//代理对象被强行转换
TrainStation$$EnhancerByCGLIB$$5e21b681 var1 = (TrainStation$$EnhancerByCGLIB$$5e21b681)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
// ThreadLocal CGLIB$THREAD_CALLBACKS;
// 这个线程中得到
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];
}
}
原来这个方法拦截器是通过一个线程中得到的,那么我们的问题又变成了 这个线程类CGLIB$THREAD_CALLBACKS是什么时候被赋值的
这个线程其实是在我们创建动态代理类后创建动态代理对象前被赋值的 具体我们继续看源码
在我们的方法中 最后一步就是生成代理类对象 我们源码也是从这里开始分析
create方法 源码
public Object create() {
classOnly = false;
argumentTypes = null;
//这里 我们继续跟进
return createHelper();
}
createHelper()方法 源码
private Object createHelper() {
preValidate();
Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
ReflectUtils.getNames(interfaces),
filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
callbackTypes,
useFactory,
interceptDuringConstruction,
serialVersionUID);
this.currentKey = key;
//这里返回的是我们的动态代理对象 我们继续跟进 key是我们真实主题类
Object result = super.create(key);
return result;
}
create(key)方法 源码
protected Object create(Object key) {
try {
ClassLoader loader = getClassLoader();
Map<ClassLoader, ClassLoaderData> cache = CACHE;
ClassLoaderData data = cache.get(loader);
if (data == null) {
synchronized (AbstractClassGenerator.class) {
cache = CACHE;
data = cache.get(loader);
if (data == null) {
Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
data = new ClassLoaderData(loader);
newCache.put(loader, data);
CACHE = newCache;
}
}
}
this.key = key;
//这里会进行缓存 如果将enhancer.useCache 设置为false 每次创建代理对象都会是新的代理对象
Object obj = data.get(this, getUseCache());
if (obj instanceof Class) {
// 在第一次创建代理对象的时候会调用这个方法
return firstInstance((Class) obj);
}
//否则就会进入这个方法
return nextInstance(obj);
} catch (RuntimeException e) {
throw e;
} catch (Error e) {
throw e;
} catch (Exception e) {
throw new CodeGenerationException(e);
}
}
我们就以第一次创建 为例子继续跟进源码
firstInstance方法 源码
protected Object firstInstance(Class type) throws Exception {
if (classOnly) {
return type;
} else {
//这里会执行这个方法 继续跟进
return createUsingReflection(type);
}
}
createUsingReflection方法 源码
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);
}
}
通过查看源码 可以发现之前我们提到的线程类 是在 创建代理类之后,创建代理对象之前 进行设置的
(关于怎么生成代理对象的我们这里就不讲了)
那么这个 值是如何被赋进去的呢 我们接着跟进 setThreadCallbacks(type, callbacks); 查看
setThreadCallbacks方法 源码
private static void setThreadCallbacks(Class type, Callback[] callbacks) {
setCallbacksHelper(type, callbacks, SET_THREAD_CALLBACKS_NAME);
}
SET_THREAD_CALLBACKS_NAME 是什么呢 我看跟进可以发现是一个
名为“CGLIB$SET_THREAD_CALLBACKS ”的字符串
这个字符串的作用是是什么呢 我们继续跟进源码
setCallbacksHelper方法 源码
private static void setCallbacksHelper(Class type, Callback[] callbacks, String methodName) {
// TODO: optimize
try {
//这里原来是根据类型和方法这个名称进行得到了具体方法
Method setter = getCallbacksSetter(type, methodName);
//通过方法名称进行反射将 callbacks赋值进去
setter.invoke(null, new Object[]{ callbacks });
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException(type + " is not an enhanced class");
} catch (IllegalAccessException e) {
throw new CodeGenerationException(e);
} catch (InvocationTargetException e) {
throw new CodeGenerationException(e);
}
}
根据代码我们发现了 反射,那就意味着在代理类对象中应该有一种方法可以进行设置我们之前说的线程类
CGLIB$SET_THREAD_CALLBACKS 方法 源码
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
CGLIB$THREAD_CALLBACKS.set(var0);
}
这和我们之前看的那个 字符串的名字是一样的 所以可以通过反射得到这个方法并且进行赋值
至此我们知道Cglib内部是如何实现动态代理的逻辑了。
那么在intercept方法中MethodProxy参数到底是作用有哪些呢? 方法中invokeSuper和invoke方法有什么不同呢。
四、MethodProxy
CGLIB$sell$0$Proxy = MethodProxy.create(var1, var0, "()V", "sell", "CGLIB$sell$0");
注意到 create方法有两个参数 分别是sell和CGLIB$sell$0 正好对应我们代理对象中的两个方法,("()v"是返回值为空的意思)
我们继续追踪create方法查看源码
create方法 源码
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;
}
我们拿到这个代理方法就可进行调用 invokeSuper和invoke方法
那么他们的差别是什么呢?
invoke和invokeSuper
invoke方法 源码
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) {
throw e.getTargetException();
} catch (IllegalArgumentException e) {
if (fastClassInfo.i1 < 0)
throw new IllegalArgumentException("Protected method: " + sig1);
throw e;
}
}
源码很容易看懂就是 讲fastClassInfo 赋值给fci并且调用fci.f1的方法 ,那么 fastClassInfo 的值从何而来,那就要继续查看 Init()方法了,看一下他里面做了哪些操作。
private void init()
{
if (fastClassInfo == null)
{
synchronized (initLock)
{
if (fastClassInfo == null)
{
//根据之前源码分析 得知 这一步将 真是主题类和代理类的信息传递给ci
CreateInfo ci = createInfo;
FastClassInfo fci = new FastClassInfo();
//将 真实主题类 也就是火车站类 传递给了f1
fci.f1 = helper(ci, ci.c1);
//将 代理类类,传递给了f2
fci.f2 = helper(ci, ci.c2);
//通过签名得到具体方法 sig1 是sell()方法
fci.i1 = fci.f1.getIndex(sig1);
//sig2 是CGLIB$sell$0()方法
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}
现在我们再回过头来看 Invoke方法
不难发现 invoke调用的是 真实主题类中sell()方法
同理我们查看 InvokeSuper方法
很容易就得知 invokeSuper调用的是 代理类中CGLIB$sell$0方法
这个时候就有一个疑问了 那我可不可以用 invoke方法调用 代理类中sell()方法,或者我用InvokeSuper方法调用 真实主题类中的CGLIB$sell$0()方法呢?
于是我进行了尝试
用 invoke方法调用 代理类中sell()方法
很显然,它报错了。为啥呢 ?
因为造成了递归死循环调用 想一下 ,代理类的sell方法 最终会去调用 Intercept增强方法 而增强方法又回去调用代理类的sell方法 这不就成了死循环了吗。
InvokeSuper方法调用 真实主题类中的CGLIB$sell$0()方法
当然也不行的,为啥呢?
从逻辑上来说 因为 真实主题类也就是 火车站类根本就没有CGLIB$sell$0()这个方法
但是它报的错误 不是说没找到该方法而是这个错误呢 因为 在FastClass类中会进行强制类型转换 ,由于 不能强制类型转换 就会报错。(代理类可以转换为真实主题类,但是真实主题类不能转换成代理类,因为子类继承自父类的原因,这也就是为啥 invoke是代理类时没有报类型转换错误的原因)
至于啥是 FastClass 可以结尾查看相应视频了解
至此 关于Cglib的相关基础逻辑全部搞明白了。
总结
感谢 b站 Java程序员周瑜的讲解
视频链接:
https://www.bilibili.com/video/BV1fF411q7QQ?p=4&vd_source=36f798afd4325366d4bae2a4aa1bdccd