關(guān)于Spring BeanPostProcessor的執(zhí)行順序
Spring BeanPostProcessor執(zhí)行順序
首先 Spring 通過調(diào)用構(gòu)造方法創(chuàng)建 User 對象;
User 對象創(chuàng)建好之后,先不直接進(jìn)行初始化操作,通過 BeanPostProcessor 對剛創(chuàng)建好的 User 對象進(jìn)行加工操作,其中 postProcessBeforeInitialization 方法的第一個(gè)參數(shù)是 User 對象,第二個(gè)參數(shù)是在配置文件中指定的 id 值;
加工好之后通過 return 將對象返回給 Spring 容器,然后 Spring 容器繼續(xù)按照流程執(zhí)行 初始化操作,先是 InitializingBean 的初始化操作;
再是 init-method 的初始化;
然后 Spring 容器再次將對象交給 BeanPostProcessor ,執(zhí)行 postProcessAfterInitialization 方法。
實(shí)際上在實(shí)戰(zhàn)中,我們很少處理 Spring 的初始化操作,所以沒有必要區(qū)分 Before 還是 After。只需要實(shí)現(xiàn)其中的一個(gè)即可,顯然選 After 方法更好。
先定義一個(gè)實(shí)體類 Category:
public class Category { private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Category{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
然后注入到 Spring 容器中:
<bean class="edu.lsu.pojo.Category" id="category"> <property name="id" value="1"/> <property name="name" value="迪麗熱巴"/> </bean>
注意此時(shí)的名字是迪麗熱巴。
此時(shí)我們定義一個(gè) BeanPostProcessor,實(shí)現(xiàn)他的后置處理器方法:
public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { Category category = (Category) bean; category.setName("古力娜扎"); return category; } }
當(dāng)我們在此時(shí)的時(shí)候,輸出結(jié)果就是古力娜扎;
@Test public void test7() { ApplicationContext ac = new ClassPathXmlApplicationContext("/applicationContext2.xml"); Category category = ac.getBean("category", Category.class); System.out.println("category = " + category); }
輸出:
category = Category{id=1, name='古力娜扎'}
Spring-BeanPostProcessor接口總結(jié)
定義
Spring提供了一個(gè)BeanPostProcessor接口,這個(gè)接口的作用在于對于新構(gòu)造的實(shí)例可以做一些自定義的修改。比如如何構(gòu)造、屬性值的修改、構(gòu)造器的選擇。
如果想改變Spring容器中bean的一些屬性或者行為,可以通過自定義類實(shí)現(xiàn)BeanPostProcessor接口實(shí)現(xiàn)。
以下基本Spring-beans 5.0.6版本說明。
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總結(jié)
- postProcessBeforeInitialization方法的作用在于目標(biāo)對象實(shí)例化之后,初始化之前調(diào)用,默認(rèn)返回原始對象,也可以返回一個(gè)包裝實(shí)例;
- 如果返回null,接下來的BeanPostProcessors都不會(huì)執(zhí)行
- postProcessAfterInitialization方法的作用在于目標(biāo)對象實(shí)例化之后,初始化之后調(diào)用,默認(rèn)返回原始對象,也可以返回一個(gè)包裝實(shí)例;
- 如果返回null,接下來的BeanPostProcessors都不會(huì)執(zhí)行
- 初始化(Initialization):表示生成對象,未設(shè)置屬性;初始化之前表示bean的初始化回調(diào)之前,如InitializingBean接口的afterPropertiesSet方法或者自定義的init-method方法
InstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor接口繼承自BeanPostProcessor接口,定義了3個(gè)方法
@Nullable default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException { return null; } default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { return true; } @Nullable default PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { return pvs; }
InstantiationAwareBeanPostProcessor總結(jié)
- postProcessBeforeInstantiation方法在目標(biāo)對象實(shí)例化之前調(diào)用,可以返回一個(gè)代理對象來代替目標(biāo)對象本身;如果返回非null對象,則除了調(diào)用postProcessAfterInitialization方法外,其他bean的構(gòu)造過程都不再調(diào)用;
- postProcessAfterInstantiation方法在對象實(shí)例化之后,屬性設(shè)置之前調(diào)用;如果返回值是true,目標(biāo)bean的屬性會(huì)被populate,返回false則忽略populate過程;
- postProcessPropertyValues方法在屬性被設(shè)置到目標(biāo)實(shí)例之前調(diào)用,可以修改屬性的設(shè)置,PropertyValues pvs表示參數(shù)值,PropertyDescriptor[] pds表示目標(biāo)bean 的屬性描述信息,返回值PropertyValues,可以用一個(gè)全新的PropertyValues來替代原來的pvs,如果返回null,將忽略屬性設(shè)置過程;
SmartInstantiationAwareBeanPostProcessor
SmartInstantiationAwareBeanPostProcessor接口繼承InstantiationAwareBeanPostProcessor接口,定義了3個(gè)方法,作用是在于目標(biāo)對象的實(shí)例化過程中需要處理的事情。
@Nullable default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException { return null; } @Nullable default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException { return null; } default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException { return bean; }
SmartInstantiationAwareBeanPostProcessor總結(jié)
- predictBeanType方法預(yù)測Bean的類型,返回預(yù)測成功的Class類型,默認(rèn)或如果不能預(yù)測返回null
- determineCandidateConstructors方法用于選擇合適的構(gòu)造器,如果類有多個(gè)構(gòu)造器,可以實(shí)現(xiàn)這個(gè)方法選擇合適的構(gòu)造器并用于實(shí)例化對象;該方法在postProcessBeforeInstantiation方法和postProcessAfterInstantiation方法之間調(diào)用,如果postProcessBeforeInstantiation方法返回了一個(gè)新的實(shí)例代替了原本該生成的實(shí)例,那么該方法會(huì)被忽略;
- getEarlyBeanReference方法用于解決循環(huán)引用問題。比如ReferenceA實(shí)例內(nèi)部有ReferenceB的引用,ReferenceB實(shí)例內(nèi)部有ReferenceA的引用。首先先實(shí)例化ReferenceA,實(shí)例化完成之后提前把這個(gè)bean暴露在ObjectFactory中,然后populate屬性,這個(gè)時(shí)候發(fā)現(xiàn)需要ReferenceB。然后去實(shí)例化ReferenceB,在實(shí)例化ReferenceB的時(shí)候它需要ReferenceA的實(shí)例才能繼續(xù),這個(gè)時(shí)候就會(huì)去ObjectFactory中找出了ReferenceA實(shí)例,ReferenceB順利實(shí)例化。ReferenceB實(shí)例化之后,ReferenceA的populate屬性過程也成功完成,注入了ReferenceB實(shí)例。提前把這個(gè)bean暴露在ObjectFactory中,這個(gè)ObjectFactory獲取的實(shí)例就是通過getEarlyBeanReference方法得到的;
DestructionAwareBeanPostProcessor
void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException; default boolean requiresDestruction(Object bean) { return true; }
DestructionAwareBeanPostProcessor總結(jié)
postProcessBeforeDestruction方法在目標(biāo)bean被銷毀之前調(diào)用,該回調(diào)適用于單例bean的使用;
判斷目標(biāo)bean是否需要回調(diào)postProcessBeforeDestruction方法;
總結(jié)一下
Spring內(nèi)部對象bean的生命周期管理有一套完成的體系,并遵循了設(shè)計(jì)模式中的開閉原則(開放擴(kuò)展,關(guān)閉修改),如果想修改bean的相關(guān)信息,可以通過Spring提供的擴(kuò)展點(diǎn),如BeanPostProcessor接口去處理,這樣做的好處是不需要關(guān)心Spring內(nèi)部處理邏輯,擴(kuò)展方便。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Spring?BeanPostProcessor后處理器源碼解析
- Spring BeanPostProcessor(后置處理器)的用法
- SpringBoot之通過BeanPostProcessor動(dòng)態(tài)注入ID生成器案例詳解
- Spring容器的創(chuàng)建過程之如何注冊BeanPostProcessor詳解
- 詳解使用Spring的BeanPostProcessor優(yōu)雅的實(shí)現(xiàn)工廠模式
- Spring中的后置處理器BeanPostProcessor詳解
- Spring BeanPostProcessor接口使用詳解
- 解析Java的Spring框架的BeanPostProcessor發(fā)布處理器
- spring中BeanPostProcessor的作用和使用注意事項(xiàng)
相關(guān)文章
在Eclipse安裝Spring boot插件的步驟(圖文)
這篇文章主要介紹了在Eclipse安裝Spring boot插件的步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08RocketMQ的push消費(fèi)方式實(shí)現(xiàn)示例
這篇文章主要為大家介紹了RocketMQ的push消費(fèi)方式實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>2022-08-08servlet監(jiān)聽實(shí)現(xiàn)統(tǒng)計(jì)在線人數(shù)功能 附源碼下載
這篇文章主要為大家詳細(xì)介紹了servlet監(jiān)聽統(tǒng)計(jì)在線人數(shù)的實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04Java獲取網(wǎng)絡(luò)文件并插入數(shù)據(jù)庫的代碼
抓取各大網(wǎng)站的數(shù)據(jù)插入數(shù)據(jù)庫,這樣就不用為沒有數(shù)據(jù)而煩惱了2010-06-06Java基于命令模式實(shí)現(xiàn)郵局發(fā)信功能詳解
這篇文章主要介紹了Java基于命令模式實(shí)現(xiàn)郵局發(fā)信功能,較為詳細(xì)的分析了命令行模式的概念、原理并結(jié)合實(shí)例形式分析了Java使用命令行模式實(shí)現(xiàn)郵局發(fā)信功能的相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2018-04-04ByteArrayOutputStream簡介和使用_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
ByteArrayOutputStream 是字節(jié)數(shù)組輸出流。它繼承于OutputStream。這篇文章主要介紹了ByteArrayOutputStream簡介和使用,需要的朋友可以參考下2017-05-05