Spring BeanPostProcessor源碼示例解析
正文
BeanPostProcessor對于Spring開發(fā)者來說一定不陌生,平時開發(fā)過程中如果涉及對中間件做增強處理或者需要對某個實際Bean做初始化前的處理,一般都可以使用該接口來實現(xiàn)。
對于自己來說自己在對接RocketMQ、RabbitMQ過程中需要實現(xiàn)一個快速接入SpringBoot的中間插件,最快速的就是實現(xiàn)該接口對中間件中的Bean做增強處理,能夠快速接入SpringBoot。
1. BeanPostProcessor介紹
BeanPostProcessor是一個接口,該接口提供給開發(fā)者使用,開發(fā)者可以實現(xiàn)該接口,然后在實現(xiàn)類中對想要處理的類做增強處理。
該接口中提供了兩個基礎(chǔ)方法:
- postProcessBeforeInitialization:Bean初始化前對Bean的增強處理
- postProcessAfterInitialization:Bean初始化后對Bean的增強處理
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
下面舉一個最簡單的例子來看一下BeanPostProcessor的使用。
2. BeanPostProcessor的使用
@Service
public class UserService {
private String name = "陳tom";
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Component
public class MyPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
UserService userService = (UserService) bean;
userService.setName("陳湯姆");
userService.setAge(21);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
@SpringBootApplication
public class BootApplication {
@Resource
private DefaultListableBeanFactory defaultListableBeanFactory;
public static void main(String[] args) {
SpringApplication.run(BootApplication.class,args);
}
@PostConstruct
public void init() {
UserService userService = defaultListableBeanFactory.getBean("userService", UserService.class);
System.out.println("測試結(jié)果:姓名:"+userService.getName()+";年齡:"+userService.getAge());
}
}

以上的實現(xiàn)中做了最簡單的實現(xiàn),通過MyPostProcessor實現(xiàn)BeanPostProcessor接口,然后在前置增強處理中加入對Bean的修改。
然后通過PostConstruct在Bean初始化后做Bean的查詢,得到通過BeanPostProcessor操作的結(jié)果。
所以BeanPostProcessor在使用上來說很簡單,對于開發(fā)者來說它很方便的提供了對于Bean對象的修改操作,提高了Spring的擴展性和靈活性。
3. BeanPostProcessor的作用
說完了最基礎(chǔ)的BeanPostProcessor的使用,通過以上的實現(xiàn)來梳理下BeanPostProcessor的作用。
- 對Bean的修改操作,通過實現(xiàn)該接口可以很快的實現(xiàn)對Bean的操作
- 提供前置和后置兩個處理,提供開發(fā)者可以在初始化前做處理以及初始化后做處理
- 對于Spring框架的靈活性,使用Spring框架也可以很方便的做自己的邏輯處理
自己對于BeanPostProcessor最大的感受就是太靈活了,開發(fā)者只要實現(xiàn)該接口,然后重寫其中的方法就可以實現(xiàn)自己的邏輯。這樣也保證了Spring容器對于開發(fā)者來說并不是一個黑盒,開發(fā)者可以通過Spring提供的鑰匙讓Spring容器暴露在開發(fā)者眼中,想要做什么處理都可以根據(jù)提供的鑰匙實現(xiàn)。(這里其實還有一個配套的BeanFactoryPostProcessor,面試的時候也經(jīng)常被問到BeanPostProcessor和BeanFactoryPostProcessor的區(qū)別,有興趣的可以自己了解下,區(qū)別只是最終服務的對象不一樣)
這里不得不說Spring YYDS?。?!
4. BeanPostProcessor注冊
Q:既然開發(fā)者通過自己的實現(xiàn)類實現(xiàn)了BeanPostProcessor,那么Spring又是如何將開發(fā)者做的實現(xiàn)類加入到Spring中并且執(zhí)行開發(fā)者重寫的前置和后置增強邏輯呢?
這里就要提到Spring對于BeanPostProcessor的設計,在Spring中初始化了一個CopyOnWriteArrayList作為存儲所有實現(xiàn)BeanPostProcessor的列表。
從實現(xiàn)上可以看到該列表是一個寫復制的列表,通俗點講就是向該列表中添加元素時,不直接往當前容器添加,而是先將當前容器進行Copy,復制出一個新的容器,然后新的容器里添加元素,添加完元素之后,再將原容器的引用指向新的容器。這里不展開說只要知道就是一個列表就可以。
Spring向該容器中添加的邏輯源碼如下:
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
//存儲BeanPostProcessor列表
private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
// Remove from old position, if any
this.beanPostProcessors.remove(beanPostProcessor);
// Track whether it is instantiation/destruction aware
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
// 將BeanPostProcessor加入beanPostProcessors列表中
this.beanPostProcessors.add(beanPostProcessor);
}
}
這里展示的只是最終寫入的邏輯,那么從源頭到寫入BeanPostProcessor的邏輯是怎么樣呢?
以ClassPatchXmlApplicationContext為例:
- org.springframework.context.support.ClassPathXmlApplicationContext#ClassPathXmlApplicationContext
- org.springframework.context.support.AbstractApplicationContext#refresh
- org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.context.support.AbstractApplicationContext)
- org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.List<org.springframework.beans.factory.config.BeanPostProcessor>)
- org.springframework.beans.factory.support.AbstractBeanFactory#addBeanPostProcessor
時序圖如下:

5. BeanPostProcessor調(diào)用
說完如何注冊BeanPostProcessor,最后來說如何將注冊到beanPostProcessors的實現(xiàn)類進行調(diào)用。
前一篇聊Spring容器時也提到了Spring在初始化Bean時會執(zhí)行BeanPostProcessor的增強處理,具體的調(diào)用源碼如下:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
//初始化Bean
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//調(diào)用BeanPostProcesso#postProcessBeforeInitialization:前置處理
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//執(zhí)行初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//調(diào)用調(diào)用BeanPostProcesso#postProcessAfterInitialization:后置處理
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
//BeanPostProcessor前置邏輯處理
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
//執(zhí)行實現(xiàn)BeanPostProcessor的實現(xiàn)類的前置增強邏輯
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
//BeanPostProcessor后置邏輯處理
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
//執(zhí)行實現(xiàn)BeanPostProcessor的實現(xiàn)類的后置增強邏輯
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
}
從以上源碼中可以看到在初始化Bean時調(diào)用前置和后置增強,并且這里也做了明確的邊界,前置增強處理一定是在invokeInitMethods之前,后置增強一定是在invokeInitMethods之后。這樣就保證了BeanPostProcessor的執(zhí)行順序,也可以讓開發(fā)者在使用過程中只要掌握Bean的生命周期,那么就可以自主的對Bean進行增強處理。
6. 總結(jié)
以上是對Spring中BeanPostProcessor的源碼梳理,對BeanPostProcessor的介紹到使用、作用、注冊實現(xiàn)和調(diào)用實現(xiàn),完成了對BeanPostProcessor的源碼分析。
對于文中提到的BeanFactoryPostProcessor有興趣的可以從源碼按照這個過程梳理一下,其實跟BeanPostProcessor作用是相同的。
以上就是Spring BeanPostProcessor源碼示例解析的詳細內(nèi)容,更多關(guān)于Spring BeanPostProcessor的資料請關(guān)注腳本之家其它相關(guān)文章!
- Spring BeanPostProcessor接口使用詳解
- Spring中的后置處理器BeanPostProcessor詳解
- SpringBoot之通過BeanPostProcessor動態(tài)注入ID生成器案例詳解
- Spring BeanPostProcessor(后置處理器)的用法
- Spring?BeanPostProcessor后處理器源碼解析
- 詳解使用Spring的BeanPostProcessor優(yōu)雅的實現(xiàn)工廠模式
- Spring探秘之如何妙用BeanPostProcessor
- Spring源碼解析之BeanPostProcessor知識總結(jié)
- Spring注解驅(qū)動之BeanPostProcessor后置處理器講解
- Spring組件初始化擴展點:BeanPostProcessor
相關(guān)文章
Java關(guān)鍵字instanceof的兩種用法實例
這篇文章主要介紹了Java關(guān)鍵字instanceof的兩種用法實例,本文給出了instanceof關(guān)鍵字用于判斷一個引用類型變量所指向的對象是否是一個類(或接口、抽象類、父類)及用于數(shù)組比較,需要的朋友可以參考下2015-03-03
SpringBoot集成JWT實現(xiàn)Token登錄驗證的示例代碼
隨著技術(shù)的發(fā)展,分布式web應用的普及,通過session管理用戶登錄狀態(tài)成本越來越高,因此慢慢發(fā)展成為token的方式做登錄身份校驗,本文就來介紹一下SpringBoot集成JWT實現(xiàn)Token登錄驗證的示例代碼,感興趣的可以了解一下2023-12-12
openEuler?搭建java開發(fā)環(huán)境的詳細過程
這篇文章主要介紹了openEuler?搭建java開發(fā)環(huán)境,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06
java list中包含某個字符串的兩種方法實現(xiàn)
在Java開發(fā)中,經(jīng)常需要判斷一個List中是否包含特定的字符串,包括使用contains()方法和循環(huán)遍歷判斷,具有一定的參考價值,感興趣的可以了解一下2024-03-03
手把手帶你掌握SpringBoot RabbitMQ延遲隊列
RabbitMQ 是一個由Erlang語言開發(fā)的AMQP的開源實現(xiàn),支持多種客戶端。用于在分布式系統(tǒng)中存儲轉(zhuǎn)發(fā)消息,在易用性、擴展性、高可用性等方面表現(xiàn)不俗,下文將帶你深入了解 RabbitMQ 延遲隊列2021-09-09
java中自定義Spring Security權(quán)限控制管理示例(實戰(zhàn)篇)
本篇文章主要介紹了java中自定義Spring Security權(quán)限控制管理示例(實戰(zhàn)篇) ,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-02-02
舉例講解Java設計模式編程中Decorator裝飾者模式的運用
這篇文章主要介紹了Java設計模式編程中Decorator裝飾者模式的運用,裝飾者模式就是給一個對象動態(tài)的添加新的功能,裝飾者和被裝飾者實現(xiàn)同一個接口,裝飾者持有被裝飾者的實例,需要的朋友可以參考下2016-05-05

