上一次講application context中bean的生命週期,後面貼了一部分代碼,但根本沒理解代碼意思,有幸在博客園看到一篇關於這部分的代碼解析,特別長,特此作了一些整理筆記,並附上連接:http://www.cnblogs.com/ITtangtang/p/3978349.htmlhtml
這部份內容從application context的建立開始講起,上次講bean的生命週期時,默認application context已經建立完了,但這部分是怎麼建立的也不是特別清楚,此次弄明白一下。git
下面主要分爲四部分:spring
一、ioc容器(application context)的建立;緩存
二、讀取配置文件,加載BeanDefinition(Bean定義資源)到ioc容器中;數據結構
三、實例化Bean多線程
四、設置屬性值,即執行setXxx()方法併發
下面依次解讀代碼:app
ApplicationContext =new FileSystemXmlApplicationContext(xmlPath);ide
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
分析FileSystemXmlApplicationContext的源代碼能夠知道,在建立FileSystemXmlApplicationContext容器時,構造方法作如下兩項重要工做:函數
Spring IoC容器對BeanDefinition(即Bean定義資源)的載入是從refresh()函數開始的。
FileSystemXmlApplicationContext經過調用其父類AbstractApplicationContext的refresh()函數啓動整個IoC容器對Bean定義的載入過程:
經過 ResourceLoader 來完成資源文件位置的定位,能夠從類路徑,文件系統, URL 等方式來定爲資源位置。若是是 XmlBeanFactory做爲 IOC 容器,容器經過使用XmlBeanDefinitionReader 來解析讀取bean的xml定義文件,而後加載bean的定義信息,並將XML的定義信息轉換爲Document對象。
以後,按照Spring的Bean規則對Document對象進行解析。通過對Spring Bean定義資源文件轉換的Document對象中的元素層層解析,Spring IoC如今已經將XML形式定義的Bean定義資源文件轉換爲Spring IoC所識別的數據結構——BeanDefinition,它是Bean定義資源文件中配置的POJO對象在Spring IoC容器中的映射。因此在解析<Bean>元素過程當中沒有建立和實例化Bean對象,只是建立了Bean對象的定義類BeanDefinition,將<Bean>元素中的配置信息設置到BeanDefinition中做爲記錄,當依賴注入時才使用這些記錄信息建立和實例化具體的Bean對象。
容器解析獲得 BeanDefinition後,須要把它在 IOC 容器中註冊,這由 IOC 實現 BeanDefinitionRegistry 接口來實現。註冊過程就是在 IOC 容器內部維護的一個HashMap 來保存獲得的 BeanDefinition 的過程。這個 HashMap 是 IoC 容器持有 bean 信息的場所,之後對 bean 的操做都是圍繞這個HashMap 來實現的。
Bean定義資源文件中配置的Bean被解析成BeanDefinition,註冊到IoC容器中,被容器管理起來,真正完成了IoC容器初始化所作的所有工做。現 在IoC容器中已經創建了整個Bean的配置信息,這些BeanDefinition信息已經可使用,而且能夠被檢索,IoC容器的做用就是對這些註冊的Bean定義信息進行處理和維護。這些的註冊的Bean定義信息是IoC容器控制反轉的基礎,正是有了這些註冊的數據,容器才能夠進行依賴注入。
Spring IoC容器完成了Bean定義資源的定位、載入和解析註冊之後,IoC容器中已經管理類Bean定義的相關數據,可是此時IoC容器尚未對所管理的Bean進行依賴注入,依賴注入在如下兩種狀況發生:
(1).用戶第一次經過getBean方法向IoC容索要Bean時,IoC容器觸發依賴注入。
(2).當用戶在Bean定義資源中爲<Bean>元素配置了lazy-init屬性,即讓容器在解析註冊Bean定義時進行預實例化,觸發依賴注入。
BeanFactory接口中定義了幾個getBean方法,就是用戶向IoC容器索取管理的Bean的方法。當調用者經過 getBean( name )向容器尋找Bean時,就能夠開始看Bean的生命週期了。詳見:http://www.cnblogs.com/hantalk/p/6644701.html
若是Bean定義的單態模式(Singleton),則容器在建立以前先從緩存中查找,以確保整個容器中只存在一個實例對象。若是Bean定義的是原型模式(Prototype),則容器每次都會建立一個新的實例對象。
Ioc容器從BeanDefinitionRegistry中取出BeanDefinition對象,調用InstantiationStrategy,採用反射機制進行Bean實例化的工做。InstantiationStrategy僅負責實例化Bean的操做,至關於執行Java語言中new的功能,不會參與Bean屬性的設置工做。
1 //使用初始化策略實例化Bean對象 2 public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) { 3 //若是Bean定義中沒有方法覆蓋,則就不須要CGLIB父類類的方法 4 if (beanDefinition.getMethodOverrides().isEmpty()) { 5 Constructor<?> constructorToUse; 6 synchronized (beanDefinition.constructorArgumentLock) { 7 //獲取對象的構造方法或工廠方法 8 constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod; 9 //若是沒有構造方法且沒有工廠方法 10 if (constructorToUse == null) { 11 //使用JDK的反射機制,判斷要實例化的Bean是不是接口 12 final Class clazz = beanDefinition.getBeanClass(); 13 if (clazz.isInterface()) { 14 throw new BeanInstantiationException(clazz, "Specified class is an interface"); 15 } 16 try { 17 if (System.getSecurityManager() != null) { 18 //這裏是一個匿名內置類,使用反射機制獲取Bean的構造方法 19 constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() { 20 public Constructor run() throws Exception { 21 return clazz.getDeclaredConstructor((Class[]) null); 22 } 23 }); 24 } 25 else { 26 constructorToUse = clazz.getDeclaredConstructor((Class[]) null); 27 } 28 beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse; 29 } 30 catch (Exception ex) { 31 throw new BeanInstantiationException(clazz, "No default constructor found", ex); 32 } 33 } 34 } 35 //使用BeanUtils實例化,經過反射機制調用」構造方法.newInstance(arg)」來進行實例化 36 return BeanUtils.instantiateClass(constructorToUse); 37 } 38 else { 39 //使用CGLIB來實例化對象 40 return instantiateWithMethodInjection(beanDefinition, beanName, owner); 41 } }
Spring IoC容器是如何將屬性的值注入到Bean實例對象中去的,經過BeanWrapper將Bean包裝起來,從Bean對應的BeanDefinition中獲取Bean屬性的配置信息PropertyValue,而後進行類型轉換解析:
(1).對於集合類型list,array,map的屬性,將其屬性值解析爲目標類型的集合後直接賦值給屬性。
(2).對於非集合類型的屬性,大量使用了JDK的反射和內省機制,經過屬性的getter方法(reader method)獲取指定屬性注入之前的值,同時調用屬性的setter方法(writer method)爲屬性設置注入後的值。看到這裏相信不少人都明白了Spring的setter注入原理。
五、關於Bean懶加載的實例化,可參考這篇文章:http://blog.csdn.net/chjttony/article/details/6278627
簡單就是說:在上面「二、BeanDefinition的加載」中執行refresh()函數時,在此進行實例化。
ApplicationContext實現的默認行爲就是在啓動時將全部singleton bean提早進行實例化。也就是說,默認狀況下lazy-init=false(不延遲加載),大部分的bean默認在refresh()的時候進行bean的預實例化,提早注入。而lazy-init=true時,纔不會提早實例化,等到beandefinition加載完了再實例化。
//容器初始化的過程,讀入Bean定義資源,並解析註冊 2 public void refresh() throws BeansException, IllegalStateException { 3 synchronized (this.startupShutdownMonitor) { 4 //調用容器準備刷新的方法,獲取容器的當時時間,同時給容器設置同步標識 5 prepareRefresh(); 6 //告訴子類啓動refreshBeanFactory()方法,Bean定義資源文件的載入從 7 //子類的refreshBeanFactory()方法啓動 8 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 9 //爲BeanFactory配置容器特性,例如類加載器、事件處理器等 10 prepareBeanFactory(beanFactory); 11 try { 12 //爲容器的某些子類指定特殊的BeanPost事件處理器 13 postProcessBeanFactory(beanFactory); 14 //調用全部註冊的BeanFactoryPostProcessor的Bean 15 invokeBeanFactoryPostProcessors(beanFactory); 16 //爲BeanFactory註冊BeanPost事件處理器. 17 //BeanPostProcessor是Bean後置處理器,用於監聽容器觸發的事件 18 registerBeanPostProcessors(beanFactory); 19 //初始化信息源,和國際化相關. 20 initMessageSource(); 21 //初始化容器事件傳播器. 22 initApplicationEventMulticaster(); 23 //調用子類的某些特殊Bean初始化方法 24 onRefresh(); 25 //爲事件傳播器註冊事件監聽器. 26 registerListeners(); 27 //這裏是對容器lazy-init屬性進行處理的入口方法 28 finishBeanFactoryInitialization(beanFactory); 29 //初始化容器的生命週期事件處理器,併發布容器的生命週期事件 30 finishRefresh(); 31 } 32 catch (BeansException ex) { 33 //銷燬以建立的單態Bean 34 destroyBeans(); 35 //取消refresh操做,重置容器的同步標識. 36 cancelRefresh(ex); 37 throw ex; 38 } 39 } }
AbstractApplicationContext類中的finishBeanFactoryInitialization方法對配置了預實例化屬性的Bean進行預初始化過程,
//對配置了lazy-init屬性的Bean進行預實例化處理 2 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { 3 //這是Spring3之後新加的代碼,爲容器指定一個轉換服務(ConversionService) 4 //在對某些Bean屬性進行轉換時使用 5 if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && 6 beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { 7 beanFactory.setConversionService( 8 beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); 9 } 10 //爲了類型匹配,中止使用臨時的類加載器 11 beanFactory.setTempClassLoader(null); 12 //緩存容器中全部註冊的BeanDefinition元數據,以防被修改 13 beanFactory.freezeConfiguration(); 14 //對配置了lazy-init屬性的單態模式Bean進行預實例化處理 15 beanFactory.preInstantiateSingletons(); }
ConfigurableListableBeanFactory是一個接口,其preInstantiateSingletons方法由其子類DefaultListableBeanFactory提供。
1//對配置lazy-init屬性單態Bean的預實例化 2public void preInstantiateSingletons() throws BeansException { 3 if (this.logger.isInfoEnabled()) { 4 this.logger.info("Pre-instantiating singletons in " + this); 5 } 6 //在對配置lazy-init屬性單態Bean的預實例化過程當中,必須多線程同步,以確保數據一致性 7 synchronized (this.beanDefinitionMap) { 8 for (String beanName : this.beanDefinitionNames) { 9 //獲取指定名稱的Bean定義 10 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); 11 //Bean不是抽象的,是單態模式的,且lazy-init屬性配置爲false 12 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { 13 //若是指定名稱的bean是建立容器的Bean 14 if (isFactoryBean(beanName)) { 15 //FACTORY_BEAN_PREFIX=」&」,當Bean名稱前面加」&」符號 16 //時,獲取的是產生容器對象自己,而不是容器產生的Bean. 17 //調用getBean方法,觸發容器對Bean實例化和依賴注入過程 18 final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName); 19 //標識是否須要預實例化 20 boolean isEagerInit; 21 if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { 22 //一個匿名內部類 23 isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { 24 public Boolean run() { 25 return ((SmartFactoryBean) factory).isEagerInit(); 26 } 27 }, getAccessControlContext()); 28 } 29 else { 30 isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit(); 31 } 32 if (isEagerInit) { 33 //調用getBean方法,觸發容器對Bean實例化和依賴注入過程 34 getBean(beanName); 35 } 36 } 37 else { 38 //調用getBean方法,觸發容器對Bean實例化和依賴注入過程 39 getBean(beanName); 40 } 41 } 42 } 43 } }
推薦參考連接: