@PostConstruct注解详解
簡(jiǎn)介
javaEE5引入了@PostConstruct和@PreDestroy兩個(gè)作用于Servlet生命周期的注解,實(shí)現(xiàn)Bean初始化之前和銷毀之前的自定義操作
使用場(chǎng)景
在項(xiàng)目中主要是在Servlet初始化之前加載一些緩存數(shù)據(jù)等
API使用說(shuō)明
PostConstruct 注釋用于在依賴關(guān)系注入完成之后需要執(zhí)行的方法上,以執(zhí)行任何初始化。此方法必須在將類放入服務(wù)之前調(diào)用。支持依賴關(guān)系注入的所有類都必須支持此注釋。即使類沒(méi)有請(qǐng)求注入任何資源,用 PostConstruct 注釋的方法也必須被調(diào)用。只有一個(gè)方法可以用此注釋進(jìn)行注釋。應(yīng)用 PostConstruct 注釋的方法必須遵守以下所有標(biāo)準(zhǔn):該方法不得有任何參數(shù),除非是在 EJB 攔截器 (interceptor) 的情況下,根據(jù) EJB 規(guī)范的定義,在這種情況下它將帶有一個(gè) InvocationContext 對(duì)象 ;該方法的返回類型必須為 void;該方法不得拋出已檢查異常;應(yīng)用 PostConstruct 的方法可以是 public、protected、package private 或 private;除了應(yīng)用程序客戶端之外,該方法不能是 static;該方法可以是 final;如果該方法拋出未檢查異常,那么不得將類放入服務(wù)中,除非是能夠處理異常并可從中恢復(fù)的 EJB。
特點(diǎn):
1、只有一個(gè)非靜態(tài)方法能使用此注解
2、被注解的方法不得有任何參數(shù)
3、被注解的方法返回值必須為void
4、被注解方法不得拋出已檢查異常
5、此方法只會(huì)被執(zhí)行一次
servlet執(zhí)行流程
注意事項(xiàng)
使用此注解時(shí)會(huì)影響服務(wù)啟動(dòng)時(shí)間。服務(wù)啟動(dòng)時(shí)會(huì)掃描WEB-INF/classes的所有文件和WEB-INF/lib下的所有jar包。
@PostConstruct注解的用法
@PostConstruct是java5的時(shí)候引入的注解,指的是在項(xiàng)目啟動(dòng)的時(shí)候執(zhí)行這個(gè)方法,也可以理解為在spring容器啟動(dòng)的時(shí)候執(zhí)行,可作為一些數(shù)據(jù)的常規(guī)化加載,比如數(shù)據(jù)字典之類的。
被@PostConstruct修飾的方法會(huì)在服務(wù)器加載Servle的時(shí)候運(yùn)行,并且只會(huì)被服務(wù)器執(zhí)行一次。PostConstruct在構(gòu)造函數(shù)之后執(zhí)行
也就是加載順序
服務(wù)器加載Servlet -> servlet 構(gòu)造函數(shù)的加載 -> postConstruct ->init(init是在service 中的初始化方法. 創(chuàng)建service 時(shí)發(fā)生的事件.) ->Service->destory->predestory->服務(wù)器卸載serlvet
那么問(wèn)題:spring中Constructor、@Autowired、@PostConstruct的順序
Constructor >> @Autowired >> @PostConstruct
依賴注入的字面意思就可以知道,要將對(duì)象p注入到對(duì)象a,那么首先就必須得生成對(duì)象p與對(duì)象a,才能執(zhí)行注入。所以,如果一個(gè)類A中有個(gè)成員變量p被@Autowired注解,那么@Autowired注入是發(fā)生在A的構(gòu)造方法執(zhí)行完之后的。
@PostConstruct應(yīng)用場(chǎng)景:
如果想在生成對(duì)象時(shí)候完成某些初始化操作,而偏偏這些初始化操作又依賴于依賴注入,那么就無(wú)法在構(gòu)造函數(shù)中實(shí)現(xiàn)。為此,可以使用@PostConstruct注解一個(gè)方法來(lái)完成初始化,@PostConstruct注解的方法將會(huì)在依賴注入完成后被自動(dòng)調(diào)用。
在最近的工作中,get到一個(gè)很實(shí)用的注解,分享給諸位。
痛點(diǎn)
做過(guò)微信或支付寶支付的童鞋,可能遇到過(guò)這種問(wèn)題,就是填寫支付結(jié)果回調(diào),就是在支付成功之后,支付寶要根據(jù)我們給的地址給我們進(jìn)行通知,通知我們用戶是否支付成功,如果成功我們就要去處理下面相應(yīng)的業(yè)務(wù)邏輯,如果在測(cè)試服務(wù),那么這個(gè)回調(diào)地址我們就需要填寫測(cè)試服務(wù)的,如果發(fā)布到線上那么我們就需要改成線上的地址。
針對(duì)上面的場(chǎng)景,我們一般都會(huì)通過(guò)如下的方式,進(jìn)行一個(gè)動(dòng)態(tài)配置,不需要每次去改,防止出現(xiàn)問(wèn)題。
public class PayTest {@Value("${spring.profiles.active}")private String environment;public Object notify(HttpServletRequest request) {if ("prod".equals(environment)) {// 正式環(huán)境} else if ("test".equals(environment)) {// 測(cè)試環(huán)境}return "SUCCESS";} }上面的代碼看起來(lái)沒(méi)有一點(diǎn)問(wèn)題,但是身為搬磚的我們咋可能這樣搬,姿勢(shì)不對(duì)呀!
問(wèn)題:
擴(kuò)展性太差,如果這個(gè)參數(shù)我們還需要在別的地方用到,那么我們是不是還要使用@Value的注解獲取一遍,假如有天我們的leader突然說(shuō)嗎,test這個(gè)單詞看著太low了,換個(gè)高端一點(diǎn)的,換成dev,那么我們是不是要把項(xiàng)目中所有的test都要改過(guò)來(lái),如果少還好,要是很多,那我們怕不是涼了。
所以我們能不能將這些配置參數(shù)搞成一個(gè)全局的靜態(tài)變量,這樣的話我們直接飲用就好了,哪怕到時(shí)候真的要改,那我也只需要改動(dòng)一處就好了。
注意大坑
有的朋友可能就比較自信了,那我直接加個(gè)static修飾下不就好了,如果你真是打算這樣做,那你就準(zhǔn)備卷好鋪蓋走人吧。直接加static獲取到的值其實(shí)是一個(gè)null,至于原因,大家復(fù)習(xí)下類以及靜態(tài)變量變量的加載順序。
@PostConstruct注解
那么既然說(shuō)出了問(wèn)題,肯定就有解決方法,不然你以為我跟你玩呢。
首先這個(gè)注解是由Java提供的,它用來(lái)修飾一個(gè)非靜態(tài)的void方法。它會(huì)在服務(wù)器加載Servlet的時(shí)候運(yùn)行,并且只運(yùn)行一次。
改造:
@Component public class SystemConstant {public static String surroundings;@Value("${spring.profiles.active}")public String environment;@PostConstructpublic void initialize() {System.out.println("初始化環(huán)境...");surroundings = this.environment;} }結(jié)果:
我們可以看到在項(xiàng)目啟動(dòng)的時(shí)候進(jìn)行了初始化
到這里我們已經(jīng)可以拿到當(dāng)前運(yùn)行的環(huán)境是測(cè)試還是正式,這樣就可以做到動(dòng)態(tài)配置
最后想說(shuō)
其實(shí)這個(gè)注解遠(yuǎn)不止這點(diǎn)用處,像我之前寫的Redis工具類,我使用的是RedisTemplate操作Redis,導(dǎo)致寫出來(lái)的方法沒(méi)辦法用static修飾,每次使用Redis工具類只能先注入到容器然后再調(diào)用,使用了這個(gè)注解就可以完美的解決這種尷尬的問(wèn)題。代碼如下。
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;/*** @ClassName RedisUtil* @Description TODO* @Version 1.0*/ @Component public class RedisUtil {private static RedisTemplate<Object, Object> redisTemplates;@Autowiredprivate RedisTemplate<Object, Object> redisTemplate;@PostConstructpublic void initialize() {redisTemplates = this.redisTemplate;}/*** 添加元素** @param key* @param value*/public static void set(Object key, Object value) {if (key == null || value == null) {return;}redisTemplates.opsForValue().set(key, value);} }總結(jié)
以上是生活随笔為你收集整理的@PostConstruct注解详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: jdk中提供的Collection、Co
- 下一篇: 程序员法律考试笔记(2)-依法治国