天天看点

spring依赖注入、属性填充(源码分析——中)

作者:XL1024

这里我们主要分析spring是怎么去根据类型或name去找值得。

方法参数的名字:加了@Autowired 注解的方法中的参数

字段:加了@Autowired的属性

spring依赖注入、属性填充(源码分析——中)
spring依赖注入、属性填充(源码分析——中)
DependencyDescriptor descriptor           

descriptor可能是字段,也可能是方法的参数,需要根据descriptor来获取(字段或方法参数)的名字或类型。

descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());           

上面这段代码主要是为了获取方法参数的名字。

spring依赖注入、属性填充(源码分析——中)

1

spring依赖注入、属性填充(源码分析——中)

2

spring依赖注入、属性填充(源码分析——中)

3

spring依赖注入、属性填充(源码分析——中)

4

addDiscoverer(new StandardReflectionParameterNameDiscoverer());
addDiscoverer(new LocalVariableTableParameterNameDiscoverer());           

这里初始化了两种获取方法参数的名字,一种是基于反射:主要是jdk1.8以上提供的方法。一种是基于本地变量表,主要是解决jdk1.7 没有通过反射可以获取方法参数名字的问题。

1.@Autowired+@Lazy

spring依赖注入、属性填充(源码分析——中)

懒注入

Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
      descriptor, requestingBeanName);           

上面这段代码就是处理@Lazy注解:

如果加了@Lazy注解 那么就会返回一个代理对象,将代理对象赋值给属性(方法参数)。当属性(方法参数)在调用方法的时候,spring才会去找bean。

2.@Value

spring依赖注入、属性填充(源码分析——中)
spring依赖注入、属性填充(源码分析——中)

处理@Value

String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
      getMergedBeanDefinition(beanName) : null);           

这段代码是处理这种方式赋值:@Value(${"456"})

spring在最开始的时候会初始化一个Environment ,这个对象里面包含了spring.properties 配置文件中的key value 键值对.

@Value注解就是去Environment 对象中根据键找值。

value = evaluateBeanDefinitionString(strVal, bd);           

这个是为了处理:@Value("#{person}")

这种是spring表达式,可以根据person 这个名字从spring容器中找bean 给属性赋值。

3.属性定义为:Map<String,Person> person

spring依赖注入、属性填充(源码分析——中)
spring依赖注入、属性填充(源码分析——中)

这种情况,spring会根据类型去找值,找到之后会将bean 的名字作为key, 值作为value 存入到map中。 这里map 的key 只能是string。

4.拿到符合类型的bean 或 beanClass

spring依赖注入、属性填充(源码分析——中)

这里拿到的可能是bean对象,也可能是 beanClass。

spring依赖注入、属性填充(源码分析——中)
spring依赖注入、属性填充(源码分析——中)
spring依赖注入、属性填充(源码分析——中)

如上面两个图,同一个类型(Company)的bean 有两个,名字不一样。那么获取的时候不管是创建好了对象,还是没创建好,都可以通过beanDefinition来判断是不是符合该类型。

如果判断是同类型,那么就会存到map中,在存的时候如果创建好就会存bean对象,如果没有创建好就会存beanClass。

5.1通过名字来进行匹配

spring依赖注入、属性填充(源码分析——中)

如果是多个,这里会根据名字来进行匹配。 但是这里是有一个优先级的。顺序如下:

@Primary > @Primary(1)>name

5.2 处理根据类型获取单个bean 。

spring依赖注入、属性填充(源码分析——中)

6.记录beanName

spring依赖注入、属性填充(源码分析——中)

7.如果获取的是bean的类型 ,那就进行实例化

spring依赖注入、属性填充(源码分析——中)

8.处理null

spring依赖注入、属性填充(源码分析——中)
spring依赖注入、属性填充(源码分析——中)

如上图所示 定义一个bean 返回null, 那么spring 在存的时候,会以com 为key , nullBean 为值:map<com,nullBean>