cglib 动态代理原理详解

本文详细探讨了CGLIB动态代理的工作原理,包括代理类的生成、调用父类方法的方式以及调用原始方法的不同选项。通过分析源码,揭示了CGLIB如何在内部处理方法拦截,解释了为何CGLIB代理可能会导致内部调用切面失效的情况,并对比了CGLIB与JDK动态代理的性能差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

cglib 动态代理详解

我们都知道jdk的动态代理内部调用切面无效的问题,而cglib则不会出现这种情况,这是为什么?cglib就一定不会出现内部调用切面无效的问题吗?cglib针对每一个类只创建了一个代理类吗?为什么cglib的效率要比jdk的动态代理低呢?

首先我们看一下通常我们是如何使用cglib增强一个类的

public class Main {
    static class Test{
        public void test(){
            System.out.println("test");
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            innerTest();
        }

        public void innerTest(){
            System.out.println("inner test");
        }
    }

    public static void main(String[] args) throws Exception {
        Enhancer enhancer = new Enhancer();
        // 设置被代理的类
        enhancer.setSuperclass(Test.class);
        // 创建MethodInterceptor对象作为回调方法
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
                throws Throwable {
                long cost = System.currentTimeMillis();
                // 调用实际方法,也就是被代理类原本的方法
                Object result = methodProxy.invokeSuper(proxy, args);
                System.out.println("method " + method.getName() + " cost time :" + (System.currentTimeMillis() - cost));
                return result;
            }
        });
        // 生成代理类,并创建代理类对象
        Test test = (Test)enhancer.create();
        // 调用代理类对象的方法
        test.test();
    }
}

输出结果

test
inner test
method innerTest cost time :0
method test cost time :1012

结果完全符合我们的预期,内部调用的函数也被增强了,那我们接下来就一步步的看一下,cglib究竟是如何实现动态代理的。

1. cglib生成的代理类长什么样?

我们先看一下cglib是如何创建一个代理类的,从我们代码中调用的net.sf.cglib.proxy.Enhancer#create()方法开始一层层的往下看

// net.sf.cglib.proxy.Enhancer#create
// 我们创建代理类的入口
public Object create() {
    classOnly = false;
    argumentTypes = null;
    return createHelper();
}

// net.sf.cglib.proxy.Enhancer#createHelper
private Object createHelper() {
    // 预处理,验证是否有明确的回调信息
    preValidate();
    // 存储类信息、回调方法信息等,cglib使用这些信息对象作为缓存key;之后可以根据key直接去缓存中查找创建过的代理类
    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;
    // 生成代理类信息,并返回代理对象
    Object result = super.create(key);
    return result;
}

// 父类的create方法,创建代理类并获取代理类对象
// net.sf.cglib.core.AbstractClassGenerator#create
protected Object create(Object key) {
    try {
        ClassLoader loader = getClassLoader();
        /**
        * 省略从缓存中获取对象的代码
        */
        this.key = key;
        // 从缓存中获取代理类的Class对象
        Object obj = data.get(this, getUseCache());
        if (obj instanceof Class) {
            // 使用代理类的Class对象进行实例化
            return firstInstance((Class) obj);
        }
        return nextInstance(obj);
    } catch (RuntimeException e) {
        // 省略异常处理代码
        ......
    }
}
// 如果使用缓存,则从缓存中取,若不存在则先生成代理类;如果不使用缓存则直接创建
// net.sf.cglib.core.AbstractClassGenerator.ClassLoaderData#get
public Object get(AbstractClassGenerator gen, boolean useCache) {
    if (!useCache) {
        // 创建代理类并生成对象
        return gen.generate(ClassLoaderData.this);
    } else {
        Object cachedValue = generatedClasses.get(gen);
        return gen.unwrapCachedValue(cachedValue);
    }
}

// 生成代理类并创建代理对象的核心代码;cglib所有的代理类都从这里创建
// net.sf.cglib.core.AbstractClassGenerator#generate
protected Class generate(ClassLoaderData data) {
    Class gen;
    Object save = CURRENT.get();
    CURRENT.set(this);
    try {
        // 获取类加载器
        ClassLoader classLoader = data.getClassLoader();
        ....
        synchronized (classLoader) {
            // 生成代理类的类名
            String name = generateClassName(data.getUniqueNamePredicate());              
            data.reserveName(name);
            this.setClassName(name);
        }
        // 生成代理类的字节码;
        // 若想获取生成的代理类的字节码信息可以在此打断点,将字节数据输出到本地文件中,之后所有获取的代理类字节码信息均采用此方法
        byte[] b = strategy.generate(this);
        String className = ClassNameReader.getClassName(new ClassReader(b));
        ProtectionDomain protectionDomain = getProtectionDomain();
        synchronized (classLoader) { 
            // 将字节码转换
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值