【spring源碼分析】IOC容器初始化——查漏補缺(二)

前言:在【spring源碼分析】IOC容器初始化(八)中屢次提到了前置處理與後置處理,本篇文章針對此問題進行分析。Spring對前置處理或後置處理主要經過BeanPostProcessor進行實現。html


BeanPostProcessor的做用:在Bean實例化先後,若是須要對Bean進行一些配置、增長一些本身的處理邏輯,則使用BeanPostProcessor。spring

BeanPostProcessor示例

定義一個類實現BeanPostProcessor接口:緩存

 1 public class UserDefinedBeanPostProcessor implements BeanPostProcessor {
 2 
 3     @Override
 4     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 5         System.out.println("BeanName=" + beanName + " 初始化以前進入");
 6         if ("beanPostProcessorBase".equals(beanName)) {
 7             BeanPostProcessorBase processorBase = (BeanPostProcessorBase) bean;
 8             processorBase.setMsg("Hello BeanPostProcessor!!!!!!!");
 9         }
10         return bean;
11     }
12 
13     @Override
14     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
15         System.out.println("BeanName=" + beanName + " 初始化以後進入");
16         return bean;
17     }
18 
19     public void showMsg() {
20         System.out.println("BeanPostProcessor Test!!!!!!");
21     }
22 }

再定義一個基礎測試類:安全

 1 public class BeanPostProcessorBase {
 2 
 3     private String msg;
 4 
 5     public String getMsg() {
 6         return msg;
 7     }
 8 
 9     public void setMsg(String msg) {
10         this.msg = msg;
11     }
12 }

測試方法:app

1     @Test
2     public void beanPostProcessorTest() {
3         ApplicationContext context = new ClassPathXmlApplicationContext("com/dev/config/beanpostprocessor/beanpostprocessor.xml");
4         BeanPostProcessorBase postProcessor = context.getBean(BeanPostProcessorBase.class);
5         System.out.println(postProcessor.getMsg());
6     }

運行結果:ide

分析:函數

首先必須明確BeanPostProcessor的執行時機:AbstractAutowireCapableBeanFactory#initializeBean方法源碼分析

 1 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
 2         // 安全模式
 3         if (System.getSecurityManager() != null) {
 4             AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
 5                 // 激活Aware方法,對特殊bean處理:Aware、BeanClassLoaderAware、BeanFactoryAware
 6                 invokeAwareMethods(beanName, bean);
 7                 return null;
 8             }, getAccessControlContext());
 9         } else {
10             //  非安全模式下激活Aware方法,對特殊bean處理:Aware、BeanClassLoaderAware、BeanFactoryAware
11             invokeAwareMethods(beanName, bean);
12         }
13 
14         // 後置處理器 before
15         Object wrappedBean = bean;
16         if (mbd == null || !mbd.isSynthetic()) {
17             wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
18         }
19 
20         // 處理初始化方法
21         try {
22             invokeInitMethods(beanName, wrappedBean, mbd);
23         } catch (Throwable ex) {
24             throw new BeanCreationException(
25                     (mbd != null ? mbd.getResourceDescription() : null),
26                     beanName, "Invocation of init method failed", ex);
27         }
28         // 後置處理器 after
29         if (mbd == null || !mbd.isSynthetic()) {
30             wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
31         }
32 
33         return wrappedBean;
34     }

分析:post

  • 從該函數邏輯能夠看出,BeanPostProcessor的執行時機是在bean初始化先後,其實這裏也能夠看出bean的生命週期,這裏後面再分析。
  • 還有爲何要建立一個基礎測試類來進行演示,若是直接使用UserDefinedBeanPostProcessor類進行演示是得不到咱們所須要的效果的,由於ApplicationContext對象會自動註冊BeanPostProcessor,而且在註冊會實例化BeanPostProcessor,而後在第二次調用的時候就會從單例緩存中取值,所以得不到想要的效果。自動註冊並實例化BeanPostProcessor參看PostProcessorRegistrationDelegate#registerBeanPostProcessors函數,細讀該函數就會豁然開朗。

BeanPostProcessor總結

BeanPostProcessor能夠理解爲是Spring的一個工廠鉤子(其實Spring提供一系列的鉤子,如Aware 、InitializingBean、DisposableBean),它是Spring提供的對象實例化階段強有力的擴展點,容許Spring在實例化bean階段對其進行定製化修改,比較常見的使用場景是處理標記接口實現類或者爲當前對象提供代理實現(例如 AOP)。測試

BeanPostProcessor的執行時機以下:

注意:通常的BeanFactory是不支持自動註冊BeanPostProcessor,需手動調用addBeanPostProcessor進行註冊,可是ApplicationContext支持自動註冊,可是在其註冊過程當中就會對BeanPostProcessor進行初始化並進緩存,所以在示例代碼中利用了基礎測試類來進行演示。

BeanPostProcessor的做用域是容器級別的,它只和所在的容器相關,當BeanPostProcessor完成註冊後,它會應用於全部跟它在同一容器內的bean


by Shawn Chen,2019.05.05,上午。

相關文章
相關標籤/搜索