static 属性为何不能使用 @Value 注解

简介: 在某个 Spring 项目中,看到有人在 Spring Bean 中对 static 静态属性使用 @Value 注解进行属性值注入,结果没将配置文件中配置的值赋值到属性中。
我是陈皮,一个在互联网 Coding 的 ITer,个人微信公众号「陈皮的JavaLib」关注第一时间阅读最新文章。

@[TOC]

问题描述

在某个 Spring 项目中,看到有人在 Spring Bean 中对static静态属性使用@Value注解进行属性值注入,结果没将配置文件中配置的值赋值到属性中。下面演示进行问题复现。

Springboot 项目的配置文件 application.yml 有如下配置变量。

person.name: 陈皮
person.age: 18

Spring bean 类,定义2个静态熟悉,分别使用属性注入,和 set 方法注入属性值。

package com.chenpi;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author 陈皮
 * @version 1.0
 * @description
 * @date 2022/4/3
 */
@Component
public class Person {

  @Value("${person.name}")
  private static String name;

  private static String age;

  @Value("${person.age}")
  public void setAge(String age) {
    Person.age = age;
  }

  @Override
  public String toString() {
    return "Person{" + "name='" + name + '\''
        + ", age='" + age + '\''
        + '}';
  }
}

编写测试单元进行验证。

package com.chenpi;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ApplicationTests {

  @Autowired
  private Person person;

  @Test
  public void testValue() {
    System.out.println(person);
  }

}

测试结果显示,@Value 注解放在静态属性上注入值失败,而 @Value 放在 setter 方法上(注意,该方法也不能是静态方法)注入成功。

Person{name='null', age='18'}

分析

首先,从启动日志看出,Autowired 注解不能作用在静态属性上。

2022-04-03 13:47:38.156  INFO 10576 --- [    Test worker] f.a.AutowiredAnnotationBeanPostProcessor : Autowired annotation is not supported on static fields: private static java.lang.String com.chenpi.Person.name

我们通过这打印的日志,找到 Spring 源码中打印这句日志的地方,发现对于需要注入的属性或者注入方法,对 static 属性或者 static 方法进行了排除。

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
        List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
        Class<?> targetClass = clazz;

        do {
            final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();

            ReflectionUtils.doWithLocalFields(targetClass, field -> {
                AnnotationAttributes 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;
                }
                AnnotationAttributes 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 new InjectionMetadata(clazz, elements);
    }

结论

从源码中发现,理论上 Spring 是可以对静态域进行注入的,但是 Spring 没有这样做。其实应该也可以理解,毕竟 Spring 一般是对 Spring Bean 进行管理,而 Spring bean 是实例,那么对于 bean 的依赖注入发生的时机应该是在实例的生命周期中,而不是在类的生命周期中。


本次分享到此结束啦~~

如果觉得文章对你有帮助,点赞、收藏、关注、评论,您的支持就是我创作最大的动力!

相关文章
|
存储 Cloud Native 编译器
C++ static与类
C++ static与类
|
7月前
|
Java
获取 Class 对象
获取 Class 对象
41 1
|
7月前
|
Java API
Class 类
Class 类
44 1
|
存储 C++
【C++类】 -- 类与static
【C++类】 -- 类与static
66 0
|
Java 关系型数据库 MySQL
如何使用@Value注解为bean的属性赋值呢
如何使用@Value注解为bean的属性赋值呢
|
前端开发 程序员 开发者
class-使用 static 创建静态属性|学习笔记
快速学习 class-使用 static 创建静态属性
125 0
注解与反射6得到Class类的几种方式
注解与反射6得到Class类的几种方式
|
存储 Java 编译器
Java面向对象——封装、构造方法、private、static
Java面向对象——封装、构造方法、private、static
400 0
Java面向对象——封装、构造方法、private、static

热门文章

最新文章