@Value 静态属性无法注入

 2023-01-09
原文作者:阿劲 原文地址:https://juejin.cn/post/7036604000019415054

在工作中对于一些配置信息或者易变化的属性,我们通常会使用@Value进行属性注入。这样当属性变化时,我们可以直接修改配置文件,而不需要在代码中进行修改。

背景

最近接到的一个开发任务,就使用到了@Value注解对属性进行注入。

这次的开发内容主要是对外暴露一个图片路径,数据库中存放的是图片的相对路径,因此每次查询的时候都是调用封装的工具类进行域名拼接,而域名就是在工具类中通过@Value进行注入的

配置文件

    image-domain-name.prefix=http:xxxx.com

工具类

    @Getter
    @Component
    @Slf4j
    public class ImgUtil {
        @Value("image-domain-name.prefix:")
        private static String PREFIX;
    ​
        private ImgUtil() {}
        
        public static String addImgPre(String imgUrl) {
         // 方法体省略
        }
    }

本来很简单的一个开发任务,结果一测试发现图片不显示,一看路径显示是

    null/xxxx/b9a1aa85-9b40-4e18-8851-8965df2a88f8

一看到null,第一想法就是属性没有注入成功。

经过调试发现,@Value不支持直接给静态变量赋值,

未注入的原因

其实原因很简单,认真思考下就知道原因。

@Value 注解是依赖于属性的set方法进行注入的,而static修饰的属性是类属性,不存在set方法

解决方法

1、set方法手动赋值

利用非静态setter方法注入静态变量, 会在Spring加载的时候进行属性注入

    @Getter
    @Component
    @Slf4j
    public class ImgUtil {
        
        private static String PREFIX;
    ​
        private ImgUtil() {}
        
        @Value("image-domain-name.prefix:")
        public void setPreFix(String preFix) {
            ImgUtil.PREFIX = preFix;
        }
    ​
        public static String addImgPre(String imgUrl) {
         // 方法体省略
        }
    }

2、构造方法赋值

set方法差不多

    @Getter
    @Component
    @Slf4j
    public class ImgUtil {
        
        private static String PREFIX;
    ​
        private ImgUtil() {}
        
        @Value("image-domain-name.prefix:")
        public ImgUtil(String preFix) {
            ImgUtil.PREFIX = preFix;
        }
    ​
        public static String addImgPre(String imgUrl) {
         // 方法体省略
        }
    }

3、@PostConstruct

这个注解是 Common Annotations API 的一部分,也是 JDK 模块的一部分javax.annotation-apiSpring 只调用一次用@PostConstruct注释的方法,就在 bean 属性的初始化之后**。请记住,即使没有要初始化的内容,这些方法也会运行。

@PostConstruct注释的方法 可以有任何访问级别,但不能是静态的

    @Getter
    @Component
    @Slf4j
    public class ImgUtil {
        
        private static String PREFIX;
    ​
        private ImgUtil() {}
        
        @Value("image-domain-name.prefix:")
        private String PREFIX_TEMP;
        
        @PostConstruct
        public void init(){
            PREFIX = PREFIX_TEMP;
        }
    ​
        public static String addImgPre(String imgUrl) {
         // 方法体省略
        }
    }

还有其他方法可以静态属性注入,例如利用@ConfigurationProperties

总结

@Value注解可以用来对Spring容器中的bean的属性进行注入,它能够被用在属性,构造方法,普通方法上。