Spring 源碼分析之 bean 依賴注入原理(注入屬性)


最近在研究Spring bean 生命周期相關知識點以及源碼,所以打算寫一篇 Spring bean生命周期相關的文章,但是整理過程中發現涉及的點太多而且又很復雜,很難在一篇文章中把Spring bean 的生命周期講清楚,所以最后決定分解成幾個模塊來寫,最后在寫一篇文章把各個內容串聯起來,這樣可以講的更細更深入不會猶豫篇幅而講的太籠統。bean 生命周期所涉及的主要流程如下圖所示。

 

本文想寫bean 生命周期的第二階段 bean 的依賴注入(注入屬性)部分按下面幾個步驟來講解。

  • Spring容器與依賴注入
  • 什么時候會觸發依賴注入?
  • 關於依賴注入與屬性注入的幾點說明
  • 解析Spring 依賴注入源碼部分
  • 總結

一. Spring容器與依賴注入

Spring最有名的高級特性非ioc莫屬了,雖然ioc 不是本次要討論的重點,但還是有必要說一下。對於Spring的ioc我不想過多教科書式的解釋這名次,我也相信每個使用Spring的程序員都有自己的理解,只是有時很難把自己的理解清楚的解釋給別人而已。下面我說說我自己的理解,有說錯的地方歡迎大家指正。Spring ioc 至少要具備一下兩點功能:

准備Bean 整個生命周期需要的數據

這一步是Spring 容器啟動的時候會 定位 我們的配置文件, 加載 文件,並 解析 成Bean的定義文件 BeanDefinition 來為下一步作准備,這個 BeanDefinition 會貫穿Spring 啟動初始化的整個流程,非常重要,因為他是數據基礎。

管理Bean的整個生命周期

  • 需要具備創建一個Bean的功能
  • 需要具備根據Bean與Bean之間的關系依賴注入功能(本次要講的內容)
  • 需要能夠執行初始化方法以及銷毀方法

有了以上幾個功能之后Spring ioc 就能夠控制bean的流程了,這不控制反轉了么。而我們只需用注解或者配置文件配置bean的特性以及依賴關系即可。下面說一下有關ApplicationContext 和 BeanDefinition:

1. 核心容器ApplicationContext

上述這些功能都可以由Spring容器(比如 ApplicationContext )來實現,Spring啟動時會把所有需要的bean掃描並注冊到容器里,在這個過程當中Spring會根據我們定義的bean之間的依賴關系來進行注入,依賴關系的維護方式有兩種即 XML配置 文件或者 注解 ,Spring啟動時會把這些依賴關系轉化成Spring能夠識別的數據結構 BeanDefinition ,並根據它來進行bean的初始化,依賴注入等操作。下面看看一個簡單的Spring容器如下圖:

pring 依賴注入的實現是由像ApplicationContext這種容器來實現的,右邊的Map里存儲這bean之間的依賴關系的定義BeanDefinition,比如OrderController依賴OrderService這種,具體定義下面介紹。

結論:BeanDefinition提供了原材料數據基礎,而ApplicationContext 提供了流程的設計與實現的算法

2. Bean依賴關系的定義

我們需要為Spring容器提供所有bean的定義以及bean之間的依賴關系,從而進行bean的依賴注入通常有兩種方式, XML配置 或者 注解 ,不管是那種最終都會解析成BeanDefinition。

通過XML配置Bean依賴關系:

<beans xmlns="http://www.springframework.org/schema/beans">
    <!-- orderDao 不需要任何的依賴 -->
    <bean id="orderDao" class="spring.DI.OrderDao"/>
    <!-- orderService 需要依賴orderDao -->
    <bean id="orderService" class="spring.DI.OrderService">
        <property name="orderDao" ref="orderDao"/>
    </bean>
    <!-- orderController orderService 也間接依賴了orderDao -->
    <bean id="orderController" class="spring.DI.OrderController">
        <property name="orderService" ref="orderService"/>
    </bean>
</beans>
1 public class OrderController {
2     private OrderService orderService;
3     public OrderService getOrderService() {
4         return orderService;
5     }
6     public void setOrderService(OrderService orderService) {
7         this.orderService = orderService;
8     }
9 }

這種注入方式叫做set 方法注入,只需xml配置 加上對引用的bean的get set方法即可

通過注解定義置Bean依賴關系

<context:component-scan base-package="xxx.yyy"/>
 1 @Controller
 2 public class OrderController {
 3     
 4     @Autowired
 5     private OrderService orderService;
 6     public OrderController() {
 7     }
 8 }
 9 
10 Service
11 public class OrderService {
12     @Autowired
13     private OrderDao orderDao;
14     public OrderService() {
15     }
16 }
17 
18 @Repository
19 public class OrderDao {
20     public OrderDao() {
21     }
22 }

二. 什么時候會觸發依賴注入?

  • Spring 容器啟動初始化的時候(所有單例非懶加載的bean)
  • 懶加載(lazy-init)的bean 第一次進行getBean的時候

1.Spring 容器啟動初始化的時候

 1 ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
 2 
 3 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {
 4     super(parent);
 5     setConfigLocations(configLocations);
 6     if (refresh) {
 7         // 容器初始化入口
 8         refresh();
 9     }
10 }
11 
12 public void refresh() throws BeansException, IllegalStateException {
13     synchronized (this.startupShutdownMonitor) {
14         prepareRefresh();
15         // Prepare the bean factory for use in this context.
16         prepareBeanFactory(beanFactory);
17         // Allows post-processing of the bean factory in context subclasses.
18         postProcessBeanFactory(beanFactory);
19         // Invoke factory processors registered as beans in the context.
20         invokeBeanFactoryPostProcessors(beanFactory);
21         // Register bean processors that intercept bean creation.
22         registerBeanPostProcessors(beanFactory);
23         // Instantiate all remaining (non-lazy-init) singletons.
24         // 初始化所有非 懶加載的bean!!!!
25         finishBeanFactoryInitialization(beanFactory);
26         // Last step: publish corresponding event.
27         finishRefresh();
28     }
29   }

finishBeanFactoryInitialization(beanFactory);// 初始化所有非 懶加載的bean!!!

 1 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
 2        // Stop using the temporary ClassLoader for type matching.
 3        beanFactory.setTempClassLoader(null);
 4        // 此處省略多行與本次無關代碼
 5        // Instantiate all remaining (non-lazy-init) singletons.
 6        beanFactory.preInstantiateSingletons();
 7    }
 8 
 9 public void preInstantiateSingletons() throws BeansException {
10    // 所有beanDefinition集合
11    List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
12    // 觸發所有非懶加載單例bean的初始化
13    for (String beanName : beanNames) {
14       RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
15       // 判斷是否是懶加載單例bean,如果是單例的並且不是懶加載的則在Spring 容器
16       if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
17           // 判斷是否是FactoryBean
18          if (isFactoryBean(beanName)) {
19              // 對FactoryBean的處理
20          }else {
21              // 如果是普通bean則進行初始化依賴注入,此 getBean(beanName)接下來觸發的邏輯跟
22              // context.getBean("beanName") 所觸發的邏輯是一樣的
23             getBean(beanName);
24          }
25       }
26    }
27 }
28 
29 @Override
30 public Object getBean(String name) throws BeansException {   
31     return doGetBean(name, null, null, false);
32 }

2.懶加載(lazy-init)的bean 第一次進行getBean

懶加載的bean 第一次進行getBean的操作調用的也是同一個方法

1 @Override
2 public Object getBean(String name) throws BeansException {   
3     return doGetBean(name, null, null, false);
4 }

doCreateBean是依賴注入的入口,也是我們本次要談的核心函數。該方法具體實現在AbstractAutowireCapableBeanFactory類,感興趣的朋友可以進去看看調用鏈。下面才剛剛開始進入依賴注入源碼階段。

三. 關於依賴注入與屬性注入的幾點說明

依賴注入其實是屬性注入的一種特殊類型,他的特殊之處在於他要注入的是Bean,同樣由Spring管理的Bean,而不是其他的參數,如String,List,Set,Array這種。

普通的屬性的值用 value

(類型包括 String list set map ...)

Bean類型的屬性的引用ref, 這種注入屬於依賴注入

四. 解析Spring 依賴注入源碼部分

  • 依賴注入實現的入口
  • 注解形式注入的源碼
  • xml 配置形式注入的源碼

1. 依賴注入實現的入口

 1 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
 2     //第一步 創建bean實例 還未進行屬性填充和各種特性的初始化
 3     BeanWrapper instanceWrapper = null;
 4     if (instanceWrapper == null) {
 5         instanceWrapper = createBeanInstance(beanName, mbd, args);
 6     }
 7     final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
 8     Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
 9     Object exposedObject = bean;
10     try {
11         // 第二步 進行依賴注入(注入屬性)
12         populateBean(beanName, mbd, instanceWrapper);
13         if (exposedObject != null) {
14          // 第三步  執行bean的初始化方法
15         exposedObject = initializeBean(beanName, exposedObject, mbd);
16         }
17     }catch (Throwable ex) {
18      //  拋相應的異常
19     }
20     return exposedObject;
21 }

我們這里需要關注的是第二步關於依賴注入這一塊,下面這行代碼

 1 populateBean(beanName, mbd, instanceWrapper);
 2 
 3 protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
 4         // 所有的屬性
 5     PropertyValues pvs = mbd.getPropertyValues();
 6     // 這里是處理自動裝配類型的, autowire=byName 或者byType。如果不配置不走這個分支,xml或注解都可配 
 7     if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
 8             mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
 9         pvs = newPvs;
10     }
11     // 后處理器是否已經准備好(后處理器會處理已@Autowired 形式來注入的bean, 有一個  
12     // 子類AutowiredAnnotationBeanPostProcessor來處理@Autowired注入的bean)
13     boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
14     // 是否需要依賴檢查
15     boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
16     if (hasInstAwareBpps || needsDepCheck) {
17         PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
18         if (hasInstAwareBpps) {
19             for (BeanPostProcessor bp : getBeanPostProcessors()) {
20                 if (bp instanceof InstantiationAwareBeanPostProcessor) {
21                     InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
22                     // 這里會處理對注解形式的注入 重點!!!!
23                     pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
24                     if (pvs == null) {
25                         return;
26                     }
27                 }
28             }
29         }
30     }
31     // 注入參數的方法(注解的Bean的依賴注入除外)
32     applyPropertyValues(beanName, mbd, bw, pvs);
33 }

2. 注解形式注入的源碼

 1 // 后處理器是否已經准備好(后處理器會處理已@Autowired 形式來注入的bean, 有一個  
 2 // 子類AutowiredAnnotationBeanPostProcessor來處理@Autowired注入的bean)
 3 boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
 4 // 是否需要依賴檢查
 5 boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
 6 if (hasInstAwareBpps || needsDepCheck) {
 7     PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
 8     if (hasInstAwareBpps) {
 9         for (BeanPostProcessor bp : getBeanPostProcessors()) {
10             if (bp instanceof InstantiationAwareBeanPostProcessor) {
11                 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
12                 // 這里會處理對注解形式的注入,比如 @Autowired注解 由類AutowiredAnnotationBeanPostProcessor來處理
13                 pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
14                 if (pvs == null) {
15                     return;
16                 }
17             }
18         }
19     }
20 }
21 
22 pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
 1 @Override
 2 public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
 3         // 這里定義了把誰注入到哪里
 4     InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
 5     try {  
 6        // 進行注入
 7        metadata.inject(bean, beanName, pvs);
 8     }catch (Throwable ex) {
 9         throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
10     }
11     return pvs;
12 }

InjectionMetadata在這個類里頭封裝了依賴的bean與被依賴的bean的信息,比如orderCcontroller 依賴orderService,需要把orderService 注入到orderController。

其中injectedElements就是所有需要被注入的bean

 1 protected void inject(Object target, String requestingBeanName, PropertyValues pvs) throws Throwable {
 2     if (this.isField) {
 3         Field field = (Field) this.member;
 4         ReflectionUtils.makeAccessible(field);
 5         field.set(target, getResourceToInject(target, requestingBeanName));
 6     }else {
 7         if (checkPropertySkipping(pvs)) {
 8            return;
 9         }
10         try {
11            Method method = (Method) this.member;
12            ReflectionUtils.makeAccessible(method);
13            method.invoke(target, getResourceToInject(target, requestingBeanName));
14         }catch (InvocationTargetException ex) {
15           throw ex.getTargetException();
16         }
17     }
18 }

3. xml 配置形式注入的源碼

1 applyPropertyValues(beanName, mbd, bw, pvs);

這個步驟主要做的就是把屬性轉 換成 相對應的類的屬性類型,並最后注入到依賴的bean里頭,由一下步驟組成:

    • 判斷是否已轉換
    • 進行轉換
    • 注入到bean

 

 1 protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
 2         MutablePropertyValues mpvs = null;
 3         List<PropertyValue> original;
 4         if (pvs instanceof MutablePropertyValues) {
 5             mpvs = (MutablePropertyValues) pvs;
 6             // 判斷是否已轉換,已經轉換了則return
 7             if (mpvs.isConverted()) {
 8                 // Shortcut: use the pre-converted values as-is.
 9                 bw.setPropertyValues(mpvs);
10                 return;
11             }
12             original = mpvs.getPropertyValueList();
13         }
14         TypeConverter converter = getCustomTypeConverter();
15         BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
16         // Create a deep copy, resolving any references for values.
17         List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
18         boolean resolveNecessary = false;
19         for (PropertyValue pv : original) {
20             if (pv.isConverted()) {
21                 deepCopy.add(pv);
22             } else {
23                 // 屬性名 如(name,orderService)
24                 String propertyName = pv.getName();
25                 // 未轉換前的值,稍后貼出debug時的圖
26                 Object originalValue = pv.getValue();
27                 // 轉換后的值,進行轉換處理(重要!!!!)
28                 Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
29                 Object convertedValue = resolvedValue;
30                 // 
31                 if (resolvedValue == originalValue) {
32                     if (convertible) {
33                         pv.setConvertedValue(convertedValue);
34                     }
35                     deepCopy.add(pv);
36                 } else if (convertible && originalValue instanceof TypedStringValue &&
37                         !((TypedStringValue) originalValue).isDynamic() &&
38                         !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
39                     pv.setConvertedValue(convertedValue);
40                     deepCopy.add(pv);
41                 } else {
42                     resolveNecessary = true;
43                     deepCopy.add(new PropertyValue(pv, convertedValue));
44                 }
45             }
46         }
47         // 轉換完成
48         if (mpvs != null && !resolveNecessary) {
49             mpvs.setConverted();
50         }
51         // 這里就是進行屬性注入的地方,跟上面的inject方法類似
52         try {
53             bw.setPropertyValues(new MutablePropertyValues(deepCopy));
54         } catch (BeansException ex) {
55             throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);
56         }
57     }

下面介紹上述步驟中的兩個核心的流程:

  • 進行轉換操作,生成最終需要注入的類型的對象
  • 進行注入操作

1.進行轉換操作,生成最終需要注入的類型的對象

這個方法會返回一個我們最終要注入的一個屬性對應類的一個對象

1 Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);

根據參數類型做具體的轉換處理,參數類型包括 1.Bean 2.Array 3.List 4.Set 5.Map 6.String 等等。

 1 public Object resolveValueIfNecessary(Object argName, Object value) {
 2      // Bean 類型
 3     if (value instanceof RuntimeBeanReference) {
 4         RuntimeBeanReference ref = (RuntimeBeanReference) value;
 5         return resolveReference(argName, ref);
 6     }
 7     else if (value instanceof ManagedArray) {
 8         // 處理數組
 9         return resolveManagedArray(argName, (List<?>) value, elementType);
10     }
11     else if (value instanceof ManagedList) {
12         // 處理list
13         return resolveManagedList(argName, (List<?>) value);
14     }
15     else if (value instanceof ManagedSet) {
16         // 處理set
17         return resolveManagedSet(argName, (Set<?>) value);
18     }
19     else if (value instanceof ManagedMap) {
20         // 處理map
21         return resolveManagedMap(argName, (Map<?, ?>) value);
22     }
23     else if (value instanceof TypedStringValue) {
24     // 處理字符串
25     }
26     else {
27         return evaluate(value);
28     }
29 }
30 
31 private Object resolveReference(Object argName, RuntimeBeanReference ref) {
32     try {
33     String refName = ref.getBeanName();
34     refName = String.valueOf(doEvaluate(refName));
35     if (ref.isToParent()) {
36         if (this.beanFactory.getParentBeanFactory() == null) {
37             throw new BeanCreationException("");
38         }
39         return this.beanFactory.getParentBeanFactory().getBean(refName);
40     }else {
41         Object bean = this.beanFactory.getBean(refName);
42         this.beanFactory.registerDependentBean(refName, this.beanName);
43         return bean;
44     }
45     }catch (BeansException ex) {throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName,
46                 "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName,ex);
47     }
48 }
49 
50 Object bean = this.beanFactory.getBean(refName);
51 
52 this.beanFactory.getParentBeanFactory().getBean(refName);

從sprig ioc 容器的雙親中獲取bean(被依賴的bean),假如orderCcontroller依賴orderService,則從容器中獲取orderService。這里有個關鍵點,也就是這個獲取bean的過程也是一個依賴注入的過程,換句話說依賴注入是個遞歸的過程!!!!!!知道被依賴的bean不依賴任何bean。

  • orderCcontroller 依賴 orderService 的操作會觸發 orderService 依賴 orderDao的操作

2.進行注入操作

這一步是通過Java的反射機制根據set 方法把屬性注入到bean里。

 1 bw.setPropertyValues(new MutablePropertyValues(deepCopy));
 2 
 3 protected void setPropertyValue(AbstractNestablePropertyAccessor.PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
 4     String propertyName = tokens.canonicalName;
 5     String actualName = tokens.actualName;
 6     if (tokens.keys != null) {
 7      // 處理集合類型
 8     }
 9     else {
10         // 對非集合類型的處理
11         AbstractNestablePropertyAccessor.PropertyHandler ph = getLocalPropertyHandler(actualName);
12         Object oldValue = null;
13         try {
14             Object originalValue = pv.getValue();
15             Object valueToApply = originalValue;
16             if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
17                 if (pv.isConverted()) {
18                     valueToApply = pv.getConvertedValue();
19                 }else {
20                     if (isExtractOldValueForEditor() && ph.isReadable()) {
21                         try {
22                             oldValue = ph.getValue();
23                         }catch (Exception ex) {}
24                     }
25                     valueToApply = convertForProperty(propertyName, oldValue, originalValue, ph.toTypeDescriptor());
26                 }
27                 pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
28             }
29              // 通過反射注入
30             ph.setValue(object, valueToApply);
31             }
32         }
33     }
34 
35 public void setValue(final Object object, Object valueToApply) throws Exception {
36     final Method writeMethod = this.pd.getWriteMethod();
37     if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) {
38         if (System.getSecurityManager() != null) {
39             AccessController.doPrivileged(new PrivilegedAction<Object>() {
40                 @Override
41                 public Object run() {
42                     writeMethod.setAccessible(true);
43                     return null;
44                 }
45             });
46         } else {
47             writeMethod.setAccessible(true);
48         }
49     }
50     final Object value = valueToApply;
51     if (System.getSecurityManager() != null) {
52     } else {
53         // 通過反射 用set 方法注入屬性
54         writeMethod.invoke(getWrappedInstance(), value);
55     }
56 }

 轉自:https://zhuanlan.zhihu.com/p/61744838?utm_source=wechat_session&utm_medium=social&utm_oi=791980836567289856


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM