spring原始碼解析之IOC容器(四)——屬性注入

蝸牛揹著馬發表於2019-07-01

  上一篇跟蹤了bean的建立過程,接下來,我們繼續跟蹤bean的屬性填充的過程。先回到doCreateBean方法,程式碼如下:

  1 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
  2             throws BeanCreationException {
  3 
  4         // Instantiate the bean.
  5         BeanWrapper instanceWrapper = null;
  6         if (mbd.isSingleton()) {
  7             //如果是單例,先把快取中的同名Bean清除
  8             instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
  9         }
 10         //如果快取中沒有
 11         if (instanceWrapper == null) {
 12             //則建立一個例項
 13             instanceWrapper = createBeanInstance(beanName, mbd, args);
 14         }
 15         final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
 16         Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
 17         mbd.resolvedTargetType = beanType;
 18 
 19         // Allow post-processors to modify the merged bean definition.
 20         synchronized (mbd.postProcessingLock) {
 21             if (!mbd.postProcessed) {
 22                 try {
 23                     //使用後置處理器進行處理
 24                     applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
 25                 }
 26                 catch (Throwable ex) {
 27                     throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 28                             "Post-processing of merged bean definition failed", ex);
 29                 }
 30                 mbd.postProcessed = true;
 31             }
 32         }
 33 
 34         // Eagerly cache singletons to be able to resolve circular references
 35         // even when triggered by lifecycle interfaces like BeanFactoryAware.
 36         //這裡是對單例的迴圈引用的處理,單例&&允許迴圈依賴&&正在被建立同時滿足,才為true
 37         boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
 38                 isSingletonCurrentlyInCreation(beanName));
 39         if (earlySingletonExposure) {
 40             if (logger.isDebugEnabled()) {
 41                 logger.debug("Eagerly caching bean '" + beanName +
 42                         "' to allow for resolving potential circular references");
 43             }
 44             addSingletonFactory(beanName, new ObjectFactory<Object>() {
 45                 @Override
 46                 public Object getObject() throws BeansException {
 47                     return getEarlyBeanReference(beanName, mbd, bean);
 48                 }
 49             });
 50         }
 51 
 52         //這裡是對bean的初始化,依賴注入往往是在這裡進行的,這個exposedObject在初始化完成之後會作為依賴注入完成之後的Bean
 53         // Initialize the bean instance.
 54         Object exposedObject = bean;
 55         try {
 56             //屬性的填充
 57             populateBean(beanName, mbd, instanceWrapper);
 58             if (exposedObject != null) {
 59                 exposedObject = initializeBean(beanName, exposedObject, mbd);
 60             }
 61         }
 62         catch (Throwable ex) {
 63             if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
 64                 throw (BeanCreationException) ex;
 65             }
 66             else {
 67                 throw new BeanCreationException(
 68                         mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
 69             }
 70         }
 71 
 72         if (earlySingletonExposure) {
 73             Object earlySingletonReference = getSingleton(beanName, false);
 74             if (earlySingletonReference != null) {
 75                 if (exposedObject == bean) {
 76                     exposedObject = earlySingletonReference;
 77                 }
 78                 else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
 79                     String[] dependentBeans = getDependentBeans(beanName);
 80                     Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
 81                     for (String dependentBean : dependentBeans) {
 82                         if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
 83                             actualDependentBeans.add(dependentBean);
 84                         }
 85                     }
 86                     if (!actualDependentBeans.isEmpty()) {
 87                         throw new BeanCurrentlyInCreationException(beanName,
 88                                 "Bean with name '" + beanName + "' has been injected into other beans [" +
 89                                 StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
 90                                 "] in its raw version as part of a circular reference, but has eventually been " +
 91                                 "wrapped. This means that said other beans do not use the final version of the " +
 92                                 "bean. This is often the result of over-eager type matching - consider using " +
 93                                 "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
 94                     }
 95                 }
 96             }
 97         }
 98 
 99         // Register bean as disposable.
100         try {
101             registerDisposableBeanIfNecessary(beanName, bean, mbd);
102         }
103         catch (BeanDefinitionValidationException ex) {
104             throw new BeanCreationException(
105                     mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
106         }
107 
108         return exposedObject;
109     }

  對於bean的建立,IOC容器其實是採用反射和cglib技術來生成的,我們可以跟蹤一下createBeanInstance方法:

 1 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
 2         // Make sure bean class is actually resolved at this point.
 3         Class<?> beanClass = resolveBeanClass(mbd, beanName);
 4 
 5         if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
 6             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 7                     "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
 8         }
 9 
10         //使用工廠方法對Bean進行例項化
11         if (mbd.getFactoryMethodName() != null)  {
12             return instantiateUsingFactoryMethod(beanName, mbd, args);
13         }
14 
15         // Shortcut when re-creating the same bean...
16         boolean resolved = false;
17         boolean autowireNecessary = false;
18         if (args == null) {
19             synchronized (mbd.constructorArgumentLock) {
20                 if (mbd.resolvedConstructorOrFactoryMethod != null) {
21                     resolved = true;
22                     autowireNecessary = mbd.constructorArgumentsResolved;
23                 }
24             }
25         }
26         if (resolved) {
27             if (autowireNecessary) {
28                 return autowireConstructor(beanName, mbd, null, null);
29             }
30             else {
31                 return instantiateBean(beanName, mbd);
32             }
33         }
34 
35         //使用建構函式對Bean例項化
36         // Need to determine the constructor...
37         Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
38         if (ctors != null ||
39                 mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
40                 mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
41             return autowireConstructor(beanName, mbd, ctors, args);
42         }
43 
44         //使用預設的建構函式對Bean進行例項化
45         // No special handling: simply use no-arg constructor.
46         return instantiateBean(beanName, mbd);
47     }

  1、如果指定了工廠方法,則使用工廠進行建立;

  2、如果沒有指定工廠方法,則看有沒指定某個構造器進行例項化;

  3、都沒有,則採用預設的構造器進行例項化。進入預設的構造器方法:

 1 protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
 2         try {
 3             Object beanInstance;
 4             final BeanFactory parent = this;
 5             if (System.getSecurityManager() != null) {
 6                 beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
 7                     @Override
 8                     public Object run() {
 9                         return getInstantiationStrategy().instantiate(mbd, beanName, parent);
10                     }
11                 }, getAccessControlContext());
12             }
13             else {
14                 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
15             }
16             BeanWrapper bw = new BeanWrapperImpl(beanInstance);
17             initBeanWrapper(bw);
18             return bw;
19         }
20         catch (Throwable ex) {
21             throw new BeanCreationException(
22                     mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
23         }
24     }

  雖然getInstantiationStrategy()方法獲取的是CglibSubclassingInstantiationStrategy例項,但是CglibSubclassingInstantiationStrategy中只有一個instantiate帶一個引數和一個可變引數的方法,和這裡呼叫的並不是同一個方法,所以,這裡呼叫的是它的父類SimpleInstantiationStrategy中的instantiate方法,進入:

 1 public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
 2         // Don't override the class with CGLIB if no overrides.
 3         if (bd.getMethodOverrides().isEmpty()) {
 4             Constructor<?> constructorToUse;
 5             synchronized (bd.constructorArgumentLock) {
 6                 //這裡取得指定的構造器或者生產物件的工廠方法來對Bean進行例項化
 7                 constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
 8                 if (constructorToUse == null) {
 9                     final Class<?> clazz = bd.getBeanClass();
10                     if (clazz.isInterface()) {
11                         throw new BeanInstantiationException(clazz, "Specified class is an interface");
12                     }
13                     try {
14                         if (System.getSecurityManager() != null) {
15                             constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
16                                 @Override
17                                 public Constructor<?> run() throws Exception {
18                                     return clazz.getDeclaredConstructor((Class[]) null);
19                                 }
20                             });
21                         }
22                         else {
23                             constructorToUse =    clazz.getDeclaredConstructor((Class[]) null);
24                         }
25                         bd.resolvedConstructorOrFactoryMethod = constructorToUse;
26                     }
27                     catch (Throwable ex) {
28                         throw new BeanInstantiationException(clazz, "No default constructor found", ex);
29                     }
30                 }
31             }
32             //使用反射進行例項化
33             return BeanUtils.instantiateClass(constructorToUse);
34         }
35         else {
36             //使用cglb進行例項化
37             // Must generate CGLIB subclass.
38             return instantiateWithMethodInjection(bd, beanName, owner);
39         }
40     }

  這段程式碼可以看到,IOC是使用反射和cglib來進行例項化物件的。好了,我們回到之前的方法,到populateBean(beanName, mbd, instanceWrapper)方法進行跟蹤:

 1 protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
 2         //在前面解析的過程中,XML中設定的屬性已經填充到beanDefinition 的propertyValues屬性中
 3         PropertyValues pvs = mbd.getPropertyValues();
 4 
 5         if (bw == null) {
 6             if (!pvs.isEmpty()) {
 7                 throw new BeanCreationException(
 8                         mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
 9             }
10             else {
11                 // Skip property population phase for null instance.
12                 return;
13             }
14         }
15 
16         // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
17         // state of the bean before properties are set. This can be used, for example,
18         // to support styles of field injection.
19         boolean continueWithPropertyPopulation = true;
20 
21         if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
22             for (BeanPostProcessor bp : getBeanPostProcessors()) {
23                 if (bp instanceof InstantiationAwareBeanPostProcessor) {
24                     InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
25                     if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
26                         continueWithPropertyPopulation = false;
27                         break;
28                     }
29                 }
30             }
31         }
32 
33         if (!continueWithPropertyPopulation) {
34             return;
35         }
36 
37         //開始進行依賴注入的操作
38         if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
39                 mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
40             MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
41 
42             //按屬性的名字來進行注入
43             // Add property values based on autowire by name if applicable.
44             if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
45                 autowireByName(beanName, mbd, bw, newPvs);
46             }
47 
48             //按屬性的型別來進行注入
49             // Add property values based on autowire by type if applicable.
50             if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
51                 autowireByType(beanName, mbd, bw, newPvs);
52             }
53 
54             pvs = newPvs;
55         }
56 
57         boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
58         boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
59 
60         if (hasInstAwareBpps || needsDepCheck) {
61             PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
62             if (hasInstAwareBpps) {
63                 for (BeanPostProcessor bp : getBeanPostProcessors()) {
64                     if (bp instanceof InstantiationAwareBeanPostProcessor) {
65                         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
66                         pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
67                         if (pvs == null) {
68                             return;
69                         }
70                     }
71                 }
72             }
73             if (needsDepCheck) {
74                 checkDependencies(beanName, mbd, filteredPds, pvs);
75             }
76         }
77 
78         //對屬性進行注入
79         applyPropertyValues(beanName, mbd, bw, pvs);
80     }

  可以看到:

  1、我們可以在XML中指定autowired的值,是按名稱還是型別來進行注入;

  2、真正進行屬性注入的是applyPropertyValues方法,進入:

 1 protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
 2         if (pvs == null || pvs.isEmpty()) {
 3             return;
 4         }
 5 
 6         if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
 7             ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
 8         }
 9 
10         MutablePropertyValues mpvs = null;
11         List<PropertyValue> original;
12 
13         if (pvs instanceof MutablePropertyValues) {
14             mpvs = (MutablePropertyValues) pvs;
15             if (mpvs.isConverted()) {
16                 // Shortcut: use the pre-converted values as-is.
17                 try {
18                     bw.setPropertyValues(mpvs);
19                     return;
20                 }
21                 catch (BeansException ex) {
22                     throw new BeanCreationException(
23                             mbd.getResourceDescription(), beanName, "Error setting property values", ex);
24                 }
25             }
26             original = mpvs.getPropertyValueList();
27         }
28         else {
29             original = Arrays.asList(pvs.getPropertyValues());
30         }
31 
32         TypeConverter converter = getCustomTypeConverter();
33         if (converter == null) {
34             converter = bw;
35         }
36         //獲取解析器
37         BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
38 
39         // Create a deep copy, resolving any references for values.
40         List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
41         boolean resolveNecessary = false;
42         for (PropertyValue pv : original) {
43             //如果已經轉換過,就直接存入
44             if (pv.isConverted()) {
45                 deepCopy.add(pv);
46             }
47             else {
48                 //獲取屬性名稱
49                 String propertyName = pv.getName();
50                 //獲取屬性值
51                 Object originalValue = pv.getValue();
52                 //將值進行轉換,比如屬性的值有可能是陣列、集合,或者物件,並且該物件也需要進行屬性的注入,
53                 //那麼還會進行遞迴呼叫getBean方法,將該物件生成好之後再注入給當前的屬性
54                 Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
55                 Object convertedValue = resolvedValue;
56                 boolean convertible = bw.isWritableProperty(propertyName) &&
57                         !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
58                 if (convertible) {
59                     convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
60                 }
61                 // Possibly store converted value in merged bean definition,
62                 // in order to avoid re-conversion for every created bean instance.
63                 if (resolvedValue == originalValue) {
64                     if (convertible) {
65                         pv.setConvertedValue(convertedValue);
66                     }
67                     deepCopy.add(pv);
68                 }
69                 else if (convertible && originalValue instanceof TypedStringValue &&
70                         !((TypedStringValue) originalValue).isDynamic() &&
71                         !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
72                     pv.setConvertedValue(convertedValue);
73                     deepCopy.add(pv);
74                 }
75                 else {
76                     resolveNecessary = true;
77                     deepCopy.add(new PropertyValue(pv, convertedValue));
78                 }
79             }
80         }
81         if (mpvs != null && !resolveNecessary) {
82             mpvs.setConverted();
83         }
84 
85         //設定依賴注入的地方
86         // Set our (possibly massaged) deep copy.
87         try {
88             bw.setPropertyValues(new MutablePropertyValues(deepCopy));
89         }
90         catch (BeansException ex) {
91             throw new BeanCreationException(
92                     mbd.getResourceDescription(), beanName, "Error setting property values", ex);
93         }
94     }

  至此,一個完整的bean就算建立完成了,要用的時候,直接找IOC容器拿就行了。

相關文章