Error record: The construction method cannot obtain the value of @Value, problem analysis and solution

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 Springthe execution sequence when the container takes over the object

1. A.javaclass

@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

insert image description here

2. Check whether the configuration file does not have a corresponding value or the annotation @Valuedoes not take effect

1. There are two values ​​​​in the configuration file

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

2. Modify A.javathe 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.javathe Test method of the test class

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

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

3. The result @Valuedoes not take effect, and of course @ConfigurationPropertiesit will not take effect

(1), @ValueNotes

insert image description here

(2) @ConfigurationPropertiesNote, I made a breakpoint here to look directly at the entire Animal.javaclass. I didn’t put this class in this article. It’s not necessary. Anyway, it’s okay.

insert image description here

4 Conclusion

Since intthe default value of a primitive data type is 0, Stringbut a class, the default value isnull

url3, I added default values ​​to the annotations url2in 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, Springthe object is not taken over, resulting in @Valuethe annotation not taking effect at all.

3. Solution: use @PostConstructannotations

insert image description here

1. A.javaTransformation

@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();
    }
}

3. Results

insert image description here

Here is a detailed @PostConstructexplanation of annotations. Interested friends can take a look at: Spring Framework @PostConstruct Annotation Detailed Explanation - Nuggets (juejin.cn)

Guess you like

Origin blog.csdn.net/qq_57581439/article/details/130389421