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

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到自己想要的點,所以也是讓自己持續進步的一種方式。加油,各位。

 

 

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

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

【精選推薦文章】

如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

想要讓你的商品在網路上成為最夯、最多人討論的話題?

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師"嚨底家"!!

您可能也會喜歡…