SpringBoot啟動流程分析(六):IoC容器依賴注入

超級小小黑發表於2019-06-25

SpringBoot系列文章簡介

SpringBoot原始碼閱讀輔助篇:

  Spring IoC容器與應用上下文的設計與實現

SpringBoot啟動流程原始碼分析:

  1. SpringBoot啟動流程分析(一):SpringApplication類初始化過程
  2. SpringBoot啟動流程分析(二):SpringApplication的run方法
  3. SpringBoot啟動流程分析(三):SpringApplication的run方法之prepareContext()方法
  4. SpringBoot啟動流程分析(四):IoC容器的初始化過程
  5. SpringBoot啟動流程分析(五):SpringBoot自動裝配原理實現
  6. SpringBoot啟動流程分析(六):IoC容器依賴注入

筆者註釋版Spring Framework與SpringBoot原始碼git傳送門:請不要吝嗇小星星

  1. spring-framework-5.0.8.RELEASE
  2. SpringBoot-2.0.4.RELEASE

一、前言

  前面我們對IoC容器的初始化過程進行了詳細的分析,這個初始化過程完成的主要工作是在IoC容器中建立BeanDefinition資料對映。在此過程中並沒有看到IoC容器對Bean依賴關係進行注入,接下來分析一下IoC容器是怎樣對Bean的依賴關係進行注入的。

  前面在refresh()-->invokeBeanFactoryPostProcessors(beanFactory);方法中已經完成了IoC容器的初始化並已經載入了我們定義的Bean的資訊(BeanDefinition),現在我們開始分析依賴注入的原理。首先需要說明的是依賴注入在使用者第一次向IoC容器索要Bean時觸發,當然也有例外,我們可以在BeanDefinition中中通過控制lazy-init屬性來讓容器完成對Bean的預例項化。這個預例項化實際上也是一個依賴注入的過程,但它是在初始化過程中完成的。

 

二、原始碼分析

2.1、getBean()的過程

  接著前面看refresh()方法,這已經是refresh()方法的第三篇博文了,別迷糊我們還沒走出refresh()方法。

 1 // AbstractApplicationContext類
 2 @Override
 3 public void refresh() throws BeansException, IllegalStateException {
 4     synchronized (this.startupShutdownMonitor) {
 5         ...
 6         try {
 7             ...
 8             // Instantiate all remaining (non-lazy-init) singletons.
 9             finishBeanFactoryInitialization(beanFactory);
10             ...
11         }
12         ...
13     }
14 }
15 // AbstractApplicationContext類
16 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
17     ...
18     // Instantiate all remaining (non-lazy-init) singletons.
19     // 例項化所有剩餘的(non-lazy-init)單例。
20     beanFactory.preInstantiateSingletons();
21 }
22 // DefaultListableBeanFactory類
23 @Override
24 public void preInstantiateSingletons() throws BeansException {
25     ...
26     // Iterate over a copy to allow for init methods which in turn register new bean definitions.
27     // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
28     List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
29     // Trigger initialization of all non-lazy singleton beans...
30     for (String beanName : beanNames) {
31         RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
32         if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
33             if (isFactoryBean(beanName)) {
34                 Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
35                 if (bean instanceof FactoryBean) {
36                     final FactoryBean<?> factory = (FactoryBean<?>) bean;
37                     boolean isEagerInit;
38                     if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
39                         isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
40                                         ((SmartFactoryBean<?>) factory)::isEagerInit,
41                                 getAccessControlContext());
42                     } else {
43                         isEagerInit = (factory instanceof SmartFactoryBean &&
44                                 ((SmartFactoryBean<?>) factory).isEagerInit());
45                     }
46                     if (isEagerInit) {
47                         getBean(beanName);
48                     }
49                 }
50             } else {
51                 // 這裡就是觸發依賴注入的地方
52                 getBean(beanName);
53             }
54         }
55     }
56     ...
57 }

   跟蹤其呼叫棧,看到上面第52行的getBean(beanName);方法,我們再梳理一下getBean()方法,前面總結過該方法在IoC容器的頂層介面BeanFactory中定義,然後在IoC容器的具體產品DefaultListableBeanFactory類的基類AbstractBeanFactory實現了getBean()方法。接著看程式碼。

 1 // AbstractBeanFactory類
 2 @Override
 3 public Object getBean(String name) throws BeansException {
 4     return doGetBean(name, null, null, false);
 5 }
 6 @Override
 7 public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException {
 8     return doGetBean(name, requiredType, null, false);
 9 }
10 @Override
11 public Object getBean(String name, Object... args) throws BeansException {
12     return doGetBean(name, null, args, false);
13 }
14 public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
15         throws BeansException {
16     return doGetBean(name, requiredType, args, false);
17 }

  從上面程式碼可知大致可分為兩種獲取Bean的引數,一種是按名獲取,一種是按類獲取。但是最終都進入到了doGetBean()方法。

  1 // AbstractBeanFactory類
  2 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
  3         @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
  4 
  5     // bean獲取過程:先獲取bean名字
  6     // 會把帶有&字首的去掉,或者去aliasMap中找這個是不是別名,最終確定bean的id是什麼
  7     final String beanName = transformedBeanName(name);
  8     Object bean;
  9 
 10     // 1.檢查快取中或者例項工廠中是否有對應的例項
 11     // 因為在建立單例bean的時候會存在依賴注入的情況,而在建立依賴的時候為了避免迴圈依賴
 12     // Spring在建立bean的時候不會等bean建立完成就會將bean的ObjectFactory提早曝光
 13     // 也就是將ObjectFactory加入到快取中,一旦下一個要建立的bean需要依賴上個bean則直接使用ObjectFactory
 14     // 2.spring 預設是單例的,如果能獲取到直接返回,提高效率。
 15     // Eagerly check singleton cache for manually registered singletons.
 16     Object sharedInstance = getSingleton(beanName);
 17     if (sharedInstance != null && args == null) {
 18         if (logger.isDebugEnabled()) {
 19             if (isSingletonCurrentlyInCreation(beanName)) {
 20                 logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
 21                         "' that is not fully initialized yet - a consequence of a circular reference");
 22             }
 23             else {
 24                 logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
 25             }
 26         }
 27         // 用於檢測bean的正確性,同時如果獲取的是FactoryBean的話還需要呼叫getObject()方法獲取最終的那個bean例項
 28         bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
 29     }
 30 
 31     else {
 32         // Fail if we're already creating this bean instance:
 33         // We're assumably within a circular reference.
 34         if (isPrototypeCurrentlyInCreation(beanName)) {
 35             throw new BeanCurrentlyInCreationException(beanName);
 36         }
 37 
 38         // Check if bean definition exists in this factory.
 39         //這裡對IoC容器中的BeanDefinition是否存在進行檢查,檢查是否能在當前的BeanFactory中取得需要的Bean。
 40         // 如果當前的工廠中取不到,則到雙親BeanFactory中去取。如果當前的雙親工廠取不到,那就順著雙親BeanFactory
 41         // 鏈一直向上查詢。
 42         BeanFactory parentBeanFactory = getParentBeanFactory();
 43         if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 44             // Not found -> check parent.
 45             String nameToLookup = originalBeanName(name);
 46             if (parentBeanFactory instanceof AbstractBeanFactory) {
 47                 // 遞迴呼叫父bean的doGetBean查詢
 48                 return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
 49                         nameToLookup, requiredType, args, typeCheckOnly);
 50             }
 51             else if (args != null) {
 52                 // Delegation to parent with explicit args.
 53                 return (T) parentBeanFactory.getBean(nameToLookup, args);
 54             }
 55             else {
 56                 // No args -> delegate to standard getBean method.
 57                 return parentBeanFactory.getBean(nameToLookup, requiredType);
 58             }
 59         }
 60 
 61         if (!typeCheckOnly) {
 62             markBeanAsCreated(beanName);
 63         }
 64 
 65         try {
 66             //這裡根據Bean的名字取得BeanDefinition
 67             final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 68             checkMergedBeanDefinition(mbd, beanName, args);
 69 
 70             // Guarantee initialization of beans that the current bean depends on.
 71             //獲取當前Bean的所有依賴Bean,這裡會觸發getBean的遞迴呼叫。知道取到一個沒有任何依賴的Bean為止。
 72             String[] dependsOn = mbd.getDependsOn();
 73             if (dependsOn != null) {
 74                 for (String dep : dependsOn) {
 75                     if (isDependent(beanName, dep)) {
 76                         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 77                                 "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
 78                     }
 79                     registerDependentBean(dep, beanName);
 80                     try {
 81                         getBean(dep);
 82                     }
 83                     catch (NoSuchBeanDefinitionException ex) {
 84                         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 85                                 "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
 86                     }
 87                 }
 88             }
 89 
 90             // 這裡通過createBean方法建立singleton Bean的例項 這裡還有一個回撥函式
 91             // Create bean instance.
 92             if (mbd.isSingleton()) {
 93                 sharedInstance = getSingleton(beanName, () -> {
 94                     try {
 95                         // 最後在getSingleton中又會呼叫這個方法
 96                         // TODO createBean的入口
 97                         return createBean(beanName, mbd, args);
 98                     }
 99                     catch (BeansException ex) {
100                         // Explicitly remove instance from singleton cache: It might have been put there
101                         // eagerly by the creation process, to allow for circular reference resolution.
102                         // Also remove any beans that received a temporary reference to the bean.
103                         destroySingleton(beanName);
104                         throw ex;
105                     }
106                 });
107                 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
108             }
109             // 這裡是建立prototype bean的地方
110             else if (mbd.isPrototype()) {
111                 // It's a prototype -> create a new instance.
112                 Object prototypeInstance = null;
113                 try {
114                     beforePrototypeCreation(beanName);
115                     prototypeInstance = createBean(beanName, mbd, args);
116                 }
117                 finally {
118                     afterPrototypeCreation(beanName);
119                 }
120                 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
121             }
122 
123             else {
124                 String scopeName = mbd.getScope();
125                 final Scope scope = this.scopes.get(scopeName);
126                 if (scope == null) {
127                     throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
128                 }
129                 try {
130                     Object scopedInstance = scope.get(beanName, () -> {
131                         beforePrototypeCreation(beanName);
132                         try {
133                             return createBean(beanName, mbd, args);
134                         }
135                         finally {
136                             afterPrototypeCreation(beanName);
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     //這裡對建立的Bean進行型別檢查,如果沒有問題,就返回這個新建立的Bean,這個Bean已經是包含了依賴關係的Bean
157     if (requiredType != null && !requiredType.isInstance(bean)) {
158         try {
159             T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
160             if (convertedBean == null) {
161                 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
162             }
163             return convertedBean;
164         }
165         catch (TypeMismatchException ex) {
166             if (logger.isDebugEnabled()) {
167                 logger.debug("Failed to convert bean '" + name + "' to required type '" +
168                         ClassUtils.getQualifiedName(requiredType) + "'", ex);
169             }
170             throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
171         }
172     }
173     return (T) bean;
174 }

  這個就是依賴注入的入口了,依賴注入是在容器的BeanDefinition資料已經建立好的前提下進行的。“程式=資料+演算法”,很經典的一句話,前面我們詳細介紹了BeanDefinition的註冊過程,BeanDefinition就是資料。如上面程式碼所示,doGetBean()方法不涉及複雜的演算法,但是這個過程也不是很簡單,因為我們都知道,對於IoC容器的使用,Spring提供了很多的配置引數,每一個配置引數實際上就代表了一個IoC容器的實現特徵,這些特徵很多都需要在依賴注入的過程或者對Bean進行生命週期管理的過程中完成。雖然我們可以簡單的將IoC容器描述成一個ConcurrentHashMap,ConcurrentHashMap只是它的資料結構而不是IoC容器的全部。

TIPS:
  1,我在工程中簡單寫了一個controller和一個service,我們在後面debug看看依賴注入的過程是怎麼樣的,
也不知道我能不能說清楚。希望大家看到這一塊多debug一下,debug技巧如下圖所示,寫了debug的條件,
因為這邊到處都是遞迴和回撥函式,再加上有很多Spring的Bean,但是我們只關心自己的Bean,
所以就寫了這樣的過濾條件:beanName.equals("webController")||beanName.equals("webService")
@RestController
public class WebController {
    @Autowired
    private WebService webService;

    @RequestMapping("/web")
    public String web(){
        return webService.hello();
    }
}

 

  下面我們通過程式碼看看獲取bean的過程。

  OK,看程式碼,Object sharedInstance = getSingleton(beanName);如註釋所說,首先回去找在容器中是不是已經存在該單例。具體在哪找我們在前面的文章中已經說得很清楚了。看一下getSingleton()方法

 1 // DefaultSingletonBeanRegistry類
 2 protected Object getSingleton(String beanName, boolean allowEarlyReference) {
 3     // 由於scope是singleton,所以先從快取中取單例物件的例項,如果取到直接返回,沒有取到載入bean
 4     Object singletonObject = this.singletonObjects.get(beanName);
 5     // 當想要獲取的bean沒有被載入,並且也沒有正在被建立的時候,主動去載入bean
 6     if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
 7         // 鎖住單例快取區載入bean
 8         synchronized (this.singletonObjects) {
 9             // singletonObjects ,earlySingletonObjects ,singletonFactories是一個單例例項的三種存在狀態
10             // 再去earlySingletonObjects中去找
11             singletonObject = this.earlySingletonObjects.get(beanName);
12             if (singletonObject == null && allowEarlyReference) {
13                 // 去singletonFactories中去找物件的例項
14                 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
15                 if (singletonFactory != null) {
16                     singletonObject = singletonFactory.getObject();
17                     this.earlySingletonObjects.put(beanName, singletonObject);
18                     this.singletonFactories.remove(beanName);
19                 }
20             }
21         }
22     }
23     return singletonObject;
24 }

 

   在DefaultSingletonBeanRegistry類中的singletonObjects屬性就是存singleton bean的地方。

  如果getSingleton()為 null繼續往下看,會在當前的BeanFactory中獲取BeanDefinition,也就是這行方法程式碼:final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);在這行程式碼拿到BeanDefinition後,首先判斷是不是singleton Bean,如果是的話,開始執行建立Bean,正是return createBean(beanName, mbd, args);這行程式碼。如果是原型(Prototype)Bean我們就不分析了。原型bean每次執行getBean()都會建立一個例項。接下來我們看createBean()方法。

2.2、createBean()的過程

  首先看一下create bean的過程

1,Bean例項的建立
2,為Bean例項設定屬性(屬性注入,其實就是依賴注入真正發生的地方)
3,呼叫Bean的初始化方法

  前面說了getBean()是依賴注入的起點,之後會呼叫createBean(),下面通過createBean()程式碼來了解這個過程。在這個過程中,Bean物件會根據BeanDefinition定義的要求生成。

 1 // AbstractAutowireCapableBeanFactory類
 2 @Override
 3 protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
 4         throws BeanCreationException {
 5     ...
 6     try {
 7         // 驗證以及準備override的方法
 8         mbdToUse.prepareMethodOverrides();
 9     }
10     catch (BeanDefinitionValidationException ex) {
11         throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
12                 beanName, "Validation of method overrides failed", ex);
13     }
14     try {
15         // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
16         // createBean之前呼叫BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法
17         // 預設不做任何處理所以會返回null
18         // 但是如果我們重寫了這兩個方法,那麼bean的建立過程就結束了,這裡就為以後的annotation自動注入提供了鉤子
19         Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
20         if (bean != null) {
21             return bean;
22         }
23     }catch (Throwable ex) {
24         throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
25                 "BeanPostProcessor before instantiation of bean failed", ex);
26     }
27     try {
28         // 實際執行createBean的是doCreateBean()方法
29         Object beanInstance = doCreateBean(beanName, mbdToUse, args);
30         if (logger.isDebugEnabled()) {
31             logger.debug("Finished creating instance of bean '" + beanName + "'");
32         }
33         return beanInstance;
34     }
35     catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
36         // A previously detected exception with proper bean creation context already,
37         // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
38         throw ex;
39     }
40     catch (Throwable ex) {
41         throw new BeanCreationException(
42                 mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
43     }
44 }

   接著往下看doCreateBean()方法。

  1 // AbstractAutowireCapableBeanFactory類
  2 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
  3         throws BeanCreationException {
  4     // BeanWrapper是用來持有建立出來的Bean物件
  5     // Instantiate the bean.
  6     BeanWrapper instanceWrapper = null;
  7     // 如果是單例,先把快取中的同名Bean清除
  8     if (mbd.isSingleton()) {
  9         instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
 10     }
 11     // 這裡是建立Bean的地方,由createBeanInstance完成。
 12     // TODO 完成Bean初始化過程的第一步:建立例項
 13     if (instanceWrapper == null) {
 14         instanceWrapper = createBeanInstance(beanName, mbd, args);
 15     }
 16     final Object bean = instanceWrapper.getWrappedInstance();
 17     Class<?> beanType = instanceWrapper.getWrappedClass();
 18     if (beanType != NullBean.class) {
 19         mbd.resolvedTargetType = beanType;
 20     }
 21 
 22     // Allow post-processors to modify the merged bean definition.
 23     synchronized (mbd.postProcessingLock) {
 24         if (!mbd.postProcessed) {
 25             try {
 26                 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
 27             }
 28             catch (Throwable ex) {
 29                 throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 30                         "Post-processing of merged bean definition failed", ex);
 31             }
 32             mbd.postProcessed = true;
 33         }
 34     }
 35 
 36     // Eagerly cache singletons to be able to resolve circular references
 37     // even when triggered by lifecycle interfaces like BeanFactoryAware.
 38     // 是否自動解決迴圈引用
 39     // 當bean條件為: 單例&&允許迴圈引用&&正在建立中這樣的話提早暴露一個ObjectFactory
 40     boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
 41             isSingletonCurrentlyInCreation(beanName));
 42     if (earlySingletonExposure) {
 43         if (logger.isDebugEnabled()) {
 44             logger.debug("Eagerly caching bean '" + beanName +
 45                     "' to allow for resolving potential circular references");
 46         }
 47         // 把ObjectFactory放進singletonFactories中
 48         // 這裡在其他bean在建立的時候會先去singletonFactories中查詢有沒有beanName到ObjectFactory的對映
 49         // 如果有ObjectFactory就呼叫它的getObject方法獲取例項
 50         // 但是在這裡就可以對一個bean進行保證,代理等等AOP就可以在getEarlyBeanReference這裡實現
 51         addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
 52     }
 53 
 54     // Initialize the bean instance.
 55     Object exposedObject = bean;
 56     try {
 57         // TODO 完成Bean初始化過程的第二步:為Bean的例項設定屬性
 58         // Bean依賴注入發生的地方
 59         // 對bean進行屬性填充,如果存在依賴於其他的bean的屬性,則會遞迴的呼叫初始化依賴的bean
 60         populateBean(beanName, mbd, instanceWrapper);
 61         // TODO 完成Bean初始化過程的第三步:呼叫Bean的初始化方法(init-method)
 62         // 呼叫初始化方法,比如init-method方法指定的方法
 63         exposedObject = initializeBean(beanName, exposedObject, mbd);
 64     }
 65     catch (Throwable ex) {
 66         if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
 67             throw (BeanCreationException) ex;
 68         }
 69         else {
 70             throw new BeanCreationException(
 71                     mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
 72         }
 73     }
 74 
 75     if (earlySingletonExposure) {
 76         Object earlySingletonReference = getSingleton(beanName, false);
 77         if (earlySingletonReference != null) {
 78             if (exposedObject == bean) {
 79                 exposedObject = earlySingletonReference;
 80             }
 81             else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
 82                 String[] dependentBeans = getDependentBeans(beanName);
 83                 Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
 84                 for (String dependentBean : dependentBeans) {
 85                     if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
 86                         actualDependentBeans.add(dependentBean);
 87                     }
 88                 }
 89                 if (!actualDependentBeans.isEmpty()) {
 90                     throw new BeanCurrentlyInCreationException(beanName,
 91                             "Bean with name '" + beanName + "' has been injected into other beans [" +
 92                             StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
 93                             "] in its raw version as part of a circular reference, but has eventually been " +
 94                             "wrapped. This means that said other beans do not use the final version of the " +
 95                             "bean. This is often the result of over-eager type matching - consider using " +
 96                             "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
 97                 }
 98             }
 99         }
100     }
101 
102     // Register bean as disposable.
103     try {
104         // 註冊銷燬方法,比如:可以在配置bean的時候指定destory-method方法
105         registerDisposableBeanIfNecessary(beanName, bean, mbd);
106     }
107     catch (BeanDefinitionValidationException ex) {
108         throw new BeanCreationException(
109                 mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
110     }
111 
112     return exposedObject;
113 }

  結合上面的程式碼,我們再來看一下建立Bean的三個步驟,是不是有點豁然開朗的感覺。彆著急繼續往下看。

1,Bean例項的建立,instanceWrapper = createBeanInstance(beanName, mbd, args);
2,為Bean例項設定屬性,populateBean(beanName, mbd, instanceWrapper);
3,呼叫Bean的初始化方法,exposedObject = initializeBean(beanName, exposedObject, mbd);

 

2.2.1、createBeanInstance():Bean例項的建立

  看程式碼

 1 // AbstractAutowireCapableBeanFactory類
 2 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
 3     // Make sure bean class is actually resolved at this point.
 4     // 確認需要建立的Bean的例項的類可以例項化
 5     Class<?> beanClass = resolveBeanClass(mbd, beanName);
 6 
 7     if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
 8         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 9                 "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
10     }
11 
12     Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
13     if (instanceSupplier != null) {
14         return obtainFromSupplier(instanceSupplier, beanName);
15     }
16 
17     // 當有工廠方法的時候使用工廠方法初始化Bean,就是配置的時候指定FactoryMethod屬性,類似註解中的@Bean把方法的返回值作為Bean
18     if (mbd.getFactoryMethodName() != null)  {
19         return instantiateUsingFactoryMethod(beanName, mbd, args);
20     }
21 
22     // Shortcut when re-creating the same bean...
23     boolean resolved = false;
24     boolean autowireNecessary = false;
25     if (args == null) {
26         synchronized (mbd.constructorArgumentLock) {
27             if (mbd.resolvedConstructorOrFactoryMethod != null) {
28                 resolved = true;
29                 autowireNecessary = mbd.constructorArgumentsResolved;
30             }
31         }
32     }
33     if (resolved) {
34         if (autowireNecessary) {
35             // 如果有有引數的建構函式,建構函式自動注入
36             // 這裡spring會花費大量的精力去進行引數的匹配
37             return autowireConstructor(beanName, mbd, null, null);
38         }
39         else {
40             // 如果沒有有參建構函式,使用預設建構函式構造
41             return instantiateBean(beanName, mbd);
42         }
43     }
44 
45     // Need to determine the constructor...
46     // 使用建構函式進行例項化
47     Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
48     if (ctors != null ||
49             mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
50             mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
51         return autowireConstructor(beanName, mbd, ctors, args);
52     }
53 
54     // No special handling: simply use no-arg constructor.
55     // 使用預設的建構函式對Bean進行例項化
56     return instantiateBean(beanName, mbd);
57 }

 

  我們可以看到在instantiateBean()方法中生成了Bean所包含的Java物件,這個物件的生成有很多種不同的方式,可以通過工廠方法生成,也可以通過容器的autowire特性生成,這些生成方式都是由BeanDefinition決定的。對於上面我們的WebController和WebService兩個類是通過最後一行,使用預設的建構函式進行Bean的例項化。

  接著看instantiateBean()方法。

 1 // AbstractAutowireCapableBeanFactory類
 2 protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
 3     // 使用預設的例項化策略對Bean進行例項化,預設的例項化策略是CglibSubclassingInstantiationStrategy,
 4     // 也就是常說的CGLIB來對Bean進行例項化。PS:面試官常問的位元組碼增強
 5     try {
 6         Object beanInstance;
 7         final BeanFactory parent = this;
 8         if (System.getSecurityManager() != null) {
 9             beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
10                     getInstantiationStrategy().instantiate(mbd, beanName, parent),
11                     getAccessControlContext());
12         }
13         else {
14             // getInstantiationStrategy()會返回CglibSubclassingInstantiationStrategy類的例項
15             beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
16         }
17         BeanWrapper bw = new BeanWrapperImpl(beanInstance);
18         initBeanWrapper(bw);
19         return bw;
20     }
21     catch (Throwable ex) {
22         throw new BeanCreationException(
23                 mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
24     }
25 }

  這裡使用CGLIB進行Bean的例項化。CGLIB是一個常用的位元組碼生成器的類庫,其提供了一系列的API來提供生成和轉換Java位元組碼的功能。在Spring AOP中同樣也是使用的CGLIB對Java的位元組碼進行增強。在IoC容器中,使用SimpleInstantiationStrategy類。這個類是Spring用來生成Bean物件的預設類,它提供了兩種例項化Java物件的方法,一種是通過BeanUtils,它使用的是JVM的反射功能,一種是通過CGLIB來生成。

  getInstantiationStrategy()方法獲取到CglibSubclassingInstantiationStrategy例項,instantiate()是CglibSubclassingInstantiationStrategy類的父類SimpleInstantiationStrategy實現的。

  繼續看程式碼

 1 // SimpleInstantiationStrategy類
 2 @Override
 3 public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
 4     // Don't override the class with CGLIB if no overrides.
 5     // 如果BeanFactory重寫了Bean內的方法,則使用CGLIB,否則使用BeanUtils
 6     if (!bd.hasMethodOverrides()) {
 7         // 如果bean沒有需要動態替換的方法就直接反射進行建立例項
 8         Constructor<?> constructorToUse;
 9         synchronized (bd.constructorArgumentLock) {
10             constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
11             if (constructorToUse == null) {
12                 final Class<?> clazz = bd.getBeanClass();
13                 if (clazz.isInterface()) {
14                     throw new BeanInstantiationException(clazz, "Specified class is an interface");
15                 }
16                 try {
17                     if (System.getSecurityManager() != null) {
18                         constructorToUse = AccessController.doPrivileged(
19                                 (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
20                     } else {
21                         constructorToUse = clazz.getDeclaredConstructor();
22                     }
23                     bd.resolvedConstructorOrFactoryMethod = constructorToUse;
24                 } catch (Throwable ex) {
25                     throw new BeanInstantiationException(clazz, "No default constructor found", ex);
26                 }
27             }
28         }
29         // 通過BeanUtils進行例項化,這個BeanUtils的例項化通過Constructor類例項化Bean
30         // 在BeanUtils中可以看到具體的呼叫ctor.newInstances(args)
31         return BeanUtils.instantiateClass(constructorToUse);
32     } else {
33         // Must generate CGLIB subclass.
34         // TODO 使用CGLIB例項化物件
35         return instantiateWithMethodInjection(bd, beanName, owner);
36     }
37 }

  在SpringBoot中我們一般採用@Autowire的方式進行依賴注入,很少採用像SpringMVC那種在xml中使用<lookup-method>或者<replaced-method>等標籤的方式對注入的屬性進行override,所以在上面的程式碼中if(!bd.hasMethodOverrides())中的判斷為true,會採用BeanUtils的例項化方式。

 

2.2.2、populateBean();屬性設定(依賴注入)

  看程式碼

 1 protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
 2     if (bw == null) {
 3         if (mbd.hasPropertyValues()) {
 4             throw new BeanCreationException(
 5                     mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
 6         }
 7         else {
 8             // Skip property population phase for null instance.
 9             return;
10         }
11     }
12     // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
13     // state of the bean before properties are set. This can be used, for example,
14     // to support styles of field injection.
15     boolean continueWithPropertyPopulation = true;
16     // 呼叫InstantiationAwareBeanPostProcessor  Bean的後置處理器,在Bean注入屬性前改變BeanDefinition的資訊
17     if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
18         for (BeanPostProcessor bp : getBeanPostProcessors()) {
19             if (bp instanceof InstantiationAwareBeanPostProcessor) {
20                 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
21                 if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
22                     continueWithPropertyPopulation = false;
23                     break;
24                 }
25             }
26         }
27     }
28     if (!continueWithPropertyPopulation) {
29         return;
30     }
31     // 這裡取得在BeanDefinition中設定的property值,這些property來自對BeanDefinition的解析
32     // 用於在配置檔案中通過<property>配置的屬性並且顯示在配置檔案中配置了autowireMode屬性
33     PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
34     if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
35             mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
36         MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
37 
38         // Add property values based on autowire by name if applicable.
39         // 這裡對autowire注入的處理,autowire by name
40         if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
41             autowireByName(beanName, mbd, bw, newPvs);
42         }
43 
44         // Add property values based on autowire by type if applicable.
45         // 這裡對autowire注入的處理, autowire by type
46         // private List<Test> tests;
47         if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
48             autowireByType(beanName, mbd, bw, newPvs);
49         }
50 
51         pvs = newPvs;
52     }
53     boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
54     boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
55     if (hasInstAwareBpps || needsDepCheck) {
56         if (pvs == null) {
57             pvs = mbd.getPropertyValues();
58         }
59         PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
60         if (hasInstAwareBpps) {
61             for (BeanPostProcessor bp : getBeanPostProcessors()) {
62                 if (bp instanceof InstantiationAwareBeanPostProcessor) {
63                     InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
64                     // TODO @Autowire @Resource @Value @Inject 等註解的依賴注入過程
65                     pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
66                     if (pvs == null) {
67                         return;
68                     }
69                 }
70             }
71         }
72         if (needsDepCheck) {
73             checkDependencies(beanName, mbd, filteredPds, pvs);
74         }
75     }
76     if (pvs != null) {
77         // 注入配置檔案中<property>配置的屬性
78         applyPropertyValues(beanName, mbd, bw, pvs);
79     }
80 }

  上面方法中的31-52行以及78行的applyPropertyValues()方法基本都是用於SpringMVC中採用xml配置Bean的方法。所以我們不做介紹了。看註釋知道幹嘛的就行了。我們主要看的是pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);這行程式碼,這行程式碼是真正執行採用@Autowire @Resource @Value @Inject 等註解的依賴注入過程。

  接著往下看

 1 // AutowiredAnnotationBeanPostProcessor類
 2 @Override
 3 public PropertyValues postProcessPropertyValues(
 4         PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
 5     // 遍歷,獲取@Autowire,@Resource,@Value,@Inject等具備註入功能的註解
 6     InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
 7     try {
 8         // 屬性注入
 9         metadata.inject(bean, beanName, pvs);
10     } catch (BeanCreationException ex) {
11         throw ex;
12     } catch (Throwable ex) {
13         throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
14     }
15     return pvs;
16 }

  AutowiredAnnotationBeanPostProcessor類實現了postProcessPropertyValues()方法。findAutowiringMetadata(beanName, bean.getClass(), pvs);方法會尋找在當前類中的被@Autowire,@Resource,@Value,@Inject等具備註入功能的註解的屬性。

  debug看一下結果,如下圖所示,成功得到了@Autowire註解的屬性webService。

  metadata.inject(bean, beanName, pvs);方法開始執行注入的邏輯。

 1 // AutowiredAnnotationBeanPostProcessor類
 2 @Override
 3 protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
 4     // 需要注入的欄位
 5     Field field = (Field) this.member;
 6     // 需要注入的屬性值
 7     Object value;
 8     if (this.cached) {
 9         value = resolvedCachedArgument(beanName, this.cachedFieldValue);
10     } else {
11         // @Autowired(required = false),當在該註解中設定為false的時候,如果有直接注入,沒有跳過,不會報錯。
12         DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
13         desc.setContainingClass(bean.getClass());
14         Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
15         Assert.state(beanFactory != null, "No BeanFactory available");
16         TypeConverter typeConverter = beanFactory.getTypeConverter();
17         try {
18             // 通過BeanFactory 解決依賴關係
19             // 比如在webController中注入了webService,這個會去BeanFactory中去獲取webService,也就是getBean()的邏輯。
20             // 如果存在直接返回,不存在再執行createBean()邏輯。
21             // 如果在webService中依然依賴,依然會去遞迴。
22             // 這裡是一個複雜的遞迴邏輯。
23             value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
24         } catch (BeansException ex) {
25             throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
26         }
27         synchronized (this) {
28             if (!this.cached) {
29                 if (value != null || this.required) {
30                     this.cachedFieldValue = desc;
31                     registerDependentBeans(beanName, autowiredBeanNames);
32                     if (autowiredBeanNames.size() == 1) {
33                         String autowiredBeanName = autowiredBeanNames.iterator().next();
34                         if (beanFactory.containsBean(autowiredBeanName) &&
35                                 beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
36                             this.cachedFieldValue = new ShortcutDependencyDescriptor(
37                                     desc, autowiredBeanName, field.getType());
38                         }
39                     }
40                 } else {
41                     this.cachedFieldValue = null;
42                 }
43                 this.cached = true;
44             }
45         }
46     }
47     if (value != null) {
48         ReflectionUtils.makeAccessible(field);
49         field.set(bean, value);
50     }
51 }

  debug看一下field。如下圖所示正是我們的webService

  看這行程式碼:value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);注意beanFactory依舊是我們熟悉的IoC容器的具體產品,也就是實現類DefaultListableBeanFactory。見到就說一遍,方便大家記住它,很重要。

  在resolveDependency()方法中經過一頓操作,最終又會來到上面的getBean()方法。以上就是依賴注入的整個過程。注意看程式碼中的註釋哦。

2.2.3、initializeBean():呼叫Bean的初始化方法

  設定Bean的初始化方法有兩種方法,一種是在xml或者@Bean指定init-method方法。另一種是讓bean實現InitializingBean介面重寫afterPropertiesSet()方法。

 1 // AbstractAutowireCapableBeanFactory類
 2 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
 3     if (System.getSecurityManager() != null) {
 4         AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
 5             invokeAwareMethods(beanName, bean);
 6             return null;
 7         }, getAccessControlContext());
 8     }
 9     else {
10         //在呼叫Bean的初始化方法之前,呼叫一系列的aware介面實現,把相關的BeanName,BeanClassLoader,以及BeanFactory注入到Bean中去。
11         invokeAwareMethods(beanName, bean);
12     }
13 
14     Object wrappedBean = bean;
15     if (mbd == null || !mbd.isSynthetic()) {
16         // 這些都是鉤子方法,在反覆的呼叫,給Spring帶來了極大的可擴充性
17         // 初始化之前呼叫BeanPostProcessor
18         wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
19     }
20 
21     try {
22         // 呼叫指定的init-method方法
23         invokeInitMethods(beanName, wrappedBean, mbd);
24     }
25     catch (Throwable ex) {
26         throw new BeanCreationException(
27                 (mbd != null ? mbd.getResourceDescription() : null),
28                 beanName, "Invocation of init method failed", ex);
29     }
30     if (mbd == null || !mbd.isSynthetic()) {
31         // 這些都是鉤子方法,在反覆的呼叫,給Spring帶來了極大的可擴充性
32         // 初始化之後呼叫BeanPostProcessor
33         wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
34     }
35 
36     return wrappedBean;
37 }

  在呼叫Bean的初始化方法之前,呼叫一系列的aware介面實現,把相關的BeanName,BeanClassLoader,以及BeanFactory注入到Bean中去。接著會執行invokeInitMethods()方法。

 1 // AbstractAutowireCapableBeanFactory類
 2 protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
 3         throws Throwable {
 4     // 除了使用init-method指定的初始化方法,還可以讓bean實現InitializingBean介面重寫afterPropertiesSet()方法
 5     boolean isInitializingBean = (bean instanceof InitializingBean);
 6     if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
 7         if (logger.isDebugEnabled()) {
 8             logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
 9         }
10         if (System.getSecurityManager() != null) {
11             try {
12                 AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
13                     ((InitializingBean) bean).afterPropertiesSet();
14                     return null;
15                 }, getAccessControlContext());
16             }
17             catch (PrivilegedActionException pae) {
18                 throw pae.getException();
19             }
20         }
21         else {
22             // 執行afterPropertiesSet()方法進行初始化
23             ((InitializingBean) bean).afterPropertiesSet();
24         }
25     }
26 
27     // 先執行afterPropertiesSet()方法,再進行init-method
28     if (mbd != null && bean.getClass() != NullBean.class) {
29         String initMethodName = mbd.getInitMethodName();
30         if (StringUtils.hasLength(initMethodName) &&
31                 !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
32                 !mbd.isExternallyManagedInitMethod(initMethodName)) {
33             invokeCustomInitMethod(beanName, bean, mbd);
34         }
35     }
36 }

  可見該方法中首先判斷Bean是否配置了init-method方法,如果有,那麼通過invokeCustomInitMethod()方法來直接呼叫。其中在invokeCustomInitMethod()方法中是通過JDK的反射機制得到method物件,然後呼叫的init-method。最終完成Bean的初始化。

 

三、總結

  SpringBoot啟動流程相關的博文到這裡就結束了,在前面的文章中,我們詳細介紹了IoC容器的設計與實現,並結合SpringBoot的啟動流程介紹了IoC容器的初始化過程,及IoC容器的依賴注入,及大家都很關心的SpringBoot是如何實現自動裝配的。關於SpringBoot的原始碼分析基本就到這裡了,後面有計劃寫寫AOP的實現,以及很重要的Spring事務實現。

  小半個月時間,熬了很多個凌晨,終於寫完了SpringBoot啟動流程系列博文。有辛苦更有收穫,我是從今年才開始寫部落格的,以前每當想寫的時候,總想什麼時候能力足夠了,憋個大招再寫。回過頭來看之前的想法是十分錯誤的,寫博文不只是為了分享,最重要的是在寫部落格的過程中能夠系統的梳理一下某一個技術棧的知識。好記性不如爛筆頭,看別人的部落格很難get到自己想要的點,所以也是讓自己持續進步的一種方式。加油,各位。

 

 

  原創不易,轉載請註明出處。

  如有錯誤的地方還請留言指正。

相關文章