解决@Value注解不能注入static修饰的属性问题

 更新时间:2022年07月08日 14:18:38   作者:iiaythi  
这篇文章主要介绍了解决@Value注解不能注入static修饰的属性问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

@Value注解不能注入static属性

问题描述

在application.yml中:

constant:
  key: hello
  value: world

工具类ConstantHelper:

@Component
public class ConstantHelper {
    @Value("${constant.value}")
    private static String value;
    private static String key;
    public static String getValue() {
        return value;
    }
    public void setValue(String value) {
        ConstantHelper.value = value;
    }
    public static String getKey() {
        return key;
    }
    @Value("${constant.key}")
    public void setKey(String key) {
        ConstantHelper.key = key;
    }
}

测试类:

@RequestMapping("/getConfig")
public Map<String, Object> getConfig(){
    Map<String,Object> map = new HashMap<>();
    map.put("key", ConstantHelper.getKey());
    map.put("value",ConstantHelper.getValue());
    return map;
}

结果:

{
    "value": null,
    "key": "hello"
}

可以发现,@Value注解放在属性上注入值失败,而@Value放在setter方法上(注意,该方法也不能是静态方法)却能注入成功。为什么??

剖析

答案就在AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata方法中,AutowiredAnnotationBeanPostProcessor主要处理了@Autowired和@Value注解等等:

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) {
          //here!!
                    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))) {
          //here!!
                    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);
    }

The conceptual problem here is that annotation-driven injection happens for each bean instance. So we shouldn’t inject static fields or static methods there because that would happen for every instance of that class. The injection lifecycle is tied to the instance lifecycle, not to the class lifecycle. Bridging between an instance’s state and static accessor - if really desired - is up to the concrete bean implementation but arguably shouldn’t be done by the framework itself.

从源码上发现,理论上spring是可以对静态域注入的,只是spring没有这样做,它认为依赖注入发生的时段是在实例的生命周期,而不是类的生命周期

@Value(“${属性}“)注入被static修饰的属性

场景:

通过httpclient调用第三方接口的时候,ip和端口不确定

需求:

写一个工具类,可以动态配置ip和端口来修改调用的地址和端口,要求工具类方法可以静态调用。

问题描述

 static 不能和注解并用,被static修饰的成员变量,无法通过@Value注解动态获取到

解决方案

通过注入到set方法实现属性动态赋值

application.yml配置:

key:
  box:
    ip: 192.168.1.166
    port: 9987

错误代码:

@Value("${key.box.ip}")
private static String ip ;
@Value("${key.box.port}")
private static String port;

这样写的话,你会发现拿到的结果还是null

正确代码:

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
 * Created in 2021/6/29 15:07
 * @author 
 */
@Slf4j
@Component
public class KeyBoxHttpClientUtil {
    private static String ip ;
    private static String port;
    @Value("${key.box.ip}")
    public void setIP(String ip) {
        KeyBoxHttpClientUtil.ip = ip;
    }
    @Value("${key.box.port}")
    public void setPort(String port) {
        KeyBoxHttpClientUtil.port = port;
    }
}

Tips:调整代码之后,工具类必须使用@Component注解来修饰,否则依然无法获取到结果。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Collections.shuffle()方法实例解析

    Collections.shuffle()方法实例解析

    这篇文章主要介绍了Collections.shuffle()方法实例解析,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • java批量解析微信dat文件

    java批量解析微信dat文件

    这篇文章主要为大家详细介绍了java批量解析微信dat文件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-08-08
  • JDBC实现学生管理系统

    JDBC实现学生管理系统

    这篇文章主要为大家详细介绍了JDBC实现学生管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-02-02
  • Maven编译错误:程序包com.sun.*包不存在的三种解决方案

    Maven编译错误:程序包com.sun.*包不存在的三种解决方案

    J2SE中的类大致可以划分为以下的各个包:java.*,javax.*,org.*,sun.*,本文文章主要介绍了maven编译错误:程序包com.sun.xml.internal.ws.spi不存在的解决方案,感兴趣的可以了解一下
    2024-02-02
  • JAVA调用JavaScript方法代码示例

    JAVA调用JavaScript方法代码示例

    我们都知道脚本语言非常灵活,在处理某些问题的时候Java实现用十几行来写,用js可能不到十行就写完,并且非常简洁,这篇文章主要给大家介绍了关于JAVA调用JavaScript方法的相关资料,需要的朋友可以参考下
    2023-10-10
  • Spring中的@Scope注解详细讲解及示例

    Spring中的@Scope注解详细讲解及示例

    这篇文章主要介绍了Spring中的@Scope注解详细讲解及示例,@Scope注解是 Spring IOC 容器中的一个作用域,在 Spring IOC 容器中,他用来配置Bean实例的作用域对象,需要的朋友可以参考下
    2023-11-11
  • 有关ThreadLocal的面试题你真的懂了吗

    有关ThreadLocal的面试题你真的懂了吗

    这篇文章主要介绍了面试题ThreadLocal,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-06-06
  • Spring Boot 配置随机数的技巧代码详解

    Spring Boot 配置随机数的技巧代码详解

    这篇文章主要介绍了Spring Boot 配置随机数技巧,spring boot 支持在系统加载的时候配置随机数,具体实例代码大家参考下本文
    2018-05-05
  • SpringBoot2.0如何启用https协议

    SpringBoot2.0如何启用https协议

    这篇文章主要介绍了SpringBoot2.0如何启用https协议,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06
  • Springboot2集成pagehelper过程图解

    Springboot2集成pagehelper过程图解

    这篇文章主要介绍了springboot2集成pagehelper过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03

最新评论