乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      字節(jié)碼編程,Byte-buddy篇三《使用委托實(shí)現(xiàn)抽象類方法并注入自定義注解信息》

       小傅哥 2021-12-13


      作者:小傅哥
      博客:https:// - 匯總系列專題文章

      沉淀、分享、成長(zhǎng),讓自己和他人都能有所收獲!

      一、前言

      截至到本章節(jié)關(guān)于字節(jié)碼框架 Byte-buddy 的大部分常用 API 的使用已經(jīng)通過(guò)案例介紹比較全面了,接下來(lái)介紹關(guān)于如何去實(shí)現(xiàn)一個(gè)抽象類以及創(chuàng)建出相應(yīng)注解(包括類的注解和方法的注解)的知識(shí)點(diǎn)。而注解的這部分內(nèi)容在一些監(jiān)控或者攔截處理的場(chǎng)景下還是比較常用的,所以在這章節(jié)我們會(huì)通過(guò)一個(gè)例子來(lái)創(chuàng)建出含有自定義注解的類和方法。

      如果你已經(jīng)閱讀了之前的系列文章,這部分學(xué)習(xí)的內(nèi)容并不會(huì)有太多的陌生,主要是關(guān)于委托(MethodDelegation)方法的使用以及補(bǔ)充自定義注解。

      那么,接下來(lái)我們就使用委托和注解方式來(lái)創(chuàng)建這樣的案例進(jìn)行學(xué)習(xí)。

      二、開(kāi)發(fā)環(huán)境

      1. JDK 1.8.0
      2. byte-buddy 1.10.9
      3. byte-buddy-agent 1.10.9
      4. 本章涉及源碼在:itstack-demo-bytecode-2-03,可以關(guān)注公眾號(hào)bugstack蟲(chóng)洞棧,回復(fù)源碼下載獲取。你會(huì)獲得一個(gè)下載鏈接列表,打開(kāi)后里面的第17個(gè)「因?yàn)槲矣泻枚嚅_(kāi)源代碼」,記得給個(gè)Star

      三、案例目標(biāo)

      在這里我們定義了一個(gè)抽象并且含有泛型的接口類,如下;

      public abstract class Repository<T> {
      
          public abstract T queryData(int id);
      
      }
      

      那么接下來(lái)的案例會(huì)使用到委托的方式進(jìn)行實(shí)現(xiàn)抽象類方法并加入自定義注解,也就相當(dāng)于我們使用代碼進(jìn)行編程實(shí)現(xiàn)的效果。

      @RpcGatewayClazz( clazzDesc = "查詢數(shù)據(jù)信息", alias = "dataApi", timeOut = 350L )
      public class UserRepository extends Repository<String> {      
      
          @RpcGatewayMethod( methodName = "queryData", methodDesc = "查詢數(shù)據(jù)" )
          public String queryData(int var1) {
              // ...
          }
      
      }
      
      • 這里就是最終效果,我們模擬是一種網(wǎng)關(guān)接口的實(shí)現(xiàn)和定義注解暴漏接口信息(如果你是在互聯(lián)網(wǎng)中做開(kāi)發(fā),類似這樣的需求還是蠻多的,接口統(tǒng)一走網(wǎng)關(guān)服務(wù))。

      四、技術(shù)實(shí)現(xiàn)

      在技術(shù)實(shí)現(xiàn)的過(guò)程中會(huì)逐步的去實(shí)現(xiàn)我們需要的功能,將需要的用到知識(shí)點(diǎn)信息拆開(kāi)講解,以達(dá)到最終的案例目標(biāo)。

      1. 創(chuàng)建自定義注解

      模擬網(wǎng)關(guān)類注解

      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.TYPE)
      public @interface RpcGatewayClazz {
      
          String clazzDesc() default "";
          String alias() default "";
          long timeOut() default 350;
      
      }
      

      模擬網(wǎng)關(guān)方法注解

      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.METHOD)
      public @interface RpcGatewayMethod {
      
          String methodName() default "";
          String methodDesc() default "";
          
      }
      
      • 這部分你可以創(chuàng)建任何類型的注解,主要是用于模擬類和方法上分別添加注解并獲取最終屬性值的效果。

      2. 創(chuàng)建委托函數(shù)

      public class UserRepositoryInterceptor {
      
          public static String intercept(@Origin Method method, @AllArguments Object[] arguments) {
              return "小傅哥博客,查詢文章數(shù)據(jù):https:///?id=" + arguments[0];
          }
      
      }
      
      • 最終我們的字節(jié)碼操作會(huì)通過(guò)委托的方式來(lái)實(shí)現(xiàn)抽象類的功能。
      • 在委托函數(shù)中的用到注解已經(jīng)在上一章節(jié)中完整的介紹了,可以回顧參考。
      • @Origin 可以綁定到以下類型的參數(shù):Method 被調(diào)用的原始方法 Constructor 被調(diào)用的原始構(gòu)造器 Class 當(dāng)前動(dòng)態(tài)創(chuàng)建的類 MethodHandle MethodType String 動(dòng)態(tài)類的toString()的返回值 int 動(dòng)態(tài)方法的修飾符.
      • @AllArguments 綁定所有參數(shù)的數(shù)組。

      3. 創(chuàng)建方法主體信息

      // 生成含有注解的泛型實(shí)現(xiàn)字類
      DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
              .subclass(TypeDescription.Generic.Builder.parameterizedType(Repository.class, String.class).build()) // 創(chuàng)建復(fù)雜類型的泛型注解
              .name(Repository.class.getPackage().getName().concat(".").concat("UserRepository"))                  // 添加類信息包括地址
              .method(ElementMatchers.named("queryData"))                                                          // 匹配處理的方法
              .intercept(MethodDelegation.to(UserRepositoryInterceptor.class))                                     // 交給委托函數(shù)
              .annotateMethod(AnnotationDescription.Builder.ofType(RpcGatewayMethod.class).define("methodName", "queryData").define("methodDesc", "查詢數(shù)據(jù)").build())
              .annotateType(AnnotationDescription.Builder.ofType(RpcGatewayClazz.class).define("alias", "dataApi").define("clazzDesc", "查詢數(shù)據(jù)信息").define("timeOut", 350L).build())
              .make();
      
      • 這部分基本是Byte-buddy的模板方法,通過(guò)核心API;subclassname、method、intercept、annotateMethod、annotateType 的使用構(gòu)建方法。
      • 首先是定義復(fù)雜類型的自定義注解,設(shè)定為本方法的父類,這部分內(nèi)容也就是抽象類。Repository<T>,通過(guò) TypeDescription.Generic.Builder.parameterizedType(Repository.class, String.class).build() 來(lái)構(gòu)建。
      • 設(shè)定類名稱在我們之前就已經(jīng)使用過(guò),這里多加類的路徑信息。concat 函數(shù)是字符串的連接符,替換 + 號(hào)。
      • method,設(shè)定匹配處理方法名稱。
      • MethodDelegation.to(UserRepositoryInterceptor.class),最終的核心是關(guān)于委托函數(shù)的使用。這里的使用也就可以調(diào)用到我們上面定義的委托函數(shù),等最終我們通過(guò)字節(jié)碼生成的 class 類進(jìn)行查看。
      • annotateMethod、annotateType,定義類和方法的注解,通過(guò) define 設(shè)定值(可以多次使用)。

      4. 將創(chuàng)建的類寫入目錄

      // 輸出類信息到目標(biāo)文件夾下
      dynamicType.saveIn(new File(ApiTest.class.getResource("/").getPath()));
      
      • 這部分內(nèi)容是 Byte-buddy 提供的 API 方法;saveIn,把字節(jié)碼信息寫成 class 到執(zhí)行的文件夾下。這樣就可以非常方便的驗(yàn)證通過(guò)字節(jié)碼框架創(chuàng)建的方法內(nèi)容。

      字節(jié)碼方法內(nèi)容

      package org.itstack.demo.bytebuddy;
      
      @RpcGatewayClazz(
          clazzDesc = "查詢數(shù)據(jù)信息",
          alias = "dataApi",
          timeOut = 350L
      )
      public class UserRepository extends Repository<String> {
          @RpcGatewayMethod(
              methodName = "queryData",
              methodDesc = "查詢數(shù)據(jù)"
          )
          public String queryData(int var1) {
              return FindOneInterceptor.intercept(cachedValue$aGmAjHXh$iha1qv0, new Object[]{var1});
          }
      
          public UserRepository() {
          }
      
          static {
              cachedValue$aGmAjHXh$iha1qv0 = Repository.class.getMethod("queryData", Integer.TYPE);
          }
      }
      
      • 從上可以看出來(lái)我們的自定義類已經(jīng)實(shí)現(xiàn)了抽象類,同時(shí)也添加了類和方法的注解信息。
      • 而在實(shí)現(xiàn)的類中有一步是使用委托函數(shù)進(jìn)行處理方法的內(nèi)容。

      5. 輸出自定義注解信息

      // 從目標(biāo)文件夾下加載類信息
      Class<Repository<String>> repositoryClass = (Class<Repository<String>>) Class.forName("org.itstack.demo.bytebuddy.UserRepository");
      
      // 獲取類注解
      RpcGatewayClazz rpcGatewayClazz = repositoryClass.getAnnotation(RpcGatewayClazz.class);
      System.out.println("RpcGatewayClazz.clazzDesc:" + rpcGatewayClazz.clazzDesc());
      System.out.println("RpcGatewayClazz.alias:" + rpcGatewayClazz.alias());
      System.out.println("RpcGatewayClazz.timeOut:" + rpcGatewayClazz.timeOut()); 
      
      // 獲取方法注解
      RpcGatewayMethod rpcGatewayMethod = repositoryClass.getMethod("queryData", int.class).getAnnotation(RpcGatewayMethod.class);
      System.out.println("RpcGatewayMethod.methodName:" + rpcGatewayMethod.methodName());
      System.out.println("RpcGatewayMethod.methodDesc:" + rpcGatewayMethod.methodDesc());
      
      • 在這里我們使用的是 Class.forName,進(jìn)行加載類信息。也可以像以前的章節(jié)一樣使用;unloadedType.load(XXX.class.getClassLoader()) 的方式進(jìn)行直接處理字節(jié)碼。
      • 最后是讀取自定義注解的信息內(nèi)容,包括類和方法。

      6. 測(cè)試驗(yàn)證運(yùn)行

      // 實(shí)例化對(duì)象
      Repository<String> repository = repositoryClass.newInstance();
      // 測(cè)試輸出
      System.out.println(repository.queryData(10001));
      
      • 通過(guò) Class.forName 的方式就可以直接調(diào)用方法,如果加載字節(jié)碼的方式就需要通過(guò)反射進(jìn)行處理(以往章節(jié)有案例可以對(duì)照學(xué)習(xí))。

      測(cè)試結(jié)果

      RpcGatewayClazz.clazzDesc:查詢數(shù)據(jù)信息
      RpcGatewayClazz.alias:dataApi
      RpcGatewayClazz.timeOut:350
      RpcGatewayMethod.methodName:queryData
      RpcGatewayMethod.methodDesc:查詢數(shù)據(jù)
      小傅哥博客,查詢文章數(shù)據(jù):https://bugstack.cn/?id=10001
      
      Process finished with exit code 0
      
      • 不出意外你會(huì)看到以上的結(jié)果信息,通過(guò)我們使用字節(jié)碼創(chuàng)建的方法已經(jīng)可以按照我們的需求進(jìn)行內(nèi)容輸出。

      五、總結(jié)

      • 在本章節(jié)的學(xué)習(xí)中需要注意幾個(gè)知識(shí)點(diǎn)的使用,包括;委托方法使用、復(fù)雜類型的泛型創(chuàng)建、類和方法自定義注解的添加以及寫入字節(jié)碼信息到文件中
      • 截至到目前基本我們已經(jīng)對(duì)常用的字節(jié)碼框架自我學(xué)習(xí)和分享的基本完成了,另外一些其他的API的使用可以參考官方文檔;https://
      • 每一段知識(shí)都是只有進(jìn)行系統(tǒng)化的學(xué)習(xí)才能有完整的收獲,只言片語(yǔ)帶來(lái)的碎片化體驗(yàn)總是不能對(duì)一個(gè)技術(shù)進(jìn)行全方面的了解。在技術(shù)的這條路上,多加油!

      六、彩蛋

      CodeGuide | 程序員編碼指南 Go!

      本代碼庫(kù)是作者小傅哥多年從事一線互聯(lián)網(wǎng) Java 開(kāi)發(fā)的學(xué)習(xí)歷程技術(shù)匯總,旨在為大家提供一個(gè)清晰詳細(xì)的學(xué)習(xí)教程,側(cè)重點(diǎn)更傾向編寫Java核心內(nèi)容。如果本倉(cāng)庫(kù)能為您提供幫助,請(qǐng)給予支持(關(guān)注、點(diǎn)贊、分享)!

      CodeGuide | 程序員編碼指南

        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多