jar包扫描工具: gamma
1. 簡介
本項目是一個jar包掃描工具,可以支持插件化訂制不同的掃描邏輯
支持以下功能:
- 插件化訂制掃描邏輯,讓擴展更加容易
- 將掃描到的文件加載到jvm中以class的形式返回給處理插件,讓掃描邏輯寫起來更加的容易
- 支持springBoot jar 的掃描
項目地址:
- gamma掃描引擎
- github
- gitee
1.1 用途
設計gamma的初衷是為了能在ci流水線中快速的檢查已經打包好的的業務jar,并且能輕易的擴展掃描器的功能,以及和業務解耦
1.2 為什么不去掃描java文件
對于語法檢查等checkstyle插件確實直接掃描java文件是更好的選擇,但是掃描java文件意味著解析
難度變大,需要去解析對應字符串到底是屬于什么包
如:我想去收集某個項目中有多少個方法標記了 springMVC中的注解@RequestMapping, 同時把這個注解中的入參給統計一下
上述需求如果直接去解析java文件就會很麻煩,因為雖然匹配上了字符串@RequestMapping但還需要去判斷他的包名是否是屬于
spring, 還需要去解析對應注解中的參數,如果注解中使用了常量,還需要解析對應的常量類,然后才能獲取真正的值
1.3 為什么不去直接掃描class文件
通過一些字節碼工具,如asm可以直接去解析class文件,這樣確實可以解決上面提到掃描java文件中常量和類全稱的問題,
但是有一定的門檻,需要去學習字節碼的相關知識和對應的操作框架
1.4 gamma的優勢
gamma出現就是解決上面2個問題
如果我可以把這個jar文件完全給裝載進入jvm中,從jvm中獲取到我所有想掃描的class對象, 然后通過反射去獲取是否存在@RequestMapping注解,不就
能減少很多的工作量。
對應開發插件的人來說,門檻就僅僅只需要會使用反射即可
所以 gamma的優勢 如下:
- 極低的門檻讓你自定義掃描邏輯
- 插件式的方式自定義處理邏輯
1.4 實際案例
- spring接口掃描器插件
- 插件csdn博客
- github
- gitee
2. 架構設計
上面簡介中提到過,gamma的工作原理是將會 把要掃描的jar完全加載進入到jvm中,然后處理器將會依次獲得對應的class對象
,處理器將可以使用反射的方式去處理獲得的class對象(如:使用反射來獲取對應類/方法上面是否存在@RequestMapping注解)
這里的處理器,也就是需要根據實際業務去編寫的gamma插件了。
2.1 類加載器
上面提到過,gamma將會把要掃描的jar完全加載進入jvm中,那么類加載器的設計就需要滿足以下幾點
- 每個插件之間類加載器相互隔離
- 每個插件都能夠獲取到被加載進jvm的掃描Jar中的class對象
2.2 jar包的解析
這里jar包的解析分成2種情況
spring boot 的jar
- springBoot打出的jar格式和普通的jar又一定的區別,所以需要先去獲得spring提供的一個類加載器,然后才能通過這個類加載器去獲得對應業務class
普通的java jar
- 普通的jar如果引入了其他第三方依賴,那么打出來的jar中將會依賴和業務class都混合在一起,可以使用參數 scan.package來指定你想掃描的class路徑,而不需要去掃描框架引入的class
- 對應springBoot的jar來說,因為特殊的jar結構,掃描的將全部都是業務class
注意:
3.快速使用
在本項目的/dist文件夾中下載作者編譯好的文件 gamma-bootstrap.jar, 在gamma-bootstrap.jar文件同級目錄創建文件夾plugins
在plugins文件夾中創建子目錄作為插件的名稱, 然后把對應的插件jar放入子目錄中即可(插件的編寫請看4.1章節)
最簡結構 如下圖所示:
然后輸入命令
java -jar gamma-bootstrap.jar source=你要掃描的jar路徑當然如果你想修改gamma的源碼那么修改完成后在項目根路徑執行
mvn clean package執行結束后也會在/dist目錄中生成新的 gamma-bootstrap.jar
4. 插件
gamma僅僅只是一個掃描引擎,當掃描到對應的class要如何處理, 需要編寫插件來實現
如:
- spring接口掃描器插件
- github
- gitee
- csdn
4.1 自定義插件
- clone本倉庫,進入gamma-common目錄執行maven命令來安裝對應的依賴
- 創建一個新的maven項目
- 在新的插件項目中引入依賴
- 創建一個類,實現接口
- 在插件的META-INF目錄(如果沒有就在resources目錄下先創建META-INF目錄)下創建文件gamma.plugin文件,里面寫上對應你插件Processor
接口實現類的全路徑 - 執行命令打包成一個插件
注意: 打出的插件jar需要把對應的第三方依賴也一起打包進插件jar中,可以使用以下配置來完成對應的操作
添加對應的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的行為,有固定的參數
- 插件配置
- 由插件開發者自己定義的參數配置,每一個插件都可能不相同
同時不管gamma核心配置還是插件配置都有2種設置方式
- 通過program arguments方式在gamma啟動的時候設置如:
這里的 source就是通過program arguments設置進入的參數
如果要設置插件的專屬參數, 那么在參數前面需要帶上插件的名稱如:
java -jar gamma-bootstrap.jar source=你要掃描的jar路徑 mypl1:url=123這里的mypl1:url代表的就是給插件mypl1設置參數url
- 通過配置文件方式設置
創建文件 config.properties 來設置對應的配置
config.properties文件位置的不同所具有的含義也不同,如下圖所示
注意: 通過program arguments設置的參數優先級高于配置文件的方式
5.1 gamma核心配置
- source: 指定要掃描的jar包的位置
- scan.package: 指定要掃描的包名前綴,不設置將會掃描所有,多個路徑可以用逗號分隔
5.2 插件配置
上面提到了插件如何去設置自己的參數,那么設置了之后,在插件中如何去讀到對應的參數嗯?
從上面的Processor<T>接口可以看出,需要填入一個泛型T,這個泛型T就是插件自定義的配置類,
當插件被gamma加載的時候,將會回調對應的實現方法void setProperty(T t)來傳遞生成的配置對象
當然這個配置對象也是有部分規則的,需要在需要注入的配置字段上面打上注解@com.chy.gamma.common.profile.Param
如:
那么對應配置文件中的設置為:
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同時注解@Param還有一個參數nullable來控制是否可以缺省某個值,默認是false,及如果沒有傳入
對應的值將會拋出異常
6. 日志
gamma使用的日志框架是 log4j2框架,雖然對應插件的類加載器相互獨立了,但是雙親委派機制的原因
正常去獲取到的logger對象 對于所有插件來說是同一個對象,這樣所有的日志將會混雜到一起
為了能做到日志之間的相互隔離 在插件中請使用以下代碼來獲取logger對象
import com.chy.gamma.common.utils.LogUtils; public static Logger logger = LogUtils.getLogger("類路徑");同時每個插件都可以配置自己的log4j2文件來自定義輸出
7. 嵌入式使用
為了使用更方便,或者再開發插件的時候能夠更好的測試,gamma也提供了嵌入式的使用方式
注意:使用嵌入的方式只能執行一個插件
- 安裝gamma-embed模塊
進入本項目的gamma-embed模塊下,執行命令
- 在代碼中寫入
總結
以上是生活随笔為你收集整理的jar包扫描工具: gamma的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用容器搭建数据库
- 下一篇: dsp28335杂记2