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 的依赖注入发生的时机应该是在实例的生命周期中,而不是在类的生命周期中。


本次分享到此结束啦~~

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

相关文章
|
Java 测试技术 网络安全
PTS报错问题之压测报错如何解决
PTS(Performance Testing Service)是一项面向网站、应用等提供的压力测试服务,用于模拟不同场景下的用户访问,评估系统的性能表现;在进行PTS压测时,可能会出现一些异常或报错,本合集将PTS压测中频繁出现的问题及其解决办法进行汇编,旨在帮助用户更有效地进行性能测试和问题定位。
Kam
|
Java
java中使用@Value获取值为null问题解决:
java中使用@Value获取值为null问题解决
Kam
1802 0
完美解决->“pip : 无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。”
完美解决->“pip : 无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。”
完美解决->“pip : 无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。”
|
11月前
|
弹性计算 安全 应用服务中间件
阿里云服务器四种常见购买方式图文教程及适用场景参考(2025更新)
阿里云服务器如何购买?比较常见的购买方式有自定义购买、快速购买、通过活动购买、通过云市场镜像页面购买这四种购买方式,每种方式都有主要的适合对象,购买流程也不是完全一样的。例如想要快速购买的用户,一般选择快速购买、通过活动购买最好,如果是想购买的云服务器已经部署好一些自己项目运行所需的各种环境和软件,则选择通过云市场镜像页面购买这种方式更好。本文为以图文形式为大家展示用户选择较多的四种购买方式及适用场景,以供参考。
1914 16
|
负载均衡 监控 Java
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
27699 8
SpringCloud常见面试题(一):SpringCloud 5大组件,服务注册和发现,nacos与eureka区别,服务雪崩、服务熔断、服务降级,微服务监控
|
网络协议 Docker 容器
登录私有镜像仓库报错:Error response from daemon: Get https://dockerhub.thecloud.ink/v2/: dial tcp: lookup dock
登录私有镜像仓库报错:Error response from daemon: Get https://dockerhub.thecloud.ink/v2/: dial tcp: lookup dock
776 0
SpringBoot静态属性赋值:@Value注入静态属性
SpringBoot静态属性赋值:@Value注入静态属性
577 0
|
NoSQL 算法 Java
使用 Spring Boot 实现限流功能:从理论到实践
【6月更文挑战第18天】在微服务和高并发系统中,限流(Rate Limiting)是一种非常重要的技术手段,用于保护系统免受过载,确保服务的稳定性。限流可以控制请求的速率,防止单个客户端或恶意用户消耗过多的资源,从而影响其他用户。
1678 5
|
存储 关系型数据库 MySQL
Mysql有布尔(BOOL)类型吗
Mysql有布尔(BOOL)类型吗
1739 0
|
存储 算法 安全
【国密算法】国密算法在Java中的实践
【国密算法】国密算法在Java中的实践