Spring拓展介面之BeanPostProcessor,我們來看看它的底層實現
前言
開心一刻
小明:“媽,我被公司開除了”,媽:“啊,為什麼呀?”, 小明:“我罵董事長是笨蛋,公司召開高層會議還要起訴我”,媽:“告你誹謗是吧?”,小明:“不是,他們說要告我洩露公司機密”
BeanPostProcessor定義
不管三七二十一,我們先來看看它的定義,看看spring是如何描述BeanPostProcessor的
/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.config; import org.springframework.beans.BeansException; import org.springframework.lang.Nullable; /** * 允許對新的bean示例進行自定義的修改,例如檢查標誌介面或進行代理封裝 * * spring上下文會在它的beng定義中自動檢測BeanPostProcessor例項,並將它們應用於隨後建立的每一個bean例項 * * implement {@link #postProcessAfterInitialization}. * 通常,通過實現BeanPostProcessor的postProcessBeforeInitialization方法(配合標記介面,如@Autowired)來填充bean例項, * 通過BeanPostProcessor的postProcessAfterInitialization方法進行bean例項的代理 * */ public interface BeanPostProcessor { /** * 在bean例項的初始化方法(例如InitializingBean的afterPropertiesSet或自定義的init-method)回撥之前, * spring會應用此方法到bean例項上。一般用於bean例項的屬性值的填充 * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean * initialization callbacks (like InitializingBean's {@code afterPropertiesSet} * or a custom init-method). The bean will already be populated with property values. * The returned bean instance may be a wrapper around the original. * <p>The default implementation returns the given {@code bean} as-is. * @param bean the new bean instance * @param beanName the name of the bean * @return the bean instance to use, either the original or a wrapped one; * if {@code null}, no subsequent BeanPostProcessors will be invoked * @throws org.springframework.beans.BeansException in case of errors * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet */ @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } /** * 在bean例項的初始化方法(例如InitializingBean的afterPropertiesSet或自定義的init-method)回撥之後, * spring會應用此方法到bean例項上。 * 在有FactoryBean時,此方法會在FactoryBean例項與FactoryBean的目標物件建立時各呼叫一次 * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean * initialization callbacks (like InitializingBean's {@code afterPropertiesSet} * or a custom init-method). The bean will already be populated with property values. * The returned bean instance may be a wrapper around the original. * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean * instance and the objects created by the FactoryBean (as of Spring 2.0). The * post-processor can decide whether to apply to either the FactoryBean or created * objects or both through corresponding {@code bean instanceof FactoryBean} checks. * <p>This callback will also be invoked after a short-circuiting triggered by a * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method, * in contrast to all other BeanPostProcessor callbacks. * <p>The default implementation returns the given {@code bean} as-is. * @param bean the new bean instance * @param beanName the name of the bean * @return the bean instance to use, either the original or a wrapped one; * if {@code null}, no subsequent BeanPostProcessors will be invoked * @throws org.springframework.beans.BeansException in case of errors * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet * @see org.springframework.beans.factory.FactoryBean */ @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
簡單點來理解,就是spring會自動從它的所有的bean定義中檢測BeanPostProcessor型別的bean定義,然後例項化它們,再將它們應用於隨後建立的每一個bean例項,在bean例項的初始化方法回撥之前呼叫BeanPostProcessor的postProcessBeforeInitialization的方法(進行bean例項屬性的填充),在bean例項的初始化方法回撥之後呼叫BeanPostProcessor的postProcessAfterInitialization的方法(可以進行bean例項的代理封裝)
應用示例
我們先來看個簡單的示例,注意:由於spring只是從spring容器中的bean定義中自動檢測BeanPostProcessor型別的bean定義,所以我們自定義的BeanPostProcessor要通過某種方式註冊到spring容器
MyBeanPostProcessor
@Component public class MyBeanPostProcessor implements BeanPostProcessor { public MyBeanPostProcessor () { System.out.println("MyBeanPostProcessor 例項化......"); } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("spring中bean例項:" + beanName + " 初始化之前處理......"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("spring中bean例項:" + beanName + " 初始化之後處理......"); return bean; } }
AnimalConfig
@Configuration public class AnimalConfig { public AnimalConfig() { System.out.println("AnimalConfig 例項化"); } @Bean public Dog dog() { return new Dog(); } }View Code
Dog
public class Dog { private String name; public Dog() { System.out.println("Dog 例項化......"); } public String getName() { return name; } public void setName(String name) { this.name = name; } }View Code
完整例項工程:spring-boot-BeanPostProcessor 我們來看看啟動結果
有人可能會說了:“你是個逗比把,你舉的這個例子有什麼用? 實際上,根本就不會出現BeanPostProcessor的這樣用法!” 有這樣的疑問非常正常,示例中的BeanPostProcessor的兩個方法:postProcessBeforeInitialization、postProcessAfterInitialization沒做任何的處理,都只是直接返回bean,這不就是:脫了褲子放屁?
我們細看下,會發現postProcessBeforeInitialization、postProcessAfterInitialization中各多了一行列印(),其實示例只是驗證下Spring對BeanPostProcessor的支援、BeanPostProcessor的兩個方法的執行時機,是否如BeanPostProcessor 的註釋所說的那樣,實際應用中肯定不會這麼用的。那問題來了:BeanPostProcessor能用來幹什麼? 回答這個問題之前,我們先來看看spring對BeanPostProcessor的底層支援
原始碼解析
BeanPostProcessor的例項化與註冊
很明顯,我們從spring的啟動過程的refresh方法開始,如下圖
此時spring容器中所有的BeanPostProcessor都進行了例項化,並註冊到了beanFactory的beanPostProcessors屬性中
registerBeanPostProcessors
public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) { String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // Register BeanPostProcessorChecker that logs an info message when // a bean is created during BeanPostProcessor instantiation, i.e. when // a bean is not eligible for getting processed by all BeanPostProcessors. int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // Separate between BeanPostProcessors that implement PriorityOrdered, // Ordered, and the rest. // 將所有BeanPostProcessor bean定義分三類:實現了PriorityOrdered、實現了Ordered,以及剩下的常規BeanPostProcessor List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>(); List<BeanPostProcessor> internalPostProcessors = new ArrayList<>(); List<String> orderedPostProcessorNames = new ArrayList<>(); List<String> nonOrderedPostProcessorNames = new ArrayList<>(); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { // 例項化實現了PriorityOrdered介面的BeanPostProcessor BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); priorityOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } // First, register the BeanPostProcessors that implement PriorityOrdered. // 註冊實現了PriorityOrdered介面的BeanPostProcessor到beanFactory的beanPostProcessors屬性中 sortPostProcessors(priorityOrderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors); // Next, register the BeanPostProcessors that implement Ordered. List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(); for (String ppName : orderedPostProcessorNames) { // 例項化實現了Ordered介面的BeanPostProcessor BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); orderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } // 註冊實現了Ordered介面的BeanPostProcessor到beanFactory的beanPostProcessors屬性中 sortPostProcessors(orderedPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, orderedPostProcessors); // Now, register all regular BeanPostProcessors. List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(); for (String ppName : nonOrderedPostProcessorNames) { // 例項化剩下的所有的常規的BeanPostProcessors BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); nonOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors); // Finally, re-register all internal BeanPostProcessors. // 註冊所有常規的的BeanPostProcessor到beanFactory的beanPostProcessors屬性中 sortPostProcessors(internalPostProcessors, beanFactory); registerBeanPostProcessors(beanFactory, internalPostProcessors); // Re-register post-processor for detecting inner beans as ApplicationListeners, // moving it to the end of the processor chain (for picking up proxies etc). beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext)); }View Code
BeanPostProcessor的生效時機
前面我們已經知道,spring會應用BeanPostProcessor於隨後建立的每一個bean例項,具體spring是如何做到的了,我們仔細來看看
finishBeanFactoryInitialization方法例項化所有剩餘的、非延遲初始化的單例(預設情況下spring的bean都是非延遲初始化單例),具體如下
BeanPostProcessor應用場景
其實只要我們弄清楚了BeanPostProcessor的執行時機:在bean例項化之後、初始化前後被執行,允許我們對bean例項進行自定義的修改;只要我們明白了這個時機點,我們就能分辨出BeanPostProcessor適用於哪些需求場景,哪些需求場景可以用BeanPostProcessor來實現
spring中有很多BeanPostProcessor的實現,我們接觸的比較多的自動裝配:AutowiredAnnotationBeanPostProcessor也是BeanPostProcessor的實現之一,關於自動裝配我會在下篇博文中與大家一起探索
總結
spring中bean的生命週期如下圖
引用自:Spring實戰系列(三)-BeanPostProcessor的妙用