第十四讲-Cglib代理原理

第十四讲-Cglib代理原理

1. Cglib代理类的模拟实现

首先准备一个目标类:

package com.cherry.chapter1.a14;

public class Target {
    public void save(){
        System.out.println("save()");
    }

    public void save(int i){
        System.out.println("save(int)");
    }

    public void save(long i){
        System.out.println("save(long)");
    }
}

编写一个代理类来模拟Cglib的代理类,继承目标类并重写父类中的方法:

package com.cherry.chapter1.a14;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.UndeclaredThrowableException;

import java.lang.reflect.Method;

public class CglibProxy extends Target{

    private MethodInterceptor methodInterceptor;

    public CglibProxy(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }

    static Method save0;
    static Method save1;
    static Method save2;


    static {
        try{save0 = Target.class.getDeclaredMethod("save");
            save1 = Target.class.getDeclaredMethod("save", int.class);
            save2 = Target.class.getDeclaredMethod("save", long.class);
        } catch (NoSuchMethodException e){
            throw new NoSuchMethodError(e.getMessage());
        }
    }

    @Override
    public void save() {
        try {
            methodInterceptor.intercept(this, save0, new Object[0], null);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public void save(int i) {
        try {
            methodInterceptor.intercept(this, save1, new Object[]{i}, null);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public void save(long j) {
        try {
            methodInterceptor.intercept(this, save2, new Object[]{j}, null);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
}

编写一个测试类测试一下:

package com.cherry.chapter1.a14;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class A14 {
    public static void main(String[] args) {
        Target target = new Target();
        CglibProxy proxy = new CglibProxy(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("before....");
                return method.invoke(target, args);
            }
        });
        proxy.save();
        proxy.save(100);
        proxy.save(1000L);
    }
}
before....
save()
before....
save(int)
before....
save(long)

上面我们还是采用了Cglib中利用反射调用来调用方法,但是Cglib除了利用反射实现方法调用,还有一个属性,就是MethodProxy,MethodProxy可以让我们不经过反射来调用方法。现在我们来看一下MethodProxy对象是如何被创建的

package com.cherry.chapter1.a14;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.UndeclaredThrowableException;

import java.lang.reflect.Method;

public class CglibProxy extends Target {

    private MethodInterceptor methodInterceptor;

    public CglibProxy(MethodInterceptor methodInterceptor) {
        this.methodInterceptor = methodInterceptor;
    }

    static Method save0;
    static Method save1;
    static Method save2;

    // 创建MethodProxy对象
    static MethodProxy save0Proxy;
    static MethodProxy save1Proxy;
    static MethodProxy save2Proxy;


    static {
        try {
            save0 = Target.class.getDeclaredMethod("save");
            save1 = Target.class.getDeclaredMethod("save", int.class);
            save2 = Target.class.getDeclaredMethod("save", long.class);
            /**
             * create(目标类型,代理类型, 参数类型和返回值类型,带增强功能的方法名,带原始功能的方法名)
             */
            save0Proxy = MethodProxy.create(Target.class, CglibProxy.class, "()V", "save", "saveSuper");
            save1Proxy = MethodProxy.create(Target.class, CglibProxy.class, "(I)V", "save", "saveSuper");
            save2Proxy = MethodProxy.create(Target.class, CglibProxy.class, "(J)V", "save", "saveSuper");


        } catch (NoSuchMethodException e) {
            throw new NoSuchMethodError(e.getMessage());
        }
    }

    // >=======================带原始功能的方法=====================
    public void saveSuper() {
        super.save();
    }

    public void saveSuper(int i) {
        super.save(i);
    }

    public void saveSuper(long j) {
        super.save(j);
    }


    // >=======================带增强功能的方法=====================
    @Override
    public void save() {
        try {	// 讲带有增强功能的方法作为参数传递进去
            methodInterceptor.intercept(this, save0, new Object[0], save0Proxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }

    @Override
    public void save(int i) {
        try {
            methodInterceptor.intercept(this, save1, new Object[]{i}, save1Proxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
    
    @Override
    public void save(long j) {
        try {
            methodInterceptor.intercept(this, save2, new Object[]{j}, save2Proxy);
        } catch (Throwable e) {
            throw new UndeclaredThrowableException(e);
        }
    }
}

接下来我们测试一下:

package com.cherry.chapter1.a14;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class A14 {
    public static void main(String[] args) {
        Target target = new Target();
        CglibProxy proxy = new CglibProxy(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("before....");
                // return method.invoke(target, args); ---> 反射调用
                return methodProxy.invoke(target, args);// ---> 无反射调用,结合目标用
                // methodProxy.invokeSuper(o, args);	//内部无反射,结合代理用
            }
        });
        proxy.save();
        proxy.save(100);
        proxy.save(1000L);
    }
}
before....
save()
before....
save(int)
before....
save(long)

我们发现增强功能有了。

2. Cglib是如何避免反射调用的

刚才我们讲了,MethodProxy在调用invoke或者invokeSuper在内部是不会走反射的,而是正常调用, 那么其内部是怎么实现的呢?其实是它们两者的内部又会产生两个代理类,这两个代理类一个配合invoke和目标使用,另一个配合invokeSuper和代理对象使用。值得注意的是,这两个代理类都继承于FastClass这个类。我们为FastClass提供两个子类,,来看一下其中的index和invoke方法是怎么实现的。

package com.cherry.chapter1.a14;

import org.springframework.cglib.core.Signature;

import java.lang.reflect.InvocationTargetException;


/**
 * 在代理中中的MethodProxy.create()方法就会生成一个FastClass对象
 */

// 配合目标一起使用
public class TargetFastClass {

    // 声明一个签名变量,一个方法对应一个签名变量
    static Signature s0 = new Signature("save","()V");
    static Signature s1 = new Signature("save","(I)V");
    static Signature s2 = new Signature("save","(J)V");



    /**
     *
     * 获取目标方法的编号
     * Target
     *      save()              0
     *      save(int i)         1
     *      save(long j)        2
     * 针对每一个方法给定一个唯一的编号,
     * getIndex根据方法签名信息获取方法的编号
     * Signature包括方法名字,方法参数,返回值等信息
     */
    public int getIndex(Signature signature){
        if (s0.equals(signature)){
            return 0;
        } else if (s1.equals(signature)) {
            return 1;
        } else if (s2.equals(signature)) {
            return 2;
        }
        return -1;  //  表示没有找到该方法签名
    }

    /**
     * invoke根据getIndex()返回的方法编号去正常调用目标对象中的方法
     */
    public Object invoke(int index, Object target, Object[] args) throws InvocationTargetException{
        if (index == 0) {
            ((Target)target).save();    // 目标正常调用方法
            return null;
         } else if (index == 1){
            ((Target) target).save((int)args[0]);
            return null;
        } else if (index == 2){
            ((Target) target).save((long)args[0]);
            return null;
        }
    }
}

这里呢,我们梳理一下:

  1. 我们在使用MethodProxy对象时,底层就会创建一个FastClass对象(代理类对象),我们会将每一个方法封装为每一个方法签名,并且给定对应的唯一编号

  2. 当我们调用methodProxy.invoke(target, args)方法时,底层会调用fastClass对象的invoke方法,会根据传递过来的方法名和方法签名进行匹配,如果匹配上了,就会正常调用该方法,从而避免了反射调用。

posted @   LilyFlower  阅读(16)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示