很久之前使用了@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中依舊有值。