成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

探索Spring Boot中@PostConstruct的魔法

開發 項目管理
具體實現類是InitDestroyAnnotationBeanPostProcessor,具體的邏輯是:先查詢被@PostConstruct標記的方法,然后使用java反射去執行這個方法。回答完后,如果他不換一個問題的話,把Springboot的擴展點都給他盤一遍。

前言

@postContruct全限定類名是javax.annotation.PostConstruct,可以看出來其本身不是Spring定義的注解,但是Spring提供了具體的實現,所以這篇文章主要分析的是@PostConstruct在Spring項目開發中的功能特性、實現方式和基本工作原理。

功能特性

從@PostConstruct注解的注釋上看,可以了解到以下內容:

1、要在依賴加載后,對象佤用前執行,并且只執行一次;

2、所有支持依賴注入的類都需要支持此方法。即使類沒有請求注入任何的資源,也必須調用被@PostConstruct注解標記的方法;

3、一個類中在一個方法上使用@PostConstruct注解;

4、使用@PostConstruct注解標記的方法不能有參數,除非是攔截器,可以采用攔截器規范定義的InvocationContext對象。

5、使用@PostConstruct注解標記的方法不能有返回值,實際上如果有返回值,也不會報錯,但是會忽略掉;

6、使用@PostConstruct注解標記的方法的權限,public、private、protected都可以;

7、使用@PostConstruct注解標記的方法不能被static修飾,但是final是可以的;

package javax.annotation;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}

但是在在實際的Spring項目中Bean的生命周期里,其執行的時機是:1、Bean的實例化;2、Bean內依賴屬性的注入 ;3、Bean里被@PostConstruct標記的方法;

下面在實現方式里,用一個小例子來驗證一下這個過程;

實現方式

1、定義一個ExampleController類,采用setter的依賴注入的方式,注入exampleService屬性,另外在定義一個myPostConstruct方法用@PostConstruct注解標記;

@RestController
@Slf4j
public class ExampleController {


    private ExampleService exampleService;


    public ExampleController() {
        log.info("----ExampleController無參數構造方法被執行");
    }
    @Autowired
    public void setExampleService(ExampleService exampleService) {
        this.exampleService = exampleService;
        log.info("----ExampleController類的setExampleService方法被調用");
    }
    @PostConstruct
    public void myPostConstruct(){
        log.info("----ExampleController類的myPostConstruct方法被調用");
    }
}

2、定義ExampleService類

@Service
@Slf4j
public class ExampleService {
    public ExampleService() {
        log.info("----ExampleService的無參數構造方法被調用");
    }
}

3、定義一個單元測試,在單元測試中啟動Spring容器;

@Test
public void test4(){
    log.info("----單元測試執行開始");
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
    log.info("----單元測試執行完畢");
}

單元測試驗證結果:

圖片圖片

從單元測試的執行結果來看,首先,ExampleConstroller被實例化,接著是ExampleService被實例化,然后通過setter依賴注入的方式把ExampleService對象注入到了ExampleConstroller對象中,之后才開始了被@PostConstruct注解標記的myPostConstruct方法的執行。下面就單元測試的結果分析一個@PostConstruct注解的工作原理。

工作原理

@PostConstruct的工作原理的關鍵問題就是:在Spring容器啟動的過程,被@PostConstruct標記的方法是怎么被執行的?

在被@PostConstruct標記的方法上打上斷點,待程序執行的斷點的時候觀察一下方法調用棧信息,這時會發現:

1、Spring容器啟動過程的最后一步,即把需要提前注冊的一些非懶加載的單例Bean時,如ExampleController,注意這時exampleController對象實例化完成,需要注入的exampleService的屬性已經被實例化,且已經注入到exampleController對象中,在BeanPostProcessor接口的擴展方法中,被@PostConstruct標記的方法開始觸發執行,入口位置在AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization。

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
      throws BeansException {


   Object result = existingBean;
   for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessBeforeInitialization(result, beanName);
      if (current == null) {
         return result;
      }
      result = current;
   }
   return result;
}

圖片圖片

那么觸發被@PostConstruct注解標記的方法執行的BeanPostProcessor接口的具體是實現是哪個類呢?通過debug分析,是CommonAnnotationBeanPostProcessor類。

圖片圖片

2、CommonAnnotationBeanPostProcessor類繼承于InitDestroyAnnotationBeanPostProcessor,實際的觸發@PostConstruct標記方法執行的入口是在InitDestroyAnnotationBeanPostProcessor的postProcessBeforeInitialization()

3、InitDestroyAnnotationBeanPostProcessor的postProcessBeforeInitialization()內,邏輯相對比較簡潔,先查詢bean中被@PostConstruct標記的方法,然后再使用java反射來執行這個方法;

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    //查詢bean中被@PostConstruct標記的方法,相關的信息封在LifecycleMetadata對象的
    LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
   try {
    //使用java反射執行被@PostConstruct標記的方法
      metadata.invokeInitMethods(bean, beanName);
   }
   catch (InvocationTargetException ex) {
      throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
   }
   return bean;
}

圖片圖片

總結

從以上幾步的分析來看,被@PostConstruct標記的方法是怎么被執行的,這個問題回答清楚了。如果面試官問你,你了解@PostContruct注解是怎么工作的嗎?你就可以這么回答他:在Bean實例化、屬性注入后,被@PostConstruct標記的方法是在BeanPostProcessor的擴展方法postProcessBeforeInitialization()觸發執行的,具體實現類是InitDestroyAnnotationBeanPostProcessor,具體的邏輯是:先查詢被@PostConstruct標記的方法,然后使用java反射去執行這個方法。回答完后,如果他不換一個問題的話,把Springboot的擴展點都給他盤一遍。

責任編輯:武曉燕 來源: 凡夫編程
相關推薦

2025-02-05 12:28:44

2023-12-05 07:48:23

SpringBoot

2024-11-13 10:26:25

2024-11-21 14:42:31

2025-01-15 08:19:12

SpringBootRedis開源

2024-11-28 09:43:04

2024-08-13 08:41:18

2024-12-17 16:44:22

Spring開發

2024-06-25 08:26:51

高效日期計算安全

2022-12-19 15:12:34

python運算符

2023-09-22 10:12:57

2022-05-25 09:00:00

令牌JWT安全

2024-10-15 16:01:19

SpringBoot緩存預熱

2021-06-01 05:50:03

Spring@PostConstrLifecycle

2024-04-18 09:34:28

Reactor項目異步編程

2025-01-20 13:30:50

2020-03-19 10:44:19

DockerSpring Boo單層鏡像

2020-06-18 08:18:35

密碼加密安全

2024-04-18 08:28:06

2019-04-25 14:25:24

Spring Bootif elseJava
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美日韩高清一区 | 国产一区二区三区四区 | 免费激情av | 中文字幕一区二区三区精彩视频 | 中文字幕日韩av | 国产精品美女www | www.日韩高清 | 国产精品高潮呻吟久久av黑人 | 精品久久久久久 | 激情小说综合网 | 国产免费一级片 | 97国产超碰| 日韩av大片免费看 | 美女艹b| 一区二区三区精品视频 | 国产成人精品综合 | 日韩手机在线看片 | 成人在线免费电影 | japan25hdxxxx日本 做a的各种视频 | 99精品免费视频 | 亚洲一区久久 | 亚洲视频观看 | 天堂视频免费 | 亚洲精品视频免费 | 久久伊| 欧美综合国产精品久久丁香 | 日日射影院 | 免费一级黄色录像 | 91精品国产91久久久久久最新 | 大香在线伊779 | 国产黑丝在线 | 久久久久亚洲av毛片大全 | 午夜亚洲| 成人二区| 亚洲小视频 | 亚洲专区在线 | 91精品在线播放 | 日韩欧美在线一区二区 | www午夜视频 | 免费在线一区二区 | 国产精品视频久久 |