日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

从源码深处体验Spring核心技术--基于注解的IOC初始化

發布時間:2024/4/13 javascript 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从源码深处体验Spring核心技术--基于注解的IOC初始化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Annotation 的前世今生

從 Spring2.0 以后的版本中,Spring 也引入了基于注解(Annotation)方式的配置,注解(Annotation)是 JDK1.5 中引入的一個新特性,用于簡化 Bean 的配置,可以取代 XML 配置文件。

開發人員對注解(Annotation)的態度也是蘿卜青菜各有所愛,個人認為注解可以大大簡化配置,提高開發速度,但也給后期維護增加了難度。目前來說 XML 方式發展的相對成熟,方便于統一管理。

隨著 Spring Boot 的興起,基于注解的開發甚至實現了零配置。但作為個人的習慣而言,還是傾向于 XML 配置文件和注解(Annotation)相互配合使用。

Spring IOC 容器對于類級別的注解和類內部的注解分以下兩種處理策略:

1)、類級別的注解:如@Component、@Repository、@Controller、@Service 以及 JavaEE6 的 @ManagedBean 和@Named 注解,都是添加在類上面的類級別注解,Spring 容器根據注解的過濾規則掃描讀取注解 Bean 定義類,并將其注冊到 Spring IOC 容器中。

2)、類內部的注解:如@Autowire、@Value、@Resource 以及 EJB 和 WebService 相關的注解等,都是添加在類內部的字段或者方法上的類內部注解,SpringIOC 容器通過 Bean 后置注解處理器解析Bean 內部的注解。下面將根據這兩種處理策略,分別分析 Spring 處理注解相關的源碼。

定位 Bean 掃描路徑

在 Spring 中 管 理 注 解 Bean 定 義 的 容 器 有 兩 個 :

AnnotationConfigApplicationContext 和 AnnotationConfigWebApplicationContex。

這兩個類是專門處理 Spring 注解方式配置的容器,直接依賴于注解作為容器配置信息來源的 IOC 容器。

AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext 的 Web 版本,兩者的用法以及對注解的處理方式幾乎沒有差別。現在我們以AnnotationConfigApplicationContext 為例看看它的源碼:

通過上面的源碼分析,我們可以看啊到 Spring 對注解的處理分為兩種方式:

1)、直接將注解 Bean 注冊到容器中

可以在初始化容器時注冊;也可以在容器創建之后手動調用注冊方法向容器注冊,然后通過手動刷新容器,使得容器對注冊的注解 Bean 進行處理。

2)、通過掃描指定的包及其子包下的所有類

在初始化注解容器時指定要自動掃描的路徑,如果容器創建以后向給定路徑動態添加了注解 Bean,則需要手動調用容器掃描的方法,然后手動刷新容器,使得容器對所注冊的 Bean 進行處理。

接下來,將會對兩種處理方式詳細分析其實現過程。

讀取 Annotation 元數據

當創建注解處理容器時,如果傳入的初始參數是具體的注解 Bean 定義類時,注解容器讀取并注冊。

1)、AnnotationConfigApplicationContext 通過調用注解 Bean 定義讀取器

AnnotatedBeanDefinitionReader 的 register()方法向容器注冊指定的注解 Bean,注解 Bean 定義讀取器向容器注冊注解 Bean 的源碼如下:

從上面的源碼我們可以看出,注冊注解 Bean 定義類的基本步驟:

a、需要使用注解元數據解析器解析注解 Bean 中關于作用域的配置。

b、使用 AnnotationConfigUtils 的 processCommonDefinitionAnnotations()方法處理注解 Bean 定義類中通用的注解。

c、使用 AnnotationConfigUtils 的 applyScopedProxyMode()方法創建對于作用域的代理對象。

d、通過 BeanDefinitionReaderUtils 向容器注冊 Bean。

下面我們繼續分析這 4 步的具體實現過程

2)、AnnotationScopeMetadataResolver 解析作用域元數據

AnnotationScopeMetadataResolver 通過 resolveScopeMetadata()方法解析注解 Bean 定義類的作用域元信息,即判斷注冊的 Bean 是原生類型(prototype)還是單態(singleton)類型,其源碼如下:

上述代碼中的 annDef.getMetadata().getAnnotationAttributes()方法就是獲取對象中指定類型的注解的值。

3)、AnnotationConfigUtils 處理注解 Bean 定義類中的通用注解

AnnotationConfigUtils 類的 processCommonDefinitionAnnotations()在向容器注冊 Bean 之前,首先對注解 Bean 定義類中的通用 Spring 注解進行處理,源碼如下:

4)、AnnotationConfigUtils 根據注解Bean定義類中配置的作用域為其應用相應的代理策略

AnnotationConfigUtils 類的 applyScopedProxyMode()方法根據注解 Bean 定義類中配置的作用域@Scope 注解的值,為 Bean 定義應用相應的代理模式,主要是在 Spring 面向切面編程(AOP)中使用。

源碼如下:

這段為 Bean 引用創建相應模式的代理,這里不做深入的分析。

5)、BeanDefinitionReaderUtils 向容器注冊 Bean

BeanDefinitionReaderUtils 主要是校驗 BeanDefinition 信息,然后將 Bean 添加到容器中一個管理BeanDefinition 的 HashMap 中。


掃描指定包并解析為 BeanDefinition

當創建注解處理容器時,如果傳入的初始參數是注解 Bean 定義類所在的包時,注解容器將掃描給定的包及其子包,將掃描到的注解 Bean 定義載入并注冊。

1)、ClassPathBeanDefinitionScanner 掃描給定的包及其子包

AnnotationConfigApplicationContext 通 過 調 用 類 路 徑 Bean 定 義 掃 描 器 ClassPathBeanDefinitionScanner 掃描給定包及其子包下的所有類,主要源碼如下:

類路徑 Bean 定義掃描器 ClassPathBeanDefinitionScanner 主要通過findCandidateComponents()

方法調用其父類 ClassPathScanningCandidateComponentProvider 類來掃描獲取給定包及其子包下的類。

2)、ClassPathScanningCandidateComponentProvider 掃描給定包及其子包的類

ClassPathScanningCandidateComponentProvider 類的 findCandidateComponents()方法具體實現掃描給定類路徑包的功能,主要源碼如下:

注冊注解 BeanDefinition

AnnotationConfigWebApplicationContext 是 AnnotationConfigApplicationContext 的 Web 版, 它們對于注解 Bean 的注冊和掃描是基本相同的,但是AnnotationConfigWebApplicationContext 對注解 Bean 定義的載入稍有不同,AnnotationConfigWebApplicationContext 注入注解 Bean 定義源碼如下:

以上就是解析和注入注解配置資源的全過程分析。

IOC 容器小結

現在通過上面的代碼,總結一下 IOC 容器初始化的基本步驟:

1、初始化的入口在容器實現中的 refresh()調用來完成。

2、對 Bean 定義載入 IOC 容器使用的方法是 loadBeanDefinition(),

其中的大致過程如下:通過 ResourceLoader 來完成資源文件位置的定位,DefaultResourceLoader是默認的實現,同時上下文本身就給出了 ResourceLoader 的實現,可以從類路徑,文件系統,URL 等方式來定為資源位置。

如果是 XmlBeanFactory 作為 IOC 容器,那么需要為它指定 Bean 定義的資源,也 就 是 說 Bean 定 義 文 件 時 通 過 抽 象 成 Resource 來 被 IOC 容 器 處 理 的 , 容器通過BeanDefinitionReader 來 完 成 定 義 信 息 的 解 析 和 Bean 信 息 的 注 冊 , 往 往 使 用 的 是 XmlBeanDefinitionReader 來 解 析 Bean 的 XML 定 義 文 件 - 實 際 的 處 理 過 程 是 委 托 給 BeanDefinitionParserDelegate 來完成的。

從而得到 bean 的定義信息,這些信息在 Spring 中使用 BeanDefinition對象來表示-這個名字可以讓我們想到loadBeanDefinition(),registerBeanDefinition()這些相關方法。

它們都是為處理 BeanDefinitin 服務的,容器解析得到 BeanDefinition 以后,需要把它在 IOC 容器中注冊,這由 IOC 實現 BeanDefinitionRegistry 接口來實現。注冊過程就是在 IOC 容器內部維護的一個 HashMap 來保存得到的 BeanDefinition 的過程。

這個 HashMap 是 IOC 容器持有Bean 信息的場所,以后對 Bean 的操作都是圍繞這個 HashMap 來實現的。

然后我們就可以通過 BeanFactory 和 ApplicationContext 來享受到 Spring IOC 的服務了,在使用 IOC容器的時候,我們注意到除了少量粘合代碼,絕大多數以正確 IOC 風格編寫的應用程序代碼完全不用關心如何到達工廠,因為容器將把這些對象與容器管理的其他對象鉤在一起。

基本的策略是把工廠放到已知的地方,最好是放在對預期使用的上下文有意義的地方,以及代碼將實際需要訪問工廠的地方。

Spring本身提供了對聲明式載入web應用程序用法的應用程序上下文,并將其存儲在ServletContext中的框架實現。

以下是容器初始化全過程的時序圖

?

總結

以上是生活随笔為你收集整理的从源码深处体验Spring核心技术--基于注解的IOC初始化的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。