cglib动态代理

示例代码

package com.cglib.dao;
public class CglibIndexDao1 {
}
package com.cglib.dao;
public class CglibIndexDao {
}

package com.cglib;
public class A {
    public void get(){
        System.out.println("A method");
    }
}

package com.cglib;
public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib");
        return methodProxy.invokeSuper( o,null );
    }
}

package com.cglib;
@Configuration
@ComponentScan("com.cglib")
public class CglibAppConfig {

    @Bean
    public CglibIndexDao cgDao(){
        System.out.println("cgDao");
        return new CglibIndexDao();
    }

    @Bean
    public CglibIndexDao1 cgDao1(){
        System.out.println("cgDao1");
        cgDao();
        return new CglibIndexDao1();
    }

}


package com.cglib;
public class TestCglib {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext ac =
                new AnnotationConfigApplicationContext( CglibAppConfig.class );
        CglibAppConfig bean = ac.getBean( CglibAppConfig.class );
        System.out.println(bean);

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(A.class);
        enhancer.setCallback( new MyMethodInterceptor() );
        enhancer.setUseFactory(false);
        enhancer.setCallbackType( MyMethodInterceptor.class );
        A cglib = (A) enhancer.create();
        cglib.get();

        byte[] bytes= ProxyGenerator.generateProxyClass("$proxy",new Class[]{bean.getClass()}  );
        System.out.println(CglibAppConfig.class);
        FileOutputStream fileOutputStream = new FileOutputStream( "c://$proxy.class" );
        fileOutputStream.write( bytes );
        fileOutputStream.close();

    }
}

生成的代理字节码文件

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import com.cglib.A..EnhancerByCGLIB..a3f6b2d1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.MethodProxy;

public final class $proxy extends Proxy implements a3f6b2d1 {
    private static Method m1;
    private static Method m5;
    private static Method m2;
    private static Method m4;
    private static Method m3;
    private static Method m6;
    private static Method m10;
    private static Method m12;
    private static Method m0;
    private static Method m7;
    private static Method m11;
    private static Method m9;
    private static Method m8;

    public $proxy(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void CGLIB$SET_THREAD_CALLBACKS(Callback[] var1) throws  {
        try {
            super.h.invoke(this, m5, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void CGLIB$SET_STATIC_CALLBACKS(Callback[] var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void get() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final MethodProxy CGLIB$findMethodProxy(Signature var1) throws  {
        try {
            return (MethodProxy)super.h.invoke(this, m6, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final Class getClass() throws  {
        try {
            return (Class)super.h.invoke(this, m10, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void notifyAll() throws  {
        try {
            super.h.invoke(this, m12, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void wait() throws InterruptedException {
        try {
            super.h.invoke(this, m7, (Object[])null);
        } catch (RuntimeException | InterruptedException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void notify() throws  {
        try {
            super.h.invoke(this, m11, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void wait(long var1) throws InterruptedException {
        try {
            super.h.invoke(this, m9, new Object[]{var1});
        } catch (RuntimeException | InterruptedException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final void wait(long var1, int var3) throws InterruptedException {
        try {
            super.h.invoke(this, m8, new Object[]{var1, var3});
        } catch (RuntimeException | InterruptedException | Error var5) {
            throw var5;
        } catch (Throwable var6) {
            throw new UndeclaredThrowableException(var6);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m5 = Class.forName("com.cglib.A$$EnhancerByCGLIB$$a3f6b2d1").getMethod("CGLIB$SET_THREAD_CALLBACKS", Class.forName("[Lorg.springframework.cglib.proxy.Callback;"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("com.cglib.A$$EnhancerByCGLIB$$a3f6b2d1").getMethod("CGLIB$SET_STATIC_CALLBACKS", Class.forName("[Lorg.springframework.cglib.proxy.Callback;"));
            m3 = Class.forName("com.cglib.A$$EnhancerByCGLIB$$a3f6b2d1").getMethod("get");
            m6 = Class.forName("com.cglib.A$$EnhancerByCGLIB$$a3f6b2d1").getMethod("CGLIB$findMethodProxy", Class.forName("org.springframework.cglib.core.Signature"));
            m10 = Class.forName("com.cglib.A$$EnhancerByCGLIB$$a3f6b2d1").getMethod("getClass");
            m12 = Class.forName("com.cglib.A$$EnhancerByCGLIB$$a3f6b2d1").getMethod("notifyAll");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m7 = Class.forName("com.cglib.A$$EnhancerByCGLIB$$a3f6b2d1").getMethod("wait");
            m11 = Class.forName("com.cglib.A$$EnhancerByCGLIB$$a3f6b2d1").getMethod("notify");
            m9 = Class.forName("com.cglib.A$$EnhancerByCGLIB$$a3f6b2d1").getMethod("wait", Long.TYPE);
            m8 = Class.forName("com.cglib.A$$EnhancerByCGLIB$$a3f6b2d1").getMethod("wait", Long.TYPE, Integer.TYPE);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

配置类增强

对配置类CglibAppConfig进行cglib代理

debug分析

1、invokeBeanFactoryPostProcessors 执行bean工厂后置处理器
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory, BeanFactoryPostProcessor>)

invokeBeanFactoryPostProcessors.png

2、postProcessBeanFactory 执行处理bean工厂方法
postProcessBeanFactory.png

3、enhanceConfigurationClasses 增强配置类
ConfigurationClassPostProcessor#postProcessBeanFactory
enhanceConfigurationClasses.png

4、设置beanDefinition属性值
beanDefsetAttribute.png

5、createClass
newEnhance.png

6、newEnhancer
newEnhancer.png

7、设置beanDefinition的beanClass
beanDefsetBeanClass.png

CglibAppConfig配置类的实例化过程,经历与其他一般class相同的的生命周期
生成增强类
class com.cglib.CglibAppConfigc67d1aaa

@Bean处理

根据示例代码,分析创建cgDao的过程
配置类加了@Bean的中方法调用只会创建一次bean

调用链

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory, List<BeanFactoryPostProcessor>)
PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors
ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry
ConfigurationClassPostProcessor#processConfigBeanDefinitions
ConfigurationClassParser#parse(Set<BeanDefinitionHolder>)
ConfigurationClassParser#parse(AnnotationMetadata, String)
ConfigurationClassParser#processConfigurationClass
ConfigurationClassParser#doProcessConfigurationClass

debug分析

1、doProcessConfigurationClass处理配置类的@bean


processBean.png

2、retrieveBeanMethodMetadata 查找@Bean注解
在ConfigurationClassParser#doProcessConfigurationClass方法内


retrieveBeanMethodMetadata.png

3、configClass 配置类集合添加bean方法
在ConfigurationClassParser#parse(Set<BeanDefinitionHolder>)方法解析之后放到Set<ConfigurationClass>集合
configClassaddBeanMethod.png

4、加载configClass 中类
ConfigurationClassBeanDefinitionReader#loadBeanDefinitions加载


loadBeanDefinition.png

5、loadBeanDefinitionsForConfigurationClass
loadBeanDefinitionsForConfigurationClass.png

6、加载第一个@bean方法
对beanMethod中第一个cgDao加载处理
loadBeanDefinitionsForBeanMethod.png

7、设置cgDao的BeanDefinition和注册到bean工厂
beanName是方法名cgDao
registerBeanDefinition.png

8、第一个@bean方法的实例化

cgDao的实例化,getFactoryMethodName工厂方法名不为null


getFactoryMethodName.png

9、instantiateUsingFactoryMethod 用工厂方法实例化
instantiateUsingFactoryMethod.png

10、首先获取工厂bean和工厂类
factoryClassfactoryBean.png

11、获取FactoryMethod
遍历所有方法,符合是工厂方法的
candidateList.png

12、对可用的工厂、参数等赋值
factoryMethodToUse.png

13、storeCache存储缓存
storeCache.png

isCurrentlyInvokedFactoryMethod.png

14、instantiate 根据默认实例化策略实例化
instantiate.png

15、设置当前执行的线程并执行invoke方法
currentlyInvokedFactoryMethod.set(factoryMethod);
factoryMethodinvoke.png

16、对invoke方法拦截处理
在BeanMethodInterceptor#intercept进行拦截处理
查看是否有scope注解
Scope.png

17、是否是FactoryBean工厂bean
BeanFactory.png

18、当前方法是否在执行
首先得到currentlyInvokedFactoryMethod线程正在执行的方法,此时是cgDao()方法。method是当前执行的方法
isCurrentlyInvokedFactoryMethod2.png

19、当前执行与线程正在执行相同
isCurrentlyInvokedFactoryMethod(beanMethod)为true
执行cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs)方法
cglibMethodProxyinvokeSuper.png

20、MethodProxy
MethodProxy.png

经过内部代理类调用最终执行到提供的方法
MethodInterceptor#intercept 执行结束
21、CglibAppConfig内方法执行
CglibAppConfig.png

22、currentlyInvokedFactoryMethod移除
currentlyInvokedFactoryMethodremove.png

23、cgDao1方法执行与cgDao的工厂方法执行步骤相同
24、直接到达示例代码中cgDao1()方法里的cgDao()方法调用
当执行到cgDao1()方法里的cgDao()方法调用时,进入BeanMethodInterceptor拦截
25、isCurrentlyInvokedFactoryMethod 是否正在执行 方法判断
此时,当前执行的方法是cgDao()。currentlyInvokedFactoryMethod正在执行线程的工厂方法是cgDao1。
所以,返回fasle
isCurrentlyInvokedFactoryMethodcgDao11.png

26、resolveBeanReference 查询
isCurrentlyInvokedFactoryMethod(beanMethod)返回false
resolveBeanReference.png

27、beanFactory bean工厂查找
beanFactorygetBean.png

28、注册bean依赖
registerDependentBean.png

所以,在配置类中无论在其他地方调用几次@Bean的工厂方法,只会实例化一次

总结:

cglib动态代理使用enhance类进行增强
设置Callback,执行被增强类方法前调用intercept方法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 227,797评论 6 531
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 98,179评论 3 414
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 175,628评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,642评论 1 309
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,444评论 6 405
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 54,948评论 1 321
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,040评论 3 440
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,185评论 0 287
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,717评论 1 333
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,602评论 3 354
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,794评论 1 369
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,316评论 5 358
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,045评论 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,418评论 0 26
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,671评论 1 281
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,414评论 3 390
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,750评论 2 370

推荐阅读更多精彩内容