@PostConstruct、構造函數和@AutoWired的執行順序

很久之前使用了@PostConstruct註解,用來注入一些程序中需要的服務。時間久了,迷迷糊糊的不知道當時的使用場景是什麼了。最近又遇到一個場景,趕緊整理一下。

填坑前奏:

在維護一箇舊程序時,在某個類中,前一任攻城獅 寫了一段這樣的代碼:

public class AService { 
  static Map<String, String> brandType = new HashedMap();
  static Map<String, String> channelType = new HashedMap();

  static {
    brandType.put("1", "ABCD");
    brandType.put("2", "EFGH");
    ……
    //N個配置
  }

  public …… FuncB(){
	//舉個栗子
	String typeCode = brandType.getCode;
  }
}

單從語法上,上面這段代碼沒有什麼錯誤,但如果我們需要爲其中一個類別的map中添加或者修改方式,難道我們將線上機器停止,修改代碼、重新打包、然後部署??豈不荒謬,終究會把自己埋在坑裏,不能自拔。

於是小編將這些方式的配置信息存儲到mysql數據庫中,通過不同的類別來獲取。由於當前類中的其他方法還需要使用當前map中的值,所以小編考慮將dao的獲取使用@PostConstruct的方式來獲取。

public class AService {
    @Autowired(required = false)
    private MetaConfigDao configDao;

    Map<String,String> brandType = new HashedMap();
    Map<String,String> channelType = new HashedMap();

    @PostConstruct
    public void initConfigs() {
        brandType = configDao.queryConfigsByType("brand")
			.stream()
            .collect(Collectors.toMap(MetaConfigEntity::getCode,MetaConfigEntity::getName));
        channelType = configDao.queryConfigsByType("channel")
            .stream()
            .collect(Collectors.toMap(MetaConfigEntity::getCode,MetaConfigEntity::getName));
        ……
    }

	public …… FuncB(){
		//舉個栗子
		String typeCode = brandType.getCode;
	}
}

“知其然,知其所以然”,我們使用一個test類來測試一下 類的構造方法、postContruct、autoWired的執行順序;

▶ 基礎掃盲

使用@PostConstruct註解修飾的方法會在服務器加載Servlet時運行,並且只會執行一次,在構造函數之後,在init方法之前執行;

借用網上的一個圖片,執行順序爲:

執行順序

▶實踐出真知

爲了驗證上述的順序,我們通過一個測試類來演示一下:

@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class PersonalTest {

  @Autowired
  private CrowdService crowdService;

  public PersonalTest(){
    System.out.println("構造器,此時crowService還沒有被注入=" + crowdService);
  }

  @PostConstruct
  private void init(){
    System.out.println("此時crowdSrevice在依賴注入後將被自動調用,crowdService=" + crowdService);
  }
  @Test
  public void test() throws Exception{
  }
}

我們運行test()方法,打印的日誌爲:

構造器,此時crowService還沒有被注入=null  //執行的第一句日誌就是該類的構造方法

………………………………………………//此處爲springBoot程序打印的日誌

此時crowdSrevice在依賴注入後將被自動調用,crowdService=**.*****.***.CrowdService@2128762

爲了驗證 PostContruct註解所修飾的變量/方法只加載一次,我們在上述類中添加另外一個測試方法:test2();

  @Test
  public void test2() throws Exception{
    System.out.println("------前------");
    PersonalTest test = new PersonalTest();
    System.out.println("------後------");
  }

執行的結果爲:

構造器,此時crowService還沒有被注入=null  //執行的第一句日誌就是該類的構造方法

………………………………………………//此處爲springBoot程序打印的日誌

此時crowdSrevice在依賴注入後將被自動調用,crowdService=**.*****.***.CrowdService@2128762
------前------
構造器,此時crowService還沒有被注入=null
------後------

我們可以發現,當我們對類執行new操作時,該類的構造方法會再次被執行,但是PostContruct卻沒有再次執行。但是crowdService中依舊有值。

 

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