AbstractBeanFactory#getBean(java.lang.String)執行流程分析
在執行DefaultListableBeanFactory#preInstantiateSingletons方法時會建立非懶載入的單例Bean,這個建立過程是通過呼叫AbstractBeanFactory#getBean(java.lang.String)建立的;
下面分析AbstractBeanFactory#getBean(java.lang.String)的執行流程;
AbstractBeanFactory#getBean(java.lang.String)
該方法是一個空殼方法,沒有任何的實現邏輯 真正的邏輯呼叫在doGetBean()中,該介面是實現了BeanFactory的getBean(String name)介面;
AbstractBeanFactory#doGetBean
首先通過呼叫transformedBeanName(name)獲取beanName;
呼叫getSingleton(beanName)嘗試從快取中獲取物件;
判斷條件(sharedInstance ! = null && args == null)是否成立,成立則呼叫getObjectForBeanInstance(sharedInstance, name, beanName, null)返回Bean例項;如果sharedInstance 是普通的單例bean,方法會直接返回bean例項;如果sharedInstance 是 FactoryBean 型別的,則需呼叫 getObject 工廠方法獲取真正的bean例項;
條件(sharedInstance ! = null && args == null)不成立,則走下面的邏輯;
呼叫isPrototypeCurrentlyInCreation(beanName)判斷是否存在多例物件(prototype:多例物件,IOC容器啟動的時候,IOC容器啟動並不會去呼叫方法建立物件, 而是每次獲取的時候才會呼叫方法建立物件)的迴圈依賴,存在則丟擲BeanCurrentlyInCreationException異常;
注:Spring解決了單例物件的屬性注入的迴圈依賴,而構造器注入的迴圈依賴沒有解決;
建立兩個迴圈依賴的多例Bean,如下:
@Scope("prototype") @Component public class InstanceC { private final static Log LOG = LogFactory.getLog(InstanceC.class); @Autowired private InstanceD instanceD; // @Autowired // public InstanceC(InstanceD instanceD) { // this.instanceD = instanceD; // } public InstanceC() { LOG.info("InstanceC constructor"); } public void invoke() { LOG.info("C invoke..."); } public InstanceD getInstanceD() { return instanceD; } }
@Scope("prototype") @Component public class InstanceD { private final static Log LOG = LogFactory.getLog(InstanceD.class); @Autowired private InstanceC instanceC; // @Autowired // public InstanceD(InstanceC instanceC) { // this.instanceC = instanceC; // } public void invoke() { LOG.info("D invoke..."); } public InstanceC getInstanceC() { return instanceC; } }
異常如下:
getParentBeanFactory()判斷AbstractBeanFacotry工廠是否有父工廠(一般情況下是沒有父工廠因為AbstractBeanFactory直接是抽象類,不存在父工廠),存在則根據父工廠呼叫getBean,一般情況下,只有Spring 和SpringMvc整合的時才會有父子容器的概念;
呼叫getMergedLocalBeanDefinition(beanName)會合並父BeanDefinition和子BeanDefinition,子BeanDefinition會覆蓋父BeanDefintion;
測試如下:
public class ComponentC { private String name; private String id; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } @Override public String toString() { return "ComponentC{" + "name='" + name + '\'' + ", id='" + id + '\'' + '}'; } }
public class ComponentD { private String name; private String id; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } @Override public String toString() { return "ComponentC{" + "name='" + name + '\'' + ", id='" + id + '\'' + '}'; } }
bean.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="componentC" class="org.example.component.ComponentC" abstract="true"> <property name="id" value="test"></property> <property name="name" value="parent"></property> </bean> <bean id="componentD" class="org.example.component.ComponentD" parent="componentC"> <property name="name" value="son"></property> <!-- <property name="id" value="componentD"></property>--> </bean> </beans>
@Test public void xmlConfigTest() { ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); System.out.println(context.getBean("componentD")); }
執行結果如下:
將bean.xml中註釋開啟,執行結果如下:
處理Bean載入依賴順序,如果dependsOn不為空,則呼叫registerDependentBean(dep, beanName)註冊該Bean的依賴項,getBean(dep)優先建立依賴的物件;
測試如下:
public class DependsA { private final static Log LOG = LogFactory.getLog(DependsA.class); public DependsA() { LOG.info("DependsA"); } }
public class DependsB { private final static Log LOG = LogFactory.getLog(DependsB.class); public DependsB() { LOG.info("DependsB"); } }
@Configuration public class DependOnConfig { @Bean public DependsA dependsA() { return new DependsA(); } @Bean @DependsOn(value = {"dependsA"}) public DependsB dependsB() { return new DependsB(); } }
@Test public void dependsOnTest() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DependOnConfig.class); }
執行結果如下:
之後根據BeanDefinition的scope型別建立Bean例項;
下面分析scope為single型別的Bean例項建立;
呼叫getSingleton(beanName, new ObjectFactory<Object>(){})獲取單例物件;
DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
首先從單例快取池中獲取Bean例項,如果Bean例項存在,則將物件返回,否則執行建立物件的邏輯;
呼叫beforeSingletonCreation方法標記當前bean要被建立,該方法在Bean建立前呼叫的;
singletonsCurrentlyInCreation 在這裡會把beanName加入進來,標記該Bean正在建立,當第二次進入時,如果出現singletonsCurrentlyInCreation 新增失敗,這個時候出現了迴圈依賴(構造器注入);
ObjectFactory型別的入參singletonFactory呼叫getObject方法,用於返回一個Bean的例項;
在最後會呼叫afterSingletonCreation將singletonsCurrentlyInCreation標記正在建立的bean從集合中移除,addSingleton將建立的Bean例項加入到快取中
而getSingleton方法的入參是一個函式介面,執行建立的邏輯在createBean方法;
AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
這裡會呼叫resolveBeforeInstantiation方法,在註釋中的意思是給後置處理器返回一個代理物件,但一般情況下在此次是不會返回代理物件的,不論是使用JDK代理還是Cglib代理,前提條件需要有一個Bean例項,而此時的Bean例項並沒有建立,代理物件並不會生成,這裡只是將使用者定義的切面資訊進行快取;
之後執行doCreateBean方法,建立Bean例項的流程在這裡;
AbstractAutowireCapableBeanFactory#doCreateBean
呼叫createBeanInstance方法,使用合適的例項化策略建立例項;
判斷傳入的mbd.getFactoryMethodName是否為空,即有無使用@Bean通過工廠方法注入例項;
mbd的factoryMethodName在BeanDefiniton載入時賦值的,如下:
ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod
判斷Bean定義資訊中的resolvedConstructorOrFactoryMethod是否快取,因為需要根據引數確認到底使用哪個構造器,該過程比較消耗效能,所有采用快取機制;
通過Bean的後置處理器進行獲取合適的構造器物件,根據相應的策略建立物件並返回;
Spring中有三級快取,用於解決屬性賦值的迴圈依賴;
此時創建出來的Bean沒有進行屬性賦值的,屬於早期物件,isSingleton表示是否為單例,allowCircularReferences預設為true,isSingletonCurrentlyInCreation表示當前beanName的Bean正在建立;
符合條件則呼叫addSingletonFactory方法,該方法把早期物件包裝成一個ObjectFactory暴露到三級快取中;
呼叫populateBean進行屬性賦值;
物件的屬性注入是通過後置處理器處理的;
如@Autowired的屬性注入是通過AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues處理的;
虛擬碼如下:
@Component public class ComponentA { private final static Log LOG = LogFactory.getLog(ComponentA.class); @Autowired private ComponentB componentB; public ComponentA() { LOG.info("ComponentA constructor"); } } @Component public class ComponentB { private final static Log LOG = LogFactory.getLog(ComponentB.class); public ComponentB() { LOG.info("ComponentB constructor"); } }
上面的虛擬碼ComponentB是ComponentA的欄位值,需要自動注入;
後置處理器最終會根據注入的型別執行下面的注入邏輯,如欄位的注入,執行AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject方法;
AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
這裡會獲取欄位值的例項物件,並把該欄位例項物件set到依賴該物件的Bean上;
最終通過org.springframework.beans.factory.config.DependencyDescriptor#resolveCandidate獲取需要依賴的Bean的例項物件,其實該方法是通過BeanFactory#getBean獲取Bean的例項物件;
呼叫initializeBean進行物件初始化;
AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
invokeAwareMethods會將實現了XXXAware介面進行方法的回撥,invokeInitMethods方法會將實現InitializingBean介面或@PostConstruct註解修飾的方法進行回撥,applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization則會對BeanPostProcessor介面申明的方法進行回撥;
呼叫registerDisposableBeanIfNecessary方法,註冊銷燬Bean的介面DisposableBean,當Bean生命週期結束時會對該介面的destroy方法進行回撥;