@PostConstruct、构造函数和@AutoWired的执行顺序

原文链接:https://blog.csdn.net/YSC1123/article/details/84941075

填坑前奏:

在维护一个旧程序时,在某个类中,前一任攻城狮 写了一段这样的代码:

  1. public class AService {
  2. static Map<String, String> brandType = new HashedMap();
  3. static Map<String, String> channelType = new HashedMap();
  4. static {
  5. brandType.put("1", "ABCD");
  6. brandType.put("2", "EFGH");
  7. ……
  8. //N个配置
  9. }
  10. public …… FuncB(){
  11. //举个栗子
  12. String typeCode = brandType.getCode;
  13. }
  14. }

单从语法上,上面这段代码没有什么错误,但如果我们需要为其中一个类别的map中添加或者修改方式,难道我们将线上机器停止,修改代码、重新打包、然后部署??岂不荒谬,终究会把自己埋在坑里,不能自拔。

于是小编将这些方式的配置信息存储到mysql数据库中,通过不同的类别来获取。由于当前类中的其他方法还需要使用当前map中的值,所以小编考虑将dao的获取使用@PostConstruct的方式来获取。

  1. public class AService {
  2. @Autowired(required = false)
  3. private MetaConfigDao configDao;
  4. Map<String,String> brandType = new HashedMap();
  5. Map<String,String> channelType = new HashedMap();
  6. @PostConstruct
  7. public void initConfigs() {
  8. brandType = configDao.queryConfigsByType("brand")
  9. .stream()
  10. .collect(Collectors.toMap(MetaConfigEntity::getCode,MetaConfigEntity::getName));
  11. channelType = configDao.queryConfigsByType("channel")
  12. .stream()
  13. .collect(Collectors.toMap(MetaConfigEntity::getCode,MetaConfigEntity::getName));
  14. ……
  15. }
  16. public …… FuncB(){
  17. //举个栗子
  18. String typeCode = brandType.getCode;
  19. }
  20. }

“知其然,知其所以然”,我们使用一个test类来测试一下 类的构造方法、postContruct、autoWired的执行顺序;

▶ 基础扫盲

使用@PostConstruct注解修饰的方法会在服务器加载Servlet时运行,并且只会执行一次,在构造函数之后,在init方法之前执行;

借用网上的一个图片,执行顺序为:

执行顺序

▶实践出真知

为了验证上述的顺序,我们通过一个测试类来演示一下:

  1. @Transactional
  2. @RunWith(SpringJUnit4ClassRunner.class)
  3. @SpringBootTest
  4. public class PersonalTest {
  5. @Autowired
  6. private CrowdService crowdService;
  7. public PersonalTest(){
  8. System.out.println("构造器,此时crowService还没有被注入=" + crowdService);
  9. }
  10. @PostConstruct
  11. private void init(){
  12. System.out.println("此时crowdSrevice在依赖注入后将被自动调用,crowdService=" + crowdService);
  13. }
  14. @Test
  15. public void test() throws Exception{
  16. }
  17. }

我们运行test()方法,打印的日志为:

  1. 构造器,此时crowService还没有被注入=null //执行的第一句日志就是该类的构造方法
  2. ………………………………………………//此处为springBoot程序打印的日志
  3. 此时crowdSrevice在依赖注入后将被自动调用,crowdService=**.*****.***.CrowdService@2128762

为了验证 PostContruct注解所修饰的变量/方法只加载一次,我们在上述类中添加另外一个测试方法:test2();

  1. @Test
  2. public void test2() throws Exception{
  3. System.out.println("------前------");
  4. PersonalTest test = new PersonalTest();
  5. System.out.println("------后------");
  6. }

执行的结果为:

  1. 构造器,此时crowService还没有被注入=null //执行的第一句日志就是该类的构造方法
  2. ………………………………………………//此处为springBoot程序打印的日志
  3. 此时crowdSrevice在依赖注入后将被自动调用,crowdService=**.*****.***.CrowdService@2128762
  4. ------前------
  5. 构造器,此时crowService还没有被注入=null
  6. ------后------

我们可以发现,当我们对类执行new操作时,该类的构造方法会再次被执行,但是PostContruct却没有再次执行。但是crowdService中依旧有值。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章