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
方法區呼叫執行的,並生成代理物件的。