填坑前奏:
在維護一箇舊程序時,在某個類中,前一任攻城獅 寫了一段這樣的代碼:
- 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中依舊有值。