spring之依赖注入

文章详细描述了Spring框架中BeanDefinition的后置处理阶段如何寻找和处理字段和方法的注入点,包括字段注入的顺序问题和方法注入的判断逻辑,以及resolveDependency方法在依赖查找中的关键作用。
摘要由CSDN通过智能技术生成

目录

1.BeanDefinition后置处理阶段去找注入点postProcessMergedBeanDefinition()

2.处理属性(就是打了注解的属性,此处包含扩展点)给找到的注入点赋值 postProcessProperties()

字段注入

方法注入

上述两种注入的方式都会走resolveDependency 核心方法


1.BeanDefinition后置处理阶段去找注入点postProcessMergedBeanDefinition()

        实例化阶段有一个BeanDefinition后置处理阶段,在对象实例化出来以后,真正给属性赋值之前,需要收集需要属性注入的注入点。寻找注入点的过程为以下步骤:

     1. 遍历当前类的所有的属性字段Field

     2. 查看字段上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该字段 是一个注入点

     3. 如果字段是static的,则不进行注入

     4. 获取@Autowired中的required属性的值

     5. 将字段信息构造成一个AutowiredFieldElement对象,作为一个注入点对象添加到 currElements集合中。

     6. 遍历当前类的所有方法Method

     7. 判断当前Method是否是桥接方法,如果是找到原方法

     8. 查看方法上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该方法 是一个注入点

     9. 如果方法是static的,则不进行注入

    10. 获取@Autowired中的required属性的值

    11. 将方法信息构造成一个AutowiredMethodElement对象,作为一个注入点对象添加到 currElements集合中。

    12. 遍历完当前类的字段和方法后,将遍历父类的,直到没有父类。

    13. 最后将currElements集合封装成一个InjectionMetadata对象,作为当前Bean对于的注入点集合对象,并缓存。

2.处理属性(就是打了注解的属性,此处包含扩展点)给找到的注入点赋值 postProcessProperties()

       在给属性注入之前都会先判断除了@Autowired注解还有没有其他的注解@Lazy\@Value注解,注入又分为字段注入和方法注入。

字段注入

       字段注入的时候没有做判断,会出现一个问题,会先给带有@Autowired注解的字段赋值,然后才会走postProcessMergedBeanDefinition该方法(这种方式给属性赋值需要有属性的set方法),最后返回的内容是被postProcessMergedBeanDefinition该方法所覆盖的。

       1. 遍历所有的AutowiredFieldElement对象。

       2. 将对应的字段封装为DependencyDescriptor对象。

       3. 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前字段所匹配的Bean对象。

       4. 将DependencyDescriptor对象和所找到的结果对象beanName封装成一个 ShortcutDependencyDescriptor对象作为缓存,比如如果当前Bean是原型Bean,那么下次 再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象 了,不用再次进行查找了

       5. 利用反射将结果对象赋值给字段。

方法注入

       给方法赋值的时候做了判断,该方法(一般是set方法,或者构造方法)的参数值之前是否已经被赋值了,如果赋值了就返回。

      1. 遍历所有的AutowiredMethodElement对象

      2. 遍历将对应的方法的参数,将每个参数封装成MethodParameter对象

      3. 将MethodParameter对象封装为DependencyDescriptor对象

      4. 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前方法参数所匹配的Bean对象。

      5. 将DependencyDescriptor对象和所找到的结果对象beanName封装成一个 ShortcutDependencyDescriptor对象作为缓存,比如如果当前Bean是原型Bean,那么下次 再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象 了,不用再次进行查找了

      6. 利用反射将找到的所有结果对象传给当前方法,并执行。

上述两种注入的方式都会走resolveDependency 核心方法

1. resolveDependency (该依赖查找默认先通过类型查找)

       判断是不是延迟注入@Lazy,如果有的话直接返回代理对象,以后需要真正需要该对象的时候再去创建。

2. doResolveDependency

      2.1 会读取 @Value 对应的值进行注入。如果是 String 要经过三个过程:①占位符处理 -> ②EL 表达式解析 -> ③类型转换

      2.2 集合依赖查询:直接全部委托给 resolveMultipleBeans 方法。

      2.3 单个依赖查询:先调用 findAutowireCandidates 查找所有可用的依赖,如果有多个依赖,则根据规则匹配: @Primary -> @Priority(只能用在class上边,依赖注入阶段优先级) -> ③方法名称或字段名称

3. findAutowireCandidates(找到的有可能用来依赖注入的所有bean)

       3.1 先从本容器根据类型去找,再从父容器去找,找到的结果放到result中

       3.2 补偿机制. 如果找到多个bean,包括自己,则将非自身的bean放入result中。如果只找到自身的bean那么result 为空,然后判断是不是可以用自己来注入,如果可以将自身放入result中返回。

4. isAutowireCandidate(判断找到的bean到底是否可用)

isAutowireCandidate 方法过滤候选对象有三重规则:

      1. bd.autowireCandidate=true 判断bd中的类的属性autowireCandidate是否为true

          

      2. 泛型匹配 通过一些api可以拿到泛型的具体信息与变量,从而去匹配

        

      3. @Qualifier 判断两个注解的名称是否相同,如果相同表示匹配

         

  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值