赞
踩
本项目是一个jar包扫描工具,可以支持插件化订制不同的扫描逻辑
支持以下功能:
springBoot jar
的扫描项目地址:
设计gamma的初衷是为了能在ci流水线
中快速的检查已经打包好的的业务jar
,并且能轻易的扩展扫描器的功能,以及和业务解耦
对于语法检查等checkstyle
插件确实直接扫描java
文件是更好的选择,但是扫描java
文件意味着解析
难度变大,需要去解析对应字符串到底是属于什么包
如:我想去收集某个项目中有多少个方法标记了 springMVC
中的注解@RequestMapping
, 同时把这个注解中的入参给统计一下
上述需求如果直接去解析java
文件就会很麻烦,因为虽然匹配上了字符串@RequestMapping
但还需要去判断他的包名是否是属于
spring
, 还需要去解析对应注解中的参数,如果注解中使用了常量
,还需要解析对应的常量类,然后才能获取真正的值
通过一些字节码工具,如asm
可以直接去解析class文件
,这样确实可以解决上面提到扫描java
文件中常量和类全称的问题,
但是有一定的门槛,需要去学习字节码
的相关知识和对应的操作框架
gamma
出现就是解决上面2个问题
如果我可以把这个jar
文件完全给装载进入jvm
中,从jvm
中获取到我所有想扫描的class
对象, 然后通过反射去获取是否存在@RequestMapping
注解,不就
能减少很多的工作量。
对应开发插件的人来说,门槛就仅仅只需要会使用反射即可
所以 gamma的优势 如下:
上面简介中提到过,gamma
的工作原理是将会 把要扫描的jar
完全加载进入到jvm
中,然后处理器
将会依次获得对应的class对象
,处理器将可以使用反射的方式去处理获得的class对象
(如:使用反射来获取对应类
/方法
上面是否存在@RequestMapping
注解)
这里的处理器
,也就是需要根据实际业务去编写的gamma插件
了。
上面提到过,gamma
将会把要扫描的jar
完全加载进入jvm
中,那么类加载器的设计就需要满足以下几点
jvm
的扫描Jar
中的class对象这里jar
包的解析分成2种情况
spring boot
的jar
springBoot
打出的jar格式和普通的jar又一定的区别,所以需要先去获得spring提供的一个类加载器
,然后才能通过这个类加载器
去获得对应业务class
普通的java jar
scan.package
来指定你想扫描的class路径,而不需要去扫描框架引入的classspringBoot
的jar来说,因为特殊的jar结构,扫描的将全部都是业务class注意:
在本项目的/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
gamma
仅仅只是一个扫描引擎,当扫描到对应的class
要如何处理, 需要编写插件
来实现
如:
gamma-common
目录执行maven命令来安装对应的依赖mvn clean install
<dependency>
<groupId>com.chy</groupId>
<artifactId>gamma-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
/** * gamma插件的执行接口 * 泛型T 为插件需要的配置文件类,如:本插件在配置文件config.properties 中设置了属性 commitId=1234 、 ref=master * 那么泛型T需要定义 一个实体类来接收这2个属性 * 如果没有任何的属性对象,这里泛型可以填入 Void * * * @param <T> */ public interface Processor<T> { /** * 配置对象的接收,gamma将会根据配置文件以及jvm参数来生成对应的配置对象 * 如果泛型T 设置是Object那么这里注入的将会是一个HashMap对象 * @param t */ void setProperty(T t); /** * 处理的核心接口 * gamma每扫描到jar中的一个class都会回调该接口 * * @param originClass 被扫描jar中的某一个class */ void processor(Class originClass); /** * 当全部扫描完后回调 * */ void finishProcessor(); }
META-INF
目录(如果没有就在resources
目录下先创建META-INF
目录)下创建文件gamma.plugin
文件,里面写上对应你插件Processor
mvn clean package
注意: 打出的插件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>
在gamma
中配置分成2类
gamma
核心配置
插件
配置
同时不管gamma核心配置
还是插件配置
都有2种设置方式
program arguments
方式在gamma
启动的时候设置如:java -jar gamma-bootstrap.jar source=你要扫描的jar路径
这里的 source
就是通过program arguments
设置进入的参数
如果要设置插件的专属参数
, 那么在参数前面需要带上插件的名称如:
java -jar gamma-bootstrap.jar source=你要扫描的jar路径 mypl1:url=123
这里的mypl1:url
代表的就是给插件mypl1
设置参数url
配置文件
方式设置创建文件 config.properties
来设置对应的配置
config.properties
文件位置的不同所具有的含义也不同,如下图所示
注意: 通过program arguments
设置的参数优先级高于配置文件的方式
source
: 指定要扫描的jar包的位置scan.package
: 指定要扫描的包名前缀,不设置将会扫描所有,多个路径可以用逗号
分隔上面提到了插件如何去设置自己的参数,那么设置了之后,在插件中如何去读到对应的参数嗯?
从上面的Processor<T>
接口可以看出,需要填入一个泛型T
,这个泛型T
就是插件自定义的配置类,
当插件被gamma
加载的时候,将会回调对应的实现方法void setProperty(T t)
来传递生成的配置对象
当然这个配置对象也是有部分规则的,需要在需要注入的配置字段上面打上注解@com.chy.gamma.common.profile.Param
如:
@Data
public class ApiScanProperty {
@Param
private String ref;
@Param
private String commitId;
@Param(nullable = true)
private String appName;
@Param("endpoint.topology.host")
private String host;
}
那么对应配置文件中的设置为:
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
,及如果没有传入
对应的值将会抛出异常
gamma
使用的日志框架是 log4j2
框架,虽然对应插件的类加载器相互独立了,但是双亲委派
机制的原因
正常去获取到的logger
对象 对于所有插件
来说是同一个对象,这样所有的日志将会混杂到一起
为了能做到日志之间的相互隔离 在插件中请使用以下代码来获取logger
对象
import com.chy.gamma.common.utils.LogUtils;
public static Logger logger = LogUtils.getLogger("类路径");
同时每个插件都可以配置自己的log4j2
文件来自定义输出
为了使用更方便,或者再开发插件的时候能够更好的测试,gamma
也提供了嵌入式的使用方式
注意:使用嵌入的方式只能执行一个插件
gamma-embed
模块gamma-embed
模块下,执行命令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);
//执行插件
gammaContainer.start(new 你实现的Procession对象);
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。