程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 【Spring源碼分析】原型Bean實例化過程、byName與byType及FactoryBean獲取Bean源碼實現,bynamebytype

【Spring源碼分析】原型Bean實例化過程、byName與byType及FactoryBean獲取Bean源碼實現,bynamebytype

編輯:JAVA綜合教程

【Spring源碼分析】原型Bean實例化過程、byName與byType及FactoryBean獲取Bean源碼實現,bynamebytype


原型Bean加載過程

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

1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4     xsi:schemaLocation="http://www.springframework.org/schema/beans
5     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
6 
7     <bean id="prototypeBean" class="org.xrq.action.PrototypeBean" scope="prototype"  />
8     
9 </beans>

原型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<String> beanNameSet = new HashSet<String>(2);
 8         beanNameSet.add((String) curVal);
 9         beanNameSet.add(beanName);
10         this.prototypesCurrentlyInCreation.set(beanNameSet);
11     }
12     else {
13         Set<String> beanNameSet = (Set<String>) 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<String> beanNameSet = (Set<String>) 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這兩種屬性。由於自動裝配是為了解決對象注入導致的<property>過多的問題,因此很容易找到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<String> autowiredBeanNames = new LinkedHashSet<String>(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<String> 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<String> 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<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
26         if (matchingBeans.isEmpty()) {
27             if (descriptor.isRequired()) {
28                 raiseNoSuchBeanDefinitionException(type, "", descriptor);
29             }
30             return null;
31         }
32         if (matchingBeans.size() > 1) {
33             String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor);
34             if (primaryBeanName == null) {
35                 throw new NoSuchBeanDefinitionException(type, "expected single matching bean but found " +
36                         matchingBeans.size() + ": " + matchingBeans.keySet());
37             }
38             if (autowiredBeanNames != null) {
39                 autowiredBeanNames.add(primaryBeanName);
40             }
41             return matchingBeans.get(primaryBeanName);
42         }
43         // We have exactly one match.
44         Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
45         if (autowiredBeanNames != null) {
46             autowiredBeanNames.add(entry.getKey());
47         }
48         return entry.getValue();
49     }
50 }

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

 1 protected Map<String, Object> findAutowireCandidates(
 2     String beanName, Class requiredType, DependencyDescriptor descriptor) {
 3 
 4     String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
 5             this, requiredType, true, descriptor.isEager());
 6     Map<String, Object> result = new LinkedHashMap<String, Object>(candidateNames.length);
 7     for (Class autowiringType : this.resolvableDependencies.keySet()) {
 8         if (autowiringType.isAssignableFrom(requiredType)) {
 9             Object autowiringValue = this.resolvableDependencies.get(autowiringType);
10             autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
11             if (requiredType.isInstance(autowiringValue)) {
12                     result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
13                 break;
14             }
15         }
16     }
17     for (String candidateName : candidateNames) {
18         if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
19             result.put(candidateName, getBean(candidateName));
20         }
21     }
22     return result;
23 }

代碼邏輯整理一下:

  • 首先獲取候選者bean名稱,通過DefaultListableBeanFactory的getBeanNamesForType方法,即找一下所有的Bean定義中指定Type的實現類或者子類
  • 接著第7行~第16行的判斷要自動裝配的類型是不是要自動裝配的糾正類型,這個在【Spring源碼分析】非懶加載的單例Bean初始化前後的一些操作一文講PrepareBeanFactory方法的時候有講過,如果要自動裝配的類型是糾正類型,比如是一個ResourceLoader,那麼就會為該類型生成一個代理實例,具體可以看一下第10行的AutowireUtils.resolveAutowiringValue方法的實現
  • 正常來說都是執行的第17行~第21行的代碼,逐個判斷查找一下beanName對應的BeanDefinition,判斷一下是不是自動裝配候選者,默認都是的,如果<bean>的autowire-candidate屬性設置為false就不是

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

 1 Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
 2     if (matchingBeans.isEmpty()) {
 3         if (descriptor.isRequired()) {
 4             raiseNoSuchBeanDefinitionException(type, "", descriptor);
 5         }
 6         return null;
 7     }
 8     if (matchingBeans.size() > 1) {
 9         String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor);
10         if (primaryBeanName == null) {
11             throw new NoSuchBeanDefinitionException(type, "expected single matching bean but found " +
12                     matchingBeans.size() + ": " + matchingBeans.keySet());
13         }
14         if (autowiredBeanNames != null) {
15             autowiredBeanNames.add(primaryBeanName);
16         }
17         return matchingBeans.get(primaryBeanName);
18     }
19     // We have exactly one match.
20     Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
21     if (autowiredBeanNames != null) {
22         autowiredBeanNames.add(entry.getKey());
23     }
24     ...
25 }

整理一下邏輯:

  • 如果拿到的Map是空的且屬性必須注入,拋異常
  • 如果拿到的Map中有多個候選對象,判斷其中是否有<bean>中屬性配置為"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<Object>() {
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方法的時候都會新創建一個目標對象

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved