日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

Spring源码阅读笔记06:bean加载之如何获取单例

發布時間:2023/12/13 综合教程 31 生活家
生活随笔 收集整理的這篇文章主要介紹了 Spring源码阅读笔记06:bean加载之如何获取单例 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  前面的文章中主要分析Spring是如何加載配置文件以及將其轉化成BeanDefinition的,從本文開始,我們繼續研究Spring是如何創建bean的。bean加載的功能實現遠比bean的解析要復雜得多,會占用多篇文章的篇幅來進行分析,按照流程大致可以分為獲取緩存bean、準備創建bean、創建bean這幾個部分,本文會在瀏覽整個bean獲取過程的基礎上分析一下獲取緩存單例的邏輯,更復雜的bean創建的邏輯留待后面文章分析。

1. bean獲取過程概覽

  對于加載bean的功能,在Spring中的調用方式為:

TestBean myTestBean = (TestBean) xmlBeanFactory.getBean("testBean");

  這句代碼背后是怎樣實現的呢?我們可以先快速體驗一下Spring中代碼是如何實現的,這部分的代碼是實現在AbstractBeanFactory中:

  1 public Object getBean(String name) throws BeansException {
  2     return doGetBean(name, null, null, false);
  3 }
  4 
  5 protected <T> T doGetBean(
  6             final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
  7             throws BeansException {
  8     // 獲取對應的beanName
  9     final String beanName = transformedBeanName(name);
 10     Object bean;
 11     /* 檢查緩存中或者實例工廠中是否有對應的實例
 12      * 為什么首先會使用這段代碼呢,
 13      * 因為在創建單例bean的時候會存在依賴注入的情況,而在創建依賴的時候為了避免循環依賴,
 14      * Spring創建bean的原則是不等bean創建完成就會將創建bean的ObjectFact提早曝光
 15      * 也就是將objectFactory加入到緩存中,
 16      * 一旦下個bean創建時候需要依賴上個bean則直接使用objectFactory
 17      **/
 18     // Eagerly check singleton cache for manually registered singletons.
 19     // 直接嘗試從緩存獲取或者singletonFactories中的ObjectFactory中獲取
 20     Object sharedInstance = getSingleton(beanName);
 21     if (sharedInstance != null && args == null) {
 22         if (logger.isDebugEnabled()) {
 23             if (isSingletonCurrentlyInCreation(beanName)) {
 24                 logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
 25                         "' that is not fully initialized yet - a consequence of a circular reference");
 26             }
 27             else {
 28                 logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
 29             }
 30         }
 31         // 返回對應的實例,有時候存在諸如BeanFactory的情況并不是直接返回實例本身,而是返回指定方法返回的實例
 32         bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
 33     }
 34 
 35     else {
 36         // 只有在單例情況才會嘗試解決循環依賴,原型模式情況下,如果存在
 37         // A中有B的屬性,B中有A的屬性,那么當依賴注入的時候,就會產生當A還未創建完的時候由于
 38         // 對于B的創建而再次返回創建A,造循環依賴,也就是下面的情況
 39         // Fail if we're already creating this bean instance:
 40         // We're assumably within a circular reference.
 41         if (isPrototypeCurrentlyInCreation(beanName)) {
 42             throw new BeanCurrentlyInCreationException(beanName);
 43         }
 44 
 45         // Check if bean definition exists in this factory.
 46         BeanFactory parentBeanFactory = getParentBeanFactory();
 47         // 如果beanDefinitionMap中也就是在所有已經加載的類中不包括beanName則嘗試從parentBeanFactory中檢測
 48         if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 49             // Not found -> check parent.
 50             String nameToLookup = originalBeanName(name);
 51             // 遞歸到BeanFactory中尋找
 52             if (args != null) {
 53                 // Delegation to parent with explicit args.
 54                 return (T) parentBeanFactory.getBean(nameToLookup, args);
 55             }
 56             else {
 57                 // No args -> delegate to standard getBean method.
 58                 return parentBeanFactory.getBean(nameToLookup, requiredType);
 59             }
 60         }
 61         // 如果不是僅僅做類型檢查則是創建bean,這里要進行記錄
 62         if (!typeCheckOnly) {
 63             markBeanAsCreated(beanName);
 64         }
 65 
 66         try {
 67             // 將存儲XML配置文件的GernericBeanDefinition轉換為RootBeanDefinition,如果指定BeanName是子Bean的話同時會合并父類的相關屬性
 68             final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 69             checkMergedBeanDefinition(mbd, beanName, args);
 70 
 71             // Guarantee initialization of beans that the current bean depends on.
 72             // 確保當前bean依賴的bean已經實例化了,通過遞歸來實現
 73             String[] dependsOn = mbd.getDependsOn();
 74             if (dependsOn != null) {
 75                 for (String dependsOnBean : dependsOn) {
 76                     getBean(dependsOnBean);
 77                     // 緩存依賴調用
 78                     registerDependentBean(dependsOnBean, beanName);
 79                 }
 80             }
 81             // 實例化依賴的bean后便可以實例化mbd本身了
 82             // singleton模式的創建
 83             // Create bean instance.
 84             if (mbd.isSingleton()) {
 85                 sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
 86                     public Object getObject() throws BeansException {
 87                         try {
 88                             return createBean(beanName, mbd, args);
 89                         }
 90                         catch (BeansException ex) {
 91                             // Explicitly remove instance from singleton cache: It might have been put there
 92                             // eagerly by the creation process, to allow for circular reference resolution.
 93                             // Also remove any beans that received a temporary reference to the bean.
 94                             destroySingleton(beanName);
 95                             throw ex;
 96                         }
 97                     }
 98                 });
 99                 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
100             }
101             else if (mbd.isPrototype()) {
102                 // It's a prototype -> create a new instance.
103                 Object prototypeInstance = null;
104                 try {
105                     beforePrototypeCreation(beanName);
106                     prototypeInstance = createBean(beanName, mbd, args);
107                 }
108                 finally {
109                     afterPrototypeCreation(beanName);
110                 }
111                 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
112             }
113 
114             else {
115                 String scopeName = mbd.getScope();
116                 final Scope scope = this.scopes.get(scopeName);
117                 if (scope == null) {
118                     throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
119                 }
120                 try {
121                     Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
122                         public Object getObject() throws BeansException {
123                             beforePrototypeCreation(beanName);
124                             try {
125                                 return createBean(beanName, mbd, args);
126                             }
127                             finally {
128                                 afterPrototypeCreation(beanName);
129                             }
130                         }
131                     });
132                     bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
133                 }
134                 catch (IllegalStateException ex) {
135                     throw new BeanCreationException(beanName,
136                             "Scope '" + scopeName + "' is not active for the current thread; " +
137                             "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
138                             ex);
139                 }
140             }
141         }
142         catch (BeansException ex) {
143             cleanupAfterBeanCreationFailure(beanName);
144             throw ex;
145         }
146     }
147 
148     // Check if required type matches the type of the actual bean instance.
149     if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
150         try {
151             return getTypeConverter().convertIfNecessary(bean, requiredType);
152         }
153         catch (TypeMismatchException ex) {
154             if (logger.isDebugEnabled()) {
155                 logger.debug("Failed to convert bean '" + name + "' to required type [" +
156                         ClassUtils.getQualifiedName(requiredType) + "]", ex);
157             }
158             throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
159         }
160     }
161     return (T) bean;
162 }

  其實我想說我第一次看到這里,內心是崩潰的,這個方法的代碼量。。。bean的加載經歷了一個相當復雜的過程,其中涉及到各種各樣的考慮,我也只是初略地了解一下Spring加載bean的過程,這里先總結一下所涉及的步驟吧:

轉換對應beanName。

  這部分對應上面第9行,這里為什么要先轉換呢?因為這里傳入的參數可能是別名,也可能是FactoryBean(關于這個后面會專門總結),所以需要進行專門的解析,解析操作如下:

去除FactoryBean的修飾符,也就是如果name="&aa",那么會首先去除&而使name="aa";
取指定alias所表示的最終beanName,例如別名A指向名稱為B的beanvxxx則返回B;若別名A指向別名B,別名B又指向名稱為C的bean則返回C;

嘗試從緩存中加載單例。

  這部分對應上面第20行代碼。我們知道,Spring對bean創建定義了多種作用域:

singleton,單例模式;
prototype,多例模式;
request,表示針對每一次HTTP請求都會產生一個新的bean,同時該bean僅在當前HTTP request內有效;
session,表示針對每一次HTTP請求都會產生一個新的bean,同時該bean僅在當前HTTP session內有效;

  其中單例在一個Spring容器內只會被創建一次,后續再獲取bean,就直接從單例緩存中獲取了。這里也只是嘗試加載,首先嘗試從緩存中加載,如果加載不成功則再次嘗試從singletonFactories中加載。因為在創建單例bean的時候會存在依賴注入的情況,而在創建依賴的時候為了避免循環依賴,在Spring中創建bean的原則是不等bean創建完成就會將創建bean的ObjectFactory提早曝光加入到緩存中,一旦下一個bean創建時候需要依賴上一個bean則直接使用ObjectFactory(后面會對循環依賴進行重點分析)。

bean的實例化。

  這部分對應上面第32行代碼。如果從緩存中得到了bean的原始狀態,則需要對bean進行實例化。為什么緩存中記錄的只是最原始的bean狀態,而并不一定是我們最終想要的bean呢?這是因為如果我們需要對工廠bean進行處理,那么這里得到的其實是工廠bean的初始狀態,但是我們真正需要的是工廠bean中定義的factory-method方法中返回的bean,而getObjectForBeanInstance()方法就是完成這個工作的,這個后續也會詳細講解的,這里不清楚的可以先跳過去。

原型模式(即prototype)的依賴檢查。

  這部分對應上面第41行代碼。理解這一步的關鍵在于只有在單例情況下才會嘗試解決循環依賴,如果存在A中有B的屬性,B中有A的屬性,那么當依賴注入的時候,就會產生當A還未創建完的時候因為對于B的創建再次返回創建A,造成循環依賴,也就是情況:isPrototypeCurrentlyInCreation(beanName)判斷為true。

檢測parentBeanFactory。

  從代碼上看這部分對應上面第46行到58行,如果緩存沒有數據的話就直接轉到父類工廠上去加載了,但是這里也別忽略其判斷條件:parentBeanFactory != null && !containsBeanDefinition(beanName)。

其中parentBeanFactory != null即parentBeanFactory如果為空,則其他一切都是浮云,也不會轉到父類工廠去加載;
而!containsBeanDefinition(beanName),則是檢測當前加載的XML配置文件是否包含beanName所對應的配置,如果沒有就到parentBeanFactory去嘗試下加載,然后再去遞歸的調用getBean()方法;

將存儲XML配置文件的GernericBeanDefinition轉換為RootBeanDefinition。

  這部分對應上面的68行。在上文中有分析到,從XML配置文件中讀取到的Bean信息是存儲在GernericBeanDefinition中的,但是所有Bean的后續處理都是針對RootBeanDefinition進行的,所以這里需要進行一個轉換,轉換的同時如果父類bean不為空的話,也會一并合并父類的屬性。

加載依賴。

  這部分對應上面的73到78行。因為bean的初始化過程中很可能會用到某些屬性,而某些屬性很可能是動態配置的,并且配置成依賴于其他的bean,那么這個時候就有必要先加載依賴的bean,所以,在Spring的加載順序中,在初始化某一個bean的時候首先會初始化這個bean所對應的所有依賴對象。

針對不同的scope進行bean的創建。

  這部分對應上面的84到138行。我們都知道,在Spring中存在著不同的scope,其中默認的是singleton,但是還有些其他的配置諸如prototype、request之類的。在這個步驟中,Spring會根據不同的配置進行不同的初始化策略,這部分的過程很復雜,我們放到后面的文章中專門來解析這部分。

類型轉換。

  這部分對應上面的149到161行。bean的加載到這一步已經基本結束了,通常對加載bean的實際執行方法doGetBean()進行調用時傳入的參數requiredType是為空,但是還是可能會存在這樣的情況,即返回的bean其實是個String,但是requiredType卻傳入Integer類型,那么這時候本步驟就會起作用了,它的功能是將返回的bean轉換為requiredType所指定的類型。當然,String轉換為Integer是最簡單的一種轉換,在Spring中提供了各種各樣的轉換器,用戶也可以自己擴展轉換器來滿足需求。

  經過上面的步驟后bean的加載就結束了,這個時候就可以返回我們所需要的bean了。其中最重要的就是步驟8,針對不同的scope進行bean的創建,這個后面會專門寫一篇文章對這部分進行解析,接下來先來看一下除此之外的一些主要功能實現吧。

2. 嘗試從緩存加載單例

  前面提到過,單例在同一個Spring容器內只會被創建一次,所以每次獲取bean時都會先嘗試從緩存獲取,未獲取到則會嘗試從頭加載bean。

  這里的步驟是先從緩存singletonObjects獲取,沒有則再次嘗試從singletonFactories中獲取。因為在創建單例bean的時候會存在依賴注入的情況,而在創建依賴bean的時候為了避免循環依賴,Spring創建bean的原則是不等bean創建完成就會將創建bean的ObjectFactory提早曝光加入到緩存中,一旦下一個bean創建時需要依賴上個bean,則直接使用ObjectFactory。

public Object getSingleton(String beanName) {
    // 參數true設置允許早期依賴
    return getSingleton(beanName, true);
}

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 檢查緩存中是否存在實例
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // 如果為空,則鎖定全局變量并進行處理
        synchronized (this.singletonObjects) {
            // 如果此bean正在加載則不處理
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                // 當某些方法需要提前初始化的時候則會調用addSingletonFactory方法將對應的ObjectFactory初始化策略存儲在singletonFactories
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // 調用預先設定的getObject方法
                    singletonObject = singletonFactory.getObject();
                    // 記錄在緩存中,earlySingletonObjects和singletonFactories互斥
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

  這里首先嘗試從singletonObjects里面獲取實例,如果獲取不到再從earlySingletonObjects里面獲取,如果還獲取不到,再嘗試從singletonFactories里面獲取beanName對應的ObjectFactory,然后調用這個ObjectFactory的getObject()來創建bean,并放到earlySingletonObjects里面去,并且從singletonFacotories里面remove掉這個ObjectFactory,而對于后續的所有內存操作都只是為了循環依賴檢測時使用,也就是在allowEarlyReference為true的情況下才會使用。

  這里涉及用于存儲bean的不同的map,簡單解釋如下:

singletonObjects:用于保存BeanName和bean實例之間的關系,bean name-->bean instance;
singletonFactories:用于保存BeanName和創建bean的工廠之間的關系,bean name-->ObjectFactory;
earlySingletonObjects:也是保存BeanName和bean實例之間的關系,與singletonObjects的不同之處在于,當一個單例bean被放到這里面后,那么當bean還在創建過程中,就可以通過getBean方法獲取到了,其目的是用來檢測循環引用;
registeredSingletons:用來保存當前所有已注冊的bean;

  這里從緩存獲取到object,并不一定是我們最終想要的bean,比如這個bean的類型是FactoryBean,這其實是bean的初始狀態,我們真正需要的是工廠bean中定義的factory-method方法中返回的bean,而getobjectForBeanInstance方法就是完成這個工作的。關于工廠bean,這里再說幾句。

2.1 FactoryBean

  一般情況下,Spring通過反射機制利用beanDefinition的class屬性指定的實現類來實例化bean。如果按照傳統的方式,如果一個bean有很多屬性,則需要在<bean>中提供大量的配置信息,配置方式的靈活性是受限的,這時采用編碼的方式可能會得到一個更簡單的方案。Spring為此提供了一個org.Springframework.bean.factory.FactoryBean的工廠類接口,用戶可以通過實現該接口定制實例化bean的邏輯。
  FactoryBean接口對于Spring框架來說占有重要地位,其自身就提供了許多FactoryBean的實現,它們隱藏了實例化一些復雜bean的細節,給上層應用帶來了便利。該接口中定義了3個方法:

T getObject():返回由FactoryBean創建的bean實例,如果isSingleton()返回true,則該實例會放到Spring容器中單例實例緩存池中;
boolean isSingleton():返回由FactoryBean創建的bean實例的作用域是singleton還是prototype;
Class<T> getObjectType():返回FactoryBean創建的bean類型;

  當配置文件中<bean>的class屬性配置的實現類實現了FactoryBean接口時,通過getBean()方法返回的并不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的對象,相當于FactoryBean#getObject()代理了getBean()方法。例如:如果使用傳統方式配置下面Car的<bean>時,Car的每個屬性分別對應一個<property>元素標簽。

public class Car{
    private int masSpeed;
    private String brand;
    private double price;

    // get/set 方法    
}

  如果用FactoryBean的方式實現就會靈活一些,可以通過逗號分隔符的方式一次性配置所有屬性:

public class CarFactoryBean implements FactoryBean<Car> {
    private String carInfo;
    
    public car getObject() throws Exception {
        Car car = new Car();
        String[] infos = carInfo.split(",");
        car.setBrand(infos[0]);
        car.setMaxSpeed(Integer.valueOf(infos[1]));
        car.setPrice(Double.valueOf(infos[2]));
        return car;
    }

    public Class<Car> getObectType() {
        return Car.class;
    }

    public boolean inSingleton() {
        return false;
    }

    public String getCarInfo() {
        return this.carInfo;
    }

    // 接收逗號分隔符設置屬性信息
    public void setCarInfo(String carInfo) {
        this.carInfo = carInfo;
    }
}

  有了這個CarFactoryBean后,就可以在配置文件中使用下面這種自定義的配置方式進行配置了:

<bean id = "car" class = "xxx" carInfo = "保時捷,400,20000"/>

  當調用getBean("car")時,Spring通過反射機制發現CarFactoryBean實現了FactoryBean的接口,這時Spring容器就調用接口方法CarFactoryBean#getObject()返回Car的實例bean。如果希望獲取CarFactoryBean的實例,則需要在使用getBean(beanName)方法時在beanName前面顯示的加上"&"前綴,比如getBean("&car")。

3. FactoryBean的實例化

  在getBean方法中,getObjectForBeanInstance()是個高頻率使用的方法,無論是從緩存中獲得bean還是根據不同的scope策略加載bean。總之,我們得到bean的實例后要做的第一步就是調用這個方法來檢測一下正確性,其實就是用于檢測當前bean是否是FactoryBean類型的bean,如果是,那么需要調用該bean對應的FactoryBean實例中的getobject()方法。

protected Object getObjectForBeanInstance(
            Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {

    // Don't let calling code try to dereference the factory if the bean isn't a factory.
    // 如果指定的name是工廠相關(以&為前綴)且beanInstance又不是FactoryBean類型則驗證不通過
    if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
        throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
    }

    // Now we have the bean instance, which may be a normal bean or a FactoryBean.
    // If it's a FactoryBean, we use it to create a bean instance, unless the
    // caller actually wants a reference to the factory.
    // 現在我們有了個bean的實例,這個實例可能會是正常的bean或者是FactoryBean
    // 如果是FactoryBean我們將使用它創建實例,但是如果用戶想要直接獲取工廠實例而不是工廠的getObject方法對應的實例那么傳入的name應該加入前綴&
    if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
        return beanInstance;
    }
    // 加載FactoryBean
    Object object = null;
    if (mbd == null) {
        // 嘗試從緩存中加載bean
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        // Return bean instance from factory.
        // 到這里已經明確知道beanInstance一定是FactoryBean類型
        FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
        // containBeanDefinition檢測beanDefinitionMap中也就是在所有已經加載的類中檢測是否定義beanName
        // Caches object obtained from FactoryBean if it is a singleton.
        if (mbd == null && containsBeanDefinition(beanName)) {
            //將存儲XML配置文件的GernericBeanDefinition轉換為RootBeanDefinition,如果指定BeanName是子Bean的話同時會合并父類的相關屬性
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        // 是否是用戶定義的而不是應用程序本身定義的
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    }
    return object;
}

  這部分并沒有實質性的工作,主要是對傳入的bean判斷是否是FactoryBean,不是則直接返回,是則將解析bean的工作委托給getObjectFromFactoryBean()。

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    // 如果是單例模式
    if (factory.isSingleton() && containsSingleton(beanName)) {
        synchronized (getSingletonMutex()) {
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                object = doGetObjectFromFactoryBean(factory, beanName);
                // Only post-process and store if not put there already during getObject() call above
                // (e.g. because of circular reference processing triggered by custom getBean calls)
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
                    object = alreadyThere;
                }
                else {
                    if (object != null && shouldPostProcess) {
                        try {
                            // 調用objectFactory的后處理器
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        }
                        catch (Throwable ex) {
                            throw new BeanCreationException(beanName,
                                    "Post-processing of FactoryBean's singleton object failed", ex);
                        }
                    }
                    this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
                }
            }
            return (object != NULL_OBJECT ? object : null);
        }
    }
    else {
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        if (object != null && shouldPostProcess) {
            try {
                // 調用objectFactory的后處理器
                object = postProcessObjectFromFactoryBean(object, beanName);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        return object;
    }
}

  如上代碼中,如果返回的bean是單例的,那就必須要保證全局唯一,同時,也因為是單例的,所以不必重復創建,可以使用緩存來提高性能,也就是說已經加載過就要記錄下來以便于下次復用,否則的話就直接獲取了。

  如果判斷返回的bean是單例,為了避免重復創建,使用了緩存(factoryBeanObjectCache)來提高性能,如果有則直接獲取。而且必須保證全局唯一,這里使用同步鎖,并且在調用doGetObjectFromFactoryBean()之后又一次從緩存嘗試獲取,如果有則使用已創建的,并且不會執行后處理器,即調用postProcessObjectFromFactoryBean()方法,這里面主要是調用注冊的BeanPostProcessor的postProcessAfterInitialization方法進行處理,我們在實際開發過程中可以針對此特性設計自己的業務邏輯。

  在上面的方法中還是沒有真正加載bean的操作,這部分委托給doGetObjectFromFactoryBean()來完成:

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
            throws BeanCreationException {

    Object object;
    try {
        if (System.getSecurityManager() != null) {
            // 需要權限驗證
            AccessControlContext acc = getAccessControlContext();
            try {
                object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
                    public Object run() throws Exception {
                            return factory.getObject();
                        }
                    }, acc);
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            // 直接調用getObject()方法
            object = factory.getObject();
        }
    }
    catch (FactoryBeanNotInitializedException ex) {
        throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    }

    // Do not accept a null value for a FactoryBean that's not fully
    // initialized yet: Many FactoryBeans just return null then.
    if (object == null && isSingletonCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(
                beanName, "FactoryBean which is currently in creation returned null from getObject");
    }
    return object;
}

  在doGetObjectFromFactoryBean()方法中我們終于看到了我們想要看到的方法,也就是object = factory.getObject(),是的,就是這句代碼,我們的歷程猶如剝洋蔥一樣,一層一層的直到最內部的代碼實現,雖然最終實現很簡單。

4. 總結

  本文在瀏覽了完整的bean獲取流程的基礎上,著重分析了從緩存中獲取bean,這只是整個bean獲取流程中的第一步,如果從緩存獲取bean未果,那么就要開始從頭創建一個bean了,而這個過程留待后文分析。

總結

以上是生活随笔為你收集整理的Spring源码阅读笔记06:bean加载之如何获取单例的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 成人夜色 | 麻豆av网| 欧美日韩精品一区二区在线播放 | 国产肥白大熟妇bbbb视频 | 国产午夜精品一区二区三区 | 免费看a毛片 | 开心黄色网 | 2024av视频 | 亚洲wwwwww | 国产肥熟 | 亚洲性xx | 欧美一区二区三区视频 | 给我看高清的视频在线观看 | av福利影院 | 亚洲第一色网 | 香蕉av一区 | 久久久久亚洲av无码专区 | 天堂在线观看中文字幕 | 伊人久久久久久久久久 | 差差差30分钟 | 亚洲精品久久久久久久久久久久久 | 亚洲熟妇av日韩熟妇在线 | 亚洲欧美在线综合 | 亚洲一级在线播放 | 国产网站91 | 欧美日韩中文 | av 一区二区三区 | 激情午夜影院 | av激情久久 | 国产色网站 | 黄色的网站免费观看 | 欧美性xxxx图片 | 久久先锋 | 91丨porny丨九色 | 国产福利片在线 | 中文字幕亚洲不卡 | 欧美人与动物xxxxx | 四虎影视免费 | 少妇粉嫩小泬喷水视频www | 欧美性三级 | 办公室摸腿吻胸激情视频 | 欧美性视频在线播放 | 波多野在线 | 国产一区二区三区18 | 日韩欧美在线视频免费观看 | 美女一二区 | 亚洲天堂精品在线观看 | 久久成人乱码欧美精品一区二区 | 国产性猛交╳xxx乱大交一区 | 天天看夜夜爽 | 久久草av| 四虎影院成人 | 亚洲人成人无码网www国产 | 在线观看视频中文字幕 | 韩国美女福利视频 | 欧美激情国产日韩精品一区18 | 男女午夜激情视频 | 伊人久久九 | 国产无人区码熟妇毛片多 | 成人片在线免费看 | 欧美一级鲁丝片 | 国产伦一区二区 | 人人狠狠综合久久亚洲 | 青青免费在线视频 | 激情视频在线免费观看 | 都市激情校园春色亚洲 | 久久爱影视i | 91精品综合久久久久久五月天 | 色妹av | 午夜免费福利在线 | 亚洲av无一区二区三区怡春院 | 50一60岁老妇女毛片 | 亚洲国产剧情 | 午夜欧美精品久久久久久久 | av中文字幕免费观看 | 亚洲天堂男人网 | 波多野一区二区 | 日本三级黄在线观看 | 图书馆的女友在线观看 | 亚洲AV无码国产成人久久 | 中国免费黄色 | 国内视频一区二区 | 欧美天天搞 | 老太太av | 91视频免费在线观看 | 日本做爰全过程免费看 | 亚洲无码久久久久 | 99热手机在线观看 | mm131丰满少妇人体欣赏图 | 波多野结衣福利视频 | 国产中文字幕三区 | 天天尻逼 | www.欧美一区二区三区 | 久久精品www人人爽人人 | 日本一区二区久久 | 精品无码m3u8在线观看 | 欧美美女性生活视频 | 日本三级吃奶头添泬无码苍井空 | 国产又爽又黄又嫩又猛又粗 |