1. 程式人生 > >Spring對註解(Annotation)處理原始碼分析1——掃描和讀取Bean定義

Spring對註解(Annotation)處理原始碼分析1——掃描和讀取Bean定義

1.Spring2.0以後的版本中,Spring也引入了基於註解(Annotation)方式的配置,註解(Annotation)JDK1.5中引入的一個新特性,用於簡化Bean的配置,某些場合可以取代XML配置檔案。開發人員對註解(Annotation)的態度也是蘿蔔青菜各有所愛,個人認為註解可以大大簡化配置,提高開發速度,同時也不能完全取代XML配置方式,XML 方式更加靈活,並且發展的相對成熟,這種配置方式為大多數 Spring 開發者熟悉;註解方式使用起來非常簡潔,但是尚處於發展階段,XML配置檔案和註解(Annotation)可以相互配合使用。

SpringIoC容器對於類級別的註解和類內部的註解分以下兩種處理策略:

(1).類級別的註解:如@Component@Repository@Controller@Service以及JavaEE6@ManagedBean@Named註解,都是新增在類上面的類級別註解,Spring容器根據註解的過濾規則掃描讀取註解Bean定義類,並將其註冊到Spring IoC容器中。

(2).類內部的註解:如@Autowire@Value@Resource以及EJBWebService相關的註解等,都是新增在類內部的欄位或者方法上的類內部註解,SpringIoC容器通過Bean後置註解處理器解析Bean內部的註解。

下面將根據這兩種處理策略,分別分析Spring

處理註解相關的原始碼。

2.AnnotationConfigApplicationContext對註解Bean初始化:

Spring中,管理註解Bean定義的容器有兩個:AnnotationConfigApplicationContext AnnotationConfigWebApplicationContex。這兩個類是專門處理Spring註解方式配置的容器,直接依賴於註解作為容器配置資訊來源的IoC容器。 AnnotationConfigWebApplicationContextAnnotationConfigApplicationContextweb版本,兩者的用法以及對註解的處理方式幾乎沒有什麼差別,因此本文將以

AnnotationConfigApplicationContext為例進行講解。

AnnotationConfigApplicationContext的原始碼如下:

 

(1).直接將註解Bean註冊到容器中:

可以在初始化容器時註冊;也可以在容器建立之後手動呼叫註冊方法向容器註冊,然後通過手動重新整理容器,使得容器對註冊的註解Bean進行處理。

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

在初始化註解容器時指定要自動掃描的路徑,如果容器建立以後向給定路徑動態添加了註解Bean,則需要手動呼叫容器掃描的方法,然後手動重新整理容器,使得容器對所註冊的Bean進行處理。

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

當建立註解處理容器時,如果傳入的初始引數是具體的註解Bean定義類時,註解容器讀取並註冊。

(1).AnnotationConfigApplicationContext通過呼叫註解Bean定義讀取器AnnotatedBeanDefinitionReaderregister方法向容器註冊指定的註解Bean,註解Bean定義讀取器向容器註冊註解Bean的原始碼如下:

 

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

a,需要使用註解元資料解析器解析註解Bean中關於作用域的配置。

c,使用AnnotationConfigUtilsapplyScopedProxyMode方法建立對於作用域的代理物件。

d,通過BeanDefinitionReaderUtils向容器註冊Bean

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

(2).AnnotationScopeMetadataResolver解析作用域元資料:

AnnotationScopeMetadataResolver通過processCommonDefinitionAnnotations方法解析註解Bean定義類的作用域元資訊,即判斷註冊的Bean是原生型別(prototype)還是單態(singleton)型別,其原始碼如下:

 

上述程式碼中的annDef.getMetadata().getAnnotationAttributes方法就是獲取物件中指定型別的註解的值。

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

 

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

AnnotationConfigUtils類的applyScopedProxyMode方法根據註解Bean定義類中配置的作用域@Scope註解的值,為Bean定義應用相應的代理模式,主要是在Spring面向切面程式設計(AOP)中使用。原始碼如下:

 

這段為Bean引用建立相應模式的代理,如果在Spring面向切面程式設計(AOP)中涉及到再詳細分析,這裡不做深入的分析。

BeanDefinitionReaderUtils向容器註冊載入的Bean我們在第4篇部落格中已經分析過主要是校驗Bean定義然後將Bean新增到容器中一個管理Bean定義的HashMap中,這裡就不做分析。

4.AnnotationConfigApplicationContext掃描指定包及其子包下的註解Bean

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

(1).Spring中常用的註解:

a.Component註解:

 

 

c.Controller註解:

 

通過分析Spring4個常用的註解原始碼,我們看到:@Service@Controller@Repository註解都添加了一個@Component註解,因此他們都屬於@Component

註解。

(2).ClassPathBeanDefinitionScanner掃描給定的包及其子包:

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

 

類路徑Bean定義掃描器ClassPathBeanDefinitionScanner主要通過findCandidateComponents方法呼叫其父類ClassPathScanningCandidateComponentProvider類來掃描獲取給定包及其子包下的類。

(3).ClassPathScanningCandidateComponentProvider掃描給定包及其子包的類:

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

 

5.AnnotationConfigWebApplicationContext載入註解Bean定義:

AnnotationConfigWebApplicationContextAnnotationConfigApplicationContextWeb版,它們對於註解Bean的註冊和掃描是基本相同的,但是AnnotationConfigWebApplicationContext對註解Bean定義的載入稍有不同,AnnotationConfigWebApplicationContext注入註解Bean定義原始碼如下:

 

相關推薦

Spring註解(Annotation)處理原始碼分析1——掃描讀取Bean定義

1.從Spring2.0以後的版本中,Spring也引入了基於註解(Annotation)方式的配置,註解(Annotation)是JDK1.5中引入的一個新特性,用於簡化Bean的配置,某些場合可以取代XML配置檔案。開發人員對註解(Annotation)的態度也是蘿蔔

Spring註解(Annotation)處理原始碼分析2——解析注入註解配置的資源

1.類內部的註解,如:@Autowire、@Value、@Required、@Resource以及EJB和WebSerivce相關的註解,是容器對Bean物件例項化和依賴注入時,通過容器中註冊的Bean後置處理器處理這些註解的。 2.Spring中處理註解的Bean後置處

spring 註解原始碼分析-掃描讀取bean定義

1.概述 從spring2.0以後的版本中,spring也引入了基於註解方式的配置,註解是jdk1.5中引入的一個新特性,用於簡化Bean的配置,某些場合可以取代xml配置檔案。 Spring IoC容器對於類級別的註解和類內部的註解分以下兩種策略: (1)類級別的註解

Spring原始碼分析(十五)Spring中常用註解使用以及原始碼分析

從Java5.0開始,Java開始支援註解。Spring做為Java生態中的領軍框架,從2.5版本後也開始支援註解。相比起之前使用xml來配置Spring框架,使用註解提供了更多的控制Spring框架的方式。 現在越來越多的專案也都在使用註解做相關的配置,但Spring的註解非常多,相信

MyBatis原始碼閱讀——MyBatis事務的處理過程分析

事務管理器 在 MyBatis 中有兩種型別的事務管理器(也就是 type=”[JDBC|MANAGED]”): <environments default="development"> <environment id="

電影網站增刪改查 spring boots/MVC/neo4j 原始碼分析-1 前提

前提: idea , maven 專案新增 分模組 各引用大的方面分兩個模組, data  M /webui  VC: pom.xml for data module  <?xml ver

1Spring原始碼分析1讀取配置檔案

1、XMLBeanFcatory BeanFactory bf = new XmlBeanFactory(new ClassPa

Netty Pipeline原始碼分析(1)

原文連結:wangwei.one/posts/netty… 前面,我們分析了Netty EventLoop的 建立 與 啟動 原理,接下里我們來分析Netty中另外兩個重要元件—— ChannelHandler 與 Pipeline。Netty中I/O事件的傳播機制均由它負責,下面我們來看看它是如

vue原始碼分析1-new Vue做了哪些操作

首先我們可以看到vue的原始碼在github上有,大家可以克隆下來。 git地址 我們主要看src下的內容。 1.現在我們來分析下 new Vue都做了哪些操作 var app = new Vue({ el: '#app', mounted:{ console.log(t

Java程式設計師從笨鳥到菜鳥之(八十一)細談Spring(十)深入原始碼分析Spring之HibernateTemplate

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

redis原始碼分析1------dict的實現

1. 總體結構 redis的dict就是hash表,使用鏈式結構來解決key值衝突,典型的資料結構 結構體的定義如下: typedef struct dictEntry { void *key; union { void *val; uint64_t

Netty原始碼分析:1.4伺服器啟動流程

第一章節是主要是伺服器啟動的程式碼分析。章節目錄有: |———1.1初始化NioEventLoopGroup |———1.2初始化NioEventLoop |———1.3初始化NioServerSocketChannel |———1.4伺服器啟動流程 為什麼先從初始化開

Netty原始碼分析:1.3初始化NioServerSocketChannel

第一章節是主要是伺服器啟動的程式碼分析。章節目錄有: |———1.1初始化NioEventLoopGroup |———1.2初始化NioEventLoop |———1.3初始化NioServerSocketChannel |———1.4伺服器啟動流程 為什麼先從初始化開

Netty原始碼分析:1.2初始化NioEventLoop

第一章節是主要是伺服器啟動的程式碼分析。章節目錄有: |———1.1初始化NioEventLoopGroup |———1.2初始化NioEventLoop |———1.3初始化NioServerSocketChannel |———1.4伺服器啟動流程 為什麼先從初始化開

Netty原始碼分析:1.1初始化NioEventLoopGroup

第一章節是主要是伺服器啟動的程式碼分析。章節目錄有: |———1.1初始化NioEventLoopGroup |———1.2初始化NioEventLoop |———1.3初始化NioServerSocketChannel |———1.4伺服器啟動流程 為什麼先從初始化開

《2.uboot系統移植-第5部分-2.5.uboot原始碼分析1-啟動第一階段》

《2.uboot和系統移植-第5部分-2.5.uboot原始碼分析1-啟動第一階段》 第一部分、章節目錄 2.5.1.start.S引入 2.5.2.start.S解析1 2.5.3.start.S解析2 2.5.4.start.S解析3 2.5.5.start.S解析4 2.5.6.s

MyBatis原始碼分析-1-基礎支援層-反射模組-Reflector/ReflectorFactory

本文主要介紹MyBatis的反射模組是如何實現的。 MyBatis 反射的核心類Reflector,下面我先說明它的建構函式和成員變數。具體方法下面詳解。 org.apache.ibatis.reflection.Reflector public class Reflector {

rxjs 原始碼分析1-(fromEvent)

前言 Rxjs是使用 Observables 的響應式程式設計的庫,它使編寫非同步或基於回撥的程式碼更容易。我們現在針對Rxjs 6 來進行原始碼分析,分析其實現的基本原理, 我們可以根據中文文件來學習Rxjs 的基本使用,但是這個文件是Rxjs 5 的版本。其最基本的使用區別如下,Rxjs 6的操作符都放

Spring通過註解annotation方式注入Bean時,採用動態代理,那麼JDK代理CGLIB代理區別?

切面程式設計是Spring中非常重要的一個模組,切面程式設計的實現原理是動態代理,那麼動態代理又有兩種實現方式:一種方法是直接實現JDK中的InvocationHandler介面,另一種方法是繼承CGLIB。 首先如果不是很清楚兩者的區別的話,記住一般情況下Invocati

Spring-boot mongodb ID自增長註解實現 適用於JDK 1.7JDK 1.8

開發工具Idea ,JDK1.8 Entity類 SeqInfo.java package com.gl.springbootdao.mongodb.entity; import lombok.Getter; import lombok.Setter; import lombok.T