溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Spring獲取Bean的過程是怎樣的

發(fā)布時間:2021-12-21 15:52:56 來源:億速云 閱讀:107 作者:iii 欄目:編程語言

這篇文章主要講解了“Spring獲取Bean的過程是怎樣的”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Spring獲取Bean的過程是怎樣的”吧!

原型Bean加載過程

之前的文章,分析了非懶加載的單例Bean整個加載過程,除了非懶加載的單例Bean之外,Spring中還有一種Bean就是原型(Prototype)的Bean,看一下定義方式:

1 <?xml version="1.0" encoding="UTF-8"?>
2 
6 
7     
8     
9

原型Bean加載流程總得來說和單例Bean差不多,看一下不同之處,在AbstractBeanFactory的doGetBean的方法的這一步:

 1 else if (mbd.isPrototype()) { 2     // It's a prototype -> create a new instance.
 3     Object prototypeInstance = null;
 4     try { 5         beforePrototypeCreation(beanName);
 6         prototypeInstance = createBean(beanName, mbd, args); 7     }
 8     finally { 9 afterPrototypeCreation(beanName); 10 } 11     bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 12 }

第6行createBean是一樣的,原型Bean實(shí)例化的主要區(qū)別就在于第6行,它是直接創(chuàng)建bean的,而單例bean我們再對比一下:

 1 if (mbd.isSingleton()) { 2     sharedInstance = getSingleton(beanName, new ObjectFactory() { 3         public Object getObject() throws BeansException { 4             try { 5                 return createBean(beanName, mbd, args); 6             }
 7             catch (BeansException ex) { 8                 // Explicitly remove instance from singleton cache: It might have been put there 9                 // eagerly by the creation process, to allow for circular reference resolution. 10                 // Also remove any beans that received a temporary reference to the bean.
11 destroySingleton(beanName); 12                 throw ex; 13 } 14 } 15 }); 16     bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 17 }

它優(yōu)先會嘗試getSington,即先嘗試從singletonObjects中獲取一下bean是否存在,如果存在直接返回singletonObjects中的bean對象。

接著,我們看到原型bean創(chuàng)建和單例bean創(chuàng)建的區(qū)別還在于第5行和第9行,先看第5行的代碼:

 1 protected void beforePrototypeCreation(String beanName) { 2     Object curVal = this.prototypesCurrentlyInCreation.get();
 3     if (curVal == null) {
 4         this.prototypesCurrentlyInCreation.set(beanName);
 5     }
 6     else if (curVal instanceof String) { 7         Set beanNameSet = new HashSet(2);
 8         beanNameSet.add((String) curVal);
 9 beanNameSet.add(beanName); 10         this.prototypesCurrentlyInCreation.set(beanNameSet); 11 } 12     else { 13         Set beanNameSet = (Set) curVal; 14 beanNameSet.add(beanName); 15 } 16 }

這段主要是說bean在創(chuàng)建前要把當(dāng)前beanName設(shè)置到ThreadLocal中去,其目的是保證多線程不會同時創(chuàng)建同一個bean。接著看第9行的代碼實(shí)現(xiàn),即bean創(chuàng)建之后做了什么:

 1 protected void afterPrototypeCreation(String beanName) { 2     Object curVal = this.prototypesCurrentlyInCreation.get();
 3     if (curVal instanceof String) { 4         this.prototypesCurrentlyInCreation.remove();
 5     }
 6     else if (curVal instanceof Set) { 7         Set beanNameSet = (Set) curVal;
 8         beanNameSet.remove(beanName);
 9         if (beanNameSet.isEmpty()) { 10             this.prototypesCurrentlyInCreation.remove(); 11 } 12 } 13 }

很好理解,就是把當(dāng)前bean移除一下,這樣其它線程就可以創(chuàng)建bean了。第11行的代碼不看了,意思是如果bean是FactoryBean的實(shí)現(xiàn)類的話,調(diào)用getObject()方法獲取真正的對象。

byName源碼實(shí)現(xiàn)

Spring有為開發(fā)者提供Autowire(自動裝配)的功能,自動裝配最常用的就是byName和byType這兩種屬性。由于自動裝配是為了解決對象注入導(dǎo)致的過多的問題,因此很容易找到byName與byType的Spring源碼實(shí)現(xiàn)應(yīng)該在屬性注入這一塊,定位到屬性注入的代碼AbstractAutowireCapableBeanFactory的populateBean方法,直接截取重點(diǎn):

 1 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
 2         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { 3     MutablePropertyValues newPvs = new MutablePropertyValues(pvs); 4 
 5     // Add property values based on autowire by name if applicable.
 6     if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { 7         autowireByName(beanName, mbd, bw, newPvs);
 8     }
 9 
10     // Add property values based on autowire by type if applicable.
11     if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { 12 autowireByType(beanName, mbd, bw, newPvs); 13 } 14 
15     pvs = newPvs; 16 }

看到第6行第8行判斷是否byName形式,是就執(zhí)行byName自動裝配代碼;第11行第13行判斷是否byType形式,是就執(zhí)行byType自動裝配代碼。那么首先看一下第7行的byName代碼實(shí)現(xiàn):

 1 protected void autowireByName( 2         String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
 3 
 4     String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); 5     for (String propertyName : propertyNames) { 6         if (containsBean(propertyName)) { 7             Object bean = getBean(propertyName); 8             pvs.add(propertyName, bean);
 9 registerDependentBean(propertyName, beanName); 10             if (logger.isDebugEnabled()) { 11                 logger.debug("Added autowiring by name from bean name '" + beanName +
12                         "' via property '" + propertyName + "' to bean named '" + propertyName + "'"); 13 } 14 } 15         else { 16             if (logger.isTraceEnabled()) { 17                 logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
18                         "' by name: no matching bean found"); 19 } 20 } 21 } 22 }

篇幅問題,代碼不一層層跟了,邏輯梳理一下:

  • 第4行,找到Bean中不是簡單屬性的屬性,這句話有點(diǎn)繞,意思就是找到屬性是對象類型的屬性,但也不是所有的對象類型都會被找到,比如CharSequence類型、Number類型、Date類型、URL類型、URI類型、Locale類型、Class類型就會忽略,具體可見BeanUtils的isSimpleProperty方法

  • 第5行~第7行,遍歷所有被找到的屬性,如果bean定義中包含了屬性名,那么先實(shí)例化該屬性名對應(yīng)的bean

  • 第9行registerDependentBean,注冊一下當(dāng)前bean的依賴bean,用于在某個bean被銷毀前先將其依賴的bean銷毀

其余代碼都是一些打日志的,沒什么好說的。

byType源碼實(shí)現(xiàn)

上面說了byName的源碼實(shí)現(xiàn),接下來看一下byType源碼實(shí)現(xiàn):

 1 protected void autowireByType( 2         String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
 3 
 4     TypeConverter converter = getCustomTypeConverter(); 5     if (converter == null) {
 6         converter = bw; 7     }
 8 
 9     Set autowiredBeanNames = new LinkedHashSet(4); 10     String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); 11     for (String propertyName : propertyNames) { 12         try { 13             PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName); 14             // Don't try autowiring by type for type Object: never makes sense, 15             // even if it technically is a unsatisfied, non-simple property.
16             if (!Object.class.equals(pd.getPropertyType())) { 17                 MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd); 18                 // Do not allow eager init for type matching in case of a prioritized post-processor.
19                 boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass()); 20                 DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager); 21                 Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter); 22                 if (autowiredArgument != null) { 23 pvs.add(propertyName, autowiredArgument); 24 } 25                 for (String autowiredBeanName : autowiredBeanNames) { 26 registerDependentBean(autowiredBeanName, beanName); 27                     if (logger.isDebugEnabled()) { 28                         logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
29                                 propertyName + "' to bean named '" + autowiredBeanName + "'"); 30 } 31 } 32 autowiredBeanNames.clear(); 33 } 34 } 35         catch (BeansException ex) { 36             throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex); 37 } 38 } 39 }

前面一樣,到第10行都是找到Bean中屬性是對象類型的屬性。

接著就是遍歷一下PropertyName,獲取PropertyName對應(yīng)的屬性描述,注意一下16行的判斷及其對應(yīng)的注釋:不要嘗試自動裝配Object類型,這沒有任何意義,即使從技術(shù)角度看它是一個非簡單的對象屬性。

第18行~第20行跳過(沒有太明白是干什么的),byType實(shí)現(xiàn)的源碼主要在第21行的方法resolveDependency中,這個方法是AbstractAutowireCapableBeanFactory類的實(shí)現(xiàn)類DefaultListableBeanFactory中的方法:

 1 public Object resolveDependency(DependencyDescriptor descriptor, String beanName, 2     Set autowiredBeanNames, TypeConverter typeConverter) throws BeansException  { 3 
 4     descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
 5     if (descriptor.getDependencyType().equals(ObjectFactory.class)) {
 6         return new DependencyObjectFactory(descriptor, beanName); 7     }
 8     else if (descriptor.getDependencyType().equals(javaxInjectProviderClass)) { 9         return new DependencyProviderFactory().createDependencyProvider(descriptor, beanName); 10 } 11     else { 12         return doResolveDependency(descriptor, descriptor.getDependencyType(), beanName, autowiredBeanNames, typeConverter); 13 } 14 }

這里判斷一下要自動裝配的屬性是ObjectFactory.class還是javaxInjectProviderClass還是其他的,我們裝配的是其他的,看一下12行的代碼實(shí)現(xiàn):

 1 protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName, 2     Set autowiredBeanNames, TypeConverter typeConverter) throws BeansException  { 3 
 4     Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); 5     if (value != null) {
 6         if (value instanceof String) { 7             String strVal = resolveEmbeddedValue((String) value); 8             BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
 9             value = evaluateBeanDefinitionString(strVal, bd); 10 } 11         TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); 12         return converter.convertIfNecessary(value, type); 13 } 14 
15     if (type.isArray()) { 16 ... 17 } 18     else if (Collection.class.isAssignableFrom(type) && type.isInterface()) { 19 ... 20 } 21     else if (Map.class.isAssignableFrom(type) && type.isInterface()) { 22 ... 23 } 24     else { 25         Map

第四行結(jié)果是null不看了,為了簡化代碼Array裝配、Collection裝配、Map裝配的代碼都略去了,重點(diǎn)看一下普通屬性的裝配。首先是第25行獲取一下自動裝配的候選者:

 1 protected Map

代碼邏輯整理一下:

  • 首先獲取候選者bean名稱,通過DefaultListableBeanFactory的getBeanNamesForType方法,即找一下所有的Bean定義中指定Type的實(shí)現(xiàn)類或者子類

  • 接著第7行~第16行的判斷要自動裝配的類型是不是要自動裝配的糾正類型,這個在 【Spring源碼分析】非懶加載的單例Bean初始化前后的一些操作一文講PrepareBeanFactory方法的時候有講過,如果要自動裝配的類型是糾正類型,比如是一個ResourceLoader,那么就會為該類型生成一個代理實(shí)例,具體可以看一下第10行的AutowireUtils.resolveAutowiringValue方法的實(shí)現(xiàn)

  • 正常來說都是執(zhí)行的第17行~第21行的代碼,逐個判斷查找一下beanName對應(yīng)的BeanDefinition,判斷一下是不是自動裝配候選者,默認(rèn)都是的,如果的autowire-candidate屬性設(shè)置為false就不是

這樣,拿到所有待裝配對象的實(shí)現(xiàn)類或者子類的候選者,組成一個Map,Key為beanName,Value為具體的Bean。接著回看獲取Bean之后的邏輯:

 1 Map

整理一下邏輯:

  • 如果拿到的Map是空的且屬性必須注入,拋異常

  • 如果拿到的Map中有多個候選對象,判斷其中是否有中屬性配置為"primary=true"的,有就拿執(zhí)行第13行~第15行的代碼,沒有就第8行的方法返回null,拋異常,這個異常的描述相信Spring用的比較多的應(yīng)該比較熟悉

  • 如果拿到的Map中只有一個候選對象,直接拿到那個

通過這樣一整個流程,實(shí)現(xiàn)了byType自動裝配,byType自動裝配流程比較長,中間細(xì)節(jié)比較多,還需要多看看才能弄明白。

最后注意一點(diǎn),即所有待注入的PropertyName–>PropertyValue映射拿到之后都只是放在MutablePropertyValues中,最后由AbstractPropertyAccessor類的setPropertyValues方法遍歷并進(jìn)行逐一注入。

通過FactoryBean獲取Bean實(shí)例源碼實(shí)現(xiàn)

我們知道可以通過實(shí)現(xiàn)FactoryBean接口,重寫getObject()方法實(shí)現(xiàn)個性化定制Bean的過程,這部分我們就來看一下Spring源碼是如何實(shí)現(xiàn)通過FactoryBean獲取Bean實(shí)例的。代碼直接定位到AbstractBeanFactory的doGetBean方法創(chuàng)建單例Bean這部分:

 1 // Create bean instance.
 2 if (mbd.isSingleton()) { 3     sharedInstance = getSingleton(beanName, new ObjectFactory() { 4         public Object getObject() throws BeansException { 5             try { 6                 return createBean(beanName, mbd, args); 7             }
 8             catch (BeansException ex) { 9                 // Explicitly remove instance from singleton cache: It might have been put there 10                 // eagerly by the creation process, to allow for circular reference resolution. 11                 // Also remove any beans that received a temporary reference to the bean.
12 destroySingleton(beanName); 13                 throw ex; 14 } 15 } 16 }); 17     bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 18 }

FactoryBean首先是個Bean且被實(shí)例化出來成為一個對象之后才能調(diào)用getObject()方法,因此還是會執(zhí)行第3行~第16行的代碼,這段代碼之前分析過了就不說了。之后執(zhí)行第17行的方法:

 1 protected Object getObjectForBeanInstance( 2         Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
 3 
 4     // Don't let calling code try to dereference the factory if the bean isn't a factory.
 5     if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) { 6         throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); 7     }
 8 
 9     // Now we have the bean instance, which may be a normal bean or a FactoryBean. 10     // If it's a FactoryBean, we use it to create a bean instance, unless the 11     // caller actually wants a reference to the factory.
12     if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { 13         return beanInstance; 14 } 15 
16     Object object = null; 17     if (mbd == null) { 18         object = getCachedObjectForFactoryBean(beanName); 19 } 20     if (object == null) { 21         // Return bean instance from factory.
22         FactoryBean factory = (FactoryBean) beanInstance; 23         // Caches object obtained from FactoryBean if it is a singleton.
24         if (mbd == null && containsBeanDefinition(beanName)) { 25             mbd = getMergedLocalBeanDefinition(beanName); 26 } 27         boolean synthetic = (mbd != null && mbd.isSynthetic()); 28         object = getObjectFromFactoryBean(factory, beanName, !synthetic); 29 } 30     return object; 31 }

首先第5行~第7行判斷一下是否beanName以"&“開頭并且不是FactoryBean的實(shí)現(xiàn)類,不滿足則拋異常,因?yàn)閎eanName以”&"開頭是FactoryBean的實(shí)現(xiàn)類bean定義的一個特征。

接著判斷第12行~第14行,如果:

  • bean不是FactoryBean的實(shí)現(xiàn)類

  • beanName以"&"開頭

這兩種情況,都直接把生成的bean對象返回出去,不會執(zhí)行余下的流程。

最后流程走到第16行~第30行,最終調(diào)用getObject()方法實(shí)現(xiàn)個性化定制bean,先執(zhí)行第28行的方法:

 1 protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) { 2     if (factory.isSingleton() && containsSingleton(beanName)) { 3         synchronized (getSingletonMutex()) { 4             Object object = this.factoryBeanObjectCache.get(beanName);
 5             if (object == null) {
 6                 object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess); 7                 this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT)); 8             }
 9             return (object != NULL_OBJECT ? object : null); 10 } 11 } 12     else { 13         return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess); 14 } 15 }

第1行第11行的代碼與第12行第13行的代碼最終都是一樣的,調(diào)用了如下一段:

 1 private Object doGetObjectFromFactoryBean( 2         final FactoryBean factory, final String beanName, final boolean shouldPostProcess) 3         throws BeanCreationException { 4 
 5     Object object;
 6     try { 7         if (System.getSecurityManager() != null) {
 8             AccessControlContext acc = getAccessControlContext(); 9             try { 10                 object = AccessController.doPrivileged(new PrivilegedExceptionAction() { 11                     public Object run() throws Exception { 12                             return factory.getObject(); 13 } 14 }, acc); 15 } 16             catch (PrivilegedActionException pae) { 17                 throw pae.getException(); 18 } 19 } 20         else { 21             object = factory.getObject(); 22 } 23 } 24     catch (FactoryBeanNotInitializedException ex) { 25         throw new BeanCurrentlyInCreationException(beanName, ex.toString()); 26 } 27     catch (Throwable ex) { 28         throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex); 29 } 30         
31     // Do not accept a null value for a FactoryBean that's not fully 32     // initialized yet: Many FactoryBeans just return null then.
33     if (object == null && isSingletonCurrentlyInCreation(beanName)) { 34         throw new BeanCurrentlyInCreationException( 35                 beanName, "FactoryBean which is currently in creation returned null from getObject"); 36 } 37 
38     if (object != null && shouldPostProcess) { 39         try { 40             object = postProcessObjectFromFactoryBean(object, beanName); 41 } 42         catch (Throwable ex) { 43             throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex); 44 } 45 } 46 
47     return object; 48 }

第12行和第21行的代碼,都一樣,最終調(diào)用getObject()方法獲取對象?;剡^頭去看之前的getObjectFromFactoryBean方法,雖然if…else…邏輯最終都是調(diào)用了以上的方法,但是區(qū)別在于:

  • 如果FactoryBean接口實(shí)現(xiàn)類的isSington方法返回的是true,那么每次調(diào)用getObject方法的時候會優(yōu)先嘗試從FactoryBean對象緩存中取目標(biāo)對象,有就直接拿,沒有就創(chuàng)建并放入FactoryBean對象緩存,這樣保證了每次單例的FactoryBean調(diào)用getObject()方法后最終拿到的目標(biāo)對象一定是單例的,即在內(nèi)存中都是同一份

  • 如果FactoryBean接口實(shí)現(xiàn)類的isSington方法返回的是false,那么每次調(diào)用getObject方法的時候都會新創(chuàng)建一個目標(biāo)對象

感謝各位的閱讀,以上就是“Spring獲取Bean的過程是怎樣的”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Spring獲取Bean的過程是怎樣的這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI