Spring原始碼剖析4:其餘方式獲取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例項化的主要區別就在於第6行,它是直接建立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 }
它優先會嘗試getSington,即先嚐試從singletonObjects中獲取一下bean是否存在,如果存在直接返回singletonObjects中的bean物件。
接著,我們看到原型bean建立和單例bean建立的區別還在於第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在建立前要把當前beanName設定到ThreadLocal中去,其目的是保證多執行緒不會同時建立同一個bean。接著看第9行的程式碼實現,即bean建立之後做了什麼:
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 }
很好理解,就是把當前bean移除一下,這樣其它執行緒就可以建立bean了。第11行的程式碼不看了,意思是如果bean是FactoryBean的實現類的話,呼叫getObject()方法獲取真正的物件。
byName原始碼實現
Spring有為開發者提供Autowire(自動裝配)的功能,自動裝配最常用的就是byName和byType這兩種屬性。由於自動裝配是為了解決物件注入導致的過多的問題,因此很容易找到byName與byType的Spring原始碼實現應該在屬性注入這一塊,定位到屬性注入的程式碼AbstractAutowireCapableBeanFactory的populateBean方法,直接擷取重點:
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形式,是就執行byName自動裝配程式碼;第11行第13行判斷是否byType形式,是就執行byType自動裝配程式碼。那麼首先看一下第7行的byName程式碼實現:
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中不是簡單屬性的屬性,這句話有點繞,意思就是找到屬性是物件型別的屬性,但也不是所有的物件型別都會被找到,比如CharSequence型別、Number型別、Date型別、URL型別、URI型別、Locale型別、Class型別就會忽略,具體可見BeanUtils的isSimpleProperty方法
- 第5行~第7行,遍歷所有被找到的屬性,如果bean定義中包含了屬性名,那麼先例項化該屬性名對應的bean
- 第9行registerDependentBean,註冊一下當前bean的依賴bean,用於在某個bean被銷燬前先將其依賴的bean銷燬
其餘程式碼都是一些打日誌的,沒什麼好說的。
byType原始碼實現
上面說了byName的原始碼實現,接下來看一下byType原始碼實現:
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對應的屬性描述,注意一下16行的判斷及其對應的註釋:不要嘗試自動裝配Object型別,這沒有任何意義,即使從技術角度看它是一個非簡單的物件屬性。
第18行~第20行跳過(沒有太明白是幹什麼的),byType實現的原始碼主要在第21行的方法resolveDependency中,這個方法是AbstractAutowireCapableBeanFactory類的實現類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行的程式碼實現:
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
第四行結果是null不看了,為了簡化程式碼Array裝配、Collection裝配、Map裝配的程式碼都略去了,重點看一下普通屬性的裝配。首先是第25行獲取一下自動裝配的候選者:
1 protected Map
程式碼邏輯整理一下:
- 首先獲取候選者bean名稱,透過DefaultListableBeanFactory的getBeanNamesForType方法,即找一下所有的Bean定義中指定Type的實現類或者子類
- 接著第7行~第16行的判斷要自動裝配的型別是不是要自動裝配的糾正型別,這個在 【Spring原始碼分析】非懶載入的單例Bean初始化前後的一些操作一文講PrepareBeanFactory方法的時候有講過,如果要自動裝配的型別是糾正型別,比如是一個ResourceLoader,那麼就會為該型別生成一個代理例項,具體可以看一下第10行的AutowireUtils.resolveAutowiringValue方法的實現
- 正常來說都是執行的第17行~第21行的程式碼,逐個判斷查詢一下beanName對應的BeanDefinition,判斷一下是不是自動裝配候選者,預設都是的,如果的autowire-candidate屬性設定為false就不是
這樣,拿到所有待裝配物件的實現類或者子類的候選者,組成一個Map,Key為beanName,Value為具體的Bean。接著回看獲取Bean之後的邏輯:
1 Map
整理一下邏輯:
- 如果拿到的Map是空的且屬性必須注入,拋異常
- 如果拿到的Map中有多個候選物件,判斷其中是否有中屬性配置為"primary=true"的,有就拿執行第13行~第15行的程式碼,沒有就第8行的方法返回null,拋異常,這個異常的描述相信Spring用的比較多的應該比較熟悉
- 如果拿到的Map中只有一個候選物件,直接拿到那個
透過這樣一整個流程,實現了byType自動裝配,byType自動裝配流程比較長,中間細節比較多,還需要多看看才能弄明白。
最後注意一點,即所有待注入的PropertyName–>PropertyValue對映拿到之後都只是放在MutablePropertyValues中,最後由AbstractPropertyAccessor類的setPropertyValues方法遍歷並進行逐一注入。
透過FactoryBean獲取Bean例項原始碼實現
我們知道可以透過實現FactoryBean介面,重寫getObject()方法實現個性化定製Bean的過程,這部分我們就來看一下Spring原始碼是如何實現透過FactoryBean獲取Bean例項的。程式碼直接定位到AbstractBeanFactory的doGetBean方法建立單例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且被例項化出來成為一個物件之後才能呼叫getObject()方法,因此還是會執行第3行~第16行的程式碼,這段程式碼之前分析過了就不說了。之後執行第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的實現類,不滿足則拋異常,因為beanName以”&"開頭是FactoryBean的實現類bean定義的一個特徵。
接著判斷第12行~第14行,如果:
- bean不是FactoryBean的實現類
- beanName以"&"開頭
這兩種情況,都直接把生成的bean物件返回出去,不會執行餘下的流程。
最後流程走到第16行~第30行,最終呼叫getObject()方法實現個性化定製bean,先執行第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行的程式碼最終都是一樣的,呼叫瞭如下一段:
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行的程式碼,都一樣,最終呼叫getObject()方法獲取物件。回過頭去看之前的getObjectFromFactoryBean方法,雖然if…else…邏輯最終都是呼叫了以上的方法,但是區別在於:
- 如果FactoryBean介面實現類的isSington方法返回的是true,那麼每次呼叫getObject方法的時候會優先嚐試從FactoryBean物件快取中取目標物件,有就直接拿,沒有就建立並放入FactoryBean物件快取,這樣保證了每次單例的FactoryBean呼叫getObject()方法後最終拿到的目標物件一定是單例的,即在記憶體中都是同一份
- 如果FactoryBean介面實現類的isSington方法返回的是false,那麼每次呼叫getObject方法的時候都會新建立一個目標物件
微信公眾號【黃小斜】作者是螞蟻金服 JAVA 工程師,專注於 JAVA
後端技術棧:SpringBoot、SSM全家桶、MySQL、分散式、中介軟體、微服務,同時也懂點投資理財,堅持學習和寫作,相信終身學習的力量!關注公眾號後回覆”架構師“即可領取
Java基礎、進階、專案和架構師等免費學習資料,更有資料庫、分散式、微服務等熱門技術學習影片,內容豐富,兼顧原理和實踐,另外也將贈送作者原創的Java學習指南、Java程式設計師面試指南等乾貨資源
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69906029/viewspace-2654864/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Spring原始碼剖析4:懶載入的單例Bean獲取過程分析Spring原始碼單例Bean
- Spring 原始碼(13)Spring Bean 的建立過程(4)Spring原始碼Bean
- 【Spring原始碼分析】原型Bean例項化過程、byName與byType及FactoryBean獲取Bean原始碼實現Spring原始碼原型Bean
- Spring原始碼分析之Bean的建立過程詳解Spring原始碼Bean
- Spring 原始碼(10)Spring Bean 的建立過程(1)Spring原始碼Bean
- Spring 原始碼(11)Spring Bean 的建立過程(2)Spring原始碼Bean
- Spring 原始碼(12)Spring Bean 的建立過程(3)Spring原始碼Bean
- Spring 原始碼(14)Spring Bean 的建立過程(5)Spring原始碼Bean
- Spring Ioc原始碼分析系列--Bean例項化過程(二)Spring原始碼Bean
- Spring Ioc原始碼分析系列--Bean例項化過程(一)Spring原始碼Bean
- Spring在程式碼中獲取bean的幾種方式SpringBean
- Spring 原始碼(17)Spring Bean的建立過程(8)Bean的初始化Spring原始碼Bean
- Spring Bean 的例項化過程原始碼解析SpringBean原始碼
- Spring 原始碼(9)Spring Bean的建立過程的前期準備Spring原始碼Bean
- Spring原始碼剖析3:Spring IOC容器的載入過程Spring原始碼
- Spring 原始碼(16)Spring Bean的建立過程(7)屬性填充Spring原始碼Bean
- Spring 原始碼(14)Spring Bean 的建立過程(6)物件的提前暴露Spring原始碼Bean物件
- Spring啟動過程——原始碼分析Spring原始碼
- 【Spring原始碼分析】非懶載入的單例Bean初始化過程(下篇)Spring原始碼單例Bean
- 【Spring原始碼分析】非懶載入的單例Bean初始化過程(上篇)Spring原始碼單例Bean
- Spring原始碼系列(二)--bean元件的原始碼分析Spring原始碼Bean元件
- 獲取spring裡的beanSpringBean
- Spring6 當中 獲取 Bean 的四種方式SpringBean
- Spring 原始碼學習 - 單例bean的例項化過程Spring原始碼單例Bean
- Spring原始碼淺析之bean例項的建立過程(一)Spring原始碼Bean
- Spring原始碼淺析之bean例項的建立過程(二)Spring原始碼Bean
- 在專案中獲取Spring的Bean的幾種方式SpringBean
- Spring Boot原始碼分析-啟動過程Spring Boot原始碼
- Spring MVC 啟動過程原始碼分析SpringMVC原始碼
- Spring原始碼分析之`BeanFactoryPostProcessor`呼叫過程Spring原始碼Bean
- 【spring原始碼學習】spring的IOC容器在初始化bean過程Spring原始碼Bean
- Flutter原始碼剖析(一):原始碼獲取與構建Flutter原始碼
- 深入剖析Vue原始碼 - 完整渲染過程Vue原始碼
- 批次過程獲取指令碼指令碼
- Universal-Image-Loader原始碼解解析---display過程 + 獲取bitmap過程原始碼
- Spring Security原始碼分析一:Spring Security認證過程Spring原始碼
- Spring Security原始碼分析二:Spring Security授權過程Spring原始碼
- Spring原始碼剖析9:Spring事務原始碼剖析Spring原始碼