使用@Autowrite、@Value、@Inject注解标记注入点。Spring会根据对注入点进行注入操作。
在属性上使用@Laze注解,自动注入时,会生成代理对象赋值给属性;当真正使用属性的方法时,才会找真实的对象,进行赋值,与真实方法的调用

一、过期的依赖注入方式

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
image.png
Spring默认自动注入操作(byName、byType),借助实例的set方法,不用额外使用@Autowrite等注解,目前一般不用了。目前使用@Autowired注解,进行更细粒度的注入控制

手动注入

  1. //通过【set方法】注入
  2. <bean name="userService" class="com.service.UserService">
  3. <property name="orderService" ref="orderService"/>
  4. </bean>
  5. //通过【构造方法】注入
  6. <bean name="userService" class="com.service.UserService">
  7. <constructor-arg index="0" ref="orderService"/>
  8. </bean>

自动注入

  1. XML的autowire自动注入
  2. @Autowired注解的自动注入

XML自动注入
定义一个Bean时去指定这个Bean的自动注入模式。

  1. byType
  2. byName
  3. constructor
  4. default(标签中设置的autowire)
  5. no
    1. //这个属性上不需要有@Autowired注解,但这个属性需要有对应的set方法
    2. <bean id="userService" class="com.service.UserService" autowire="byType"/>

    二、注解注入方式

    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean

    1.扫描注入点

    MergedBeanDefinitionPostProcessor
    实例化步骤之后,实例化后步骤之前。执行
    image.png
    image.png
    调用AutowiredAnnotationBeanPostProcessor,查找注入点(@Autowired、@Value、@Inject标记的属性、方法),进行缓存,为后续属性注入做准备
    调用CommonAnnotationBeanPostProcessor,查找注入点(@Resource标记的属性与方法),进行缓存。为后续属性注入做准备。
    AutowiredAnnotationBeanPostProcessor扫描过程
  1. 属性注入点扫描
    1. 遍历当前类的所有的属性字段Field
    2. 查看字段上是否存在@Autowired、@Value、@Inject中的其中任意一个。存在,则认为该字段是一个注入点
    3. 如果字段是static的,则不进行注入(static属性属于类,而不是实例。针对原型Bean。如果对static赋值,则对相同类产生的不同实例,会造成static属性覆盖)
    4. 获取@Autowired中的required属性的值
    5. 将字段信息构造成一个AutowiredFieldElement对象,作为一个注入点对象添加到currElements集合中。
  2. 方法注入点扫描
    1. 遍历当前类的所有方法Method
    2. 判断当前Method是否是桥接方法,如果是找到原方法
    3. 查看方法上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该方法是一个注入点
    4. 如果方法是static的,则不进行注入
    5. 获取@Autowired中的required属性的值
    6. 将方法信息构造成一个AutowiredMethodElement对象,作为一个注入点对象添加到currElements集合中。
    7. 遍历完当前类的字段和方法后,将遍历父类的,直到没有父类。
    8. 最后将currElements集合封装成一个InjectionMetadata对象,作为当前Bean对于的注入点集合对象,并缓存。

对于无参的方法。使用Autowired标记,会在属性注入时被调用。从某种程度可以作为初始化方法的替代品

2.执行注入

调用InstantiationAwareBeanPostProcessor#postProcessProperties类型实例,进行属性注入。不管那种注入方式,底层都使用反射技术。
image.png
image.png

AutowiredAnnotationBeanPostProcessor

image.png
字段注入

  1. 遍历所有的AutowiredFieldElement对象。
  2. 将对应的字段封装为DependencyDescriptor对象
  3. 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前字段所匹配的Bean对象。
  4. DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,如果当前Bean是单例Bean,再次创建该Bean时,可以通过beanName直接在BeanFactory拿缓存的结果对象,不用再次进行查找了
  5. 利用反射将结果对象赋值给字段。

Set方法注入

  1. 遍历所有的AutowiredMethodElement对象
  2. 遍历将对应的方法的参数,将每个参数封装成MethodParameter对象
  3. MethodParameter对象封装为DependencyDescriptor对象
  4. 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前方法参数所匹配的Bean对象。
  5. DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,如果当前Bean是单例Bean,再次创建该Bean时,可以通过beanName直接在BeanFactory拿缓存的结果对象,不用再次进行查找了
  6. 利用反射将找到的所有结果对象传给当前方法,并执行。

    CommonAnnotationBeanPostProcessor(@Resource)

    image.png
    image.png

三、获取注入实例对象

resolveDependency(获取实例)

  1. 方法执行准备
    1. 初始化方法参数名获取器
    2. 判断是否使用@Lazy注解修饰(存在,则返回代理对象,属性真正使用时才会注入,[即执行resolveDependency方法])
  2. 执行方法主逻辑(doResolveDependency)

    1. 尝试从缓存中获取实例。
    2. 处理@Value注解
      1. 占位符填充,即替换${value} [原理:使用Spring环境变量中的值,进行替换]
      2. 执行SpringEL表达式(@Value(“#{value}”))
      3. 获取类型转换器。利用类型转换器(TypeConverter),将字符串转换为实例对象。
    3. 处理注入点属性类型是数组、集合、Map情况。根据注入点属性类型,获取实例。image.png
    4. 注入点属性类型为普通类型时,调用方法findAutowireCandidates,按类型查找所有符合条件的实例。
      1. 如果未查到,则判断是否为必须注入。必须注入,则报错。否则返回null
      2. 查找到一个实例。
      3. 查找到多个实例。则进行筛选(1.@Primary (标记主Bean) 2.@Priority(标记Bean使用优先级) 3.名字判断 4.@Bean中是否支持依赖注入判断 5.泛型判断 6.@Qualifier注解判断(指定注入名)),最终返回符合的实例,进行注入操作
      4. 查到到对象类型为Class对象。则(调用getBean)实例化。

        findAutowireCandidates(根据类型获取可注入实例)

        org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
        按类型。找到所有的Bean。key:BeanName。value:可能是Bean对象,也可能是BeanClass[因为可以通BeanDefinition进行判断是否符合注入条件]
  3. 从beanFactory查找所有符合类型实例的beanName。

    1. 基于单例池和BeanDefinition集合,查找本容器以及父容器。
    2. DefaultListableBeanFactory#doGetBeanNamesForType
      1. 遍历beanDefinitionNames。首先通过单例池判断,如果没有实例化,则通过BeanDefinition判断
  4. 查找集合resolvableDependencies【Spring启动时,初始化。key:Class,value:Class实例对象】中,是否存在requiredType类型。
  5. 筛选步骤1中的实例
    1. 判断是否自己注入自己(如果存在多个,优先注入其他实例)
    2. 判断步骤1中的实例是否支持依赖注入。
    3. image.png

四、重要方法解析

resolveDependency(获取实例)

org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
https://www.processon.com/view/link/5f8d3c895653bb06ef076688
image.png

findAutowireCandidates(根据类型获取实例)

org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
image.png