Error record: The construction method cannot obtain the value of @Value, problem analysis and solution
Sometimes we need to initialize properties in the constructor. The old project used I/O streams to obtain the value of the configuration file. The current configuration is converted to online, and Apollo is used to obtain the value. Because the obtained value of Apollo is encapsulated in Spring In the container, we need to use the configuration value in the Spring container
The easiest way to obtain the configuration is to use the @Value annotation, but in the old project, the construction method is used to initialize the configuration information of Kafka. Here, the project initialization will report an error. After debugging, it is found that the obtained configuration file information is null, resulting in a bug.
Because:
对象被Spring容器接管之前会调用构造函数构造对象,导致注解失效,构造函数执行完成被Spring容器接管之后才会调用@Value注解将配置注入对应的属性当中
Here is the solution
1. View Spring
the execution sequence when the container takes over the object
1. A.java
class
@Component
public class A {
public A(){
System.out.println("构造函数");
}
public void Test(){
System.out.println("Test");
}
}
2. Test classATest.java
@SpringBootTest
public class ATest {
@Autowired
private A a;
@Test
public void TestA(){
a.Test();
}
}
3. Results
2. Check whether the configuration file does not have a corresponding value or the annotation @Value
does not take effect
1. There are two values in the configuration file
num=1
url="http://localhost:8080/test"
2. Modify A.java
the class and look at the common method
@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. Run ATest.java
the Test method of the test class
@SpringBootTest
public class ATest {
@Autowired
private A a;
@Test
public void TestA(){
a.Test();
}
}
3. The result @Value
does not take effect, and of course @ConfigurationProperties
it will not take effect
(1), @Value
Notes
(2) @ConfigurationProperties
Note, I made a breakpoint here to look directly at the entire Animal.java
class. I didn’t put this class in this article. It’s not necessary. Anyway, it’s okay.
4 Conclusion
Since
int
the default value of a primitive data type is0
,String
but a class, the default value isnull
url3
, I added default values to the annotationsurl2
in these two properties . If it takes effect and the value cannot be found in the configuration file, then the default value will be returned@Value
@Value
The basic default values returned by the four properties here indicate that when the constructor is executed,
Spring
the object is not taken over, resulting in@Value
the annotation not taking effect at all.
3. Solution: use @PostConstruct
annotations
1. A.java
Transformation
@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. Execute the test classATest.java
@SpringBootTest
public class ATest {
@Autowired
private A a;
@Test
public void TestA(){
a.Test();
}
}