版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
</div>
<!--一个博主专栏付费入口-->
<!--一个博主专栏付费入口结束-->
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-4a3473df85.css">
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-4a3473df85.css">
<div class="htmledit_views" id="content_views">
<p>很久之前使用了@PostConstruct注解,用来注入一些程序中需要的服务。时间久了,迷迷糊糊的不知道当时的使用场景是什么了。最近又遇到一个场景,赶紧整理一下。</p>
填坑前奏:
在维护一个旧程序时,在某个类中,前一任攻城狮 写了一段这样的代码:
-
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中依旧有值。