spring原始碼解析之IOC容器(三)——依賴注入

蝸牛揹著馬發表於2019-06-26

  上一篇主要是跟蹤了IOC容器對bean標籤進行解析之後存入Map中的過程,這些bean只是以BeanDefinition為載體單純的儲存起來了,並沒有轉換成一個個的物件,今天繼續進行跟蹤,看一看IOC容器是怎樣例項化物件的。

  我們都使用過以下程式碼:

1 FileSystemXmlApplicationContext  context=new FileSystemXmlApplicationContext("bean.xml");
2 User user=context.getBean("user",User.class);

  這樣我們就能獲取到user物件了,所以,不難想象,這個getBean方法就是例項化物件的入口。接下來我們就以這個方法為切入點,來探究IOC容器中bean的例項化過程。getBean方法是在FileSystemXmlApplicationContext的基類AbstractApplicationContext中定義的,程式碼如下:

1 public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
2         assertBeanFactoryActive();
3         return getBeanFactory().getBean(name, requiredType);
4     }

  裡面有很多過載方法,裡面有呼叫了某個beanFactory的getBean方法。AbstractApplicationContext中並沒有定義getBeanFactory這個方法,那一定是在FileSystemXmlApplicatio

—ntext的某個父類中定義的,我們再回過頭看一下它的UML圖:

  經過查詢之後,是在AbstractRefreshableApplicationContext中定義的,且這個beanFactory是DefaultListableBeanFactory型別的:

 1 public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
 2 
 3     private Boolean allowBeanDefinitionOverriding;
 4 
 5     private Boolean allowCircularReferences;
 6 
 7     /** Bean factory for this context */
 8     private DefaultListableBeanFactory beanFactory;
 9 
10     /** Synchronization monitor for the internal BeanFactory */
11     private final Object beanFactoryMonitor = new Object();

  直接進入DefaultListableBeanFactory中,檢視它的getBean方法:

public <T> T getBean(Class<T> requiredType) throws BeansException {
        return getBean(requiredType, (Object[]) null);
    }
public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
        NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args);
        if (namedBean != null) {
            return namedBean.getBeanInstance();
        }
        BeanFactory parent = getParentBeanFactory();
        if (parent != null) {
            return parent.getBean(requiredType, args);
        }
        throw new NoSuchBeanDefinitionException(requiredType);
    }

  發現裡面只有這兩個過載方法,其他getBean方法,包括例子中使用的那個過載方法沒有看到,我們看一下DefaultListableBeanFactory類的UML圖:

  經查詢,發現在父類AbstractBeanFactory中定義了其他的getBean方法,如下:

1 public Object getBean(String name, Object... args) throws BeansException {
2         return doGetBean(name, null, args, false);
3     }
1 public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {
2         return doGetBean(name, requiredType, args, false);
3     }

  裡面都呼叫了doGetBean方法,那麼進入繼續跟蹤:

  1 protected <T> T doGetBean(
  2             final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
  3             throws BeansException {
  4         //將bean的name進行轉換,比如將name前面的“&”符去掉,帶“&”的name,獲取的是beanFactory本身,而不是
  5         //beanFactory生成出來的bean例項
  6         final String beanName = transformedBeanName(name);
  7         Object bean;
  8 
  9         // Eagerly check singleton cache for manually registered singletons.
 10         //看快取中是否已經有該bean
 11         Object sharedInstance = getSingleton(beanName);
 12         //如果快取中有
 13         if (sharedInstance != null && args == null) {
 14             if (logger.isDebugEnabled()) {
 15                 if (isSingletonCurrentlyInCreation(beanName)) {
 16                     logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
 17                             "' that is not fully initialized yet - a consequence of a circular reference");
 18                 }
 19                 else {
 20                     logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
 21                 }
 22             }
 23             //如果sharedInstance是FactoryBean型別,則返回它生產的物件,否則,返回它本身
 24             bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
 25         }
 26         //如果快取中沒有,第一次建立的時候
 27         else {
 28             // Fail if we're already creating this bean instance:
 29             // We're assumably within a circular reference.
 30             if (isPrototypeCurrentlyInCreation(beanName)) {
 31                 throw new BeanCurrentlyInCreationException(beanName);
 32             }
 33 
 34             // Check if bean definition exists in this factory.
 35             //獲取父容器
 36             BeanFactory parentBeanFactory = getParentBeanFactory();
 37             //如果父容器存在,且在當前容器中沒有找到該名稱的bean的資料
 38             if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 39                 //則到父容器中進行處理
 40                 // Not found -> check parent.
 41                 //將name前加上“&”
 42                 String nameToLookup = originalBeanName(name);
 43                 //分別對是否有引數的情況進行處理
 44                 if (args != null) {
 45                     // Delegation to parent with explicit args.
 46                     return (T) parentBeanFactory.getBean(nameToLookup, args);
 47                 }
 48                 else {
 49                     // No args -> delegate to standard getBean method.
 50                     return parentBeanFactory.getBean(nameToLookup, requiredType);
 51                 }
 52             }
 53 
 54             if (!typeCheckOnly) {
 55                 markBeanAsCreated(beanName);
 56             }
 57 
 58             try {
 59                 //將資料封裝成RootBeanDefinition物件
 60                 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 61                 //檢查是否為抽象類
 62                 checkMergedBeanDefinition(mbd, beanName, args);
 63 
 64                 // Guarantee initialization of beans that the current bean depends on.
 65                 //獲取當前建立的bean的依賴的bean
 66                 String[] dependsOn = mbd.getDependsOn();
 67                 if (dependsOn != null) {
 68                     for (String dep : dependsOn) {
 69                         if (isDependent(beanName, dep)) {
 70                             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 71                                     "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
 72                         }
 73                         //為當前bean和它的依賴物件建立對映關係
 74                         registerDependentBean(dep, beanName);
 75                         try {
 76                             //遞迴呼叫getBean方法,建立依賴物件,直到沒有依賴物件為止
 77                             getBean(dep);
 78                         }
 79                         catch (NoSuchBeanDefinitionException ex) {
 80                             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 81                                     "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
 82                         }
 83                     }
 84                 }
 85 
 86                 // Create bean instance.
 87                 if (mbd.isSingleton()) {
 88                     sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
 89                         @Override
 90                         public Object getObject() throws BeansException {
 91                             try {
 92                                 //回撥方法
 93                                 return createBean(beanName, mbd, args);
 94                             }
 95                             catch (BeansException ex) {
 96                                 // Explicitly remove instance from singleton cache: It might have been put there
 97                                 // eagerly by the creation process, to allow for circular reference resolution.
 98                                 // Also remove any beans that received a temporary reference to the bean.
 99                                 destroySingleton(beanName);
100                                 throw ex;
101                             }
102                         }
103                     });
104                     bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
105                 }
106 
107                 else if (mbd.isPrototype()) {
108                     // It's a prototype -> create a new instance.
109                     Object prototypeInstance = null;
110                     try {
111                         beforePrototypeCreation(beanName);
112                         prototypeInstance = createBean(beanName, mbd, args);
113                     }
114                     finally {
115                         afterPrototypeCreation(beanName);
116                     }
117                     bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
118                 }
119 
120                 else {
121                     String scopeName = mbd.getScope();
122                     final Scope scope = this.scopes.get(scopeName);
123                     if (scope == null) {
124                         throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
125                     }
126                     try {
127                         Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
128                             @Override
129                             public Object getObject() throws BeansException {
130                                 beforePrototypeCreation(beanName);
131                                 try {
132                                     return createBean(beanName, mbd, args);
133                                 }
134                                 finally {
135                                     afterPrototypeCreation(beanName);
136                                 }
137                             }
138                         });
139                         bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
140                     }
141                     catch (IllegalStateException ex) {
142                         throw new BeanCreationException(beanName,
143                                 "Scope '" + scopeName + "' is not active for the current thread; consider " +
144                                 "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
145                                 ex);
146                     }
147                 }
148             }
149             catch (BeansException ex) {
150                 cleanupAfterBeanCreationFailure(beanName);
151                 throw ex;
152             }
153         }
154 
155         // Check if required type matches the type of the actual bean instance.
156         if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
157             try {
158                 return getTypeConverter().convertIfNecessary(bean, requiredType);
159             }
160             catch (TypeMismatchException ex) {
161                 if (logger.isDebugEnabled()) {
162                     logger.debug("Failed to convert bean '" + name + "' to required type '" +
163                             ClassUtils.getQualifiedName(requiredType) + "'", ex);
164                 }
165                 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
166             }
167         }
168         return (T) bean;
169     }

  可以看到對不同scope域的bean的建立過程,其中會進行遞迴建立,現在進入createBean方法中,其實現是在AbstractAutowireCapableBeanFactory類中,程式碼如下:

 1 protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
 2         if (logger.isDebugEnabled()) {
 3             logger.debug("Creating instance of bean '" + beanName + "'");
 4         }
 5         RootBeanDefinition mbdToUse = mbd;
 6 
 7         // Make sure bean class is actually resolved at this point, and
 8         // clone the bean definition in case of a dynamically resolved Class
 9         // which cannot be stored in the shared merged bean definition.
10         //判斷需要建立的bean是否可以例項化,是否可以通過類裝載其進行裝載
11         Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
12         if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
13             mbdToUse = new RootBeanDefinition(mbd);
14             mbdToUse.setBeanClass(resolvedClass);
15         }
16 
17         // Prepare method overrides.
18         try {
19             //這裡是對overrides屬性和look-up屬性的處理
20             mbdToUse.prepareMethodOverrides();
21         }
22         catch (BeanDefinitionValidationException ex) {
23             throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
24                     beanName, "Validation of method overrides failed", ex);
25         }
26 
27         try {
28             //AOP就是這裡操作的,如果配置了postProcessor,則生成一個proxy返回,即代理類
29             // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
30             Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
31             if (bean != null) {
32                 return bean;
33             }
34         }
35         catch (Throwable ex) {
36             throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
37                     "BeanPostProcessor before instantiation of bean failed", ex);
38         }
39         //建立bean的方法呼叫
40         Object beanInstance = doCreateBean(beanName, mbdToUse, args);
41         if (logger.isDebugEnabled()) {
42             logger.debug("Finished creating instance of bean '" + beanName + "'");
43         }
44         return beanInstance;
45     }

  進入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         //這裡是對單例的迴圈引用的處理
 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會將該bean的名字存一份到singletonsCurrentlyInCreation這個map中,然後每次建立的時候都會到裡面進行檢查當前bean是否正在被建立。為了避免發生迴圈引用(A依賴B,B依賴C,C依賴A)引起是迴圈,在第一次建立bean時,IOC容器會把用於建立這個bean的工廠物件放入singletonFactories這個map中,key是這個正在被建立的bean的名字。這樣發生迴圈依賴的時候,就不再呼叫getBean方法了,而是直接使用工廠建立一個bean給被依賴的物件。比如第一次建立A時,將A的名稱存入了singletonsCurrentlyInCreation這個map中,並且呼叫addSingletonFactory方法,將建立A的工廠放到singletonFactories中了,然後遞迴呼叫getBean建立依賴物件B、C,建立C時,要先建立它的依賴物件A,此時,IOC容器檢查到singletonsCurrentlyInCreation中已經有這個A了,說明它已經在建立的過程中,只是還沒有完成建立,此時,IOC容器直接就使用這個工廠將A建立出來賦給C了,然後再往回完成B和A的建立。可以看一下addSingletonFactory方法的實現:

 1 protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
 2         Assert.notNull(singletonFactory, "Singleton factory must not be null");
 3         synchronized (this.singletonObjects) {
 4             if (!this.singletonObjects.containsKey(beanName)) {
 5                 this.singletonFactories.put(beanName, singletonFactory);
 6                 this.earlySingletonObjects.remove(beanName);
 7                 this.registeredSingletons.add(beanName);
 8             }
 9         }
10     }
1 public Object getSingleton(String beanName) {
2         return getSingleton(beanName, true);
3     }
 1 protected Object getSingleton(String beanName, boolean allowEarlyReference) {
 2         //從快取中獲取該bean的例項,已經填充了屬性值的例項
 3         Object singletonObject = this.singletonObjects.get(beanName);
 4         //建立bean時,IOC會在this.singletonsCurrentlyInCreation中存一個該bean的名稱,表示正在建立這個bean
 5         if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
 6             synchronized (this.singletonObjects) {
 7                 //也是從快取中獲取例項,但是這個快取中的例項是沒有經過填充的例項
 8                 singletonObject = this.earlySingletonObjects.get(beanName);
 9                 if (singletonObject == null && allowEarlyReference) {
10                     //獲取生成該bean的beanFactory
11                     ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
12                     if (singletonFactory != null) {
13                         //獲取這個bean的例項
14                         singletonObject = singletonFactory.getObject();
15                         //將這個還未經填充屬性的bean存入新生代快取中(自己取的名字,類似於JVM)
16                         this.earlySingletonObjects.put(beanName, singletonObject);
17                         //將這個生產bean的工廠移除
18                         this.singletonFactories.remove(beanName);
19                     }
20                 }
21             }
22         }
23         return (singletonObject != NULL_OBJECT ? singletonObject : null);
24     }

  在進行遞迴呼叫getBean方法建立依賴物件之前,getSignal方法是先呼叫的,前面的程式碼,doGetBean方法中可以看到,可以多看幾遍就能理解。另外,對於原型例項,不允許迴圈引用。迴圈引用只針對單例。下一篇跟蹤bean的屬性的填充。

相關文章