天天看点

spring依赖注入、属性填充(上)

作者:XL1024

我们会经常使用@Autowired、@Resource、@Value 这些注解给属性赋值。

那么这几个注解是怎么给属性赋值的呢?还有其他的方法可以给属性赋值吗?

使用@Bean注解+set方法,设置依赖注入方式(byName,byType)。

spring依赖注入、属性填充(上)

配置类

spring依赖注入、属性填充(上)

bean

spring依赖注入、属性填充(上)

测试

上面几张图:在配置类中使用@Bean 注解并设置注入方式, 配置bean。

这种方式在spring中已经被定义为过期的方法,但是还能用,只是spring不建议使用。

person类的属性上并没有加@Autowired,但是也能注入成功。

spring依赖注入、属性填充(上)

上图这段代码就是记录这种注入方式的代码,记住是记录,意思是说:只要用这种方式注入bean的spring都会在这个地方记录,就是将这些bean的名字存到一个集合中,方便后续注入。

spring依赖注入、属性填充(上)
spring依赖注入、属性填充(上)
PropertyDescriptor[] pds = bw.getPropertyDescriptors();           

PropertyDescriptor:属性描述器, 是javaBean 里自带的。在这个属性描述器里会记录属性的名字,属性的set 方法 ,get方法,等等。

前提是必须要有set方法或是get方法,如果一个类里只定义了属性,没有set方法或则是getf方法,那么也是拿不到这个属性的。

PropertyDescriptor中的name属性是通过解析set方法获取的。例如:setOr123 , 那么name属性的值就是 or123。

spring 在拿到所有属性后进行循环遍历

for (PropertyDescriptor pd : pds) { 
   if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
         !BeanUtils.isSimpleProperty(pd.getPropertyType())) {
      result.add(pd.getName());
   }
}           
  1. pd.getWriteMethod() != null : 将没有set方法的属性给过滤掉。
  2. !pvs.contains(pd.getName()) : 将在MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition方法中赋值过的属性过滤掉。
  3. !BeanUtils.isSimpleProperty(pd.getPropertyType()): 将简单类型的属性过滤掉。
spring依赖注入、属性填充(上)

上图这个方法的最后面,就是下面这段代码

if (pvs != null) {
   applyPropertyValues(beanName, mbd, bw, pvs);
}           

将记录属性进行赋值。

@Autowired,@Value,@Resource给属性赋值

spring依赖注入、属性填充(上)
spring依赖注入、属性填充(上)

上图中的1是处理 @Autowired,@Value ,2是处理@Resource。

以下主要看是AutowiredAnnotationBeanPostProcessor 这个实现类。

spring依赖注入、属性填充(上)

上图中可以看到 AutowiredAnnotationBeanPostProcessor 实现了SmartInstantiationAwareBeanPostProcessor 和 MergedBeanDefinitionPostProcessor 这两个接口。

MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition寻找注入点

spring依赖注入、属性填充(上)
spring依赖注入、属性填充(上)

根据类找到注入点

注入点:加了@Autowired 的属性或者方法。

spring依赖注入、属性填充(上)
ReflectionUtils.doWithLocalFields(targetClass, field -> {
   MergedAnnotation<?> ann = findAutowiredAnnotation(field);
   if (ann != null) {
      if (Modifier.isStatic(field.getModifiers())) {
         if (logger.isInfoEnabled()) {
            logger.info("Autowired annotation is not supported on static fields: " + field);
         }
         return;
      }
      boolean required = determineRequiredStatus(ann);
      currElements.add(new AutowiredFieldElement(field, required));
   }
});           

上述代码就是拿到类的所有属性,然后循环判断属性上面有没有加注解(@Autowired或@Value只要有一个注解就行)如果有注解且不是静态属性,就会加入到缓存中 currElements。

1.静态的属性属于类的,不依赖于某个对象,也可以称为类属性。不同的对象都可以访问到类的属性。带参数的构造方法中不能包含静态的属性。 它的生命随着类的消亡而消亡。

2.非静态属性只能属于某个对象,其它的对象不能访问它的属性。随着对象的消亡而消亡。

spring依赖注入、属性填充(上)

boolean required = determineRequiredStatus(ann);

这行代码的作用 就是处理 required 的,如果等于true 就是必须要给该属性赋值,如果没有值就会报异常。

ReflectionUtils.doWithLocalMethods(targetClass, method -> {
   Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
   if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
      return;
   }
   MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
   if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
      if (Modifier.isStatic(method.getModifiers())) {
         if (logger.isInfoEnabled()) {
            logger.info("Autowired annotation is not supported on static methods: " + method);
         }
         return;
      }
      if (method.getParameterCount() == 0) {
         if (logger.isInfoEnabled()) {
            logger.info("Autowired annotation should only be used on methods with parameters: " +
                  method);
         }
      }
      boolean required = determineRequiredStatus(ann);
      PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
      currElements.add(new AutowiredMethodElement(method, required, pd));
   }
});           

上述这段代码是处理方法的,和上面的属性大致差不多。

唯一不同的是:

Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
   return;
}           

这个就是处理桥接方法,有兴趣的可以搜一下。

if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
   return InjectionMetadata.EMPTY;
}           

这段代码就是判断这个bean 的类型。如果是String等基础数据类型则不需要寻找注入点,就会直接返回。

SmartInstantiationAwareBeanPostProcessor.postProcessProperties 主要是处理属性

spring依赖注入、属性填充(上)

在拿到注入点后就会执行这个方法,这个方法中会找到注入点的值,并给注入点赋值。

spring依赖注入、属性填充(上)
spring依赖注入、属性填充(上)
spring依赖注入、属性填充(上)

标号1的地方是找值,找到值后,就会执行标号2 ,给注入点赋值。