Skip to content

Commit

Permalink
README
Browse files Browse the repository at this point in the history
  • Loading branch information
wangchirl committed Mar 14, 2023
1 parent 0125081 commit dbda99d
Showing 1 changed file with 123 additions and 40 deletions.
163 changes: 123 additions & 40 deletions README.md
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 参数:
Expand All @@ -34,6 +104,7 @@
> - methodBody :暴露 HTTP 请求的方法体,已提供以上四种定时任务实现方式【可选】
> - httpUri :暴露 HTTP 请求的 URI 前缀,会拼接上 /{taskKey} ,默认 /agent/run【可选】
> - debug :是否 debug 模式,次模式方便调试,可生成对应的增强的 controller 类信息文件【可选】
> - logger :打印 agent 中的一些提示信息【可选】
>
> ##### Dynamic time 参数:
>
Expand All @@ -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
```


Expand All @@ -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 定时任务存在特殊性:
Expand All @@ -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?
```


Expand All @@ -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
>
Expand Down

0 comments on commit dbda99d

Please sign in to comment.