报错记录:构造方法获取不了@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
url3
、url2
这两个属性中的@Value
注解我加入了默认值,如果@Value
生效了,且在配置文件中找不到值,那么返回的则是默认值而此处四个属性都返回的基本的默认值,说明执行构造函数的时候,
Spring
并没有接管该对象,导致@Value
注解根本就没有生效
三、解决方案:使用@PostConstruct
注解
扫描二维码关注公众号,回复:
14994451 查看本文章
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();
}
}