1. 程式人生 > >Spring 註解程式設計之 AnnotationMetadata

Spring 註解程式設計之 AnnotationMetadata

在上篇文章 Spring 註解程式設計之模式註解 中我們講到 Spring 模式註解底層原理,依靠 AnnotationMetadata 介面判斷是否存在指定元註解。

這篇文章我們主要深入 AnnotationMetadata,瞭解其底層原理。

Spring 版本為 5.1.8-RELEASE

AnnotationMetadata 結構

使用 IDEA 生成 AnnotationMetadata 類圖,如下:

AnnotationMetadata 存在兩個實現類分別為 StandardAnnotationMetadataAnnotationMetadataReadingVisitor

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 應用掃描指定範圍內模式註解時使用。

擴充套件閱讀

  1. 例項分析JAVA CLASS的檔案結構
  2. asm 官方文件
  3. 『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】—AOPAspectJ註解方式實現聲明式事務管理

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