您好,登錄后才能下訂單哦!
這篇文章主要講解了“Spring Ioc中各個scope的Bean是怎么創建的”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Spring Ioc中各個scope的Bean是怎么創建的”吧!
代碼:
// Create bean instance. //創建單例Bean if (mbd.isSingleton()) { //這里使用了一個匿名內部類,創建Bean實例對象,并且注冊給所依賴的對象 sharedInstance = getSingleton(beanName, () -> { try { //創建一個指定Bean實例對象,如果有父級繼承,則合并子類和父類的定義 return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. //顯式地從容器單例模式Bean緩存中清除實例對象 destroySingleton(beanName); throw ex; } }); //獲取給定Bean的實例對象 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
這里使用了匿名內部類,先通過createBean(beanName, mbd, args)
方法獲取一個 ObjectFactory
把 ObjectFactory 作為參數傳入 getSingleton(beanName,objectFactory)
方法
使用 getSingleton(beanName,objectFactory) 方法返回的 sharedInstance 作為參數傳入 getObjectForBeanInstance(sharedInstance, name, beanName, mbd)
來回去最終的Bean實例(詳情見Spring Ioc 之 Bean的加載(一))
createBean(beanName, mbd, args)
方法比較復雜,在之后的文章中會詳細分析,這里就先略過,直接看 getSingleton(beanName,objectFactory)
方法。
// DefaultSingletonBeanRegistry.java public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); //全局加鎖 synchronized (this.singletonObjects) { // 從緩存中獲取單例bean // 因為 singleton 模式其實就是復用已經創建的 bean 所以這步驟必須檢查 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { //是否正在銷毀該bean if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } // 加載前置處理 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 初始化 bean // 這個過程其實是調用 createBean() 方法 singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } //后置處理 afterSingletonCreation(beanName); } if (newSingleton) { //加入緩存中 addSingleton(beanName, singletonObject); } } return singletonObject; } }
在這段代碼中,其實主要是做了一些準備和預處理步驟,真正創建Bean是在singletonFactory.getObject()
方法實現的,而 singletonFactory 是由createBean()方法創建后回調的參數。
那么這段代碼主要做的事情是什么呢?
嘗試從緩存中獲取單例Bean
如果已經加載了則直接返回,否則開始加載過程
加載前置處理
獲取Bean實例
后置處理
加入緩存
beforeSingletonCreation(beanName)
是個標記方法,我們來看代碼:
// 用于添加標志,當前 bean 正處于創建中 protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { //添加失敗,拋出異常 throw new BeanCurrentlyInCreationException(beanName); } }
把 beanName 添加到 singletonsCurrentlyInCreation
map中,用來表示該單例bean正在創建,如果添加失敗,拋出異常。
通過createBean(beanName)
方法返回的 singletonFactory 獲取Bean。
afterSingletonCreation(beanName)
同樣是個表示方法:
// 用于移除標記,當前 Bean 不處于創建中 protected void afterSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { //移除失敗,拋出異常 throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); } }
創建Bean之后移除創建標示。
前置處理和后置處理的這個創建標示,會在調用isSingletonCurrentlyInCreation(String beanName)
時用到,該方法用來判斷當前bean是否已經在創建中。
直接看代碼:
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
一個 put、一個 add、兩個 remove 操作。
【put】singletonObjects 屬性,單例 bean 的緩存。
【remove】singletonFactories 屬性,單例 bean Factory 的緩存。
【remove】earlySingletonObjects 屬性,“早期”創建的單例 bean 的緩存。
【add】registeredSingletons 屬性,已經注冊的單例緩存。
代碼:
//創建多例Bean else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. //原型模式(Prototype)是每次都會創建一個新的對象 Object prototypeInstance = null; try { //加載前置處理,默認的功能是注冊當前創建的原型對象 beforePrototypeCreation(beanName); //創建指定Bean對象實例 prototypeInstance = createBean(beanName, mbd, args); } finally { //加載后置處理,默認的功能告訴IOC容器指定Bean的原型對象不再創建 afterPrototypeCreation(beanName); } //獲取給定Bean的實例對象 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); }
原型模式很簡單,直接創建一個新的實例就好了,不再從緩存中去獲取。
beforePrototypeCreation(beanName)
前置處理,將當前bean標記為正在創建的原型。
afterPrototypeCreation(beanName)
后置處理,取消當前bean的正在創建標示。
調用getObjectFrBeanInstance()
方法獲取最終bean。(詳情見Spring Ioc 之 Bean的加載(一))
//要創建的Bean既不是Singleton也不是Prototype //如: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) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } }
分為以下幾個步驟:
從Scope注解中獲取scope名稱
前置處理
createBean()
后置處理
scope.get()獲取bean
getObjectForBeanInstance()方法獲取Bean
核心流程與原型模式一樣,只不過這里調用了scope.get()來獲取bean。
Object get(String name, ObjectFactory<?> objectFactory);
scope.get()是一個接口,它有多種實現類:
我們看一下spring自帶的一個實現 SimpleThreadScope:
//SimpleThreadScope.java private final ThreadLocal<Map<String, Object>> threadScope = new NamedThreadLocal<Map<String, Object>>("SimpleThreadScope") { @Override protected Map<String, Object> initialValue() { return new HashMap<>(); } }; //獲取bean的實例 @Override public Object get(String name, ObjectFactory<?> objectFactory) { // 獲取 scope 緩存 Map<String, Object> scope = this.threadScope.get(); Object scopedObject = scope.get(name); if (scopedObject == null) { scopedObject = objectFactory.getObject(); // 加入緩存 scope.put(name, scopedObject); } return scopedObject; }
其他scope的實現就不一一去看了,感興趣的朋友可以自己看一下。
總結
上面的代碼中有2個重要方法:
createBean(beanName, mbd, args)
getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd)
這2個方法在3個代碼分支中都用到了,createBean
下篇文章會詳細分析,getObjectForBeanInstance
方法在Spring Ioc 之 Bean的加載(一)中已經分析過了。
這里再引用下《Spring 源碼深度解析》對該方法的分析:
這個方法主要是驗證以下我們得到的 bean 的正確性,其實就是檢測當前 bean 是否是 FactoryBean 類型的 bean 。
如果是,那么需要調用該 bean 對應的 FactoryBean 實例的 getObject() 方法,作為返回值。
無論是從緩存中獲得到的 bean 還是通過不同的 scope 策略加載的 bean 都只是最原始的 bean 狀態,并不一定就是我們最終想要的 bean。
舉個例子,假如我們需要對工廠 bean 進行處理,那么這里得到的其實是工廠 bean 的初始狀態,但是我們真正需要的是工廠 bean 中定義 factory-method 方法中返回的 bean,而 getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) 方法,就是完成這個工作的。
感謝各位的閱讀,以上就是“Spring Ioc中各個scope的Bean是怎么創建的”的內容了,經過本文的學習后,相信大家對Spring Ioc中各個scope的Bean是怎么創建的這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。