Spring 源码分析之 bean 依赖注入原理(注入属性)

本文内容纲要:

- 一. Spring容器与依赖注入

- 二. 什么时候会触发依赖注入?

- 三. 关于依赖注入与属性注入的几点说明

- 四. 解析Spring 依赖注入源码部分

最近在研究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 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 deepCopy = new ArrayList(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

本文内容总结:一. Spring容器与依赖注入,二. 什么时候会触发依赖注入?,三. 关于依赖注入与属性注入的几点说明,四. 解析Spring 依赖注入源码部分,

原文链接:https://www.cnblogs.com/fnlingnzb-learner/p/10694592.html

以上是 Spring 源码分析之 bean 依赖注入原理(注入属性) 的全部内容, 来源链接: utcz.com/z/362604.html

回到顶部