解决@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注解来修饰,否则依然无法获取到结果。

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

相关文章

  • 深入理解Java中的克隆

    深入理解Java中的克隆

    想必大家对克隆都有耳闻,世界上第一只克隆羊多莉就是利用细胞核移植技术将哺乳动物的成年体细胞培育出新个体,甚为神奇。其实在Java中也存在克隆的概念,即实现对象的复制。本文将尝试介绍一些关于Java中的克隆和一些深入的问题,希望可以帮助大家更好地了解克隆。
    2016-08-08
  • Mybatis打印替换占位符后的完整Sql教程

    Mybatis打印替换占位符后的完整Sql教程

    这篇文章主要介绍了Mybatis打印替换占位符后的完整Sql教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • 浅谈java异常链与异常丢失

    浅谈java异常链与异常丢失

    下面小编就为大家带来一篇浅谈java异常链与异常丢失。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • java.lang.IncompatibleClassChangeError异常的问题解决

    java.lang.IncompatibleClassChangeError异常的问题解决

    本文主要介绍了java.lang.IncompatibleClassChangeError异常的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-06-06
  • Java数组队列概念与用法实例分析

    Java数组队列概念与用法实例分析

    这篇文章主要介绍了Java数组队列概念与用法,结合实例形式分析了Java数组队列相关概念、原理、用法及操作注意事项,需要的朋友可以参考下
    2020-03-03
  • JFinal 调用存储过程的步骤

    JFinal 调用存储过程的步骤

    这篇文章主要介绍了JFinal 调用存储过程的步骤,帮助大家更好的理解和学习使用JFinal,感兴趣的朋友可以了解下
    2021-03-03
  • Java 中的FileReader和FileWriter源码分析_动力节点Java学院整理

    Java 中的FileReader和FileWriter源码分析_动力节点Java学院整理

    本文给大家分享一段示例程序,通过示例代码可以看出FileReader是基于InputStreamReader实现的,FileWriter是基于OutputStreamWriter实现的,具体程序代码大家通过本文了解下吧
    2017-05-05
  • SpringBoot项目中忽略某属性返回数据给前端

    SpringBoot项目中忽略某属性返回数据给前端

    在Spring Boot中,保护敏感信息和减少数据传输是很重要的,我们可以使用多种方法来忽略返回数据中的字段,无论是使用@JsonIgnore注解、Projection投影、@JsonIgnoreProperties注解还是自定义序列化器,都能达到我们的目的,在实际应用中,根据具体场景和需求选择合适的方法
    2024-05-05
  • springboot hazelcast缓存中间件的实例代码

    springboot hazelcast缓存中间件的实例代码

    这篇文章主要介绍了springboot hazelcast缓存中间件的实例代码,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-08-08
  • javaweb实战之商城项目开发(一)

    javaweb实战之商城项目开发(一)

    这篇文章主要针对javaweb商城项目开发进行实战演习,对javaweb商城项目开发进行详细分析,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-02-02

最新评论