设为首页 加入收藏

TOP

动态代理-cglib分析(一)
2023-07-26 08:17:14 】 浏览:105
Tags:-cglib分析

生成代理类文件的方式

jvm添加此启动参数,后面就是代理类class生成的地址
-Dcglib.debugLocation=~/baldhead/java/dynamic-proxy-cglib/src/main/java/com/baldhead/dynamic/proxy/cglib/class

添加这个参数之后,CGLIB就会把生成的代理Class文件存在指定的路径

生成动态代理对象流程

  1. CGLIB首先生成代理类
  2. 代码中的 static 静态代码块 会调用 CGLIB$STATICHOOK1(); 方法,方法作用
    3. 新建一个名字为 CGLIB$THREAD_CALLBACKSThreadLocal,用来存放所设置的 callback
    4. 使用反射找到代理类中的所有方法,包括(toStringhashCodeequalsclone),名字为模板 CGLIB$METHODNAME$数字编号$Method
    并且给对应的方法创建代理方法 名字模板CGLIB$METHODNAME$数字编号$Proxy
  3. 调用构造方法创建代理对象
  4. 然后CGLIB会调用代理对象的 CGLIB$SET_THREAD_CALLBACKS 方法,将传入的 callBack存到 ThreadLocal(CGLIB$THREAD_CALLBACKS) 中去
  5. 后续在对象执行需要代理的方法的时候,就会从CGLIB$THREAD_CALLBACKS中拿到所设置的 CallBack并调用它的intercept()方法

代理对象的创建

static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.baldhead.dynamic.proxy.cglib.Impl.UserService$$EnhancerByCGLIB$$e34eec9a");
        Class var1;
        CGLIB$test$0$Method = ReflectUtils.findMethods(new String[]{"test", "()V"}, (var1 = Class.forName("com.baldhead.dynamic.proxy.cglib.Impl.UserService")).getDeclaredMethods())[0];
        CGLIB$test$0$Proxy = MethodProxy.create(var1, var0, "()V", "test", "CGLIB$test$0");
    }

以上代码经过简化的,主要看下面给出的一行
CGLIB$test$0$Proxy = MethodProxy.create(var1, var0, "()V", "test", "CGLIB$test$0");
对应的方法如下

public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
        /**
         * 这几个参数都可以找到入参对象
         * c1: 被代理类对象的class,也就是原始对象的class
         * c2: 代理类对象的 class
         * desc: 方法的返回值类型
         * name1: 原始代理方法的名称
         * name2: 代理方法在代理类中的名称(CGLIB$test$0)
         */
        MethodProxy proxy = new MethodProxy();
        proxy.sig1 = new Signature(name1, desc);
        proxy.sig2 = new Signature(name2, desc);
        proxy.createInfo = new CreateInfo(c1, c2);
        return proxy;
    }

在MethodProxy中有三个很重要的属性

  • sig1: 表示test方法
  • sig2: 表示 CGLIB$test$0 方法
  • createInfo: 表示原始类和代理类

invoke和invokeSuper方法

 public Object invoke(Object obj, Object[] args) throws Throwable {
        try {
            this.init();
            FastClassInfo fci = this.fastClassInfo;
            return fci.f1.invoke(fci.i1, obj, args);
        } catch (InvocationTargetException var4) {
            throw var4.getTargetException();
        } catch (IllegalArgumentException var5) {
            if (this.fastClassInfo.i1 < 0) {
                throw new IllegalArgumentException("Protected method: " + this.sig1);
            } else {
                throw var5;
            }
        }
    }

    public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        try {
            this.init();
            FastClassInfo fci = this.fastClassInfo;
            return fci.f2.invoke(fci.i2, obj, args);
        } catch (InvocationTargetException var4) {
            throw var4.getTargetException();
        }
    }

两个方法大差不差的,但是都用到了一个对象 fastClassInfo 这个对象是在 init()方法中构造的

private void init() {
        if (this.fastClassInfo == null) {
            synchronized(this.initLock) {
                if (this.fastClassInfo == null) {
                    CreateInfo ci = this.createInfo;
                    FastClassInfo fci = new FastClassInfo();
                    fci.f1 = helper(ci, ci.c1);
                    fci.f2 = helper(ci, ci.c2);
                    fci.i1 = fci.f1.getIndex(this.sig1);
                    fci.i2 = fci.f2.getIndex(this.sig2);
                    this.fastClassInfo = fci;
                    this.createInfo = null;
                }
            }
        }

    }

fastClassInfo对象中主要是有四个属性

  • f1: 原始类对应的一个FastClass 代理对象
  • f2: 代理类对应的一个FastClass 代理对象
  • i1: test方法在原始类对应的一个FastClass代理对象中的下标
  • i2: CGLIB$test$0方法在代理类对应的一个 FastClass 代理对象中的下标
    这里产生了两个代理对象
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇【踩坑记录】@Transactional注解.. 下一篇手把手教你将Eureka升级Nacos注册..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目