Spring为什么不支持static字段的注入?

2023年 9月 30日 66.9k 0

我们都知道Spring在创建一个bean的时候,还要去填充bean的属性

大致流程如下:

反射创建bean // createBeanInstance
填充bean // populateBean
初始化bean // initializeBean(包括前后置增强)
注册bean的销毁方法 // registerDisposableBeanIfNecessary

这个填充bean的逻辑是在populateBean

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   // ...

   PropertyDescriptor[] filteredPds = null;
   if (hasInstAwareBpps) {
      if (pvs == null) {
         pvs = mbd.getPropertyValues();
      }
      for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
         // here
         PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
         if (pvsToUse == null) {
            if (filteredPds == null) {
               filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
               return;
            }
         }
         pvs = pvsToUse;
      }
   }
   // ...

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

而除了applyPropertyValues可以填充bean的属性外

更多的填充逻辑(字段注入)应该是在InstantiationAwareBeanPostProcessor中的postProcessProperties里面,字段注入就是常用的@Autowired、@Resource注解

InstantiationAwareBeanPostProcessor是一个接口

它的子类中实现Autowired注入的是AutowiredAnnotationBeanPostProcessor,实现Resource注入的是CommonAnnotationBeanPostProcessor

接下来分析一下AutowiredAnnotationBeanPostProcessor是怎么进行字段注入的

// AutowiredAnnotationBeanPostProcessor.postProcessProperties
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   // 找到需要Autowired的元数据(字段、方法) 
   InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
   try {
      // 注入
      metadata.inject(bean, beanName, pvs);
   }
   catch (BeanCreationException ex) {
      throw ex;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
   }
   return pvs;
}

以上这段代码是AutowiredAnnotationBeanPostProcessor实现的postProcessProperties

流程就是先找到需要通过findAutowiringMetadata找到需要Autowired的元数据(字段、方法) ,然后再inject

先看看findAutowiringMetadata

// AutowiredAnnotationBeanPostProcessor.findAutowiringMetadata
private InjectionMetadata findAutowiringMetadata(String beanName, Class clazz, @Nullable PropertyValues pvs) {
   // Fall back to class name as cache key, for backwards compatibility with custom callers.
   String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
   // Quick check on the concurrent map first, with minimal locking.
   InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
   if (InjectionMetadata.needsRefresh(metadata, clazz)) {
      synchronized (this.injectionMetadataCache) {
         metadata = this.injectionMetadataCache.get(cacheKey);
         if (InjectionMetadata.needsRefresh(metadata, clazz)) {
            if (metadata != null) {
               metadata.clear(pvs);
            }
            metadata = buildAutowiringMetadata(clazz);
            this.injectionMetadataCache.put(cacheKey, metadata);
         }
      }
   }
   return metadata;
}

这个needsRefresh简单看看就好,我们是第一次进入这个方法,所以这个metadata是null,那么这个方法返回的是true

public static boolean needsRefresh(@Nullable InjectionMetadata metadata, Class clazz) {
   return (metadata == null || metadata.needsRefresh(clazz));
}

那么会进入到这个方法buildAutowiringMetadata

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

   List elements = new ArrayList();
   Class targetClass = clazz;

   do {
      final List currElements = new ArrayList();
      // 处理字段
      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));
         }
      });
      // 处理方法
      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));
         }
      });

      elements.addAll(0, currElements);
      // 获取父类,继续找
      targetClass = targetClass.getSuperclass();
   }
   while (targetClass != null && targetClass != Object.class);

   return InjectionMetadata.forElements(elements, clazz);
}

这边传入的clazz就是bean的Class,忘记了可以找上面的代码看一下

这里源码写了很多,我们暂时只关心注入字段的那一块

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));
   }
});

处理字段的时候进入了ReflectionUtilsdoWithLocalFields方法

// ReflectionUtils.doWithLocalFields
public static void doWithLocalFields(Class clazz, FieldCallback fc) {
   for (Field field : getDeclaredFields(clazz)) {
      try {
         fc.doWith(field);
      }
      catch (IllegalAccessException ex) {
         throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + ex);
      }
   }
}

继续追溯一下可以得知,这里是获取clazz的所有字段并进行处理,这个FieldCallback是一个函数式接口,它的实现就是外面传进来的这段代码

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修饰

// AutowiredAnnotationBeanPostProcessor.findAutowiredAnnotation
@Nullable
private MergedAnnotation findAutowiredAnnotation(AccessibleObject ao) {
MergedAnnotations annotations = MergedAnnotations.from(ao);
// autowiredAnnotationTypes包含 @Autowired,@Value,@Inject
for (Class

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论