關於Spring BeanPostProcessor的執行順序
Spring BeanPostProcessor執行順序
首先 Spring 通過調用構造方法創建 User 對象;
User 對象創建好之後,先不直接進行初始化操作,通過 BeanPostProcessor 對剛創建好的 User 對象進行加工操作,其中 postProcessBeforeInitialization 方法的第一個參數是 User 對象,第二個參數是在配置文件中指定的 id 值;
加工好之後通過 return 將對象返回給 Spring 容器,然後 Spring 容器繼續按照流程執行 初始化操作,先是 InitializingBean 的初始化操作;
再是 init-method 的初始化;
然後 Spring 容器再次將對象交給 BeanPostProcessor ,執行 postProcessAfterInitialization 方法。
實際上在實戰中,我們很少處理 Spring 的初始化操作,所以沒有必要區分 Before 還是 After。隻需要實現其中的一個即可,顯然選 After 方法更好。
先定義一個實體類 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>
註意此時的名字是迪麗熱巴。
此時我們定義一個 BeanPostProcessor,實現他的後置處理器方法:
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; } }
當我們在此時的時候,輸出結果就是古力娜紮;
@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接口總結
定義
Spring提供瞭一個BeanPostProcessor接口,這個接口的作用在於對於新構造的實例可以做一些自定義的修改。比如如何構造、屬性值的修改、構造器的選擇。
如果想改變Spring容器中bean的一些屬性或者行為,可以通過自定義類實現BeanPostProcessor接口實現。
以下基本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總結
- postProcessBeforeInitialization方法的作用在於目標對象實例化之後,初始化之前調用,默認返回原始對象,也可以返回一個包裝實例;
- 如果返回null,接下來的BeanPostProcessors都不會執行
- postProcessAfterInitialization方法的作用在於目標對象實例化之後,初始化之後調用,默認返回原始對象,也可以返回一個包裝實例;
- 如果返回null,接下來的BeanPostProcessors都不會執行
- 初始化(Initialization):表示生成對象,未設置屬性;初始化之前表示bean的初始化回調之前,如InitializingBean接口的afterPropertiesSet方法或者自定義的init-method方法
InstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor接口繼承自BeanPostProcessor接口,定義瞭3個方法
@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總結
- postProcessBeforeInstantiation方法在目標對象實例化之前調用,可以返回一個代理對象來代替目標對象本身;如果返回非null對象,則除瞭調用postProcessAfterInitialization方法外,其他bean的構造過程都不再調用;
- postProcessAfterInstantiation方法在對象實例化之後,屬性設置之前調用;如果返回值是true,目標bean的屬性會被populate,返回false則忽略populate過程;
- postProcessPropertyValues方法在屬性被設置到目標實例之前調用,可以修改屬性的設置,PropertyValues pvs表示參數值,PropertyDescriptor[] pds表示目標bean 的屬性描述信息,返回值PropertyValues,可以用一個全新的PropertyValues來替代原來的pvs,如果返回null,將忽略屬性設置過程;
SmartInstantiationAwareBeanPostProcessor
SmartInstantiationAwareBeanPostProcessor接口繼承InstantiationAwareBeanPostProcessor接口,定義瞭3個方法,作用是在於目標對象的實例化過程中需要處理的事情。
@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總結
- predictBeanType方法預測Bean的類型,返回預測成功的Class類型,默認或如果不能預測返回null
- determineCandidateConstructors方法用於選擇合適的構造器,如果類有多個構造器,可以實現這個方法選擇合適的構造器並用於實例化對象;該方法在postProcessBeforeInstantiation方法和postProcessAfterInstantiation方法之間調用,如果postProcessBeforeInstantiation方法返回瞭一個新的實例代替瞭原本該生成的實例,那麼該方法會被忽略;
- getEarlyBeanReference方法用於解決循環引用問題。比如ReferenceA實例內部有ReferenceB的引用,ReferenceB實例內部有ReferenceA的引用。首先先實例化ReferenceA,實例化完成之後提前把這個bean暴露在ObjectFactory中,然後populate屬性,這個時候發現需要ReferenceB。然後去實例化ReferenceB,在實例化ReferenceB的時候它需要ReferenceA的實例才能繼續,這個時候就會去ObjectFactory中找出瞭ReferenceA實例,ReferenceB順利實例化。ReferenceB實例化之後,ReferenceA的populate屬性過程也成功完成,註入瞭ReferenceB實例。提前把這個bean暴露在ObjectFactory中,這個ObjectFactory獲取的實例就是通過getEarlyBeanReference方法得到的;
DestructionAwareBeanPostProcessor
void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException; default boolean requiresDestruction(Object bean) { return true; }
DestructionAwareBeanPostProcessor總結
postProcessBeforeDestruction方法在目標bean被銷毀之前調用,該回調適用於單例bean的使用;
判斷目標bean是否需要回調postProcessBeforeDestruction方法;
總結一下
Spring內部對象bean的生命周期管理有一套完成的體系,並遵循瞭設計模式中的開閉原則(開放擴展,關閉修改),如果想修改bean的相關信息,可以通過Spring提供的擴展點,如BeanPostProcessor接口去處理,這樣做的好處是不需要關心Spring內部處理邏輯,擴展方便。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Spring源碼解析之BeanPostProcessor知識總結
- Spring BeanPostProcessor源碼示例解析
- Spring BeanPostProcessor(後置處理器)的用法
- 深入瞭解Spring的Bean生命周期
- 詳解Spring中Bean後置處理器(BeanPostProcessor)的使用