摘要:初始化我們知道容器初始化后會對容器中非懶加載的,單例的以及非抽象的定義進行的初始化操作,所以我們分析源碼的入口也就是在容器初始化的入口,分析容器初始化后在什么地方開始第一次的初始化。
前言
Spring IOC容器在初始化之后會對容器中非懶加載的,單例的以及非抽象的bean定義進行bean的初始化操作,同時會也涉及到Bean的后置處理器以及DI(依賴注入)等行為。對于Bean的初始化,Spring是通過第一次調用getBean方法向容器獲取bean實例時進行的。下面的源碼分析也是基于getBean()作為入口一步步去了解Spring是如何初始化單例Bean的。
Bean初始化我們知道Spring IOC容器初始化后會對容器中非懶加載的,單例的以及非抽象的bean定義進行bean的初始化操作,所以我們分析源碼的入口也就是在容器初始化的入口,分析容器初始化后Spring在什么地方開始第一次的Bean初始化。
在之前的一篇博文Spring專題之IOC源碼分析中有分析到Spring IOC容器初始化的過程,過程源碼如下:
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方法源碼如下:
//對配置了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); } ListbeanNames = 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 ) () -> ((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方法及相關調用源碼如下:
//獲取IOC容器中指定名稱的Bean public Object getBean(String name) throws BeansException { //doGetBean才是真正向IoC容器獲取被管理Bean的過程 return doGetBean(name, null, null, false); } //真正實現向IOC容器獲取Bean的功能,也是觸發依賴注入功能的地方 protectedT doGetBean(final String name, @Nullable final Class 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的。
至此,通過上述的源碼分析,我們對Spring在IOC初始化后對bean的初始化過程有了大致的了解,下篇博客會繼續這篇通過源碼分析Spring初始化的具體過程。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77002.html
摘要:前言這篇是專題初始化的第二篇,主要對初始化具體過程的源碼分析。上篇博客專題之初始化源碼分析中我們對如何開始初始化以及初始化的總體過程有了大致的了解,接下來就繼續上篇博客的結尾處開始來分析初始化的具體過程。 前言 這篇是Spring專題Bean初始化的第二篇,主要對bean初始化具體過程的源碼分析。上篇博客Spring專題之Bean初始化源碼分析(1)中我們對Spring如何開始初始化b...
摘要:前言以下源碼基于版本解析。實現源碼分析對于的實現,總結來說就是定位加載和注冊。定位就是需要定位配置文件的位置,加載就是將配置文件加載進內存注冊就是通過解析配置文件注冊。下面我們從其中的一種使用的方式一步一步的分析的實現源碼。 前言 以下源碼基于Spring 5.0.2版本解析。 什么是IOC容器? 容器,顧名思義可以用來容納一切事物。我們平常所說的Spring IOC容器就是一個可以容...
摘要:的在單例被破壞時由進行方法調用。定義并實現這兩個接口容器創建完成注解是的縮寫,意思是規范提案。在創建完成并且屬性賦值完成來執行初始化方法在容器銷毀之前回調通知支持自動裝配,類似。 Spring注解應用篇--IOC容器Bean生命周期 這是Spring注解專題系類文章,本系類文章適合Spring入門者或者原理入門者,小編會在本系類文章下進行企業級應用實戰講解以及spring源碼跟進。本文...
摘要:入門篇學習總結時間年月日星期三說明本文部分內容均來自慕課網。主要的功能是日志記錄,性能統計,安全控制,事務處理,異常處理等等。 《Spring入門篇》學習總結 時間:2017年1月18日星期三說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com教學示例源碼:https://github.com/zccodere/s...個人學習源碼:https://git...
閱讀 1557·2023-04-26 01:36
閱讀 2724·2021-10-08 10:05
閱讀 2780·2021-08-05 09:57
閱讀 1540·2019-08-30 15:52
閱讀 1196·2019-08-30 14:12
閱讀 1316·2019-08-30 11:17
閱讀 3101·2019-08-29 13:07
閱讀 2424·2019-08-29 12:35