SpringBoot 使用@Value注入静态属性失败解决方案

问题背景

背景

最近在写代码时,遇到了一个基础的问题,使用@Value注解进行注入的时候,发现注入失败。下面先贴出我的环境代码

@Component
public class WxUtils {
    private static AccessToken at;
    private static String GET_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";

    @Value("${miniProjectInfo.app-id}")
    private static String appId;

    @Value("${miniProjectInfo.app-secret}")
    private static String appSecret;
    // 省略其他代码....
}

以上代码经过测试发现注入失败,获取值为null。

问题分析

当遇到这种情况,可以分别检查以下地方是有问题:

1. 语法错误

@Value("${miniProjectInfo.app-id}")
private static String appId;
此处暂未发现语法错误

 2. 配置文件错误

需要去检查程序的application.properties/application.yml配置文件是否正确配置该内容

小程序信息
miniProjectInfo:
  app-id: "wx8665*******7be3"
  app-secret: "bec3e143f22a****************dd73c"
此处暂未发现语法错误

需要注意的是,如果不是配置到了默认的application.yml,而是自定义配置文件的话,在Spring Boot项目中,如果是自定义的my.yml文件,需要在某个类中通过@PropertySource 引入该配置文件,而application.yml中的属性会自动被加载。

3. 当前类是否是Bean

@Value注解通常用于将属性值注入到Spring容器管理的Bean中。因此,@Value注解必须作用在Bean类中,才能发挥它的作用。

在注入属性值时,@Value注解可以用于注入配置文件中的属性值、表达式、环境变量、系统属性等,但这些属性值都必须是在Spring容器中管理的Bean中定义的。

如果在非Bean类中使用@Value注解,或者在Bean类中使用@Value注解注入非Spring容器管理的Bean的属性值,通常会导致注入失败或者无法正常使用注入的属性值。

因此,建议将@Value注解作用在Spring容器管理的Bean类中,以便正常使用它的属性注入功能。

4. 书写方式

不要在无参构造器中,进行new对象的操作。否则就会造成@Value注解失败。

在无参构造器中进行new对象的操作不会直接导致@Value注解失败,但可能会影响到@Value注解的使用。

在Spring容器中,Bean的初始化顺序是先执行构造器,然后执行@PostConstruct注解标注的方法。因此,如果在无参构造器中进行new对象的操作,可能会导致@Value注解注入的属性值还未被正确地注入到对象中。这样,在new对象后,使用@Value注解注入的属性值仍然为null。

为了避免这种情况,建议在Bean对象初始化完成后再进行new对象的操作,可以使用@PostConstruct注解标注的方法,在其中进行new对象的操作。这样,可以确保@Value注解注入的属性值已经正确地注入到对象中。

需要注意的是,在使用@PostConstruct注解标注的方法中,可以正常使用@Value注解注入的属性值,因为此时属性值已经被成功注入到对象中。

5. 无法直接注入静态属性

通过观察发现,在如上我的代码中,我是在静态属性上进行了注入,所以导致已知注入失败,获取为空的问题。

使用@Value直接放在static的属性上是无法注入内容的!!!

此方式会一直是null.

在使用@Value注入静态属性时,获取为null的原因可能有以下几种:

1. 静态属性的初始化顺序问题。在类加载时,静态属性会被初始化,此时@Value注解还未生效,因此获取的值为null。解决方法是可以使用Spring提供的静态属性注入方式,即使用@Value注解结合静态setter方法进行注入。

2. 静态属性的作用域问题。静态属性属于类级别,而Spring容器是基于实例的,因此,如果直接使用@Value注解注入静态属性,可能会导致无法获取到正确的值。解决方法是可以使用静态setter方法,将注入的值赋给静态属性。

需要注意的是,尽管可以使用@Value注解注入静态属性,但这种做法不太符合Spring的设计思想,因为Spring是基于实例的容器,而静态属性是与类相关的。建议还是尽可能地避免使用静态属性,或者使用静态setter方法进行注入。

6. 其他情况

检查项目的pom配置文件的打包方式,这个<packaging>此属性可设置三种参数,分别为:

  • pom 【父类型及抽出的公共组件都为pom类型,没有application文件,不能单独启动运行】
  • jar 【内部调用或者是做服务使用】
  • war 【需要部署的项目】

需要注意的是,packaging打包方式不能是pom!!

问题解决

通过以上问题分析,可以发现问题出在了不可以在静态属性上直接进行@Value注入。

解决办法:

1.将这两个私有属性的set方法从私有变成公开(private -->>> public);

2.生成这两个静态属性的set方法;

3.将原来在静态属性上的@Value() 注解改到设在 set方法上;

4.去除这两个静态属性set方法的static关键字

类上面的@Compoent 注解一定要有。

最终结果如下:

@Component
public class WxUtils {
    private static AccessToken at;
    private static String GET_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";

    public static String appId;

    public static String appSecret;

    @Value("${miniProjectInfo.app-id}")
    public void setAppId(String appId) {
        WxUtils.appId = appId;
    }

    @Value("${miniProjectInfo.app-secret}")
    public void setAppSecret(String appSecret) {
        WxUtils.appSecret = appSecret;
    }
// 省略其他代码....
}

 

补充

使用@Value注解时,需要注意什么

1. 需要在配置文件中配置相应的属性值。
2. 需要在需要注入属性的类中使用@Value注解,并指定属性的名称。
3. 如果属性值是一个表达式,需要使用SpEL语法。
4. 如果注入的属性值是一个数组或集合,需要使用逗号或分号分隔不同的值。
5. 如果属性值是一个对象,可以使用@Value注解嵌套注入。
6. 如果需要使用默认值,可以在@Value注解中指定defaultValue属性。
7. 如果需要使用环境变量中的值,可以使用${}语法。
8. 如果需要使用系统属性中的值,可以使用#{systemProperties}语法。
9. 如果需要使用随机数生成的值,可以使用#{random}语法。
10. 如果需要使用Spring表达式,可以使用#{expression}语法。

使用@Value注入值为null的几种原因

在使用@Value注入值为null时,可能有以下几种原因:

1. 未在配置文件中定义对应的属性值,导致注入的值为null。
2. 使用@Value注解时,没有指定默认值,而在配置文件中也未定义对应的属性值,导致注入的值为null。
3. 在使用@Value注解时,将required属性设置为true(默认为true),但在配置文件中未定义对应的属性值,导致注入的值为null。
4. 在使用@Value注解时,将ignore-resource-not-found属性设置为true(默认为false),但在配置文件中未定义对应的属性值,导致注入的值为null。
5. 如果配置文件中定义的属性值为null,则使用@Value注入时,会注入null值。

需要注意的是,如果注入的值为null,可能会导致程序出现空指针异常等问题。因此,在使用@Value注解时,需要确保配置文件中定义了对应的属性值,并且设置了合理的默认值或者校验逻辑,以避免出现异常情况。

微信关注

编程那点事儿

 

 

阅读剩余
THE END