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

我是陈皮,一个在互联网 Coding 的 ITer,个人微信公众号「陈皮的JavaLib」关注第一时间阅读最新文章。

问题描述

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


本次分享到此结束啦~~

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

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈皮的JavaLib

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值