Spring擴展接口SmartInstantiationAwareBeanPostProcessor

SmartInstantiationAwareBeanPostProcessor接口繼承InstantiationAwareBeanPostProcessor接口,它們的作用相似,但是SmartInstantiationAwareBeanPostProcessor又多了3個方法,源碼如下:


Spring擴展接口SmartInstantiationAwareBeanPostProcessor


新增的3個方法解釋如下:

predictBeanType:用來返回目標對象的類型,(比如代理對象通過raw class獲取proxy type 用於類型匹配)。當你調用BeanFactory.getType(name)時當通過Bean定義無法得到Bean類型信息時就調用該回調方法來決定類型信息;BeanFactory.isTypeMatch(name, targetType)用於檢測給定名字的Bean是否匹配目標類型(如在依賴注入時需要使用)。

determineCandidateConstructors:用來解析獲取用來實例化的構造器。比如目標對象有多個構造器,在這裡可以進行一些定製化,選擇合適的構造器。如AutowiredAnnotationBeanPostProcessor實現將自動掃描通過@Autowired/@Value註解的構造器從而可以完成構造器注入。

getEarlyBeanReference:獲得提前暴露的bean引用。主要用於解決循環引用的問題。只有單例對象才會調用此方法。


我們可以來自定義實現一個:

<code>protected  T doGetBean(final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException {final String beanName = transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons.Object sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {if (logger.isDebugEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +"' that is not fully initialized yet - a consequence of a circular reference");}else {logger.debug("Returning cached instance of singleton bean '" + beanName + "'");}}bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// Fail if we're already creating this bean instance:// We're assumably within a circular reference.if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// Check if bean definition exists in this factory.BeanFactory parentBeanFactory = getParentBeanFactory();if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.String nameToLookup = originalBeanName(name);if (args != null) {// Delegation to parent with explicit args.return (T) parentBeanFactory.getBean(nameToLookup, args);}else {// No args -> delegate to standard getBean method.return parentBeanFactory.getBean(nameToLookup, requiredType);}}if (!typeCheckOnly) {markBeanAsCreated(beanName);}try {final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}registerDependentBean(dep, beanName);getBean(dep);}}// Create bean instance.if (mbd.isSingleton()) {          //獲取Bean對象,實際上是通過createBean去創建一個bean對象並返回sharedInstance = getSingleton(beanName, new ObjectFactory<object>() {@Overridepublic Object getObject() throws BeansException {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else {String scopeName = mbd.getScope();final Scope scope = this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {Object scopedInstance = scope.get(beanName, new ObjectFactory<object>() {@Overridepublic Object getObject() throws BeansException {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}}});bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {throw new BeanCreationException(beanName,"Scope '" + scopeName + "' is not active for the current thread; consider " +"defining a scoped proxy for this bean if you intend to refer to it from a singleton",ex);}}}catch (BeansException ex) {cleanupAfterBeanCreationFailure(beanName);throw ex;}}// Check if required type matches the type of the actual bean instance.if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {try {return getTypeConverter().convertIfNecessary(bean, requiredType);}catch (TypeMismatchException ex) {if (logger.isDebugEnabled()) {logger.debug("Failed to convert bean '" + name + "' to required type '" +ClassUtils.getQualifiedName(requiredType) + "'", ex);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}}return (T) bean;}/<object>/<object> 
/<code>

此時創建兩個bean互相依賴:

<code>@Component    static class A {        @Autowired        B b;    } @Component  static class B {       @Autowired        A a;  }/<code>


啟動程序時會先創建Bean A,所以我們跟蹤源碼,AbstractBeanFactory類的doGetBean方法:

<code>protected  T doGetBean(final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException {final String beanName = transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons.Object sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {if (logger.isDebugEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +"' that is not fully initialized yet - a consequence of a circular reference");}else {logger.debug("Returning cached instance of singleton bean '" + beanName + "'");}}bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// Fail if we're already creating this bean instance:// We're assumably within a circular reference.if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// Check if bean definition exists in this factory.BeanFactory parentBeanFactory = getParentBeanFactory();if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.String nameToLookup = originalBeanName(name);if (args != null) {// Delegation to parent with explicit args.return (T) parentBeanFactory.getBean(nameToLookup, args);}else {// No args -> delegate to standard getBean method.return parentBeanFactory.getBean(nameToLookup, requiredType);}}if (!typeCheckOnly) {markBeanAsCreated(beanName);}try {final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}registerDependentBean(dep, beanName);getBean(dep);}}// Create bean instance.if (mbd.isSingleton()) {          //獲取Bean對象,實際上是通過createBean去創建一個bean對象並返回sharedInstance = getSingleton(beanName, new ObjectFactory<object>() {@Overridepublic Object getObject() throws BeansException {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else {String scopeName = mbd.getScope();final Scope scope = this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {Object scopedInstance = scope.get(beanName, new ObjectFactory<object>() {@Overridepublic Object getObject() throws BeansException {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}}});bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {throw new BeanCreationException(beanName,"Scope '" + scopeName + "' is not active for the current thread; consider " +"defining a scoped proxy for this bean if you intend to refer to it from a singleton",ex);}}}catch (BeansException ex) {cleanupAfterBeanCreationFailure(beanName);throw ex;}}// Check if required type matches the type of the actual bean instance.if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {try {return getTypeConverter().convertIfNecessary(bean, requiredType);}catch (TypeMismatchException ex) {if (logger.isDebugEnabled()) {logger.debug("Failed to convert bean '" + name + "' to required type '" +ClassUtils.getQualifiedName(requiredType) + "'", ex);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}}return (T) bean;}/<object>/<object>/<code>

1、首先會獲取Bean A,通過getSingleton(beanName)方法獲取為空,則通過匿名內部類去創建一個bean對象並返回。sharedInstance = getSingleton(beanName, new ObjectFactory<object>() {/<object>

@Override

public Object getObject() throws BeansException {

try {

return createBean(beanName, mbd, args);

}catch (BeansException ex) {

destroySingleton(beanName);

throw ex;

}

}

});


2、接著執行DefaultSingletonBeanRegistry類 getSingleton(String beanName, ObjectFactory> singletonFactory)方法,其中執行beforeSingletonCreation(beanName),它會將當前的bean A添加到singletonsCurrentlyInCreation集合中


Spring擴展接口SmartInstantiationAwareBeanPostProcessor

<code>protected void beforeSingletonCreation(String beanName) {    //判斷beanName的同時將當前的beanName添加到singletonsCurrentlyInCreation集合if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}}/<code>

3、接著繼續執行singletonObject = singletonFactory.getObject(),singletonFactory就是前面步驟1定義的匿名內部類,所以就是執行getObject()方法中的createBean(beanName, mbd, args);方法。

4、執行AbstractAutowireCapableBeanFactory中的createBean方法,也就是執行doCreateBean方法。

Spring擴展接口SmartInstantiationAwareBeanPostProcessor


5、doCreateBean方法中有一個是否暴露前置單例bean的判斷,

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&

isSingletonCurrentlyInCreation(beanName)),其中isSingletonCurrentlyInCreation()方法中的

singletonsCurrentlyInCreation集合就是前面添加元素的集合,可以肯定集合中是存在當前beanName的。所以這裡是提前暴露前置單例bean,那麼就將當前的bean添加到singletonFactories集合中。


Spring擴展接口SmartInstantiationAwareBeanPostProcessor


Spring擴展接口SmartInstantiationAwareBeanPostProcessor

6、接下來執行populateBean(beanName, mbd, instanceWrapper),這個方法會注入Bean A的屬性B,

然後去獲取bean B,接著以同樣的方式去創建B。同樣在populateBean(beanName, mbd, instanceWrapper)方法時會去注入Bean A,在獲取的時候發現singletonObjects和earlySingletonObjects集合都沒有A,唯獨singletonFactories集合有A的ObjectFactory。然後通過ObjectFactory.getObject()就調用了在AbstractAutowireCapableBeanFactory的doCreateBean()方法中定義的匿名類的getObject()方法,從而調用getEarlyBeanReference(),getEarlyBeanReference()就會調用我們自定義的或框架中其他的getEarlyBeanReference()方法,也就是SmartInstantiationAwareBeanPostProcessor接口的實現方法。


Spring擴展接口SmartInstantiationAwareBeanPostProcessor


Spring擴展接口SmartInstantiationAwareBeanPostProcessor


從以上我們可以看到有幾個Map集合緩存:

singletonFactories:單例對象工廠的cache

earlySingletonObjects:提前暴光的單例對象的Cache

singletonObjects:單例對象的cache

在創建bean時,首先是從singletonObjects這個緩存中獲取單例bean。如果獲取不到,並且對象正在創建中,那麼就從二級緩存earlySingletonObjects中獲取。如果還獲取不到且允許singletonFactories通過getObject()獲取,那麼就從三級緩存singletonFactory.getObject()獲取,如果獲取到了則從singletonFactories中移除,並放入earlySingletonObjects中。也就是從三級緩存移到了二級緩存。

因此我們分析可以知道,Spring解決循環依賴的訣竅就在於singletonFactories這個三級緩存。它發生在createBeanInstance之後,也就是說單例對象此時已經被創建出來了(調用了構造器),雖然這個對象還不完美(還沒有進行初始化的第二步和第三步),但是已經存在堆中了,所以spring將這個對象提前曝光出來。

所以,如果A的構造方法中依賴了B的實例對象,同時B的構造方法中依賴了A的實例對象,Spring是無法解決的。因為加入singletonFactories三級緩存的前提是執行了構造器,所以構造器的循環依賴沒法解決。


在Spring中默認實現了它的有兩個類:

AbstractAutoProxyCreator

InstantiationAwareBeanPostProcessorAdapter:這個抽象類沒做任何處理,只是實現了一下接口。


分享到:


相關文章: