报错记录:构造方法获取不了@Value的值,问题刨析与解决方案

报错记录:构造方法获取不了@Value的值,问题刨析与解决方案

有时我们需要在构造函数中初始化属性,之前老的项目是用的I/O流来获取配置文件的值,目前配置转为线上,使用Apollo来获取值,由于获取Apollo的值被封装到了Spring容器中,我们就需要使用Spring容器中的配置值

而获取配置最简单的方式就是使用@Value注解,但是老的项目中使用构造方法来初始化kafka的配置信息,这里项目初始化就会报错,debug后,发现获取的配置文件信息为null,导致bug出现

原因是:对象被Spring容器接管之前会调用构造函数构造对象,导致注解失效,构造函数执行完成被Spring容器接管之后才会调用@Value注解将配置注入对应的属性当中

下面是解决方案

一、查看Spring容器接管对象时的执行顺序

1、A.java

@Component
public class A {
    
    
    public A(){
    
    
        System.out.println("构造函数");
    }
    public void Test(){
    
    
        System.out.println("Test");
    }
}

2、测试类ATest.java

@SpringBootTest
public class ATest {
    
    
    @Autowired
    private A a;

    @Test
    public void TestA(){
    
    
        a.Test();
    }
}

3、结果

在这里插入图片描述

二、查看到底是配置文件没有对应的值还是说@Value注解没生效

1、在配置文件中有两个值

num=1
url="http://localhost:8080/test"

2、改造一下A.java类,看看普通方法

@SpringBootTest
public class ATest {
    
    
    @Value("${num}")
    private int num;

    @Value("${url}")
    private String url;

    @Value("${url:测试}")
    private String url2;

    @Value("${url3:测试默认值}")
    private String url3;

    @Autowired
    private A a;

    public A(){
    
    
        System.out.println("===========构造函数================");
        System.err.println(num);
        System.err.println(url);
        System.err.println(url2);
        System.err.println(url3);
    }
    public void Test(){
    
    
        System.out.println("===========Test方法================");
        System.err.println(num);
        System.err.println(url);
        System.err.println(url2);
        System.err.println(url3);
    }
}

2、运行测试类ATest.java的Test方法

@SpringBootTest
public class ATest {
    
    
    @Autowired
    private A a;

    @Test
    public void TestA(){
    
    
        a.Test();
    }
}

3、结果@Value没有生效,当然@ConfigurationProperties也不会生效

(1)、@Value注解

在这里插入图片描述

(2)、@ConfigurationProperties注解,我这里打了个断点直接看整个Animal.java类,这个类我没有放到本文的里面,没有必要,反正不行就对了

在这里插入图片描述

4、结论

由于基本数据类型int的默认值为0,而String是一个类,默认值就是null

url3url2这两个属性中的@Value注解我加入了默认值,如果@Value生效了,且在配置文件中找不到值,那么返回的则是默认值

而此处四个属性都返回的基本的默认值,说明执行构造函数的时候,Spring并没有接管该对象,导致@Value注解根本就没有生效

三、解决方案:使用@PostConstruct注解

在这里插入图片描述

1、改造A.java

@Component
public class A {
    
    

    @Value("${num}")
    private int num;

    @Value("${url}")
    private String url;

    @Value("${url:测试}")
    private String url2;

    @Value("${url3:测试默认值}")
    private String url3;

    public A(){
    
    
        System.out.println("===========构造函数================");
        System.err.println(num);
        System.err.println(url);
        System.err.println(url2);
        System.err.println(url3);
    }
    public void Test(){
    
    
        System.out.println("===========Test方法================");
        System.err.println(num);
        System.err.println(url);
        System.err.println(url2);
        System.err.println(url3);
    }
    @PostConstruct
    public void initField(){
    
    
        System.out.println("===========构造函数结束之后自动执行================");
        System.err.println(num);
        System.err.println(url);
        System.err.println(url2);
        System.err.println(url3);
    }
}

2、执行测试类ATest.java

@SpringBootTest
public class ATest {
    
    
    @Autowired
    private A a;

    @Test
    public void TestA(){
    
    
        a.Test();
    }
}

3、结果

在这里插入图片描述

这里有关于@PostConstruct注解的详解有兴趣的小伙伴可以看一下:Spring框架@PostConstruct注解详解 - 掘金 (juejin.cn)

猜你喜欢

转载自blog.csdn.net/qq_57581439/article/details/130389421