使用@Autowrite、@Value、@Inject注解标记注入点。Spring会根据对注入点进行注入操作。
在属性上使用@Laze注解,自动注入时,会生成代理对象赋值给属性;当真正使用属性的方法时,才会找真实的对象,进行赋值,与真实方法的调用
一、过期的依赖注入方式
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
Spring默认自动注入操作(byName、byType),借助实例的set方法,不用额外使用@Autowrite等注解,目前一般不用了。目前使用@Autowired注解,进行更细粒度的注入控制
手动注入
//通过【set方法】注入
<bean name="userService" class="com.service.UserService">
<property name="orderService" ref="orderService"/>
</bean>
//通过【构造方法】注入
<bean name="userService" class="com.service.UserService">
<constructor-arg index="0" ref="orderService"/>
</bean>
自动注入
- XML的autowire自动注入
- @Autowired注解的自动注入
XML自动注入
定义一个Bean时去指定这个Bean的自动注入模式。
- byType
- byName
- constructor
- default(
标签中设置的autowire) - no
//这个属性上不需要有@Autowired注解,但这个属性需要有对应的set方法
<bean id="userService" class="com.service.UserService" autowire="byType"/>
二、注解注入方式
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean1.扫描注入点
MergedBeanDefinitionPostProcessor
实例化步骤之后,实例化后步骤之前。执行
调用AutowiredAnnotationBeanPostProcessor,查找注入点(@Autowired、@Value、@Inject标记的属性、方法),进行缓存,为后续属性注入做准备
调用CommonAnnotationBeanPostProcessor,查找注入点(@Resource标记的属性与方法),进行缓存。为后续属性注入做准备。
AutowiredAnnotationBeanPostProcessor扫描过程
- 属性注入点扫描
- 遍历当前类的所有的属性字段Field
- 查看字段上是否存在@Autowired、@Value、@Inject中的其中任意一个。存在,则认为该字段是一个注入点
- 如果字段是static的,则不进行注入(static属性属于类,而不是实例。针对原型Bean。如果对static赋值,则对相同类产生的不同实例,会造成static属性覆盖)
- 获取@Autowired中的required属性的值
- 将字段信息构造成一个AutowiredFieldElement对象,作为一个注入点对象添加到currElements集合中。
- 方法注入点扫描
- 遍历当前类的所有方法Method
- 判断当前Method是否是桥接方法,如果是找到原方法
- 查看方法上是否存在@Autowired、@Value、@Inject中的其中任意一个,存在则认为该方法是一个注入点
- 如果方法是static的,则不进行注入
- 获取@Autowired中的required属性的值
- 将方法信息构造成一个AutowiredMethodElement对象,作为一个注入点对象添加到currElements集合中。
- 遍历完当前类的字段和方法后,将遍历父类的,直到没有父类。
- 最后将currElements集合封装成一个InjectionMetadata对象,作为当前Bean对于的注入点集合对象,并缓存。
对于无参的方法。使用Autowired标记,会在属性注入时被调用。从某种程度可以作为初始化方法的替代品
2.执行注入
调用InstantiationAwareBeanPostProcessor#postProcessProperties类型实例,进行属性注入。不管那种注入方式,底层都使用反射技术。
AutowiredAnnotationBeanPostProcessor
字段注入
- 遍历所有的AutowiredFieldElement对象。
- 将对应的字段封装为DependencyDescriptor对象。
- 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前字段所匹配的Bean对象。
- 将DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,如果当前Bean是单例Bean,再次创建该Bean时,可以通过beanName直接在BeanFactory拿缓存的结果对象,不用再次进行查找了
- 利用反射将结果对象赋值给字段。
Set方法注入
- 遍历所有的AutowiredMethodElement对象
- 遍历将对应的方法的参数,将每个参数封装成MethodParameter对象
- 将MethodParameter对象封装为DependencyDescriptor对象
- 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前方法参数所匹配的Bean对象。
- 将DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,如果当前Bean是单例Bean,再次创建该Bean时,可以通过beanName直接在BeanFactory拿缓存的结果对象,不用再次进行查找了
- 利用反射将找到的所有结果对象传给当前方法,并执行。
CommonAnnotationBeanPostProcessor(@Resource)
三、获取注入实例对象
resolveDependency(获取实例)
- 方法执行准备
- 初始化方法参数名获取器
- 判断是否使用@Lazy注解修饰(存在,则返回代理对象,属性真正使用时才会注入,[即执行resolveDependency方法])
执行方法主逻辑(doResolveDependency)
- 尝试从缓存中获取实例。
- 处理@Value注解
- 占位符填充,即替换${value} [原理:使用Spring环境变量中的值,进行替换]
- 执行SpringEL表达式(@Value(“#{value}”))
- 获取类型转换器。利用类型转换器(TypeConverter),将字符串转换为实例对象。
- 处理注入点属性类型是数组、集合、Map情况。根据注入点属性类型,获取实例。
- 注入点属性类型为普通类型时,调用方法findAutowireCandidates,按类型查找所有符合条件的实例。
- 如果未查到,则判断是否为必须注入。必须注入,则报错。否则返回null
- 查找到一个实例。
- 查找到多个实例。则进行筛选(1.@Primary (标记主Bean) 2.@Priority(标记Bean使用优先级) 3.名字判断 4.@Bean中是否支持依赖注入判断 5.泛型判断 6.@Qualifier注解判断(指定注入名)),最终返回符合的实例,进行注入操作
- 查到到对象类型为Class对象。则(调用getBean)实例化。
findAutowireCandidates(根据类型获取可注入实例)
org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates
按类型。找到所有的Bean。key:BeanName。value:可能是Bean对象,也可能是BeanClass[因为可以通BeanDefinition进行判断是否符合注入条件]
从beanFactory查找所有符合类型实例的beanName。
- 基于单例池和BeanDefinition集合,查找本容器以及父容器。
- DefaultListableBeanFactory#doGetBeanNamesForType
- 遍历beanDefinitionNames。首先通过单例池判断,如果没有实例化,则通过BeanDefinition判断
- 查找集合resolvableDependencies【Spring启动时,初始化。key:Class,value:Class实例对象】中,是否存在requiredType类型。
- 筛选步骤1中的实例
- 判断是否自己注入自己(如果存在多个,优先注入其他实例)
- 判断步骤1中的实例是否支持依赖注入。
四、重要方法解析
resolveDependency(获取实例)
org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
https://www.processon.com/view/link/5f8d3c895653bb06ef076688
findAutowireCandidates(根据类型获取实例)
org.springframework.beans.factory.support.DefaultListableBeanFactory#findAutowireCandidates