代碼入口程序員
以前寫文章都會囉囉嗦嗦一大堆再開始,進入【Spring源碼分析】這個板塊就直接切入正題了。spring
不少朋友可能想看Spring源碼,可是不知道應當如何入手去看,這個能夠理解:Java開發者一般從事的都是Java Web的工做,對於程序員來講,一個Web項目用到Spring,只是配置一下配置文件而已,Spring的加載過程相對是不太透明的,不太好去找加載的代碼入口。數組
下面有很簡單的一段代碼能夠做爲Spring代碼加載的入口:多線程
1 ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml"); 2 ac.getBean(XXX.class);
ClassPathXmlApplicationContext用於加載CLASSPATH下的Spring配置文件,能夠看到,第二行就已經能夠獲取到Bean的實例了,那麼必然第一行就已經完成了對全部Bean實例的加載,所以能夠經過ClassPathXmlApplicationContext做爲入口。爲了後面便於代碼閱讀,先給出一下ClassPathXmlApplicationContext這個類的繼承關係:併發
大體的繼承關係是如上圖所示的,因爲版面的關係,沒有繼續畫下去了,左下角的ApplicationContext應當還有一層繼承關係,比較關鍵的一點是它是BeanFactory的子接口。app
最後聲明一下,本文使用的Spring版本爲3.0.7,比較老,使用這個版本純粹是由於公司使用而已。函數
ClassPathXmlApplicationContext存儲內容源碼分析
爲了更理解ApplicationContext,拿一個實例ClassPathXmlApplicationContext舉例,看一下里面存儲的內容,加深對ApplicationContext的認識,以表格形式展示:post
對象名 | 類 型 | 做 用 | 歸屬類 |
configResources | Resource[] | 配置文件資源對象數組 | ClassPathXmlApplicationContext |
configLocations | String[] | 配置文件字符串數組,存儲配置文件路徑 | AbstractRefreshableConfigApplicationContext |
beanFactory | DefaultListableBeanFactory | 上下文使用的Bean工廠 | AbstractRefreshableApplicationContext |
beanFactoryMonitor | Object | Bean工廠使用的同步監視器 | AbstractRefreshableApplicationContext |
id | String | 上下文使用的惟一Id,標識此ApplicationContext | AbstractApplicationContext |
parent | ApplicationContext | 父級ApplicationContext | AbstractApplicationContext |
beanFactoryPostProcessors | List<BeanFactoryPostProcessor> | 存儲BeanFactoryPostProcessor接口,Spring提供的一個擴展點 | AbstractApplicationContext |
startupShutdownMonitor | Object | refresh方法和destory方法公用的一個監視器,避免兩個方法同時執行 | AbstractApplicationContext |
shutdownHook | Thread | Spring提供的一個鉤子,JVM中止執行時會運行Thread裏面的方法 | AbstractApplicationContext |
resourcePatternResolver | ResourcePatternResolver | 上下文使用的資源格式解析器 | AbstractApplicationContext |
lifecycleProcessor | LifecycleProcessor | 用於管理Bean生命週期的生命週期處理器接口 | AbstractApplicationContext |
messageSource | MessageSource | 用於實現國際化的一個接口 | AbstractApplicationContext |
applicationEventMulticaster | ApplicationEventMulticaster | Spring提供的事件管理機制中的事件多播器接口 | AbstractApplicationContext |
applicationListeners | Set<ApplicationListener> | Spring提供的事件管理機制中的應用監聽器 | AbstractApplicationContext |
ClassPathXmlApplicationContext構造函數學習
看下ClassPathXmlApplicationContext的構造函數:
1 public ClassPathXmlApplicationContext(String configLocation) throws BeansException { 2 this(new String[] {configLocation}, true, null); 3 }
1 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) 2 throws BeansException { 3 4 super(parent); 5 setConfigLocations(configLocations); 6 if (refresh) { 7 refresh(); 8 } 9 }
從第二段代碼看,總共就作了三件事:
一、super(parent)
沒什麼太大的做用,設置一下父級ApplicationContext,這裏是null
二、setConfigLocations(configLocations)
代碼就不貼了,一看就知道,裏面作了兩件事情:
(1)將指定的Spring配置文件的路徑存儲到本地
(2)解析Spring配置文件路徑中的${PlaceHolder}佔位符,替換爲系統變量中PlaceHolder對應的Value值,System自己就自帶一些系統變量好比class.path、os.name、user.dir等,也能夠經過System.setProperty()方法設置本身須要的系統變量
三、refresh()
這個就是整個Spring Bean加載的核心了,它是ClassPathXmlApplicationContext的父類AbstractApplicationContext的一個方法,顧名思義,用於刷新整個Spring上下文信息,定義了整個Spring上下文加載的流程。
refresh方法
上面已經說了,refresh()方法是整個Spring Bean加載的核心,所以看一下整個refresh()方法的定義:
1 public void refresh() throws BeansException, IllegalStateException { 2 synchronized (this.startupShutdownMonitor) { 3 // Prepare this context for refreshing. 4 prepareRefresh(); 5 6 // Tell the subclass to refresh the internal bean factory. 7 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 8 9 // Prepare the bean factory for use in this context. 10 prepareBeanFactory(beanFactory); 11 12 try { 13 // Allows post-processing of the bean factory in context subclasses. 14 postProcessBeanFactory(beanFactory); 15 16 // Invoke factory processors registered as beans in the context. 17 invokeBeanFactoryPostProcessors(beanFactory); 18 19 // Register bean processors that intercept bean creation. 20 registerBeanPostProcessors(beanFactory); 21 22 // Initialize message source for this context. 23 initMessageSource(); 24 25 // Initialize event multicaster for this context. 26 initApplicationEventMulticaster(); 27 28 // Initialize other special beans in specific context subclasses. 29 onRefresh(); 30 31 // Check for listener beans and register them. 32 registerListeners(); 33 34 // Instantiate all remaining (non-lazy-init) singletons. 35 finishBeanFactoryInitialization(beanFactory); 36 37 // Last step: publish corresponding event. 38 finishRefresh(); 39 } 40 41 catch (BeansException ex) { 42 // Destroy already created singletons to avoid dangling resources. 43 destroyBeans(); 44 45 // Reset 'active' flag. 46 cancelRefresh(ex); 47 48 // Propagate exception to caller. 49 throw ex; 50 } 51 } 52 }
每一個子方法的功能以後一點一點再分析,首先refresh()方法有幾點是值得咱們學習的:
一、方法是加鎖的,這麼作的緣由是避免多線程同時刷新Spring上下文
二、儘管加鎖能夠看到是針對整個方法體的,可是沒有在方法前加synchronized關鍵字,而使用了對象鎖startUpShutdownMonitor,這樣作有兩個好處:
(1)refresh()方法和close()方法都使用了startUpShutdownMonitor對象鎖加鎖,這就保證了在調用refresh()方法的時候沒法調用close()方法,反之亦然,避免了衝突
(2)另一個好處不在這個方法中體現,可是提一下,使用對象鎖能夠減少了同步的範圍,只對不能併發的代碼塊進行加鎖,提升了總體代碼運行的效率
三、方法裏面使用了每一個子方法定義了整個refresh()方法的流程,使得整個方法流程清晰易懂。這點是很是值得學習的,一個方法裏面幾十行甚至上百行代碼寫在一塊兒,在我看來會有三個顯著的問題:
(1)擴展性下降。反過來說,假使把流程定義爲方法,子類能夠繼承父類,能夠根據須要重寫方法
(2)代碼可讀性差。很簡單的道理,看代碼的人是願意看一段500行的代碼,仍是願意看10段50行的代碼?
(3)代碼可維護性差。這點和上面的相似但又有不一樣,可維護性差的意思是,一段幾百行的代碼,功能點不明確,不易後人修改,可能會致使「牽一髮而動全身」
prepareRefresh方法
下面挨個看refresh方法中的子方法,首先是prepareRefresh方法,看一下源碼:
1 /** 2 * Prepare this context for refreshing, setting its startup date and 3 * active flag. 4 */ 5 protected void prepareRefresh() { 6 this.startupDate = System.currentTimeMillis(); 7 synchronized (this.activeMonitor) { 8 this.active = true; 9 } 10 11 if (logger.isInfoEnabled()) { 12 logger.info("Refreshing " + this); 13 } 14 }
這個方法功能比較簡單,顧名思義,準備刷新Spring上下文,其功能註釋上寫了:
一、設置一下刷新Spring上下文的開始時間
二、將active標識位設置爲true
另外能夠注意一下12行這句日誌,這句日誌打印了真正加載Spring上下文的Java類。
obtainFreshBeanFactory方法
obtainFreshBeanFactory方法的做用是獲取刷新Spring上下文的Bean工廠,其代碼實現爲:
1 protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { 2 refreshBeanFactory(); 3 ConfigurableListableBeanFactory beanFactory = getBeanFactory(); 4 if (logger.isDebugEnabled()) { 5 logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); 6 } 7 return beanFactory; 8 }
其核心是第二行的refreshBeanFactory方法,這是一個抽象方法,有AbstractRefreshableApplicationContext和GenericApplicationContext這兩個子類實現了這個方法,看一下上面ClassPathXmlApplicationContext的繼承關係圖即知,調用的應當是AbstractRefreshableApplicationContext中實現的refreshBeanFactory,其源碼爲:
1 protected final void refreshBeanFactory() throws BeansException { 2 if (hasBeanFactory()) { 3 destroyBeans(); 4 closeBeanFactory(); 5 } 6 try { 7 DefaultListableBeanFactory beanFactory = createBeanFactory(); 8 beanFactory.setSerializationId(getId()); 9 customizeBeanFactory(beanFactory); 10 loadBeanDefinitions(beanFactory); 11 synchronized (this.beanFactoryMonitor) { 12 this.beanFactory = beanFactory; 13 } 14 } 15 catch (IOException ex) { 16 throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); 17 } 18 }
這段代碼的核心是第7行,這行點出了DefaultListableBeanFactory這個類,這個類是構造Bean的核心類,這個類的功能會在下一篇文章中詳細解讀,首先給出DefaultListableBeanFactory的繼承關係圖:
AbstractAutowireCapableBeanFactory這個類的繼承層次比較深,版面有限,就沒有繼續畫下去了,本圖基本上清楚地展現了DefaultListableBeanFactory的層次結構。
爲了更清晰地說明DefaultListableBeanFactory的做用,列舉一下DefaultListableBeanFactory中存儲的一些重要對象及對象中的內容,DefaultListableBeanFactory基本就是操做這些對象,以表格形式說明:
對象名 | 類 型 | 做 用 | 歸屬類 |
aliasMap | Map<String, String> | 存儲Bean名稱->Bean別名映射關係 | SimpleAliasRegistry |
singletonObjects | Map<String, Object> | 存儲單例Bean名稱->單例Bean實現映射關係 | DefaultSingletonBeanRegistry |
singletonFactories | Map<String, ObjectFactory> | 存儲Bean名稱->ObjectFactory實現映射關係 | DefaultSingletonBeanRegistry |
earlySingletonObjects | Map<String, Object> | 存儲Bean名稱->預加載Bean實現映射關係 | DefaultSingletonBeanRegistry |
registeredSingletons | Set<String> | 存儲註冊過的Bean名 | DefaultSingletonBeanRegistry |
singletonsCurrentlyInCreation | Set<String> | 存儲當前正在建立的Bean名 | DefaultSingletonBeanRegistry |
disposableBeans | Map<String, Object> | 存儲Bean名稱->Disposable接口實現Bean實現映射關係 |
DefaultSingletonBeanRegistry |
factoryBeanObjectCache | Map<String, Object> | 存儲Bean名稱->FactoryBean接口Bean實現映射關係 | FactoryBeanRegistrySupport |
propertyEditorRegistrars | Set<PropertyEditorRegistrar> | 存儲PropertyEditorRegistrar接口實現集合 | AbstractBeanFactory |
embeddedValueResolvers | List<StringValueResolver> | 存儲StringValueResolver(字符串解析器)接口實現列表 | AbstractBeanFactory |
beanPostProcessors | List<BeanPostProcessor> | 存儲 BeanPostProcessor接口實現列表 | AbstractBeanFactory |
mergedBeanDefinitions | Map<String, RootBeanDefinition> | 存儲Bean名稱->合併過的根Bean定義映射關係 | AbstractBeanFactory |
alreadyCreated | Set<String> | 存儲至少被建立過一次的Bean名集合 | AbstractBeanFactory |
ignoredDependencyInterfaces | Set<Class> | 存儲不自動裝配的接口Class對象集合 | AbstractAutowireCapableBeanFactory |
resolvableDependencies | Map<Class, Object> | 存儲修正過的依賴映射關係 | DefaultListableBeanFactory |
beanDefinitionMap | Map<String, BeanDefinition> | 存儲Bean名稱-->Bean定義映射關係 | DefaultListableBeanFactory |
beanDefinitionNames | List<String> | 存儲Bean定義名稱列表 | DefaultListableBeanFactory |