日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
@PostConstruct注解是Spring提供的?今天講點(diǎn)不一樣的

本文轉(zhuǎn)載自微信公眾號(hào)「程序新視界」,作者二師兄。轉(zhuǎn)載本文請(qǐng)聯(lián)系程序新視界公眾號(hào)。

成都創(chuàng)新互聯(lián)專注于廣靈企業(yè)網(wǎng)站建設(shè),自適應(yīng)網(wǎng)站建設(shè),商城網(wǎng)站定制開發(fā)。廣靈網(wǎng)站建設(shè)公司,為廣靈等地區(qū)提供建站服務(wù)。全流程按需定制設(shè)計(jì),專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,成都創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)

前言

我們?cè)谥v《Spring的Lifecycle》時(shí)提到,在Spring的使用中可以通過(guò)Lifecycle接口實(shí)現(xiàn)一些基于Spring容器生命周期邏輯。與此對(duì)照的就是通過(guò)@PostConstruct和@PreDestroy在Bean初始化或銷毀時(shí)執(zhí)行一些操作。

很明顯Spring的Lifecycle是基于容器的生命周期來(lái)處理邏輯,而@PostConstruct和@PreDestroy是基于Bean的生命周期來(lái)處理業(yè)務(wù)邏輯。

這里很多朋友就產(chǎn)生了一個(gè)誤解,以為@PostConstruct注解也是Spring提供的。其實(shí)不然,它是Java自帶的注解,下面我們就從頭來(lái)聊聊@PostConstruct注解。

JSR-250規(guī)范

在了解@PostConstruct注解之前,我們先來(lái)科普一個(gè)概念:JSR-250規(guī)范。

JSR-250主要圍繞著“資源”的使用預(yù)定義了一些注解(Annotation),這里的“資源”可以理解為一個(gè)Class類的實(shí)例、一個(gè)JavaBean、或者一個(gè)Spring中的Bean。

JSR-250相關(guān)的注解全部在javax.annotation和javax.annotation.security包中,包括:資源定義和權(quán)限控制。像我們經(jīng)常用到的@Resource、@PostConstruct、@PreDestroy、@Generated等都屬于這個(gè)規(guī)范中定義的注解。

該規(guī)范并沒(méi)有提供具體的實(shí)現(xiàn)方式,僅僅是提供了指導(dǎo)性的文檔和幾個(gè)注解,由具體的框架去實(shí)現(xiàn)。

也就是說(shuō),@PostConstruct注解并不是Spring提供的注解,只不過(guò)Spring按照J(rèn)SR-250規(guī)范實(shí)現(xiàn)了規(guī)范中對(duì)@PostConstruct的約定。而別的框架,或者你自己寫一個(gè)框架,同樣可以按照約定進(jìn)行實(shí)現(xiàn)。

@PostConstruct的約定

@PostConstruct和@PreDestroy是在Java EE 5引入的,位于javax.annotation包下,也就是java拓展包定義的注解。其中,javax中的x就是extension的意思。Java最初的設(shè)計(jì)者認(rèn)為,這些功能并不是Java核心API,因此就放到了擴(kuò)展包中,誰(shuí)用誰(shuí)實(shí)現(xiàn),按照約定就行。

下面直接看看該類上的注解說(shuō)明:

“PostConstruct注釋用于在依賴關(guān)系注入完成之后需要執(zhí)行的方法上,以執(zhí)行任何初始化。此方法必須在將類放入服務(wù)之前調(diào)用。支持依賴關(guān)系注入的所有類都必須支持此注釋。即使類沒(méi)有請(qǐng)求注入任何資源,用PostConstruct注釋的方法也必須被調(diào)用。只有一個(gè)方法可以用此注釋進(jìn)行注釋?!?/p>

“應(yīng)用PostConstruct注釋的方法必須遵守以下所有標(biāo)準(zhǔn):

  • 該方法不得有任何參數(shù),除非是在EJB攔截器(interceptor)的情況下,它將帶有一個(gè)InvocationContext對(duì)象;
  • 該方法的返回類型必須為void;
  • 該方法不得拋出已檢查異常;
  • 應(yīng)用PostConstruct的方法可以是public、protected、package private或private;
  • 除了應(yīng)用程序客戶端之外,該方法不能是static;
  • 該方法可以是final;
  • 如果該方法拋出未檢查異常,那么不得將類放入服務(wù)中,除非是能夠處理異常并可從中恢復(fù)的EJB。

除了上述約定,如果用在Servlet容器當(dāng)中,還有有一定的處理時(shí)機(jī)。

@PostConstruct的執(zhí)行時(shí)機(jī)

下面所講的@PostConstruct的執(zhí)行時(shí)機(jī)是基于Spring的實(shí)現(xiàn)來(lái)講的。被@PostConstruct修飾的方法會(huì)在服務(wù)器加載Servlet時(shí)運(yùn)行,并且只會(huì)被執(zhí)行一次。PostConstruct在構(gòu)造函數(shù)之后執(zhí)行,init()方法之前執(zhí)行。

對(duì)應(yīng)的流程圖如下:

實(shí)例演示

理解了上面的基本概念,就先來(lái)看一個(gè)實(shí)例演示吧,使用起來(lái)非常簡(jiǎn)單。

基于Java 8的Spring Boot項(xiàng)目中添加如下類:

 
 
 
 
  1. @Service
  2. public class OrderService {
  3.     public OrderService(){
  4.         System.out.println("OrderService構(gòu)造方法被執(zhí)行...");
  5.     }
  6.     @PostConstruct
  7.     private void init() {
  8.         System.out.println("PostConstruct注解方法被調(diào)用");
  9.     }
  10.     @PreDestroy
  11.     private void shutdown() {
  12.         System.out.println("PreDestroy注解方法被調(diào)用");
  13.     }
  14. }

啟動(dòng)Spring Boot項(xiàng)目,控制臺(tái)打印日志如下:

 
 
 
 
  1. OrderService構(gòu)造方法被執(zhí)行...
  2. PostConstruct注解方法被調(diào)用

當(dāng)關(guān)閉服務(wù)時(shí),會(huì)打?。?/p>

 
 
 
 
  1. PreDestroy注解方法被調(diào)用

通過(guò)實(shí)例,基本印證了上述說(shuō)的理論。

Java9的以后的移除

在Java 8中我們可以直接使用對(duì)應(yīng)的注解即可,但到Java 9及以后,J2EE棄用了@PostConstruct和@PreDestroy這兩個(gè)注解,并計(jì)劃在Java 11中將其刪除。

針對(duì)這種情況,我們有兩種解決方案:第一添加額外的依賴;第二,換用其他的方式。

第一種方案針對(duì)的是,你非要使用這個(gè)注解,或者說(shuō)你的項(xiàng)目暫時(shí)沒(méi)辦法棄用這兩個(gè)注解。那么,可以手動(dòng)添加依賴:

 
 
 
 
  1.     javax.annotation
  2.     javax.annotation-api
  3.     1.3.2

也就是說(shuō),雖然移除了,但是你把它們的依賴添加上,依舊還是可以用的。但此時(shí)也給我們提了一個(gè)醒兒,在項(xiàng)目中盡量別用這兩個(gè)注解了,Java 11都計(jì)劃將其移除了。

此時(shí),如果你使用的是Spring的項(xiàng)目,則可考慮另外一種方式,基于Spring的InitializingBean和DisposableBean接口來(lái)實(shí)現(xiàn)同樣的功能:

 
 
 
 
  1. @Service
  2. public class PaymentService implements InitializingBean, DisposableBean {
  3.     public PaymentService(){
  4.         System.out.println("PaymentService構(gòu)造方法被執(zhí)行...");
  5.     }
  6.     @Override
  7.     public void destroy() throws Exception {
  8.         System.out.println("destroy方法被調(diào)用");
  9.     }
  10.     @Override
  11.     public void afterPropertiesSet() throws Exception {
  12.         System.out.println("afterPropertiesSet方法被調(diào)用");
  13.     }
  14. }

啟動(dòng)項(xiàng)目,打印日志如下:

 
 
 
 
  1. PaymentService構(gòu)造方法被執(zhí)行...
  2. afterPropertiesSet方法被調(diào)用

停止項(xiàng)目,打印如下信息:

 
 
 
 
  1. destroy方法被調(diào)用

也就是說(shuō)在Spring的生態(tài)中,我們已經(jīng)有替代方案可實(shí)現(xiàn)了,而且是比較推薦的方式。

其實(shí)Spring并沒(méi)有遵守約定

在上面的約定中我們講到一個(gè)類中“只有一個(gè)方法可以用此注釋進(jìn)行注釋”,在OrderService中再添加一個(gè)@PostConstruct注解的方法試試:

 
 
 
 
  1. @Service
  2. public class OrderService {
  3.     public OrderService(){
  4.         System.out.println("OrderService構(gòu)造方法被執(zhí)行...");
  5.     }
  6.     @PostConstruct
  7.     private void init() {
  8.         System.out.println("PostConstruct注解方法被調(diào)用");
  9.     }
  10.     @PostConstruct
  11.     private void init1() {
  12.         System.out.println("PostConstruct init1 注解方法被調(diào)用");
  13.     }
  14.     @PreDestroy
  15.     private void shutdown() {
  16.         System.out.println("PreDestroy注解方法被調(diào)用");
  17.     }
  18. }

啟動(dòng)程序,打印日志:

 
 
 
 
  1. OrderService構(gòu)造方法被執(zhí)行...
  2. PostConstruct init1 注解方法被調(diào)用
  3. PostConstruct注解方法被調(diào)用

不但沒(méi)報(bào)錯(cuò),而且兩個(gè)方法還都執(zhí)行了。這說(shuō)明什么?這說(shuō)明約定有時(shí)候就是用來(lái)被打破的,記住這一特殊情況就好。

Spring中的實(shí)現(xiàn)原理

以上是對(duì)@PostConstruct的簡(jiǎn)單介紹,下面會(huì)從Spring源碼層面簡(jiǎn)單分析一下實(shí)現(xiàn)原理。

我們先來(lái)看一個(gè)Spring的接口BeanPostProcessor:

 
 
 
 
  1. public interface BeanPostProcessor {
  2.  
  3.     // 任何Bean實(shí)例化,并且Bean已經(jīng)populated(填充屬性) 就會(huì)回調(diào)這個(gè)方法
  4.     Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
  5.  
  6.     // 任何Bean實(shí)例化,并且Bean已經(jīng)populated(填充屬性) 就會(huì)回調(diào)這個(gè)方法
  7.     Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

BeanPostProcessor是Spring IOC容器給我們提供的一個(gè)擴(kuò)展接口,它兩個(gè)回調(diào)方法。當(dāng)一個(gè)BeanPostProcessor的實(shí)現(xiàn)類注冊(cè)到Spring IOC容器后,對(duì)于該Spring IOC容器所創(chuàng)建的每個(gè)bean實(shí)例在初始化方法(如afterPropertiesSet和任意已聲明的init方法)調(diào)用前,將會(huì)調(diào)用BeanPostProcessor中的postProcessBeforeInitialization方法,而在bean實(shí)例初始化方法調(diào)用完成后,則會(huì)調(diào)用BeanPostProcessor中的postProcessAfterInitialization方法,整個(gè)調(diào)用順序可以簡(jiǎn)單示意如下:

 
 
 
 
  1. --> Spring IOC容器實(shí)例化Bean
  2. --> 調(diào)用BeanPostProcessor的postProcessBeforeInitialization方法
  3. --> 調(diào)用bean實(shí)例的初始化方法
  4. --> 調(diào)用BeanPostProcessor的postProcessAfterInitialization方法

而BeanPostProcessor有個(gè)實(shí)現(xiàn)類CommonAnnotationBeanPostProcessor,就是專門處理@PostConstruct和@PreDestroy注解。其中CommonAnnotationBeanPostProcessor的父類InitDestroyAnnotationBeanPostProcessor中,對(duì)應(yīng)的調(diào)用邏輯如下:

 
 
 
 
  1. InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization()
  2.     InitDestroyAnnotationBeanPostProcessor.findLifecycleMetadata()
  3.         // 組裝生命周期元數(shù)據(jù)
  4.         InitDestroyAnnotationBeanPostProcessor.buildLifecycleMetadata()
  5.             // 查找@PostConstruct注釋的方法
  6.             InitDestroyAnnotationBeanPostProcessor.initAnnotationType
  7.             // 查找@PreDestroy注釋方法
  8.             InitDestroyAnnotationBeanPostProcessor.destroyAnnotationType
  9.  // 反射調(diào)用          
  10.  metadata.invokeInitMethods(bean, beanName);

關(guān)于業(yè)務(wù)邏輯的處理細(xì)節(jié),這里就不再逐一展示,大家感興趣的話可以跟蹤一下源代碼。

小結(jié)

本篇文章我們需要留意幾點(diǎn):第一,Spring只是實(shí)現(xiàn)了Java中對(duì)@PostConstruct注解定義的規(guī)范;第二,該注解在Java 9逐步開始廢棄,不建議再使用;第三,可采用Spring的InitializingBean和DisposableBean來(lái)替代對(duì)應(yīng)的功能。


本文名稱:@PostConstruct注解是Spring提供的?今天講點(diǎn)不一樣的
網(wǎng)頁(yè)地址:http://www.5511xx.com/article/dhccsdj.html