精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Java注解及其底層原理解析2

jf_78858299 ? 來源:小牛呼嚕嚕 ? 作者:小牛呼嚕嚕 ? 2023-02-09 14:18 ? 次閱讀

最后我們寫一個(gè)測(cè)試類

public class TestAn {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {

        //獲取Person class 實(shí)例
        Class c1 = Person.class;

        //反射獲取 類上的注解
        MyAnnotation classAnnotation = c1.getAnnotation(MyAnnotation.class);
        System.out.println(classAnnotation.msg());

        //反射獲取 private屬性上的注解
        Field we = c1.getDeclaredField("weight");
        MyAnnotation fieldAnnotation = we.getAnnotation(MyAnnotation.class);
        System.out.println(fieldAnnotation.msg());

        //反射獲取 public屬性上的注解
        Field he = c1.getDeclaredField("height");
        MyAnnotation field2Annotation = he.getAnnotation(MyAnnotation.class);
        System.out.println(field2Annotation.msg());

        //反射獲取 方法上的注解
        Method me = c1.getMethod("dance",null);
        MyAnnotation methodAnnotation = me.getAnnotation(MyAnnotation.class);
        System.out.println(methodAnnotation.msg());
        

    }
}

結(jié)果:

this person class this person field private this person field public this person method

我們通過反射讀取api時(shí),一般會(huì)先去校驗(yàn)這個(gè)注解存不存在:

if(c1.isAnnotationPresent(MyAnnotation.class)) {
    //存在 MyAnnotation 注解
}else {
    //不存在 MyAnnotation 注解
}

我們發(fā)現(xiàn)反射真的很強(qiáng)大,不僅可以讀取類的屬性、方法、構(gòu)造器等信息,還可以讀取類的注解相關(guān)信息。

那反射是如何實(shí)現(xiàn)工作的?

我們來看下源碼:

c1.getAnnotation(MyAnnotation.class);通過idea點(diǎn)進(jìn)去查看源碼,把重點(diǎn)的給貼出來,其他的就省略了

Map<Classextends Annotation>, Annotation> declaredAnnotations =
            AnnotationParser.parseAnnotations(getRawAnnotations(), getConstantPool(), this);

parseAnnotations()去 分析注解 ,其第一個(gè)參數(shù)是 獲取原始注解,第二個(gè)參數(shù)是獲取常量池內(nèi)容

public static Annotation annotationForMap(final Classextends Annotation> var0, final Map<String, Object> var1) {
        return (Annotation)AccessController.doPrivileged(new PrivilegedAction() {
            public Annotation run() {
                return (Annotation)Proxy.newProxyInstance(var0.getClassLoader(), new Class[]{var0}, new AnnotationInvocationHandler(var0, var1));
            }
        });
    }

Proxy._newProxyInstance_(var0.getClassLoader(), new Class[]{var0}, new AnnotationInvocationHandler(var0, var1)創(chuàng)建動(dòng)態(tài)代理,此處var0參數(shù)是由常量池獲取的數(shù)據(jù)轉(zhuǎn)換而來。

我們監(jiān)聽此處的var0:

圖片

image-20220616225518195

可以推斷出注解相關(guān)的信息 是存放在常量池中的

我們來總結(jié)一下,反射調(diào)用getAnnotations(MyAnnotation.class)方法的背后主要操作:

解析注解parseAnnotations()的時(shí)候 從該注解類的常量池中取出注解相關(guān)的信息,將其轉(zhuǎn)換格式后,通過newProxyInstance(注解的類加載器,注解的class實(shí)例 ,AnotationInvocationHandler實(shí)例)來創(chuàng)建代理對(duì)象,作為參數(shù)傳進(jìn)去,最后返回一個(gè)代理實(shí)例。

其中AnotationInvocationHandler類是一個(gè)典型的動(dòng)態(tài)代理類, 這邊先挖個(gè)坑,暫不展開,不然這篇文章是寫不完了

關(guān)于動(dòng)態(tài)代理類我們只需先知道: 對(duì)象的執(zhí)行方法,交給代理來負(fù)責(zé)

class AnnotationInvocationHandler implements InvocationHandler, Serializable {
    ...
    private final Map<String, Object> memberValues;//存放該注解所有屬性的值
    private transient volatile Method[] memberMethods = null;

    AnnotationInvocationHandler(Classextends Annotation> var1, Map<String, Object> var2) {
    ...
    }

    public Object invoke(Object var1, Method var2, Object[] var3) {
    ...
     //調(diào)用委托類對(duì)象的方法,具體等等一些操作
    }
    ...
}

反射調(diào)用getAnnotations(MyAnnotation.class),返回一個(gè)代理實(shí)例,我們可以通過這個(gè)實(shí)例來操作該注解

示例:注解 模擬訪問權(quán)限控制

當(dāng)我們引入springsecurity來做安全框架,然后只需添加@PreAuthorize**(**"hasRole('Admin')"**)**注解,就能實(shí)現(xiàn)權(quán)限的控制,簡(jiǎn)簡(jiǎn)單單地一行代碼,就優(yōu)雅地實(shí)現(xiàn)了權(quán)限控制,覺不覺得很神奇?讓我們一起模擬一個(gè)出來吧

@Retention(RetentionPolicy.RUNTIME)
public @interface MyPreVer {
    String value() default "no role";
}
public class ResourceLogin {
    private String name;

    @MyPreVer(value = "User")
    private void rsA() {
        System.out.println("資源A");
    }
    @MyPreVer(value = "Admin")
    private void rsB() {
        System.out.println("資源B");
    }
}
public class TestLogin {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        //模擬 用戶的權(quán)限
        String role = "User";
        //模擬 需要的權(quán)限
        final String RoleNeeded = "Admin";

        //獲取Class實(shí)例
        Class c1 = ResourceLogin.class;

        //訪問資源A
        Method meA = c1.getDeclaredMethod("rsA",null);
        MyPreVer meAPre = meA.getDeclaredAnnotation(MyPreVer.class);
        if(meAPre.value().equals(RoleNeeded)) {//模擬攔截器
            meA.setAccessible(true);
            meA.invoke(c1.newInstance(),null);//模擬訪問資源
        }else {
            System.out.println("騷瑞,你無權(quán)訪問該資源");
        }

        //訪問資源B
        Method meB = c1.getDeclaredMethod("rsB",null);
        MyPreVer meBPre = meB.getDeclaredAnnotation(MyPreVer.class);
        if(meBPre.value().equals(RoleNeeded)) {//模擬攔截器
            meB.setAccessible(true);
            meB.invoke(c1.newInstance());//模擬訪問資源

        }else {
            System.out.println("騷瑞,你無權(quán)訪問該資源");
        }

    }
}

結(jié)果:

騷瑞,你無權(quán)訪問該資源 資源B

尾語

注解 是一種 標(biāo)記、標(biāo)簽 來修飾代碼, 但它不是代碼本身的一部分,即 注解本身對(duì)代碼邏輯沒有任何影響 ,如何使用注解完全取決于我們開發(fā)者Java反射來讀取和使用。

我們發(fā)現(xiàn)反射真的很強(qiáng)大,不僅可以讀取類的屬性、方法、構(gòu)造器等信息,還可以讀取類的注解相關(guān)信息,以后還會(huì)經(jīng)常遇到它。

注解一般用于

  • 編譯器可以利用注解來探測(cè)錯(cuò)誤和檢查信息,像@override檢查是否重寫
  • 適合工具類型的軟件用的,避免繁瑣的代碼,生成代碼配置,比如jpa自動(dòng)生成sql,日志注解,權(quán)限控制
  • 程序運(yùn)行時(shí)的處理:某些注解可以在程序運(yùn)行的時(shí)候接受代碼的讀取,比如我們可以自定義注解

平時(shí)我們只知道如何使用注解,卻不知道其是如何起作用的,理所當(dāng)然的往往是我們所忽視的。

參考資料

《Java核心技術(shù) 卷一》

https://blog.csdn.net/qq_20009015/article/details/106038023

https://zhuanlan.zhihu.com/p/258429599

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2958

    瀏覽量

    104544
  • spring
    +關(guān)注

    關(guān)注

    0

    文章

    338

    瀏覽量

    14308
  • 注解
    +關(guān)注

    關(guān)注

    0

    文章

    18

    瀏覽量

    2668
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    如何通過注解來優(yōu)化我們的Java代碼

    Java注解可以說是我們編碼過程中最常用的。本篇文章將給大家介紹Java注解的概念、作用以及如何使用注解來提升代碼的可讀性和靈活性,并介紹如
    的頭像 發(fā)表于 09-30 11:39 ?593次閱讀

    java經(jīng)典面試題深度解析

    免費(fèi)視頻教程:java經(jīng)典面試題深度解析對(duì)于很多初學(xué)者來說,學(xué)好java在后期面試的階段都沒什么經(jīng)驗(yàn),為了讓大家更好的了解面試相關(guān)知識(shí),今天在這里給大家分享了一個(gè)java經(jīng)典面試題深度
    發(fā)表于 06-20 15:16

    詳細(xì)介紹了Java泛型、注解、并發(fā)編程

    介紹了Java泛型、注解、并發(fā)編程、數(shù)據(jù)傳輸與序列化、高效IO、容器集合、反射與類加載以及JVM重點(diǎn)知識(shí)線程、內(nèi)存模型、JVM運(yùn)行時(shí)內(nèi)存、垃圾回收與算法、Java中四種引用類型、GC 分代收集算法
    發(fā)表于 08-20 06:09

    HarmonyOS注解的使用方法分享

    定義我們的注解自定義注解1、聲明注解功能:檢測(cè)類中是否有規(guī)范的get方法新建java libray的module,命名為annotation,創(chuàng)建
    發(fā)表于 03-28 14:04

    微信ANR原理解析與解決方案

    理解析 CSDN 博客專家@三精-大精wing 對(duì)于導(dǎo)致微信 ANR 的根本原因進(jìn)行了解析(以下為授權(quán)發(fā)布): 本文目的在于學(xué)習(xí)研究Android技術(shù),若有侵犯,聯(lián)系作者將及時(shí)刪除。 首先,微信
    發(fā)表于 09-26 17:09 ?0次下載
    微信ANR原<b class='flag-5'>理解析</b>與解決方案

    分析java注解基本概念

    什么是注解(Annotation): Annotation(注解)就是Java提供了一種元程序中的元素關(guān)聯(lián)任何信息和著任何元數(shù)據(jù)(metadata)的途徑和方法。Annotion(注解
    發(fā)表于 09-27 14:53 ?0次下載

    Java底層實(shí)現(xiàn),CPU還有10個(gè)術(shù)語!

    Java底層實(shí)現(xiàn)——CPU的10個(gè)術(shù)語
    的頭像 發(fā)表于 03-28 14:14 ?6218次閱讀

    注解定義Bean及開發(fā)

    注解本質(zhì)是一個(gè)繼承了Annotation 的特殊接口,其具體實(shí)現(xiàn)類是Java 運(yùn)行時(shí)生成的動(dòng)態(tài)代理類。
    發(fā)表于 08-02 10:26 ?432次閱讀

    Java注解及其底層理解析 1

    什么是注解? 當(dāng)我們開發(fā)SpringBoot項(xiàng)目,我們只需對(duì)啟動(dòng)類加上`@SpringBootApplication`,就能自動(dòng)裝配,不需要編寫冗余的xml配置。當(dāng)我們?yōu)轫?xiàng)目添加lombok
    的頭像 發(fā)表于 02-09 14:18 ?727次閱讀
    <b class='flag-5'>Java</b><b class='flag-5'>注解</b><b class='flag-5'>及其</b><b class='flag-5'>底層</b>原<b class='flag-5'>理解析</b> 1

    容器配置及Spring Boot注解

    Autowired注解用于標(biāo)記Spring將要解析和注入的依賴項(xiàng)。此注解可以作用在構(gòu)造函數(shù)、字段和setter方法上。
    的頭像 發(fā)表于 04-07 11:45 ?558次閱讀
    容器配置及Spring Boot<b class='flag-5'>注解</b>

    SpringBoot的核心注解2

    今天跟大家來探討下SpringBoot的核心注解@SpringBootApplication以及run方法,理解下springBoot為什么不需要XML,達(dá)到零配置
    的頭像 發(fā)表于 04-07 14:34 ?1925次閱讀
    SpringBoot的核心<b class='flag-5'>注解</b><b class='flag-5'>2</b>

    JAVA注解是怎么做到的(上)

    。它可以聲明在包、類、字段、方法、局部變量、方法參數(shù)等的前面,用來對(duì)這些元素進(jìn)行說明,注釋。那么你知道JDK什么是元注解嗎?注解有哪些分類嗎?以及注解Java中最本質(zhì)究竟是什么東西,
    的頭像 發(fā)表于 05-11 10:57 ?622次閱讀

    JAVA注解是怎么做到的(下)

    。它可以聲明在包、類、字段、方法、局部變量、方法參數(shù)等的前面,用來對(duì)這些元素進(jìn)行說明,注釋。那么你知道JDK什么是元注解嗎?注解有哪些分類嗎?以及注解Java中最本質(zhì)究竟是什么東西,
    的頭像 發(fā)表于 05-11 10:57 ?548次閱讀
    <b class='flag-5'>JAVA</b>中<b class='flag-5'>注解</b>是怎么做到的(下)

    3分鐘純Java注解搭個(gè)管理系統(tǒng)

    Erupt一個(gè)通用后臺(tái)管理框架,據(jù)說有 超低代碼量 、 零前端代碼 、零 CURD操作 、無需建表 ,純Java注解開發(fā) 等特色,號(hào)稱三分鐘就可以搭建一個(gè)完整的后臺(tái)管理系統(tǒng)。
    的頭像 發(fā)表于 07-28 11:27 ?1048次閱讀
    3分鐘純<b class='flag-5'>Java</b><b class='flag-5'>注解</b>搭個(gè)管理系統(tǒng)

    springmvc常用5種注解

    SpringMVC是一種基于Java的Web框架,使用注解可以更加方便靈活地開發(fā)和管理控制器,實(shí)現(xiàn)請(qǐng)求的映射和處理。在SpringMVC中,有許多常用的注解,本文將詳細(xì)介紹其中的五種注解
    的頭像 發(fā)表于 11-22 16:51 ?812次閱讀