-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
123 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,96 @@ | ||
### javaagent 技术 | ||
### 项目介绍 | ||
|
||
#### 1、技术点 | ||
#### 1、抛出问题 | ||
|
||
- 在基于 JAVA (SpringBoot)开发定时任务时,一般的情况下会使用以下几种进行实现 | ||
- Xxl | ||
- Quartz | ||
- Spring 注解 @Scheduled | ||
- 定时任务开发完成后,需要针对定时任务进行测试,一般的测试思路 | ||
1. 写 http 接口对外暴露进行测试,可能需要给每一个定时任务都需要写一个接口 | ||
2. 一般定时任务是基于 Cron 表达式写在配置文件中,通过修改定配合重启服务进行测试 | ||
|
||
> 以上发现基于上面的测试方式很麻烦且很费时,浪费大量开发和测试时间 | ||
#### 2、解决思路 | ||
|
||
- 分析常见的定时任务实现原理,找到存储定时任务的地方(源码阅读): 针对 Xxl、Quartz、Spring 注解 @Scheduled 进行源码分析 | ||
- 针对不同实现的定时任务暴露2个 http 接口,可对其进行立即执行和CRUD操作(接口定义): 约定对外暴露 http 接口的入参出参 | ||
- 暴露的 http 接口可针对定时任务进行传参测试(可先写死): 在 controller 中写死逻辑 | ||
- 做到代码无侵入(最终目标): 使用 javaagent 技术进行代理实现 | ||
|
||
#### 4、实现技术 | ||
|
||
- javaagent | ||
- javassist | ||
- xxl job | ||
- quartz job | ||
- spring job | ||
- simple 自定义 job | ||
- Javassist、ASM、ByteBuddy | ||
- Xxl、Spring、Quartz、Simple(基于Spring) 定时任务 | ||
|
||
#### 5、使用说明 | ||
|
||
1. git 拉取项目 | ||
|
||
```sh | ||
git clone [email protected]:wangchirl/javaagent.git | ||
``` | ||
|
||
2. 进入项目使用 maven 打包 | ||
|
||
```sh | ||
cd javaagent | ||
mvn clean package -Dmaven.test.skip=true | ||
``` | ||
|
||
3. git 拉取测试项目 | ||
|
||
```sh | ||
git clone [email protected]:wangchirl/scheduler.git | ||
``` | ||
|
||
4. 进入项目使用 maven 打包 | ||
|
||
```sh | ||
cd scheduler | ||
mvn clean package -Dmaven.test.skip=true | ||
``` | ||
|
||
#### 2、说明 | ||
5. 进入测试项目target目录下,执行脚本 | ||
|
||
- 定时任务开发完成后,如果要进行测试时,需要修改定时任务时间,不能立即执行,测试不方便 | ||
- 项目针对以上问题做了针对以上定时任务实现方式的代理实现,利用 javaagent 技术,无侵入 | ||
- 此项目可直接打包为 jar 包 | ||
- 可结合测试仓库进行测试,测试仓库地址 :https://github.com/wangchirl/scheduler.git | ||
- 源码以开源,可根据自己需求进行改造 | ||
- 后续版本将使用 ASM 、Byte buddy 来对项目进行改造 | ||
- 目前实现了 load time 、dynamic 的 javassist 实现方式,其他方式将在后续进行实现 | ||
```sh | ||
java -javaagent:本地路径(替换为自己的)\javaagent\target\SuperAgent-jar-with-dependencies.jar=ctlClass=com.shadow.controller.AgentBaseController,tlClass=com.shadow.supports.framework.ScheduleService,tlFieldName=JOB_PARAMETERS_THREAD_LOCAL,debug=true,logger=true,crudFieldName=xxxx,crud=true,proxyType=asm,jobType=spring -jar shadow.jar | ||
``` | ||
|
||
#### 3、针对测试仓库进行测试的相关说明 | ||
6. 测试定时任务立即执行及CRUD | ||
|
||
```sh | ||
# 执行定时任务 [spring2] 为 spring 定时任务的方法名称 | ||
# 立即执行 请求参数为 test Spring | ||
curl localhost:50084/shadow/api/system/agent/run/spring2?params=test%20Spring | ||
# 修改 cron 表达式为 0/3 * * * * ? | ||
curl localhost:50084/shadow/api/system/agent/crud/1/spring1?cron=0/3%20*%20*%20*%20*%20? | ||
``` | ||
|
||
7. 可在本地自行导入 [postman 测试文件](./javaagent+schedule项目POSTMAN测试.json) 进行测试 | ||
|
||
#### 6、特别说明 | ||
|
||
> 接口说明: | ||
> | ||
> - 立即执行路径:/agent/run/{taskKey} | ||
> - CRUD路径:/agent/crud/{operation}/{taskKey} | ||
> | ||
> > 动态参数说明: | ||
> > | ||
> > - taskKey(字符串) | ||
> > | ||
> > 定时任务名称 | ||
> > | ||
> > - operation (数字) | ||
> > | ||
> > - 0 删除定时任务 | ||
> > - 1 添加定时任务 | ||
> > - 2 更新定时任务 | ||
> > - 其他数字 查询定时任务 | ||
> | ||
> 参数说明: | ||
> | ||
> ##### Load time 参数: | ||
|
@@ -34,6 +104,7 @@ | |
> - methodBody :暴露 HTTP 请求的方法体,已提供以上四种定时任务实现方式【可选】 | ||
> - httpUri :暴露 HTTP 请求的 URI 前缀,会拼接上 /{taskKey} ,默认 /agent/run【可选】 | ||
> - debug :是否 debug 模式,次模式方便调试,可生成对应的增强的 controller 类信息文件【可选】 | ||
> - logger :打印 agent 中的一些提示信息【可选】 | ||
> | ||
> ##### Dynamic time 参数: | ||
> | ||
|
@@ -49,17 +120,20 @@ | |
> > - methodName :暴露 HTTP 请求的方法的名称,有默认值【可选】 | ||
> > - methodBody :暴露 HTTP 请求的方法体,已提供以上四种定时任务实现方式【可选】 | ||
> > - debug :是否 debug 模式,此模式方便调试,可生成对应的增强的 controller 类信息文件【可选】 | ||
> > - logger :打印 agent 中的一些提示信息【可选】 | ||
|
||
- xxl job 测试 | ||
|
||
```sh | ||
# 启动项目 | ||
-javaagent:F:\source\javaagent\target\SuperAgent-jar-with-dependencies.jar=jobType=XXL&ctlClass=com.shadow.controller.AgentBaseController&debug=true&tlClass=com.shadow.supports.framework.ScheduleService&tlFieldName=JOB_PARAMETERS_THREAD_LOCAL | ||
java -javaagent:本地路径(替换为自己的)\javaagent\target\SuperAgent-jar-with-dependencies.jar=ctlClass=com.shadow.controller.AgentBaseController,tlClass=com.shadow.supports.framework.ScheduleService,tlFieldName=JOB_PARAMETERS_THREAD_LOCAL,debug=true,logger=true,crudFieldName=xxxx,crud=true,proxyType=asm,jobType=xxl -jar shadow.jar | ||
``` | ||
|
||
```sh | ||
# 执行定时任务 [xxl2] 为定时任务JOB NAME | ||
localhost:50084/shadow/api/system/agent/run/xxl2?params=王钦测试Xxl | ||
curl localhost:50084/shadow/api/system/agent/run/xxl2?params=testXxl | ||
# XXL 只有查询实现,因为其调度器和执行器是分离的 | ||
curl localhost:50084/shadow/api/system/agent/crud/1/1 | ||
``` | ||
|
||
|
||
|
@@ -68,12 +142,14 @@ | |
|
||
```sh | ||
# 启动项目 | ||
-javaagent:F:\source\javaagent\target\SuperAgent-jar-with-dependencies.jar=jobType=QUARTZ&ctlClass=com.shadow.controller.AgentBaseController&debug=true&tlClass=com.shadow.supports.framework.ScheduleService&tlFieldName=JOB_PARAMETERS_THREAD_LOCAL | ||
java -javaagent:本地路径(替换为自己的)\javaagent\target\SuperAgent-jar-with-dependencies.jar=ctlClass=com.shadow.controller.AgentBaseController,tlClass=com.shadow.supports.framework.ScheduleService,tlFieldName=JOB_PARAMETERS_THREAD_LOCAL,debug=true,logger=true,crudFieldName=xxxx,crud=true,proxyType=asm,jobType=quartz -jar shadow.jar | ||
``` | ||
|
||
```sh | ||
# 执行定时任务 [quartzTriggerKey] 为 Trigger Bean,[quartzJob]为 job detail ID | ||
localhost:50084/shadow/api/system/agent/run/quartzTriggerKey?params=quartzJob | ||
curl -H "Content-Type:application/json" -X POST --data "{\"name\":\"shadow\",\"age\":20}" localhost:50084/shadow/api/system/agent/run/quartzTriggerKey?params=quartzJob | ||
# 修改 cron 表达式为 0/3 * * * * ? | ||
curl localhost:50084/shadow/api/system/agent/crud/1/quartzTriggerKey@quartzJob?cron=0/3%20*%20*%20*%20*%20? | ||
``` | ||
|
||
> Quartz 定时任务存在特殊性: | ||
|
@@ -85,12 +161,15 @@ | |
|
||
```sh | ||
# 启动项目 | ||
-javaagent:F:\source\javaagent\target\SuperAgent-jar-with-dependencies.jar=jobType=SPRING&ctlClass=com.shadow.controller.AgentBaseController&debug=true&tlClass=com.shadow.supports.framework.ScheduleService&tlFieldName=JOB_PARAMETERS_THREAD_LOCAL | ||
java -javaagent:本地路径(替换为自己的)\javaagent\target\SuperAgent-jar-with-dependencies.jar=ctlClass=com.shadow.controller.AgentBaseController,tlClass=com.shadow.supports.framework.ScheduleService,tlFieldName=JOB_PARAMETERS_THREAD_LOCAL,debug=true,logger=true,crudFieldName=xxxx,crud=true,proxyType=asm,jobType=spring -jar shadow.jar | ||
``` | ||
|
||
```sh | ||
# 执行定时任务 [spring2] 为 spring 定时任务的方法名称 | ||
localhost:50084/shadow/api/system//agent/run/spring2?params=王钦测试Spring | ||
# 立即执行 请求参数为 test Spring | ||
curl localhost:50084/shadow/api/system/agent/run/spring2?params=test%20Spring | ||
# 修改 cron 表达式为 0/3 * * * * ? | ||
curl localhost:50084/shadow/api/system/agent/crud/1/spring1?cron=0/3%20*%20*%20*%20*%20? | ||
``` | ||
|
||
|
||
|
@@ -99,37 +178,41 @@ | |
|
||
```sh | ||
# 启动项目 | ||
-javaagent:F:\source\javaagent\target\SuperAgent-jar-with-dependencies.jar=jobType=SIMPLE&ctlClass=com.shadow.controller.AgentBaseController&debug=true&tlClass=com.shadow.supports.framework.ScheduleService&tlFieldName=JOB_PARAMETERS_THREAD_LOCAL | ||
java -javaagent:本地路径(替换为自己的)\javaagent\target\SuperAgent-jar-with-dependencies.jar=ctlClass=com.shadow.controller.AgentBaseController,tlClass=com.shadow.supports.framework.ScheduleService,tlFieldName=JOB_PARAMETERS_THREAD_LOCAL,debug=true,logger=true,crudFieldName=xxxx,crud=true,proxyType=asm,jobType=simple -jar shadow.jar | ||
``` | ||
|
||
```sh | ||
# 执行定时任务 [simple1] 为 spring 容器 Bean 名称 | ||
localhost:50084/shadow/api/system//agent/run/simple1?王钦测试Simple | ||
curl localhost:50084/shadow/api/system//agent/run/simple1?testSimple | ||
# 修改 cron 表达式为 0/3 * * * * ? | ||
curl localhost:50084/shadow/api/system/agent/crud/1/simple2?cron=0/3%20*%20*%20*%20*%20? | ||
``` | ||
|
||
|
||
#### 4、最全的 agent 请求参数传递 | ||
#### 7、最全的 agent 请求参数传递 | ||
|
||
> ```sh | ||
> -javaagent:F:\source\javaagent\target\SuperAgent-jar-with-dependencies.jar=jobType=XXL&ctlClass=com.shadow.controller.AgentBaseController&tlClass=com.shadow.supports.framework.ScheduleService&tlFieldName=JOB_PARAMETERS_THREAD_LOCAL&methodName=testMethod&iocFieldName=ioc&httpUri=/test/run&debug=true | ||
> java -javaagent:本地路径(替换为自己的)\javaagent\target\SuperAgent-jar-with-dependencies.jar=ctlClass=com.shadow.controller.AgentBaseController,tlClass=com.shadow.supports.framework.ScheduleService,tlFieldName=JOB_PARAMETERS_THREAD_LOCAL,debug=true,logger=true,httpUri=/test/run,methodName=testMethod,iocFieldName=ioc,crudFieldName=xxxx,crud=true,proxyType=asm,jobType=simple -jar shadow.jar | ||
> ``` | ||
> | ||
> 说明: | ||
> | ||
> - 定时任务类型为 XXL | ||
> - 暴露 HTTP 的 controller 是 com.shadow.controller.AgentBaseController | ||
> - ThreadLocal 参数传递的类是 com.shadow.supports.framework.ScheduleService | ||
> - ThreadLocal 对象的字段名称是 JOB_PARAMETERS_THREAD_LOCAL | ||
> - 暴露 HTTP 接口方法名称是 testMethod | ||
> - 注入到 controller 类中的 Spring IOC 容器字段名称是 ioc | ||
> - HTTP 请求路径是 当前 controller 的 path + /test/run/{taskKey} | ||
> - debug 是 true,会在当前位置生成所增强的 controller 的字节码文件 | ||
|
||
#### 5、postman 相关测试在同目录下的 `javaagent+schedule项目POSTMAN测试.json` | ||
|
||
|
||
|
||
#### 6、Attach 机制 - 可动态替换定时任务类型 | ||
> - jobType :定时任务类型为 XXL | ||
> - proxyType :asm 表示使用 ASM 代理,可选 buddy 和 javassist | ||
> - crud :true 表示暴露 CRUD 接口 | ||
> - crudFieldName :crud 需要使用的字段名称,避免和代理类字段冲突使用 xxxx | ||
> - iocFieldName :spring ioc 的字段名称,避免和代理类中 spring ioc 名称的冲突使用 ioc | ||
> - methodName :立即执行接口的方法名称,避免和代理类方法名称冲突使用 testMethod | ||
> - httpUri :立即执行接口的路径,避免和代理类路径冲突使用 /test/run/{taskKey} | ||
> - logger :true 表示打印代理过程中的提示信息 | ||
> - debug :true 表示生成代理后的 class 文件 | ||
> - tlFieldName :定义的 ThreadLocal 的字段名称 JOB_PARAMETERS_THREAD_LOCAL | ||
> - tlClass :定义 ThreadLocal 的类名称 com.shadow.supports.framework.ScheduleService | ||
> - ctlClass :代理的 controller 类 com.shadow.controller.AgentBaseController | ||
|
||
|
||
|
||
#### 8、Attach 机制 - 可动态替换定时任务类型 TODO | ||
|
||
> 测试类:com.shadow.agent.AttachAgentTest | ||
> | ||
|