回覆列表
  • 1 # 列克美食

    Spirng中BeanPostProcessor和InstantiationAwareBeanPostProcessorAdapter兩個介面都可以實現對bean前置後置處理的效果,那這次先講解一下BeanPostProcessor處理器的使用

    先看一下BeanPostProcessor介面的原始碼,它定義了兩個方法,一個在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; }}

    下面,我們來實現這個類,測試一下Spring中的前置後置處理器吧

    首先是pom.xml,增加Spring相關的依賴

    定義介面實現類:

    public class ISomeService implements BaseService { public String doSomething() { // 增強效果:返回內容全部大寫 return "Hello i am kxm"; } public String eat() { return "eat food"; }}

    實現BeanPostProcessor介面

    public class MyBeanPostProcessor implements BeanPostProcessor { // 前置處理器 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { Class beanClass = bean.getClass(); if (beanClass == ISomeService.class) { System.out.println("bean 物件初始化之前······"); } return bean; }

    // 後置處理器 --- 此處具體的實現用的是Java中的動態代理

    public Object postProcessAfterInitialization(final Object beanInstance, String beanName) throws BeansException { // 為當前 bean 物件註冊監控代理物件,負責增強 bean 物件方法的能力 Class beanClass = beanInstance.getClass(); if (beanClass == ISomeService.class) { Object proxy = Proxy.newProxyInstance(beanInstance.getClass().getClassLoader(),beanInstance.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("ISomeService 中的 doSome() 被攔截了···"); String result = (String) method.invoke(beanInstance, args); return result.toUpperCase(); } }); return proxy; } return beanInstance; }}

    Spring的配置檔案如下:

    <bean></bean>

    測試類如下:

    public class TestBeanPostProcessor { public static void main(String[] args) { /** * BeanPostProcessor 前置後置處理器 */ ApplicationContext factory = new ClassPathXmlApplicationContext("spring_config.xml"); BaseService serviceObj = (BaseService) factory.getBean("iSomeService"); System.out.println(serviceObj.doSomething()); }}

    測試結果截圖:

    可以觀察到,我們明明在程式碼中對於doSomething方法定義的是小寫,但是通過後置處理器,攔截了原本的方法,而是透過動態代理的方式把方法的結果進行了一定程度的改變,這就是Spring中的前置後置處理器----BeanPostProcessor

  • 2 # 程式猿W

    其實無論是前置和後置,還是其他介面,都是Spring 可擴充套件性表現。下面將會說明 Spring的前置和後置處理器,以及在 Spring 原始碼裡執行的時機。最後說明 Spring 其他介面的 說明

    下面將從以下幾個方面進行說明:

    前置處理器和後置處理器

    Spring 的生命週期

    Spring 生命週期所涉及的原始碼

    Spring 其他可擴充套件介面

    前置處理器和後置處理器

    Spring 的後置處理器主要為 BeanFactoryPostProcessor 和 BeanPostProcessor

    1、BeanFactoryPostProcessor

    BeanFactoryPostProcessor 是針對BeanDefinition 級別的後置處理器,它可以修改Bean的 定義,呼叫該介面時,bean還沒有進行初始化,它只有一個方法如下:

    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

    ① 怎樣自定義BeanFactoryPostProcessor?

    透過實現BeanFactoryPostProcessor 介面方法,來修改yjLog bean的載入方式。

    ② 使用場景有哪些 ?

    比如我們配置資料庫資訊時,經常使用佔位符${username},那麼 Spring在什麼時候進行值的替換呢?

    當BeanFactory 在 第一階段載入 完成配置資訊時,儲存的物件屬性資訊還是以佔位符的形式 存在,這個解析的工作是在 PropertySourcesPlaceholderConfigurer 中進行解析的。

    從下面類圖看:

    PropertySourcesPlaceholderConfigurer 實現了 BeanFactoryPostProcessor 的介面

    在下面的方法執行的替換:

    呼叫鏈如下:

    Spring 初始化的主要步驟如下:

    BeanFactoryPostProcessor 的 呼叫是在下面方法中

    // Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);

    執行堆疊如下:

    我們驗證一下:BeanFactoryPostProcessor 實在 BeanDefinition 都載入完成才呼叫的

    執行上述方法前:Beanfactory裡的BeanDefiniton定義如下:

    2、BeanFactoryPostProcessor

    BeanFactoryPostProcessor 是針對getBean操作獲得的 對的後置處理器 。他有兩個方法,一個在Bean初始化前執行,一個在初始化後執行

    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean;}

    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean;}

    ① 怎樣自定義 BeanFactoryPostProcessor

    ② 在原始碼的執行位置

    執行堆疊如下:

    呼叫步驟如下:

    // 1.呼叫類的構造方法

    if (instanceWrapper == null) {

    instanceWrapper = createBeanInstance(beanName, mbd, args);

    }

    Object exposedObject = bean;

    try {

    //2.給屬性賦值

    populateBean(beanName, mbd, instanceWrapper);

    //3.初始化bean

    exposedObject = initializeBean(beanName, exposedObject, mbd);

    }

    1.呼叫類的構造 方法

    2.給屬性賦值

    3. 初始化

    (1) 給 *Aware 介面複製

    (2) 執行 BeanPostProcessor postProcessBeforeInitialization

    (3) 執行 InitializingBean 介面方法,執行 自定義的init-mathod

    (4) 執行 BeanPostProcessor postProcessAfterInitialization 方法

    3、BeanDefinitionRegistryPostProcessor

    執行時機:所有的bean定義資訊將要被載入到容器中,Bean例項還沒有被初始化。

    BeanDefinitionRegistryPostProcessor 介面可以看作是BeanFactoryPostProcessor和ImportBeanDefinitionRegistrar的功能集合

    既可以獲取和修改BeanDefinition的元資料,也可以實現BeanDefinition的註冊、移除等操作。

    怎樣自定義一個 BeanFactoryPostProcessor

    驗證 執行時機:

    此時registry 已經以Bean的 定義資訊

    spring 生命週期如下圖

    執行步驟如下:

    1、執行建構函式

    2、給屬性賦值

    3、給呼叫*aware介面

    4、執行BeanPostProcessor前置方法

    5、呼叫InitializingBean的介面afterPropertiesSet方法

    6、呼叫自定義的init方法

    @Component

    public class Book {

    public Book() {

    System.out.println("book 的構造方法");

    }

    @PostConstruct

    public void init() {

    System.out.println("book 的PostConstruct標誌的方法");

    }

    @PreDestroy

    public void destory() {

    System.out.println("book 的PreDestory標註的方法");

    }

    }

    7、執行BeanPostProcessor後置方法

    8、呼叫 DisposableBean destroy 銷燬

    9、呼叫自定義的銷燬方法

    @PreDestroy

    public void destory() {

    System.out.println("book 的PreDestory標註的方法");

    }

    Spring 生命週期所涉及的原始碼

    主要的程式碼如下:

    ① instanceWrapper = createBeanInstance(beanName, mbd, args);

    呼叫構造方法

    ② populateBean(beanName, mbd, instanceWrapper)

    給屬性賦值

    (1) invokeAwareMethods(beanName, bean);

    執行* Aware 介面

    (2) BeanPostProcessor 前置方法

    (3) invokeInitMethods

    呼叫InitializingBean的介面afterPropertiesSet方法 或者自定義的init方法

    ④ 呼叫 BeanPostProcessor 後置方法

    Spring 其他可擴充套件介面

    1、ImportBeanDefinitionRegistrar介面

    2、FactoryBean介面

    3、ApplicationListener

    --------------------------

  • 中秋節和大豐收的關聯?
  • 林黛玉代表的形象是什麼?