日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

jar包扫描工具: gamma

發(fā)布時(shí)間:2024/1/8 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jar包扫描工具: gamma 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1. 簡(jiǎn)介

本項(xiàng)目是一個(gè)jar包掃描工具,可以支持插件化訂制不同的掃描邏輯

支持以下功能:

  • 插件化訂制掃描邏輯,讓擴(kuò)展更加容易
  • 將掃描到的文件加載到j(luò)vm中以class的形式返回給處理插件,讓掃描邏輯寫起來(lái)更加的容易
  • 支持springBoot jar 的掃描

項(xiàng)目地址:

  • gamma掃描引擎
    • github
    • gitee

1.1 用途

設(shè)計(jì)gamma的初衷是為了能在ci流水線中快速的檢查已經(jīng)打包好的的業(yè)務(wù)jar,并且能輕易的擴(kuò)展掃描器的功能,以及和業(yè)務(wù)解耦

1.2 為什么不去掃描java文件

對(duì)于語(yǔ)法檢查等checkstyle插件確實(shí)直接掃描java文件是更好的選擇,但是掃描java文件意味著解析
難度變大,需要去解析對(duì)應(yīng)字符串到底是屬于什么包

如:我想去收集某個(gè)項(xiàng)目中有多少個(gè)方法標(biāo)記了 springMVC中的注解@RequestMapping, 同時(shí)把這個(gè)注解中的入?yún)⒔o統(tǒng)計(jì)一下

上述需求如果直接去解析java文件就會(huì)很麻煩,因?yàn)殡m然匹配上了字符串@RequestMapping但還需要去判斷他的包名是否是屬于
spring, 還需要去解析對(duì)應(yīng)注解中的參數(shù),如果注解中使用了常量,還需要解析對(duì)應(yīng)的常量類,然后才能獲取真正的值

1.3 為什么不去直接掃描class文件

通過(guò)一些字節(jié)碼工具,如asm可以直接去解析class文件,這樣確實(shí)可以解決上面提到掃描java文件中常量和類全稱的問(wèn)題,
但是有一定的門檻,需要去學(xué)習(xí)字節(jié)碼的相關(guān)知識(shí)和對(duì)應(yīng)的操作框架

1.4 gamma的優(yōu)勢(shì)

gamma出現(xiàn)就是解決上面2個(gè)問(wèn)題

如果我可以把這個(gè)jar文件完全給裝載進(jìn)入jvm中,從jvm中獲取到我所有想掃描的class對(duì)象, 然后通過(guò)反射去獲取是否存在@RequestMapping注解,不就
能減少很多的工作量。

對(duì)應(yīng)開(kāi)發(fā)插件的人來(lái)說(shuō),門檻就僅僅只需要會(huì)使用反射即可

所以 gamma的優(yōu)勢(shì) 如下:

  • 極低的門檻讓你自定義掃描邏輯
  • 插件式的方式自定義處理邏輯

1.4 實(shí)際案例

  • spring接口掃描器插件
    • 插件csdn博客
    • github
    • gitee

2. 架構(gòu)設(shè)計(jì)

上面簡(jiǎn)介中提到過(guò),gamma的工作原理是將會(huì) 把要掃描的jar完全加載進(jìn)入到j(luò)vm中,然后處理器將會(huì)依次獲得對(duì)應(yīng)的class對(duì)象
,處理器將可以使用反射的方式去處理獲得的class對(duì)象(如:使用反射來(lái)獲取對(duì)應(yīng)類/方法上面是否存在@RequestMapping注解)

這里的處理器,也就是需要根據(jù)實(shí)際業(yè)務(wù)去編寫的gamma插件了。

2.1 類加載器

上面提到過(guò),gamma將會(huì)把要掃描的jar完全加載進(jìn)入jvm中,那么類加載器的設(shè)計(jì)就需要滿足以下幾點(diǎn)

  • 每個(gè)插件之間類加載器相互隔離
  • 每個(gè)插件都能夠獲取到被加載進(jìn)jvm的掃描Jar中的class對(duì)象

2.2 jar包的解析

這里jar包的解析分成2種情況

  • spring boot 的jar

    • springBoot打出的jar格式和普通的jar又一定的區(qū)別,所以需要先去獲得spring提供的一個(gè)類加載器,然后才能通過(guò)這個(gè)類加載器去獲得對(duì)應(yīng)業(yè)務(wù)class
  • 普通的java jar

    • 普通的jar如果引入了其他第三方依賴,那么打出來(lái)的jar中將會(huì)依賴和業(yè)務(wù)class都混合在一起,可以使用參數(shù) scan.package來(lái)指定你想掃描的class路徑,而不需要去掃描框架引入的class
    • 對(duì)應(yīng)springBoot的jar來(lái)說(shuō),因?yàn)樘厥獾膉ar結(jié)構(gòu),掃描的將全部都是業(yè)務(wù)class
  • 注意:

    3.快速使用

    在本項(xiàng)目的/dist文件夾中下載作者編譯好的文件 gamma-bootstrap.jar, 在gamma-bootstrap.jar文件同級(jí)目錄創(chuàng)建文件夾plugins
    在plugins文件夾中創(chuàng)建子目錄作為插件的名稱, 然后把對(duì)應(yīng)的插件jar放入子目錄中即可(插件的編寫請(qǐng)看4.1章節(jié))

    最簡(jiǎn)結(jié)構(gòu) 如下圖所示:

    然后輸入命令

    java -jar gamma-bootstrap.jar source=你要掃描的jar路徑

    當(dāng)然如果你想修改gamma的源碼那么修改完成后在項(xiàng)目根路徑執(zhí)行

    mvn clean package

    執(zhí)行結(jié)束后也會(huì)在/dist目錄中生成新的 gamma-bootstrap.jar

    4. 插件

    gamma僅僅只是一個(gè)掃描引擎,當(dāng)掃描到對(duì)應(yīng)的class要如何處理, 需要編寫插件來(lái)實(shí)現(xiàn)

    如:

    • spring接口掃描器插件
      • github
      • gitee
      • csdn

    4.1 自定義插件

    • clone本倉(cāng)庫(kù),進(jìn)入gamma-common目錄執(zhí)行maven命令來(lái)安裝對(duì)應(yīng)的依賴
    mvn clean install
    • 創(chuàng)建一個(gè)新的maven項(xiàng)目
    • 在新的插件項(xiàng)目中引入依賴
    <dependency><groupId>com.chy</groupId><artifactId>gamma-common</artifactId><version>1.0-SNAPSHOT</version> </dependency>
    • 創(chuàng)建一個(gè)類,實(shí)現(xiàn)接口
    /*** gamma插件的執(zhí)行接口* 泛型T 為插件需要的配置文件類,如:本插件在配置文件config.properties 中設(shè)置了屬性 commitId=1234 、 ref=master* 那么泛型T需要定義 一個(gè)實(shí)體類來(lái)接收這2個(gè)屬性* 如果沒(méi)有任何的屬性對(duì)象,這里泛型可以填入 Void* * * @param <T>*/ public interface Processor<T> {/*** 配置對(duì)象的接收,gamma將會(huì)根據(jù)配置文件以及jvm參數(shù)來(lái)生成對(duì)應(yīng)的配置對(duì)象* 如果泛型T 設(shè)置是Object那么這里注入的將會(huì)是一個(gè)HashMap對(duì)象* @param t*/void setProperty(T t);/*** 處理的核心接口* gamma每掃描到j(luò)ar中的一個(gè)class都會(huì)回調(diào)該接口* * @param originClass 被掃描jar中的某一個(gè)class*/void processor(Class originClass);/*** 當(dāng)全部掃描完后回調(diào)**/void finishProcessor();}
    • 在插件的META-INF目錄(如果沒(méi)有就在resources目錄下先創(chuàng)建META-INF目錄)下創(chuàng)建文件gamma.plugin文件,里面寫上對(duì)應(yīng)你插件Processor
      接口實(shí)現(xiàn)類的全路徑
    • 執(zhí)行命令打包成一個(gè)插件
    mvn clean package

    注意: 打出的插件jar需要把對(duì)應(yīng)的第三方依賴也一起打包進(jìn)插件jar中,可以使用以下配置來(lái)完成對(duì)應(yīng)的操作

    添加對(duì)應(yīng)的maven插件

    <plugin><artifactId>maven-assembly-plugin</artifactId><executions><execution><!-- 綁定到package生命周期 --><phase>package</phase><goals><goal>single</goal></goals></execution></executions><configuration><descriptorRefs><!-- 將依賴一起打包到 JAR --><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs><appendAssemblyId>false</appendAssemblyId></configuration> </plugin>

    5. 配置

    在gamma中配置分成2類

    • gamma核心配置
      • 該配置用于控制gamma的行為,有固定的參數(shù)
    • 插件配置
      • 由插件開(kāi)發(fā)者自己定義的參數(shù)配置,每一個(gè)插件都可能不相同

    同時(shí)不管gamma核心配置還是插件配置都有2種設(shè)置方式

    • 通過(guò)program arguments方式在gamma啟動(dòng)的時(shí)候設(shè)置如:
    java -jar gamma-bootstrap.jar source=你要掃描的jar路徑

    這里的 source就是通過(guò)program arguments設(shè)置進(jìn)入的參數(shù)

    如果要設(shè)置插件的專屬參數(shù), 那么在參數(shù)前面需要帶上插件的名稱如:

    java -jar gamma-bootstrap.jar source=你要掃描的jar路徑 mypl1:url=123

    這里的mypl1:url代表的就是給插件mypl1設(shè)置參數(shù)url

    • 通過(guò)配置文件方式設(shè)置

    創(chuàng)建文件 config.properties 來(lái)設(shè)置對(duì)應(yīng)的配置

    config.properties文件位置的不同所具有的含義也不同,如下圖所示

    注意: 通過(guò)program arguments設(shè)置的參數(shù)優(yōu)先級(jí)高于配置文件的方式

    5.1 gamma核心配置

    • source: 指定要掃描的jar包的位置
    • scan.package: 指定要掃描的包名前綴,不設(shè)置將會(huì)掃描所有,多個(gè)路徑可以用逗號(hào)分隔

    5.2 插件配置

    上面提到了插件如何去設(shè)置自己的參數(shù),那么設(shè)置了之后,在插件中如何去讀到對(duì)應(yīng)的參數(shù)嗯?

    從上面的Processor<T>接口可以看出,需要填入一個(gè)泛型T,這個(gè)泛型T就是插件自定義的配置類,
    當(dāng)插件被gamma加載的時(shí)候,將會(huì)回調(diào)對(duì)應(yīng)的實(shí)現(xiàn)方法void setProperty(T t)來(lái)傳遞生成的配置對(duì)象

    當(dāng)然這個(gè)配置對(duì)象也是有部分規(guī)則的,需要在需要注入的配置字段上面打上注解@com.chy.gamma.common.profile.Param
    如:

    @Data public class ApiScanProperty {@Paramprivate String ref;@Paramprivate String commitId;@Param(nullable = true)private String appName;@Param("endpoint.topology.host")private String host; }

    那么對(duì)應(yīng)配置文件中的設(shè)置為:

    endpoint.topology.host=http://127.0.0.1:3222 ref=master commitId=23123131 appName=chyapp

    或者是:

    java -jar gamma-bootstrap.jar source=你要掃描的jar路徑 插件名稱:ref=master 插件名稱:endpoint.topology.host=http://127.0.0.1:3222 插件名稱:commitId=23123131 插件名稱:appName=chyapp

    同時(shí)注解@Param還有一個(gè)參數(shù)nullable來(lái)控制是否可以缺省某個(gè)值,默認(rèn)是false,及如果沒(méi)有傳入
    對(duì)應(yīng)的值將會(huì)拋出異常

    6. 日志

    gamma使用的日志框架是 log4j2框架,雖然對(duì)應(yīng)插件的類加載器相互獨(dú)立了,但是雙親委派機(jī)制的原因
    正常去獲取到的logger對(duì)象 對(duì)于所有插件來(lái)說(shuō)是同一個(gè)對(duì)象,這樣所有的日志將會(huì)混雜到一起

    為了能做到日志之間的相互隔離 在插件中請(qǐng)使用以下代碼來(lái)獲取logger對(duì)象

    import com.chy.gamma.common.utils.LogUtils; public static Logger logger = LogUtils.getLogger("類路徑");

    同時(shí)每個(gè)插件都可以配置自己的log4j2文件來(lái)自定義輸出

    7. 嵌入式使用

    為了使用更方便,或者再開(kāi)發(fā)插件的時(shí)候能夠更好的測(cè)試,gamma也提供了嵌入式的使用方式

    注意:使用嵌入的方式只能執(zhí)行一個(gè)插件

    • 安裝gamma-embed模塊
      進(jìn)入本項(xiàng)目的gamma-embed模塊下,執(zhí)行命令
    mvn clean install
    • 在代碼中寫入
    public static void main(String[] args) {Map<String, String> config = new HashMap<>();//插件的配置信息config.put("endpoint.topology.host","127.0.0.1:8080");config.put("ref","master");config.put("commitId","1234567");config.put("appName","1234567");config.put("scan.package","com.chy,com.chy2,com.example");//生成GammaContainer容器GammaContainer gammaContainer = new GammaContainer("你要掃描的jar路徑", config);//執(zhí)行插件gammaContainer.start(new 你實(shí)現(xiàn)的Procession對(duì)象);}

    總結(jié)

    以上是生活随笔為你收集整理的jar包扫描工具: gamma的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。