繼續上一篇Spring Bean
的建立過程的解讀,上一篇介紹了Spring
在建立過程中doGetBean
方法,在執行過程中會呼叫getSingleton
方法並且設定一個lambda
表示式,這個lambda
表示式是ObjectFactory
的實現,當呼叫這個介面的getObject
方法時就會執行到createBean
方法,在createBean
方法中會進行bean
型別的解析,並且會進行方法覆蓋的設定,當我們配置瞭如:lookup-method
或者replace-method
方法的時候就會在建立Bean
的過程中設定一個CGLIB
的工廠類為Bean
的物件,當呼叫的時候就會觸發CGLIB
的攔截器方法執行具體的Bean
的獲取,如果是單例物件引用了多例物件,那麼就會每次建立一個新的物件給呼叫的方法執行。
接下來繼續解讀Spring
建立Bean
的過程。
早期Bean的建立
在createBean
方法中有一段程式碼:
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 解析提前例項化,使用InstantiationAwareBeanPostProcessor實現
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
點進去:
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
// 判斷是否有InstantiationAwareBeanPostProcessor在容器中
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;
}
這裡判斷了容器中如果有實現InstantiationAwareBeanPostProcessor
介面,那麼就執行前置例項化,InstantiationAwareBeanPostProcessor
介面繼承了BeanPostProcessor
,並且這個介面的方法跟BeanPostProcessor
非常相似,InstantiationAwareBeanPostProcessor
的介面一個是前置的例項化postProcessBeforeInstantiation
,一個是後置的例項化postProcessAfterInstantiation
,而BeanPostProcessor
的介面一個是前置初始化postProcessBeforeInitialization
,一個是後置初始化postProcessAfterInitialization
。
在Spring
中Bean
的建立分為例項化+初始化,當然還有屬性填充,這裡進行提前例項化其實就是給了一個擴充套件點,讓物件可以提前建立,而不用再繼續走doCreateBean
方法裡面的複雜邏輯,這樣的話就提供給使用者能夠自己控制物件的建立過程以及執行增強等操作。
那這個例項化增強類是何時放進Spring容器的呢?
答案很簡單,InstantiationAwareBeanPostProcessor
是一個BeanPostProcessor
,那麼自然也就是在註冊BeanPostProcessor
時放進去的。
看原始碼:
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
// Remove from old position, if any
// 先刪除掉舊的
this.beanPostProcessors.remove(beanPostProcessor);
// Track whether it is instantiation/destruction aware
// 如果是InstantiationAwareBeanPostProcessor 設定屬性
if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
this.hasInstantiationAwareBeanPostProcessors = true;
}
// 設定銷燬的標識位
if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
this.hasDestructionAwareBeanPostProcessors = true;
}
// Add to end of list
// 新增到連結串列尾
this.beanPostProcessors.add(beanPostProcessor);
}
接下來試試提前例項化的案例:
InstantiationAwareBeanPostProcessor 實驗
建立一個需要提前例項化的物件:
/**
* @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class MyBeforeInstantiation {
public void beforeInvoke(){
System.out.println("提前例項化,開始執行業務....");
}
}
建立一個InstantiationAwareBeanPostProcessor
的實現類:
/**
* @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "執行了 postProcessBeforeInstantiation 方法");
// 提前進行例項化
if (beanClass == MyBeforeInstantiation.class) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(beanClass);
enhancer.setCallback(new MyMethodInterceptor());
Object obj = enhancer.create();
System.out.println("建立物件:" + obj);
return obj;
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "執行了 postProcessAfterInstantiation 方法");
return false;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "執行了 postProcessProperties 方法");
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "執行了 postProcessBeforeInitialization 方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("beanName: " + beanName + "執行了 postProcessAfterInitialization 方法");
return bean;
}
}
這裡使用了CGLIB 動態代理去增強建立代理物件,編寫一個回撥攔截器:
/**
* @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class MyMethodInterceptor 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;
}
}
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="myBeforeInstantiation" class="com.redwinter.test.beforeInstantiation.MyBeforeInstantiation"/>
<bean id="myInstantiationAwareBeanPostProcessor" class="com.redwinter.test.beforeInstantiation.MyInstantiationAwareBeanPostProcessor"/>
</beans>
測試類:
/**
* @author <a href="https://www.cnblogs.com/redwinter/">redwinter</a>
* @since 1.0
**/
public class BeforeInstantiationTest {
@Test
public void test(){
ApplicationContext ac = new ClassPathXmlApplicationContext("before-instantiation.xml");
MyBeforeInstantiation bean = ac.getBean(MyBeforeInstantiation.class);
bean.beforeInvoke();
}
}
輸出:
beanName: myBeforeInstantiation執行了 postProcessBeforeInstantiation 方法
方法執行前:public java.lang.String java.lang.Object.toString()
方法執行前:public native int java.lang.Object.hashCode()
方法執行後:public native int java.lang.Object.hashCode()
方法執行後:public java.lang.String java.lang.Object.toString()
建立物件:com.redwinter.test.beforeInstantiation.MyBeforeInstantiation$$EnhancerByCGLIB$$f92db8b4@1fd3711
beanName: myBeforeInstantiation執行了 postProcessAfterInitialization 方法
方法執行前:public void com.redwinter.test.beforeInstantiation.MyBeforeInstantiation.beforeInvoke()
提前例項化,開始執行業務....
方法執行後:public void com.redwinter.test.beforeInstantiation.MyBeforeInstantiation.beforeInvoke()
可以看到,這裡只執行了兩個方法,一個是postProcessBeforeInstantiation
,是InstantiationAwareBeanPostProcessor
的前置例項化介面,一個是postProcessAfterInitialization
,是BeanPostProcessor
的後置例項化介面。
相當於說Bean
物件提前被建立了,而沒有執行下面的doCreateBean
方法的邏輯。 Spring
設計了很多的擴充套件點,幫助使用者實現很多自定義的處理,Spring
強大之處就在這裡。
這篇就介紹到這裡,下一篇介紹Spring
其他方式的進行提前建立Bean
物件。