type
status
date
slug
summary
tags
category
icon
password
URL
文章来源说明

依赖注入

notion image
 

Spring中到底有几种依赖注入的方式?

首先分两种:
  1. 手动注入
  1. 自动注入
 

手动注入

在XML中定义Bean时,就是手动注入,因为是程序员手动给某个属性指定了值
上面这种底层是通过set方法进行注入。
 
上面这种底层是通过构造方法进行注入。
 
所以手动注入的底层也就是分为两种:
  1. set方法注入
  1. 构造方法注入
 

自动注入

自动注入又分为两种:
  1. XML的autowire自动注入
  1. @Autowired注解的自动注入

XML的autowire自动注入

在XML中,我们可以在定义一个Bean时去指定这个Bean的自动注入模式:
  1. byType
  1. byName
  1. constructor
  1. default
  1. no

@Autowired注解的自动注入

上文说了@Autowired注解,是byType和byName的结合。
@Autowired注解可以写在:
  1. 属性上:先根据属性类型去找Bean,如果找到多个再根据属性名确定一个
  1. 构造方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
  1. set方法上:先根据方法参数类型去找Bean,如果找到多个再根据参数名确定一个
而这种底层到了:
  1. 属性注入
  1. set方法注入
  1. 构造方法注入

寻找注入点

在创建一个Bean的过程中,Spring会利用AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition()找出注入点并缓存,找注入点的流程为:
  1. 遍历当前类的所有的属性字段Field
  1. 查看字段上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该字段是一个注入点
  1. 如果字段是static的,则不进行注入
  1. 获取@Autowired中的required属性的值
  1. 将字段信息构造成一个AutowiredFieldElement对象,作为一个注入点对象添加到currElements集合中。
  1. 遍历当前类的所有方法Method
  1. 判断当前Method是否是桥接方法,如果是找到原方法
  1. 查看方法上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该方法是一个注入点
  1. 如果方法是static的,则不进行注入
  1. 获取@Autowired中的required属性的值
  1. 将方法信息构造成一个AutowiredMethodElement对象,作为一个注入点对象添加到currElements集合中。
  1. 遍历完当前类的字段和方法后,将遍历父类的,直到没有父类。
  1. 最后将currElements集合封装成一个InjectionMetadata对象,作为当前Bean对于的注入点集合对象,并缓存。

static的字段或方法为什么不支持

 
看上面代码,UserService和OrderService都是原型Bean,假设Spring支持static字段进行自动注入,那么现在调用两次
  1. UserService userService1 = context.getBean("userService")
  1. UserService userService2 = context.getBean("userService")
问此时,userService1的orderService值是什么?还是它自己注入的值吗?
答案是不是,一旦userService2 创建好了之后,static orderService字段的值就发生了修改了,从而出现bug。
 

注入点进行注入

Spring在AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法中,会遍历所找到的注入点依次进行注入。

字段注入

  1. 遍历所有的AutowiredFieldElement对象。
  1. 将对应的字段封装为DependencyDescriptor对象
  1. 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前字段所匹配的Bean对象。
  1. DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,比如如果当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了,不用再次进行查找了
  1. 利用反射将结果对象赋值给字段。

Set方法注入

  1. 遍历所有的AutowiredMethodElement对象
  1. 遍历将对应的方法的参数,将每个参数封装成MethodParameter对象
  1. MethodParameter对象封装为DependencyDescriptor对象
  1. 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前方法参数所匹配的Bean对象。
  1. DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,比如如果当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了,不用再次进行查找了
  1. 利用反射将找到的所有结果对象传给当前方法,并执行。
 
致谢:
💡
有关Notion安装或者使用上的问题,欢迎您在底部评论区留言,一起交流~
 
 
spring的bean的生命周期源码spring循环依赖
Loading...