tft每日頭條

 > 圖文

 > 如何對一個注解的default方法賦值

如何對一個注解的default方法賦值

圖文 更新时间:2024-11-25 20:26:35
CommonAnnotationBeanPostProcessor解析@Resource、@PostConstruct、@PreDestroy注解

我們在之前的文章分析裡已經知道AnnotationConfigServletWebServerApplicationContext在初始化時會實例化一些後置處理器,其中就包括CommonAnnotationBeanPostProcessor處理器,通過之前我們分析@Autowired注解解析流程知道比較關鍵的兩個流程是通過MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()對需要處理的注解進行解析并封裝成InjectionMetadata,然後通過InstantiationAwareBeanPostProcessor.postProcessProperties()方法對InjectionMetadata進行處理,把相應的對象或value找到并填充到屬性中。而CommonAnnotationBeanPostProcessor

跟AutowiredAnnotationBeanPostProcessor繼承體系是一樣的,流程也差不多,隻是在處理細節上稍微有一些區别。

CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition方法

如何對一個注解的default方法賦值(ResourcePostConstruct)1

首先調了父類的postProcessMergedBeanDefinition方法,而他的父類是InitDestroyAnnotationBeanPostProcessor,所以先看父類的實現邏輯:

InitDestroyAnnotationBeanPostProcessor.InitDestroyAnnotationBeanPostProcessor方法

如何對一個注解的default方法賦值(ResourcePostConstruct)2

代碼結構幾乎是一樣的,那麼我們重點關注的是InitDestroyAnnotationBeanPostProcessor處理的是哪些注解以及在什麼時候開始注解邏輯。

如何對一個注解的default方法賦值(ResourcePostConstruct)3

調用細節這裡就不多說了,跟@Autowired流程一樣,從buildLifecycleMetadata方法可以看出:主要是解析initAnnotationType和destroyAnnotationType兩個注解,然後封裝成LifecycleElement和LifecycleMetadata,需要注意的是被修飾的方法必須是無參方法,那麼initAnnotationType和destroyAnnotationType具體代表是哪兩個注解呢

initAnnotationType和destroyAnnotationType具體代表是哪兩個注解呢

如何對一個注解的default方法賦值(ResourcePostConstruct)4

從CommonAnnotationBeanPostProcessor的構造方法可以看出,initAnnotationType就是@PostConstruct注解,destroyAnnotationType就是@PreDestroy注解。initAnnotationType和destroyAnnotationType這兩個注解的含義以及被這兩個注解的解析過程已經了解了,那麼什麼時候對封裝後的LifecycleElement和LifecycleMetadata進行處理呢?

LifecycleElement和LifecycleMetadata處理入口以及流程

這個流程就要回到bean的實例化流程裡:通過doCreateBean方法對bean實例化時會先用無參構造器或工廠方法進行實例化類,然後用populateBean方法對實例化對象進行屬性的填充,填充完之後用initializeBean方法對bean實例化時需要調用的一些初始化方法進行最後的調用,然後就算實例化完成了,在就注冊了一些bean銷毀時調用的後置處理器(DestructionAwareBeanPostProcessor)。而我們的@PostConstruct就是在initializeBean方法中處理,@PreDestroy在bean銷毀時DestructionAwareBeanPostProcessor.postProcessBeforeDestruction方法中處理。

initializeBean方法處理@PostConstruct

如何對一個注解的default方法賦值(ResourcePostConstruct)5

  1. 對BeanNameAware、BeanClassLoaderAware、BeanFactoryAware中的方法進行調用
  2. 調用BeanPostProcessor.postProcessBeforeInitialization()方法
  3. 調用InitializingBean.afterPropertiesSet()方法和bean的自定義init方法
  4. 調用BeanPostProcessor.postProcessAfterInitialization()方法

而我們的@PostConstruct就是在BeanPostProcessor.postProcessBeforeInitialization()方法中被處理。

InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization()方法

如何對一個注解的default方法賦值(ResourcePostConstruct)6

如何對一個注解的default方法賦值(ResourcePostConstruct)7

如何對一個注解的default方法賦值(ResourcePostConstruct)8

可以看到實際上就是使用了反射調用了@PostConstruct修飾的方法。

InitDestroyAnnotationBeanPostProcessor.postProcessBeforeDestruction()方法

如何對一個注解的default方法賦值(ResourcePostConstruct)9

如何對一個注解的default方法賦值(ResourcePostConstruct)10

如何對一個注解的default方法賦值(ResourcePostConstruct)11

可以看到實際上就是使用了反射調用了@PreDestroy修飾的方法。

至此,InitDestroyAnnotationBeanPostProcessor對于@PostConstruct和@PreDestroy的處理邏輯就處理完了。我們接着看CommonAnnotationBeanPostProcessor中的postProcessMergedBeanDefinition()邏輯。

CommonAnnotationBeanPostProcessor.findResourceMetadata方法

如何對一個注解的default方法賦值(ResourcePostConstruct)12

如何對一個注解的default方法賦值(ResourcePostConstruct)13

resourceAnnotationTypes這個屬性是使用下面這個static代碼塊初始化的

如何對一個注解的default方法賦值(ResourcePostConstruct)14

而@Resource注解會被封裝成ResourceElement對象。

ResourceElement.getResourceToInject方法

如何對一個注解的default方法賦值(ResourcePostConstruct)15

可以看到@Resource默認是name進行注入,如果@Resource設置了name則以設置的為準否則以屬性的變量名為準。

總結:
  1. CommonAnnotationBeanPostProcessor實際上處理了@PostConstruct、@PreDestroy和@Resource注解,但@PostConstruct、@PreDestroy是交給父類DestructionAwareBeanPostProcessor來處理。
  2. @PostConstruct是在bean已經實例化且屬性也已經填充完後在initializeBean方法中進行處理,@PostConstruct在bean被銷毀時處理
  3. @Resource注入時是按name來注入,name優先取@Resource中的name否則取變量名。而@Autowired默認是按classType注入,當找到多個classType類時按變量名注入。
,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关圖文资讯推荐

热门圖文资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved