jar包扫描工具: gamma
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)的依賴
- 創(chuàng)建一個(gè)新的maven項(xiàng)目
- 在新的插件項(xiàng)目中引入依賴
- 創(chuàng)建一個(gè)類,實(shí)現(xiàn)接口
- 在插件的META-INF目錄(如果沒(méi)有就在resources目錄下先創(chuàng)建META-INF目錄)下創(chuàng)建文件gamma.plugin文件,里面寫上對(duì)應(yīng)你插件Processor
接口實(shí)現(xiàn)類的全路徑 - 執(zhí)行命令打包成一個(gè)插件
注意: 打出的插件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è)置如:
這里的 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
如:
那么對(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í)行命令
- 在代碼中寫入
總結(jié)
以上是生活随笔為你收集整理的jar包扫描工具: gamma的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 使用容器搭建数据库
- 下一篇: dsp28335杂记2