Spring擴充套件介面(4):InstantiationAwareBeanPostProcessor

夕陽醉了發表於2023-10-30

在此係列文章中,我總結了Spring幾乎所有的擴充套件介面,以及各個擴充套件點的使用場景。並整理出一個bean在spring中從被載入到最終初始化的所有可擴充套件點的順序呼叫圖。這樣,我們也可以看到bean是如何一步步載入到spring容器中的。


InstantiationAwareBeanPostProcessor

1、概述

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
    @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 postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        return null;
    }
}

Spring框架提供了許多擴充套件介面,用於在Bean的生命週期中插入自定義邏輯。其中之一是InstantiationAwareBeanPostProcessor介面,它允許我們在Spring容器例項化Bean之前和之後進行一些自定義處理。

InstantiationAwareBeanPostProcessor介面是BeanPostProcessor介面的子介面,它定義了在Bean例項化過程中的擴充套件點。與BeanPostProcessor介面相比,InstantiationAwareBeanPostProcessor介面提供了更細粒度的控制能力。它在Bean例項化的不同階段提供了多個回撥方法,允許我們在不同的時機對Bean進行自定義處理。

在Spring容器啟動過程中,InstantiationAwareBeanPostProcessor介面的方法執行順序如下:

  1. postProcessBeforeInstantiation方法:在Bean例項化之前呼叫,如果返回null,一切按照正常順序執行,如果返回的是一個例項的物件,那麼這個將會跳過例項化、初始化的過程
  2. postProcessAfterInstantiation方法:在Bean例項化之後呼叫,可以對已例項化的Bean進行進一步的自定義處理。
  3. postProcessPropertyValues方法:在Bean的屬性注入之前呼叫,可以修改Bean的屬性值或進行其他自定義操作,當postProcessAfterInstantiation返回true才執行。
方法 執行順序 備註
postProcessBeforeInstantiation() 在 Bean 建立前呼叫 可用於建立代理類,如果返回的不是 null(也就是返回的是一個代理類) ,那麼後續只會呼叫 postProcessAfterInitialization() 方法
postProcessAfterInstantiation() 在 Bean 建立後呼叫 返回值會影響 postProcessProperties() 是否執行,其中返回 false 的話,是不會執行。
postProcessProperties() 在 Bean 設定屬性前呼叫 用於修改 bean 的屬性,如果返回值不為空,那麼會更改指定欄位的值

2、簡單案例

下面是一個示例,演示了TestUser這個Bean內部的執行流程。


// InstantiationAwareBeanPostProcessor擴充套件實現
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if(isMatchClass(beanClass)){
            System.out.println("呼叫 postProcessBeforeInstantiation 方法");
        }
        return null;
    }

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if(isMatchClass(bean.getClass())){
            System.out.println("呼叫 postProcessAfterInstantiation 方法");
        }
        return true;
    }

    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if(isMatchClass(bean.getClass())){
            System.out.println("呼叫 postProcessProperties 方法");
        }
        return pvs;
    }

    private boolean isMatchClass(Class<?> beanClass){
        return TestUser.class.equals(ClassUtils.getUserClass(beanClass));
    }
}

// TestUser測試類
@Component
public class TestUser implements InitializingBean {
    String name;
    String password;

    public TestUser() {
        System.out.println("建立【TestUser】物件");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("設定【name】屬性");
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        System.out.println("設定【password】屬性");
        this.password = password;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("所有屬性設定完畢");
    }
}

輸出:

呼叫 postProcessBeforeInstantiation 方法
建立【TestUser】物件
呼叫 postProcessAfterInstantiation 方法
呼叫 postProcessProperties 方法
所有屬性設定完畢

3、原始碼分析

InstantiationAwareBeanPostProcessor是在物件例項化和初始化前後執行的邏輯,因此主要的程式碼都在getBean,doGetBean,cerateBean方法中。

  • 在MyBeanFactoryPostProcessor打上斷點,啟動SpringApplication,可以看到左下角的呼叫鏈路。

  • spring的AbstractApplicationContext的refresh方法,執行this.onRefresh()。

  • 在例項化之前,呼叫postProcessBeforeInstantiation方法入口就在this.resolveBeforeInstantiation(beanName, mbdToUse)中。

  • bean = this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName)中遍歷InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法。
  • 若 this.applyBeanPostProcessorsBeforeInstantiation(targetType, beanName)返回了已例項化的Bean,則執行呼叫postProcessAfterInitialization方法。

  • 在執行完resolveBeforeInstantiation()後,呼叫doCreateBean()
  • doCreateBean()中先例項化Bean,再呼叫populateBean()執行後續的postProcessAfterInstantiation()和postProcessProperties()。

相關文章