1. 程式人生 > 其它 >Spring的bean建立過程分析之resolveBeforeInstantiation的呼叫執行

Spring的bean建立過程分析之resolveBeforeInstantiation的呼叫執行

Spring的bean建立過程分析之resolveBeforeInstantiation的呼叫執行

我們接著上面的Bean 的建立流程,今天來談談 resolveBeforeInstantiation 的呼叫執行。

此方法存在的意義在於給BeanPostProcessor的實現子類一個機會去生成代理物件來替代物件。

顧名思義, 我們需要生成的物件是一個代理物件。 這樣也可以建立bean。

1、案例實現

  • BeforeInstantiation.java
package com.qzk.QzkResolveBeforeInstantiation;

/**
 * @ClassName BeforeInstantiation
 * @Description 建立一個 BeforeInstantiation 的一個類, 該類只有一個方法, do some things
 * @Author qzk
 * @Date 2022/4/26 11:43 下午
 * @Version 1.0
 **/
public class BeforeInstantiation {

    public void doSomething(){
        System.out.println(" 執行do some thing ...");
    }
}
  • QzkMethodInterceptor.java
package com.qzk.QzkResolveBeforeInstantiation;

import org.aopalliance.intercept.MethodInvocation;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 *
 * @ClassName QzkMethodInterceptor
 * @Description 攔截器
 * @Author qzk
 * @Date 2022/4/26 11:52 下午
 * @Version 1.0
 **/
public class QzkMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("目標方法執行之前: " + method);
        Object o1 = methodProxy.invokeSuper(o, objects);
        System.out.println("目標方法執行之後: " + method);
        return o1;
    }
}

package com.qzk.QzkResolveBeforeInstantiation;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.cglib.proxy.Enhancer;

/**
 * @ClassName QzkInstantiationAwareBeanPostProcessor
 * @Description
 * @Author qzk
 * @Date 2022/4/26 11:45 下午
 * @Version 1.0
 **/
public class QzkInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {


    /**
     * 例項化之前的操作
     *
     * @param beanClass the class of the bean to be instantiated
     * @param beanName  the name of the bean
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {

//        if (beanClass.equals(BeforeInstantiation.class)) {
            System.out.println("當前beanName:" + beanName + "--> 執行:postProcessBeforeInstantiation 例項化之前");
            if (beanClass == BeforeInstantiation.class) {
                // 建立動態代理類的增強類
                Enhancer enhancer = new Enhancer();
                //  設定類載入器
                enhancer.setClassLoader(beanClass.getClassLoader());
                //  設定被動態代理類所代理的 被代理類
                enhancer.setSuperclass(beanClass);
                // 設定方法攔截器
                enhancer.setCallback(new QzkMethodInterceptor());
                //  建立代理類
                BeforeInstantiation beforeInstantiation = (BeforeInstantiation) enhancer.create();
                System.out.println("建立代理物件:" + beforeInstantiation);
                return beforeInstantiation;
            }
            return nulll;
    }

    /**
     * 例項化之後的操作
     *
     * @param bean     the bean instance created, with properties not having been set yet
     * @param beanName the name of the bean
     * @return
     * @throws BeansException
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("當前beanName:" + beanName + "--> 執行:postProcessAfterInstantiation 例項化之後");
        return false;
    }

    /**
     * 對當前屬性值的一個相關處理工作
     *
     * @param pvs      the property values that the factory is about to apply (never {@code null})
     * @param bean     the bean instance created, but whose properties have not yet been set
     * @param beanName the name of the bean
     * @return
     * @throws BeansException
     */
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        System.out.println("當前beanName:" + beanName + "--> 執行:postProcessProperties 屬性值的處理");
        return pvs;
    }

    /**
     * 初始化之前的做哪些操作
     *
     * @param bean     the new bean instance
     * @param beanName the name of the bean
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("當前beanName:" + beanName + "--> 執行:postProcessBeforeInitialization 初始化之前");

        return bean;
    }

    /**
     * 初始化之後做哪些操作
     *
     * @param bean     the new bean instance
     * @param beanName the name of the bean
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("當前beanName:" + beanName + "--> 執行:postProcessAfterInitialization 初始化之後");
        return bean;
    }
}

  • 測試類
package com.qzk.QzkResolveBeforeInstantiation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @ClassName QzkTest
 * @Description TODO
 * @Author qzk
 * @Date 2022/4/27 12:01 上午
 * @Version 1.0
 **/
public class QzkTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("QzkResolveBeforeInstantiation.xml");
        BeforeInstantiation bean = context.getBean(BeforeInstantiation.class);
        bean.doSomething();
    }
}

  • xml配置檔案
<?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 id="beforeInstantiation" class="com.qzk.QzkResolveBeforeInstantiation.BeforeInstantiation"></bean>
    <bean id="myInstantiationAwareBeanPostProcessor" class="com.qzk.QzkResolveBeforeInstantiation.QzkInstantiationAwareBeanPostProcessor"></bean>

</beans>

在上面的程式碼中,我們看到有一個類 是實現了InstantiationAwareBeanPostProcessor 介面的,針對這個介面,我們可以先看一下他的一個類圖的繼承關係。

根據上圖所示, 因此, QzkInstantiationAwareBeanPostProcessor在實現 InstantiationAwareBeanPostProcessor 介面之後,是屬於 BeanPostProcessor的,因此在refresh() 的流程中, 是通過registerBeanPostProcessors(beanFactory) 方式, 實現的一個BPP的建立的。

當我們執行 finishBeanFactoryInitialization(beanFactory) 的時候, 裡面繼續執行到 preInstantiateSingletons

緊接著就是執行我們的getBean --> doGetBean --> createBean ---> doCreateBean 的一個流程, 這裡不做過多的贅述。

在具體的執行過程中, 我們自定義的 beforeInstatiation 此時會走下面的邏輯

![image-20220511132013946](/Users/qzk/Library/Application Support/typora-user-images/image-20220511132013946.png)

![image-20220511132209559](/Users/qzk/Library/Application Support/typora-user-images/image-20220511132209559.png)

![image-20220511132307893](/Users/qzk/Library/Application Support/typora-user-images/image-20220511132307893.png)

![image-20220511132451405](/Users/qzk/Library/Application Support/typora-user-images/image-20220511132451405.png)

當第二次for BeanName 迴圈的時候, 是獲取 Qzk... ,此時執行到如下圖的doGetBean 方法的時候,因為可以從快取中獲取到這個BPP,所以是通過 getObjetcForBeanInstance 方法來獲取bean 的。

上圖就是通過攔截器來進行執行的操作結果。

總結:

  • Spring 中bean的建立, 還可以通過 實現了 InstantiationAwarePostProcessor 介面的類 , 並結合動態代理去實現建立我們所需要的動態代理物件。
  • 這個過程是通過 resolveBeforeInstantiation 方法區呼叫執行的,並生成代理物件的。