前言
- 上篇博客spring 5.0.x源碼學習系列六: 后置處理器ConfigurationClassPostProcessor之BeanDefinitionRegistryPostProcessor身份主要介紹了ConfigurationClassPostProcessor的BeanDefinitionRegistryPostProcessor身份, 為了精通spring, 我們還需要對它的第二個身份
BeanFactoryPostProcessor進行總結
一、ConfigurationClassPostProcessor之BeanFactoryPostProcessor身份
- 它的這個身份同樣起到了非常重要的作用: 為全配置類添加cglib代理,防止以@Bean的方式創(chuàng)建bean時出現(xiàn)重復調(diào)用相同邏輯的問題。 接下來我們按照如下demo一起探究它。
二、項目demo
2.1 項目全景圖
在這里插入圖片描述
2.1.1 AppConfig
在這里插入圖片描述
2.1.2 Bean1
在這里插入圖片描述
2.1.3 Bean2
在這里插入圖片描述
2.1.4 Entry
在這里插入圖片描述
在這里插入圖片描述
2.2 運行結果
2.2.1 AppConfig類中無@Configuration注解的運行結果
在這里插入圖片描述
2.2.1 AppConfig類中有@Configuration注解的運行結果
在這里插入圖片描述
2.3 解釋運行結果
| 情形 | 運行結果 | 原因 |
|---|---|---|
| AppConfig中無@Configuration注解 | 打印了兩次"creating bean1" | 運行的沒有一點毛病, 按照正常邏輯, 執(zhí)行了兩次(spring創(chuàng)建Bean1的時候調(diào)用了一次, 創(chuàng)建Bean2的時候又調(diào)用了一次)創(chuàng)建bean的方法, 所以輸出兩次"creating bean1", 沒毛病 |
| AppConfig中存在@Configuration注解 | 只打印了一次"creating bean1" | 是因為spring在執(zhí)行BeanFactoryPostProcessor后置處理器時. 執(zhí)行到了ConfigurationClassPostProcessor的postProcessBeanFactory方法, 此方法對所有的全注解類進行了CGLIB代理, 對方法進行了增強, 但此時只是將產(chǎn)生的cglib的class添加到了當前全配置類對應的beanDefinition的beanClass屬性中(注意: 此時并沒有產(chǎn)生bean, 只是改變了beanClass屬性) |
2.4 查看cglib代理類內(nèi)容
2.4.1 設置指定屬性, 將cglib代理類保存至指定地方
// 將整個工程中產(chǎn)生的cglib代理類全部存入g盤的cglib文件夾中
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "g://cglib");
2.4.2 運行項目并查看文件夾
在這里插入圖片描述
2.4.3 將整個com文件夾copy至idea中可以解析class文件的目錄下
因spring源碼是用gradle編譯的, 我copy進的是out文件夾中, 若是普通的maven項目, 把它copy至target文件夾中即可
-
生成的代理類文件夾結構如下:
在這里插入圖片描述 -
代理類源碼:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.eugene.sumarry.csdn.invokeBeanFactoryPostProcessor3; import java.lang.reflect.Method; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.cglib.core.ReflectUtils; import org.springframework.cglib.core.Signature; import org.springframework.cglib.proxy.Callback; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import org.springframework.cglib.proxy.NoOp; import org.springframework.context.annotation.ConfigurationClassEnhancer.EnhancedConfiguration; /** * 它繼承了AppConfig, 所以斷定它就是AppConfig類的cglib代理類 */ public class AppConfig$$EnhancerBySpringCGLIB$$912e823e extends AppConfig implements EnhancedConfiguration { 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 MethodInterceptor CGLIB$CALLBACK_1; private NoOp CGLIB$CALLBACK_2; private static Object CGLIB$CALLBACK_FILTER; private static final Method CGLIB$bean1$0$Method; private static final MethodProxy CGLIB$bean1$0$Proxy; private static final Object[] CGLIB$emptyArgs; private static final Method CGLIB$bean2$1$Method; private static final MethodProxy CGLIB$bean2$1$Proxy; private static final Method CGLIB$setBeanFactory$6$Method; private static final MethodProxy CGLIB$setBeanFactory$6$Proxy; public BeanFactory $$beanFactory; static void CGLIB$STATICHOOK1() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; Class var0 = Class.forName("com.eugene.sumarry.csdn.invokeBeanFactoryPostProcessor3.AppConfig$$EnhancerBySpringCGLIB$$912e823e"); Class var1; CGLIB$setBeanFactory$6$Method = ReflectUtils.findMethods(new String[]{"setBeanFactory", "(Lorg/springframework/beans/factory/BeanFactory;)V"}, (var1 = Class.forName("org.springframework.beans.factory.BeanFactoryAware")).getDeclaredMethods())[0]; CGLIB$setBeanFactory$6$Proxy = MethodProxy.create(var1, var0, "(Lorg/springframework/beans/factory/BeanFactory;)V", "setBeanFactory", "CGLIB$setBeanFactory$6"); Method[] var10000 = ReflectUtils.findMethods(new String[]{"bean1", "()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean1;", "bean2", "()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean2;"}, (var1 = Class.forName("com.eugene.sumarry.csdn.invokeBeanFactoryPostProcessor3.AppConfig")).getDeclaredMethods()); CGLIB$bean1$0$Method = var10000[0]; CGLIB$bean1$0$Proxy = MethodProxy.create(var1, var0, "()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean1;", "bean1", "CGLIB$bean1$0"); CGLIB$bean2$1$Method = var10000[1]; CGLIB$bean2$1$Proxy = MethodProxy.create(var1, var0, "()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean2;", "bean2", "CGLIB$bean2$1"); } final Bean1 CGLIB$bean1$0() { return super.bean1(); } /** * 代理增強的bean1方法 */ public final Bean1 bean1() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? (Bean1)var10000.intercept(this, CGLIB$bean1$0$Method, CGLIB$emptyArgs, CGLIB$bean1$0$Proxy) : super.bean1(); } final Bean2 CGLIB$bean2$1() { return super.bean2(); } /** * 代理增強的bean2方法 */ public final Bean2 bean2() { // 這里獲取到產(chǎn)生cglib代理類時的方法攔截器 // 在spring中默認的方法攔截器有這三個: // private static final Callback[] CALLBACKS = new Callback[] { // new BeanMethodInterceptor(), // new BeanFactoryAwareMethodInterceptor(), // NoOp.INSTANCE // }; // 方法攔截器的具體作用沒有去研究, 這里大致走的是方法攔截器, 在方法攔截器中對bean2方法進行了增強 MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } return var10000 != null ? (Bean2)var10000.intercept(this, CGLIB$bean2$1$Method, CGLIB$emptyArgs, CGLIB$bean2$1$Proxy) : super.bean2(); } final void CGLIB$setBeanFactory$6(BeanFactory var1) throws BeansException { super.setBeanFactory(var1); } public final void setBeanFactory(BeanFactory var1) throws BeansException { MethodInterceptor var10000 = this.CGLIB$CALLBACK_1; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_1; } if (var10000 != null) { var10000.intercept(this, CGLIB$setBeanFactory$6$Method, new Object[]{var1}, CGLIB$setBeanFactory$6$Proxy); } else { super.setBeanFactory(var1); } } public static MethodProxy CGLIB$findMethodProxy(Signature var0) { String var10000 = var0.toString(); switch(var10000.hashCode()) { case -1792804773: if (var10000.equals("bean2()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean2;")) { return CGLIB$bean2$1$Proxy; } break; case 720662557: if (var10000.equals("bean1()Lcom/eugene/sumarry/csdn/invokeBeanFactoryPostProcessor3/Bean1;")) { return CGLIB$bean1$0$Proxy; } break; case 2095635076: if (var10000.equals("setBeanFactory(Lorg/springframework/beans/factory/BeanFactory;)V")) { return CGLIB$setBeanFactory$6$Proxy; } } return null; } public AppConfig$$EnhancerBySpringCGLIB$$912e823e() { 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) { AppConfig$$EnhancerBySpringCGLIB$$912e823e var1 = (AppConfig$$EnhancerBySpringCGLIB$$912e823e)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; } } Callback[] var10001 = (Callback[])var10000; var1.CGLIB$CALLBACK_2 = (NoOp)((Callback[])var10000)[2]; var1.CGLIB$CALLBACK_1 = (MethodInterceptor)var10001[1]; var1.CGLIB$CALLBACK_0 = (MethodInterceptor)var10001[0]; } } static { CGLIB$STATICHOOK2(); CGLIB$STATICHOOK1(); } static void CGLIB$STATICHOOK2() { } }
三、總結
- ConfigurationClassPostProcessor之BeanFactoryPostProcessor身份最重要的就是為全注解類添加cglib代理了。當然除此之外, 還注冊了一個類型為ImportAwareBeanPostProcessor的BeanPostProcessor,這里還未總結到它有何用。
- I am a slow walker, but I never walk backwards.
- github spring源碼學習地址: https://github.com/AvengerEug/spring/tree/develop/resourcecode-study