Spring IOC容器在初始化以後會對容器中非懶加載的,單例的以及非抽象的bean定義進行bean的初始化操做,同時會也涉及到Bean的後置處理器以及DI(依賴注入)等行爲。對於Bean的初始化,Spring是經過第一次調用getBean方法向容器獲取bean實例時進行的。下面的源碼分析也是基於getBean()做爲入口一步步去了解Spring是如何初始化單例Bean的。segmentfault
咱們知道Spring IOC容器初始化後會對容器中非懶加載的,單例的以及非抽象的bean定義進行bean的初始化操做,因此咱們分析源碼的入口也就是在容器初始化的入口,分析容器初始化後Spring在什麼地方開始第一次的Bean初始化。緩存
在以前的一篇博文Spring專題之IOC源碼分析中有分析到Spring IOC容器初始化的過程,過程源碼以下:session
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. //調用容器準備刷新的方法,獲取容器的當時時間,同時給容器設置同步標識 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. //告訴子類啓動refreshBeanFactory()方法,Bean定義資源文件的載入從 //子類的refreshBeanFactory()方法啓動 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. //爲BeanFactory配置容器特性,例如類加載器、事件處理器等 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. //爲容器的某些子類指定特殊的BeanPost事件處理器 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. //調用全部註冊的BeanFactoryPostProcessor的Bean invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. //爲BeanFactory註冊BeanPost事件處理器. //BeanPostProcessor是Bean後置處理器,用於監聽容器觸發的事件 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. //初始化信息源,和國際化相關. initMessageSource(); // Initialize event multicaster for this context. //初始化容器事件傳播器. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. //調用子類的某些特殊Bean初始化方法 onRefresh(); // Check for listener beans and register them. //爲事件傳播器註冊事件監聽器. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. //初始化全部剩餘的單例Bean finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. //初始化容器的生命週期事件處理器,併發布容器的生命週期事件 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. //銷燬已建立的Bean destroyBeans(); // Reset 'active' flag. //取消refresh操做,重置容器的同步標識. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
上述源碼能夠觀察看在IOC容器被初始化後進行了不少其餘的操做,但這些如今咱們暫時不關心,咱們須要關注的只有finishBeanFactoryInitialization這個方法,這個方法的做用就是初始化全部剩餘的單例Bean,因此這也是咱們如下分析源碼的入口。併發
finishBeanFactoryInitialization方法源碼以下:app
//對配置了lazy-init屬性的Bean進行預實例化處init屬性的Bean進行預實例化處理理 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { .... // Instantiate all remaining (non-lazy-init) singletons. //對配置了lazy-init屬性的單態模式Bean進行預實例化處理 beanFactory.preInstantiateSingletons(); }
這個方法前面一些處理暫時不看,能夠知道最後調用了ConfigurableListableBeanFactory的preInstantiateSingletons方法,也就是對配置了lazy-init屬性的單態模式Bean進行預實例化處理。
下面進入preInstantiateSingletons方法分析,源碼以下:源碼分析
//對配置lazy-init屬性單態Bean的預實例化 public void preInstantiateSingletons() throws BeansException { if (this.logger.isDebugEnabled()) { this.logger.debug("Pre-instantiating singletons in " + this); } List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); for (String beanName : beanNames) { //獲取指定名稱的Bean定義 RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); //Bean不是抽象的,是單態模式的,且lazy-init屬性配置爲false if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { //若是指定名稱的bean是建立容器的Bean if (isFactoryBean(beanName)) { //FACTORY_BEAN_PREFIX=」&」,當Bean名稱前面加」&」符號 //時,獲取的是產生容器對象自己,而不是容器產生的Bean. //調用getBean方法,觸發容器對Bean實例化和依賴注入過程 final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); //標識是否須要預實例化 boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { //一個匿名內部類 isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> ((SmartFactoryBean<?>) factory).isEagerInit(), getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { //調用getBean方法,觸發容器對Bean實例化和依賴注入過程 getBean(beanName); } } else { //調用getBean方法,觸發容器對Bean實例化和依賴注入過程 getBean(beanName); } } } //觸發bean初始化後的回調 ... }
經過源碼解析,咱們能夠看到這裏對於不是抽象的,是單態模式的,且lazy-init屬性配置爲false的Bean定義進行初始化,而初始化過程正是調用了getBean方法。下面咱們進入getBean方法觀察Spring對bean的初始化過程。getBean方法及相關調用源碼以下:post
//獲取IOC容器中指定名稱的Bean public Object getBean(String name) throws BeansException { //doGetBean纔是真正向IoC容器獲取被管理Bean的過程 return doGetBean(name, null, null, false); } //真正實現向IOC容器獲取Bean的功能,也是觸發依賴注入功能的地方 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { //根據指定的名稱獲取被管理Bean的名稱,剝離指定名稱中對容器的相關依賴,若是指定的是別名,將別名轉換爲規範的Bean名稱 final String beanName = transformedBeanName(name); Object bean; //先從緩存中取是否已經有被建立過的單態類型的Bean,對於單例模式的Bean整個IOC容器中只建立一次,不須要重複建立 Object sharedInstance = getSingleton(beanName); //IOC容器建立單例模式Bean實例對象 if (sharedInstance != null && args == null) { if (logger.isDebugEnabled()) { //若是指定名稱的Bean在容器中已有單例模式的Bean被建立 //直接返回已經建立的Bean 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的實例對象,主要是完成FactoryBean的相關處理。注意:BeanFactory是管理容器中Bean的工廠,而FactoryBean是建立建立對象的工廠Bean,二者之間有區別 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { //緩存沒有正在建立的單例模式Bean,緩存中已經有已經建立的原型模式Bean,可是因爲循環引用的問題致使實例化對象失敗 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } //對IOC容器中是否存在指定名稱的BeanDefinition進行檢查,首先檢查是否能在當前的BeanFactory中獲取的所須要的Bean,若是不能則委託當前容器的父級容器去查找,若是仍是找不到則沿着容器的繼承體系向父級容器查找 BeanFactory parentBeanFactory = getParentBeanFactory(); //當前容器的父級容器存在,且當前容器中不存在指定名稱的Bean if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { //解析指定Bean名稱的原始名稱 String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { //委派父級容器根據指定名稱和顯式的參數查找 return (T) parentBeanFactory.getBean(nameToLookup, args); } else { //委派父級容器根據指定名稱和類型查找 return parentBeanFactory.getBean(nameToLookup, requiredType); } } //建立的Bean是否須要進行類型驗證,通常不須要 if (!typeCheckOnly) { //向容器標記指定的Bean已經被建立 markBeanAsCreated(beanName); } try { //根據指定Bean名稱獲取其父級的Bean定義 //主要解決Bean繼承時子類合併父類公共屬性問題 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); //獲取當前Bean全部依賴Bean的名稱 String[] dependsOn = mbd.getDependsOn(); //若是當前Bean有依賴Bean 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 + "'"); } //遞歸調用getBean方法,獲取當前Bean的依賴Bean registerDependentBean(dep, beanName); //把被依賴Bean註冊給當前依賴的Bean getBean(dep); } } //建立單例模式Bean的實例對象 if (mbd.isSingleton()) { //這裏使用了一個匿名內部類,建立Bean實例對象,而且註冊給所依賴的對象 sharedInstance = getSingleton(beanName, () -> { try { //建立一個指定Bean實例對象,若是有父級繼承,則合併子類和父類的定義 return createBean(beanName, mbd, args); } catch (BeansException ex) { //顯式地從容器單例模式Bean緩存中清除實例對象 destroySingleton(beanName); throw ex; } }); //獲取給定Bean的實例對象 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } //IOC容器建立原型模式Bean實例對象 else if (mbd.isPrototype()) { //原型模式(Prototype)是每次都會建立一個新的對象 Object prototypeInstance = null; try { //回調beforePrototypeCreation方法,默認的功能是註冊當前建立的原型對象 beforePrototypeCreation(beanName); //建立指定Bean對象實例 prototypeInstance = createBean(beanName, mbd, args); } finally { //回調afterPrototypeCreation方法,默認的功能告訴IOC容器指定Bean的原型對象再也不建立 afterPrototypeCreation(beanName); } //獲取給定Bean的實例對象 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } //要建立的Bean既不是單例模式,也不是原型模式,則根據Bean定義資源中配置的生命週期範圍,選擇實例化Bean的合適方法,這種在Web應用程序中,比較經常使用,如:request、session、application等生命週期 else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); //Bean定義資源中沒有配置生命週期範圍,則Bean定義不合法 if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { //這裏又使用了一個匿名內部類,獲取一個指定生命週期範圍的實例 Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); //獲取給定Bean的實例對象 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { ... } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } //對建立的Bean實例對象進行類型檢查 if (requiredType != null && !requiredType.isInstance(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return convertedBean; } catch (TypeMismatchException ex) { ... } } return (T) bean; }
這裏經過上述源碼的分析,總結如下Spring初始化bean的過程,首先Spring會去緩存中搜索是否已存在bean實例,若是存在則直接取出返回,不存在就判斷是否存在父容器,存在則調用父容器的getBean方法進行初始化,不然經過判斷bean定義是不是單例bean,是不是原型bena進行相關的初始化操做,能夠知道最後都是調用了createBean方法去建立bean的。ui
至此,經過上述的源碼分析,咱們對Spring在IOC初始化後對bean的初始化過程有了大體的瞭解,下篇博客會繼續這篇經過源碼分析Spring初始化的具體過程。this