@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中依舊有值。

 

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