Spring 註解程式設計之 AnnotationMetadata
在上篇文章 Spring 註解程式設計之模式註解 中我們講到 Spring 模式註解底層原理,依靠 AnnotationMetadata
介面判斷是否存在指定元註解。
這篇文章我們主要深入 AnnotationMetadata
,瞭解其底層原理。
Spring 版本為 5.1.8-RELEASE
AnnotationMetadata 結構
使用 IDEA 生成 AnnotationMetadata
類圖,如下:
AnnotationMetadata
存在兩個實現類分別為 StandardAnnotationMetadata
與 AnnotationMetadataReadingVisitor
StandardAnnotationMetadata
主要使用 Java 反射原理獲取元資料,而 AnnotationMetadataReadingVisitor
使用 ASM 框架獲取元資料。
Java 反射原理大家一般比較熟悉,而 ASM 技術可能會比較陌生,下面主要篇幅介紹 AnnotationMetadataReadingVisitor
實現原理。
基於
AnnotationMetadata#getMetaAnnotationTypes
方法,檢視兩者實現區別。
AnnotationMetadataReadingVisitor
ASM 是一個通用的 Java 位元組碼操作和分析框架。它可以用於修改現有類或直接以二進位制形式動態生成類。 ASM 雖然提供與其他 Java 位元組碼框架如 Javassist
CGLIB
類似的功能,但是其設計與實現小而快,且效能足夠高。
Spring 直接將 ASM 框架核心原始碼內嵌於 Spring-core
中,目前 Spring 5.1 使用 ASM 7 版本。
ASM 框架簡單應用
Java 原始碼經過編譯器編譯之後生成了 .class
檔案。
Class檔案是有8個位元組為基礎的位元組流構成的,這些位元組流之間都嚴格按照規定的順序排列,並且位元組之間不存在任何空隙,對於超過8個位元組的資料,將按 照Big-Endian的順序儲存的,也就是說高位位元組儲存在低的地址上面,而低位位元組儲存到高地址上面,其實這也是class檔案要跨平臺的關鍵,因為 PowerPC架構的處理採用Big-Endian的儲存順序,而x86系列的處理器則採用Little-Endian的儲存順序,因此為了Class文 件在各中處理器架構下保持統一的儲存順序,虛擬機器規範必須對起進行統一。
Class 檔案中包含類的所有資訊,如介面,欄位屬性,方法,在內部這些資訊按照一定規則緊湊排序。ASM 框會以檔案流的形式讀取 class 檔案,然後解析過程中使用觀察者模式(Visitor),當解析器碰到相應的資訊委託給觀察者(Visitor)。
使用 ASM 框架首先需要繼承 ClassVisitor
,完成解析相應資訊,如解析方法,欄位等。
然後使用 ClassReader
讀取類檔案,然後再使用 ClassReader#accpet
接受 ClassVisitor
。
輸出結果為:
com/spring/learning/customizescanning/asm/Person extends java/lang/Object {
Lcom/spring/learning/customizescanning/asm/ASMAnnotation;
Ljava/lang/String; name class org.objectweb.asm.Type
I age class org.objectweb.asm.Type
<init>()V
add(II)I
getName()Ljava/lang/String;
setName(Ljava/lang/String;)V
getAge()I
setAge(I)V
}
可以看到 ClassVisitor
相應方法可以用來解析類的相關資訊,這裡我們主要關注解析類上註解資訊。解析註解將會在 ClassVisitor#visitAnnotation
完成解析。 該方法返回了一個 AnnotationVisitor
物件,其也是一個 Visitor 物件。後續解析器會繼續呼叫 AnnotationVisitor
內部方法進行再次解析。
以上實現採用 ASM Core API ,而 ASM 框架還提供 Tree API 用法。具體用法參考:https://asm.ow2.io/
AnnotationMetadataReadingVisitor#getMetaAnnotationTypes 原始碼解析
AnnotationMetadataReadingVisitor#getMetaAnnotationTypes
方法實現非常簡單,直接從 metaAnnotationMap
根據註解類名稱獲取其上面所有元註解。註解相關資訊解析由 AnnotationMetadataReadingVisitor#visitAnnotation
完成。
在 visitAnnotation
方法中,metaAnnotationMap
當做構造引數傳入了 AnnotationAttributesReadingVisitor
物件中,metaAnnotationMap
會在這裡面完成賦值。
AnnotationAttributesReadingVisitor#visitEnd
將會排除 java.lang.annotation
下的註解,然後通過遞迴呼叫 recursivelyCollectMetaAnnotations
獲取元註解,不斷將元註解置入 metaAnnotationMap
中。
最後使用 UML 時序圖中,概括以上呼叫流程。
Spring 4 之後版本才有遞迴查詢元註解的方法。各位同學可以翻閱 Spring3 的版本作為比較,可以看出 Spring 的程式碼功能也是逐漸迭代升級的。
StandardAnnotationMetadata
StandardAnnotationMetadata
主要使用 Java 反射原理獲取相關資訊。在 Spring 中封裝很多了反射工具類用於操作。
StandardAnnotationMetadata#getMetaAnnotationTypes
通過使用 Spring 工具類 AnnotatedElementUtils.getMetaAnnotationTypes
方法獲取。原始碼呼叫比較清晰,各位同學可以自行翻閱理解,可以參考下面時序圖理解,這裡不再敘述。
總結
本文介紹了 AnnotationMetadata
兩種實現方案,一種基於 Java 反射,另一種基於 ASM 框架。
兩種實現方案適用於不同場景。StandardAnnotationMetadata
基於 Java 反射,需要載入類檔案。而 AnnotationMetadataReadingVisitor
基於 ASM 框架無需提前載入類,所以適用於 Spring 應用掃描指定範圍內模式註解時使用。
擴充套件閱讀
- 例項分析JAVA CLASS的檔案結構
- asm 官方文件
- 『Spring Boot 程式設計思想』-小馬哥
另外歡迎加入 Java 極客技術知識星球,獲取最新 Java 技術。
相關推薦
Spring 註解程式設計之 AnnotationMetadata
在上篇文章 Spring 註解程式設計之模式註解 中我們講到 Spring 模式註解底層原理,依靠 AnnotationMetadata 介面判斷是否存在指定元註解。 這篇文章我們主要深入 AnnotationMetadata,瞭解其底層原理。 Spring 版本為 5.1.8-RELEASE Annot
Spring 註解程式設計之模式註解
Spring 框架中有很多可用的註解,其中有一類註解稱模式註解(Stereotype Annotations),包括 @Component, @Service,@Controller,@Repository 等。只要在相應的類上標註這些註解,就能成為 Spring 中元件(Bean)。 需要配置開啟自動掃描
Spring 註解程式設計之註解屬性別名與覆蓋
前兩篇文章咱聊了深入瞭解了 Spring 註解程式設計一些原理,這篇文章我們關注註解屬性方法,聊聊 Spring 為註解的帶來的功能,屬性別名與覆蓋。 註解屬性方法 在進入瞭解 Spring 註解屬性功能之前,我們先看一個正常 Java 註解。 在註解中,屬性方法與其他類/介面方法寫法類似,但是存在一些區
Spring註解程式設計(三)---註解配置給IOC容器新增元件方式
[email protected]&@Bean給容器中註冊元件 //配置類==配置檔案 @Configuration //告訴Spring這是一個配置類 public class MainConfig { //給容器中註冊一個Bean;型別為返回值的型別
【譯】spring註解程式設計模型
原文連結: https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model#stereotype-annotations 原文連結: https://github.
Spring註解開發之自動裝配
自動裝配:Spring利用依賴注入(DI),完成對IOC容器中中各個元件的依賴關係賦值; 自動裝配[email protected]&@Qualifier&@Primary 使用@Autowire註解可以為SpringBean物件自動注
《Spring 5官方文件》35. Spring註解程式設計模型
原文連結 譯者:葉揚V 介紹 這篇文件是以Spring Framework 4.2作為框架基礎編寫的,但是,這篇文件是一份還在進行的工作。所以隨著時間推移,你會看到這份文件還在更新。 目錄 概要 術語 例子 FAQ 附錄 概要 這些年,Spring Framework已經頻繁的升級它可
Spring註解程式設計時用junit測試時,顯示jdK版本過低問題,更改版本後仍然不行的解決方法
Spring註解程式設計時,用Junit測試時報錯JDK版本過低,更換JDK版本後, 會報錯不支援本JDK版本的解決方法;;;; 弄了好長時間沒弄好 原來先把JDK版本換到JDK6或者JDK7的版本 並且配置好環境變數 和 eclipse執行JDK版本 使他們和你安
Spring註解解析之ConfigurationClassPostProcessor
概述 Spring中有各種註解,比如@Configuration、@Import、@ComponentScan、@Autowi
理解 Spring 註解程式設計模型
理解 Spring 註解程式設計模型 Spring 中有一個概念叫「元註解」(Meta-Annotation),通過元註解,實現註解的「派生性」,官方的說法是「Annotation Hierarchy」。 什麼是元註解 所謂元註解,即標註在註解上的註解。這種方式所形成的註解層級結構中,元註解在層級結構的上面,
spring AOP解析之註解方式詳解
parser 分享 pro asp mes aop log space spec 命名空間處理器是AopNamespaceHandler,我們可以看到這裏註冊了幾個解析器,第一個我們知道是xml形式的解析,接下來我們看AspectJAutoProxyBeanDefiniti
Spring基礎知識之基於註解的AOP
sdn 相互 com 目的 declare 裝配bean 四種 ace 裝配 背景概念: 1)橫切關註點:散布在應用中多處的功能稱為橫切關註點 2)通知(Advice):切面完成的工作。通知定了了切面是什麽及何時調用。 5中可以應用的通知:
Spring註解之BeanPostProcessor與InitializingBean
cati 構造 ID The invoke leg .net 源碼 bool /*** BeanPostProcessor 為每個bean實例化時提供個性化的修改,做些包裝等*/ package org.springframework.beans.factory.con
【Spring】—AOP之AspectJ註解方式實現聲明式事務管理
source xml配置 blog org 僅支持 選擇 imp 獨立 col 前言 這回來說下註解方式的聲明式事務管理。 正文 Demo 1、引入相關的jar包這裏寫圖片描述 2、引入AOP約束<beans xmlns:xsi="http://www.w3
Spring註解開發-全面解析常用註解使用方法之生命周期
統一 ota tco conf struct 賦值 組件註冊 功能 pri 本文github位置:https://github.com/WillVi/Spring-Annotation/ 往期文章:Spring註解開發-全面解析常用註解使用方法之組件註冊 bean生命周期
Spring Boot2.0之註解方式啟動Springmvc
sch 一個tomcat user use embed spring serve XML java代碼 回顧下springmvc原理圖: DispatcherServlet是Spring MVC的核心,每當應用接受一個HTTP請求,由DispatcherServl
spring aop註解失效之謎
問題: 在spring 中使用 @Transactional 、 @Cacheable 或 自定義 AOP 註解時,會發現個問題: 在物件內部的方法中呼叫該物件的其他使用aop機制的方法,被呼叫方法的aop註解失效。 這句話可能說的有點拗口,那麼我們來看幾個 aop 失效的例子吧
spring-aop註解程式設計
今天價紹的是AspectJ的註解開發: 一 AOP術語 要想面向切面程式設計,我們首先得了解一些基本的術語以及幾種不同的通知: 1.target目標類:需要被代理的類,我們可以簡單的理解為需要服務層中需要公共模組能力的類; 2.JoinPoint連線
Spring註解驅動開發之IOC
getprop student type() tco 簡單 erb als com edt 1、最簡單的註解驅動開發實例: <dependency> <groupId>org.springframework</
深入理解spring註解之@ComponentScan註解
原創 深入理解spring註解之@ComponentScan註解 知了123 0人評論 149062人閱讀 2018-05-20 10:02:23