文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-04-02 19:55

关注

@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;

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

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯