天天看點

Spring之InstantiationAwareBeanPostProcessor接口介紹

 InstantiationAwareBeanPostProcessor接口是BeanPostProcessor的子接口,通過接口字面意思翻譯該接口的作用是感覺Bean執行個體話的處理器。實際上該接口的作用也是确實如此。

Spring之BeanPostProcessor(後置處理器)介紹

文章目錄

   InstantiationAwareBeanPostProcessor接口介紹

       1.接口介紹

       2.舉例說明

           1).建立接口實作類

           2).建立目标類

           3).配置檔案注冊

           4).測試

       3.分析相關方法

           1).postProcessBeforeInstantiation

           2).postProcessAfterInstantiation

           3).postProcessPropertyValues

       4.最後總結

InstantiationAwareBeanPostProcessor接口介紹

1.接口介紹

 先來看下接口的源代碼:

package org.springframework.beans.factory.config;
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

    Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;

    boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;

    PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;

}      

 從源碼中我們可以獲知的資訊是該接口除了具有父接口中的兩個方法以外還自己額外定義了三個方法。是以該接口一共定義了5個方法,這5個方法的作用分别是

方法 描述

postProcessBeforeInitialization BeanPostProcessor接口中的方法,

在Bean的自定義初始化方法之前執行

postProcessAfterInitialization BeanPostProcessor接口中的方法

在Bean的自定義初始化方法執行完成之後執行

postProcessBeforeInstantiation 自身方法,是最先執行的方法,它在目标對象執行個體化之前調用,該方法的傳回值類型是Object,我們可以傳回任何類型的值。由于這個時候目标對象還未執行個體化,是以這個傳回值可以用來代替原本該生成的目标對象的執行個體(比如代理對象)。如果該方法的傳回值代替原本該生成的目标對象,後續隻有postProcessAfterInitialization方法會調用,其它方法不再調用;否則按照正常的流程走

postProcessAfterInstantiation 在目标對象執行個體化之後調用,這個時候對象已經被執行個體化,但是該執行個體的屬性還未被設定,都是null。因為它的傳回值是決定要不要調用postProcessPropertyValues方法的其中一個因素(因為還有一個因素是mbd.getDependencyCheck());如果該方法傳回false,并且不需要check,那麼postProcessPropertyValues就會被忽略不執行;如果傳回true,postProcessPropertyValues就會被執行

postProcessPropertyValues 對屬性值進行修改,如果postProcessAfterInstantiation方法傳回false,該方法可能不會被調用。可以在該方法内對屬性值進行修改

注意兩個單詞

單詞 含義

Instantiation 表示執行個體化,對象還未生成

Initialization 表示初始化,對象已經生成

2.舉例說明

1).建立接口實作類

/**
 * 自定義處理器
 * @author dengp
 *
 */
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor{

    /**
     * BeanPostProcessor接口中的方法
     * 在Bean的自定義初始化方法之前執行
     * Bean對象已經存在了
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println(">>postProcessBeforeInitialization");
        return bean;
    }

    /**
     * BeanPostProcessor接口中的方法
     * 在Bean的自定義初始化方法執行完成之後執行
     * Bean對象已經存在了
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("<<postProcessAfterInitialization");
        return bean;
    }

    /**
     * InstantiationAwareBeanPostProcessor中自定義的方法
     * 在方法執行個體化之前執行  Bean對象還沒有
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("--->postProcessBeforeInstantiation");
        return null;
    }

    /**
     * InstantiationAwareBeanPostProcessor中自定義的方法
     * 在方法執行個體化之後執行  Bean對象已經建立出來了
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("<---postProcessAfterInstantiation");
        return true;
    }

    /**
     * InstantiationAwareBeanPostProcessor中自定義的方法
     * 可以用來修改Bean中屬性的内容
     */
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
            String beanName) throws BeansException {
        System.out.println("<---postProcessPropertyValues--->");
        return pvs;
    }
}      

2).建立目标類

public class User {

    private int id;
    
    private String name;
    
    private String beanName;
    
    public User(){
        System.out.println("User 被執行個體化");
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("設定:"+name);
        this.name = name;
    }

    public String getBeanName() {
        return beanName;
    }

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }
    public void start(){
        System.out.println("自定義初始化的方法....");
    }
    
    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", beanName=" + beanName + "]";
    }
}      

3).配置檔案注冊

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="com.dpb.pojo.User" id="user" init-method="start">
        <property name="name" value="波波烤鴨"></property>
    </bean>
    
    <!-- 注冊InstantiationAwareBeanPostProcessor對象 -->
    <bean class="com.dpb.processor.MyInstantiationAwareBeanPostProcessor"></bean>
</beans>      

4).測試

@Test
public void test1() {
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    User user = ac.getBean(User.class);
    System.out.println(user);
    // 關閉銷毀
    ac.registerShutdownHook();
}      

輸出結果

--->postProcessBeforeInstantiation
User 被執行個體化
<---postProcessAfterInstantiation
<---postProcessPropertyValues--->
設定:波波烤鴨
>>postProcessBeforeInitialization
自定義初始化的方法....
<<postProcessAfterInitialization
User [id=0, name=波波烤鴨, beanName=null]      

通過輸出結果,我們可以看到幾個方法的執行順序,而且五個方法都執行了,那麼每個方法的傳回結果對其他方法有什麼影響沒有呢,接下來分别看下這幾個方法。

3.分析相關方法

1).postProcessBeforeInstantiation

 該方法傳回的結果如果為null,後面的方法都正常執行了,但是如果該方法傳回了執行個體對象了呢?我們來看下

/**
 * InstantiationAwareBeanPostProcessor中自定義的方法 在方法執行個體化之前執行 Bean對象還沒有
 */
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    System.out.println("--->postProcessBeforeInstantiation");
    // 利用cglib動态代理生成對象傳回
    if (beanClass == User.class) {
        Enhancer e = new Enhancer();
        e.setSuperclass(beanClass);
        e.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

                System.out.println("目标方法執行前:" + method + "\n");
                Object object = methodProxy.invokeSuper(obj, objects);
                System.out.println("目标方法執行後:" + method + "\n");
                return object;
            }
        });
        User user = (User) e.create();
        // 傳回代理類
        return user;
    }
    return null;
}      

測試輸出結果:

容器開始初始化....
--->postProcessBeforeInstantiation
User 被執行個體化
<<postProcessAfterInitialization
容器初始化結束....      

 通過資料結果我們發現,postProcessBeforeInstantiation方法傳回執行個體對象後跳過了對象的初始化操作,直接執行了postProcessAfterInitialization(該方法在自定義初始化方法執行完成之後執行),跳過了postProcessAfterInstantiation,postProcessPropertyValues以及自定義的初始化方法(start方法),為什麼會這樣呢?我們要來檢視下源代碼。

在AbstractBeanFactory中的對InstantiationAwareBeanPostProcessor實作該接口的BeanPostProcessor 設定了标志

@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
    Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
    this.beanPostProcessors.remove(beanPostProcessor);
    this.beanPostProcessors.add(beanPostProcessor);
    if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
        this.hasInstantiationAwareBeanPostProcessors = true;
    }
    if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
        this.hasDestructionAwareBeanPostProcessors = true;
    }
}      

在AbstractAutowireCapableBeanFactory類中有個createBean方法,

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
       // ... 省略
    try {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
                return bean;
        }
       // ... 省略
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    if (logger.isDebugEnabled()) {
        logger.debug("Finished creating instance of bean '" + beanName + "'");
    }
    return beanInstance;
}      

Object bean = resolveBeforeInstantiation(beanName, mbdToUse);這行代碼之後之後根據bean判斷如果不為空null就直接傳回了,而不執行doCreateBean()方法了,而該方法是建立Bean對象的方法。

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    // //如果beforeInstantiationResolved還沒有設定或者是false(說明還沒有需要在執行個體化前執行的操作)
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // 判斷是否有注冊過InstantiationAwareBeanPostProcessor類型的bean
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    // 直接執行自定義初始化完成後的方法,跳過了其他幾個方法
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}      
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName); 
            //隻要有一個result不為null;後面的所有 後置處理器的方法就不執行了,直接傳回(是以執行順序很重要)
            if (result != null) {
                return result;
            }
        }
    }
    return null;
}      
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        result = processor.postProcessAfterInitialization(result, beanName);
         //如果傳回null;後面的所有 後置處理器的方法就不執行,直接傳回(是以執行順序很重要)
        if (result == null) {
            return result;
        }
    }
    return result;
}      

代碼說明:

   如果postProcessBeforeInstantiation方法傳回了Object是null;那麼就直接傳回,調用doCreateBean方法();

   如果postProcessBeforeInstantiation傳回不為null;說明修改了bean對象;然後這個時候就立馬執行postProcessAfterInitialization方法(注意這個是初始化之後的方法,也就是通過這個方法執行個體化了之後,直接執行初始化之後的方法;中間的執行個體化之後 和 初始化之前都不執行);

   在調用postProcessAfterInitialization方法時候如果傳回null;那麼就直接傳回,調用doCreateBean方法();(初始化之後的方法傳回了null,那就需要調用doCreateBean生成對象了)

   在調用postProcessAfterInitialization時傳回不為null;那這個bean就直接傳回給ioc容器了初始化之後的操作是這裡面最後一個方法了;

2).postProcessAfterInstantiation

 同樣在

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
    // 省略 。。
    boolean continueWithPropertyPopulation = true;

    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                // 此處執行 postProcessAfterInstantiation方法
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                    // postProcessAfterInstantiation 傳回true與false決定
                    // continueWithPropertyPopulation 
                    continueWithPropertyPopulation = false;
                    break;
                }
            }
        }
    }
    // postProcessAfterInstantiation false 
    // continueWithPropertyPopulation 就為false 然後該方法就結束了!!!
    if (!continueWithPropertyPopulation) {
        return;
    }
    // 省略 ...
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

    if (hasInstAwareBpps || needsDepCheck) {
        PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        if (hasInstAwareBpps) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    // 調用 postProcessPropertyValues方法
                    pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    if (pvs == null) {
                        return;
                    }
                }
            }
        }
        if (needsDepCheck) {
            checkDependencies(beanName, mbd, filteredPds, pvs);
        }
    }
    // 真正設定屬性的方法。
    applyPropertyValues(beanName, mbd, bw, pvs);
}      

 這個postProcessAfterInstantiation傳回值要注意,因為它的傳回值是決定要不要調用postProcessPropertyValues方法的其中一個因素(因為還有一個因素是mbd.getDependencyCheck());如果該方法傳回false,并且不需要check,那麼postProcessPropertyValues就會被忽略不執行;如果返true,postProcessPropertyValues就會被執行

3).postProcessPropertyValues

 在populateBean方法中我們已經看到了postProcessPropertyValues執行的位置了。我們來看下postProcessPropertyValues的效果

/**
 * InstantiationAwareBeanPostProcessor中自定義的方法 可以用來修改Bean中屬性的内容
 */
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
        String beanName) throws BeansException {
    System.out.println("<---postProcessPropertyValues--->");
    if(bean instanceof User){
        PropertyValue value = pvs.getPropertyValue("name");
        System.out.println("修改前name的值是:"+value.getValue());
        value.setConvertedValue("bobo");
    }
    return pvs;
}      

配置檔案中設值注入name屬性

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="com.dpb.pojo.User" id="user" init-method="start">
        <property name="name" value="波波烤鴨"></property>
    </bean>
    
    <!-- 注冊InstantiationAwareBeanPostProcessor對象 -->
    <bean class="com.dpb.processor.MyInstantiationAwareBeanPostProcessor"></bean>
</beans>      

測試看輸出

--->postProcessBeforeInstantiation
User 被執行個體化
<---postProcessAfterInstantiation
<---postProcessPropertyValues--->
修改前name的值是:TypedStringValue: value [波波烤鴨], target type [null]
設定:bobo
>>postProcessBeforeInitialization
自定義初始化的方法....
<<postProcessAfterInitialization
User [id=0, name=bobo, beanName=null]
容器初始化結束....      

name的屬性值被修改了。該方法執行的條件要注意postProcessAfterInstantiation傳回true且postProcessBeforeInstantiation傳回null。

4.最後總結

   InstantiationAwareBeanPostProcessor接口繼承BeanPostProcessor接口,它内部提供了3個方法,再加上BeanPostProcessor接口内部的2個方法,是以實作這個接口需要實作5個方法。InstantiationAwareBeanPostProcessor接口的主要作用在于目标對象的執行個體化過程中需要處理的事情,包括執行個體化對象的前後過程以及執行個體的屬性設定

   postProcessBeforeInstantiation方法是最先執行的方法,它在目标對象執行個體化之前調用,該方法的傳回值類型是Object,我們可以傳回任何類型的值。由于這個時候目标對象還未執行個體化,是以這個傳回值可以用來代替原本該生成的目标對象的執行個體(比如代理對象)。如果該方法的傳回值代替原本該生成的目标對象,後續隻有postProcessAfterInitialization方法會調用,其它方法不再調用;否則按照正常的流程走

   postProcessAfterInstantiation方法在目标對象執行個體化之後調用,這個時候對象已經被執行個體化,但是該執行個體的屬性還未被設定,都是null。因為它的傳回值是決定要不要調用postProcessPropertyValues方法的其中一個因素(因為還有一個因素是mbd.getDependencyCheck());如果該方法傳回false,并且不需要check,那麼postProcessPropertyValues就會被忽略不執行;如果傳回true, postProcessPropertyValues就會被執行

   postProcessPropertyValues方法對屬性值進行修改(這個時候屬性值還未被設定,但是我們可以修改原本該設定進去的屬性值)。如果postProcessAfterInstantiation方法傳回false,該方法可能不會被調用。可以在該方法内對屬性值進行修改

   父接口BeanPostProcessor的2個方法postProcessBeforeInitialization和postProcessAfterInitialization都是在目标對象被執行個體化之後,并且屬性也被設定之後調用的