⛱方法任务
# 何为方法任务
相信看到这里的小伙伴大概已经了解Gobrs-Async如何创建一个普通任务(创建一个类继承自AsyncTask
),那么有的小伙伴觉的业务不是很复杂,只是单纯的多线程开发,不想
开启一个任务就创建一个类。这违背了多线程简单上手的初衷。 那么这种场景下如何快速完成多线程开发,并且具备管理多线程(重试、回调、监控、超时)的能力呢?
# 开启方法任务
开启方法任务很简单(默认不开启方法任务,完全按照小伙伴开发喜好设计),只需要在SpringBoot
启动类中编写 @EnabledMethodTask
注解即可开启方法任务
@EnabledMethodTask
@SpringBootApplication
public class GobrsAsyncTestApplication {
/**
* The entry point of application.
* @param args the input arguments
*/
public static void main(String[] args) {
SpringApplication.run(GobrsAsyncTestApplication.class, args);
}
}
# 说明
方法任务是通过一个方法开启一个任务。 适合业务不太复杂需要开启多线程同时管理多线程的场景。
# 声明方法任务组件
所谓的方法任务组件: 方法任务所在的类。
只需要在需要想要开启方法任务的业务 service
中编码 @MethodComponent
注解,则标识该类为 Gobrs-Async的方法任务组件。
提示
@MethodComponent
注解默认集成Spring的 @Component
注解,无须重复引入。
# 方法任务
只需要使用 @MethodTask 注解到所要开启任务的方法上即可, 同时注解了@MethodTask
的方法也兼容直接当作普通方法调用,也就是说对参数没有任何限制。
# 匹配模式-取参
所谓匹配模式即为 任务流程在发起调用时,会传递给每一个任务所需要的参数, 在传递参数时,方法任务的参数传递需要使用ParamsTool.asParams
方法包裹。
否则无法在 方法任务参数中进行映射。如果未使用 ParamsTool.asParams
方法包裹。则可以使用总线模式从TaskSupport
获取参数。
提示
如果参数不匹配(数量不匹配、类型不匹配), 会打印对应状态日志。并不会抛出异常。
调用流程如下所示:
@SneakyThrows
@Test
public void launcher() {
Map<String, Object> params = new HashMap<>();
/**
* normal 任务参数 无法进行参数映射 需要在方法任务参数中注入 TaskSupport 从 TaskSupport中 获取参数值
*/
params.put("normal", new HashMap<>());
/**
* normal2 可以直接通过参数映射进行匹配取值。 需要注意的是 参数类型需要匹配正确, 否则参数获取为空
*/
params.put("normal2", ParamsTool.asParams("support seize a seat", "context"));
AsyncResult asyncResult = gobrsAsync.go("launcher", () -> params, 300000);
final Map<String, TaskResult> resultMap = asyncResult.getResultMap();
Assertions.assertEquals(resultMap.get("normal").getResult(), CaseMethodTaskOne.TASK_1_RESULT);
}
方法任务参数映射如下所示:
@MethodTask(name = "normal")
public String normal(TaskSupport taskSupport) throws InterruptedException {
String context1 = taskSupport.getParam("normal", String.class);
Thread.sleep(1000);
Assertions.assertThat(context1).isEqualTo("context");
return TASK_1_RESULT;
}
/**
* Normal 2 string.
*
* @return the string
*/
@SneakyThrows
@MethodTask
public String normal2(String param1, String param2, TaskSupport support) {
Assertions.assertThat(param1).isEqualTo("context");
/**
* 获取 task1 的返回结果
*/
String task1Result = support.getResult("normal", String.class);
Assertions.assertThat(task1Result).isEqualTo(TASK_1_RESULT);
Thread.sleep(1000);
return "task2";
}
# 总线模式-取参
如果开发者想获取 Gobrs-Async内部中的当前方法任务所依赖任务的返回结果 或者 获取当前方法任务外部传递进来的参数, 则需要参数在方法参数中添加 TaskSupport
。如下所示:
@MethodTask(name = "normal")
public String normal(TaskSupport taskSupport) throws InterruptedException {
String context1 = taskSupport.getParam("normal", String.class);
Thread.sleep(1000);
Assertions.assertThat(context1).isEqualTo("context");
return TASK_1_RESULT;
}
- 获取方法任务参数:
TaskSupport#getParam(String taskName, Class<T> class)
方法即可获取 - 获取所依赖任务的返回结果:
TaskSupport#getResult(String taskName, Class<T> class)
方法即可获取
# 其它配置
# 示例
@SneakyThrows
@MethodTask(invoke = @Invoke(onFail = "demote", rollback = "Exception"), config = @MethodConfig(retryCount = 10))
public void throwException() {
System.out.println("will throwException");
throw new RuntimeException("throwException test");
}
# 注解说明
@MethodComponent
标识类为方法任务组件, 注解在类上。@MethodTask
方法任务标识, 注解在方法上 。参数如下:name
: 方法任务名称需与 Gobrs-Async 配置文件中的 task 名称匹配,如果不编写。则默认取该注解方法的名称(会判重)invoke
: 配置方法任务的 回调方法(成功、失败、回滚、必要条件)与@Task
注解中的配置项匹配config
: 配置方法任务的任务属性(超时时间、重试次数、描述、是否具备事务属性、异常是否继续执行、描述)
# 完整案例
配置
gobrs:
async:
config:
rules:
- name: "launcher"
content: "normal->normal2"
- name: "methodRetry"
content: "throwException"
- name: "methodTimeout"
content: "timeout"
- name: "rollback"
content: "rollback1->rollback2->rollback3"
transaction: true
任务编码
@MethodComponent
public class CaseMethodTaskOne {
/**
* The constant TASK_1_RESULT.
*/
public static final String TASK_1_RESULT = "task1_result";
/**
* Case 1.
*
* @return the string
* @throws InterruptedException the interrupted exception
*/
@MethodTask(name = "normal")
public String normal(TaskSupport taskSupport) throws InterruptedException {
String context1 = taskSupport.getParam("normal", String.class);
Thread.sleep(1000);
Assertions.assertThat(context1).isEqualTo("context");
return TASK_1_RESULT;
}
/**
* Normal 2 string.
*
* @return the string
*/
@SneakyThrows
@MethodTask
public String normal2(String param1, String param2, TaskSupport support) {
Assertions.assertThat(param1).isEqualTo("context");
/**
* 获取 task1 的返回结果
*/
String task1Result = support.getResult("normal", String.class);
Assertions.assertThat(task1Result).isEqualTo(TASK_1_RESULT);
Thread.sleep(1000);
return "task2";
}
/**
* Throw exception.
*/
@SneakyThrows
@MethodTask(invoke = @Invoke(onFail = "demote", rollback = "Exception"), config = @MethodConfig(retryCount = 10))
public void throwException() {
System.out.println("will throwException");
throw new RuntimeException("throwException test");
}
/**
* Demote.
*/
public void demote() {
System.out.println("task2 execute fail");
}
/**
* Timeout.
*/
@SneakyThrows
@MethodTask
public void timeout() {
Thread.sleep(30000);
}
/**
* Rollback 1.
*/
@SneakyThrows
@MethodTask(invoke = @Invoke(rollback = "rool1"))
public void rollback1() {
System.out.println("rooback1");
Thread.sleep(1000);
}
/**
* Rollback 2.
*/
@SneakyThrows
@MethodTask(invoke = @Invoke(rollback = "rool2"))
public void rollback2() {
System.out.println("rollback2");
Thread.sleep(1000);
}
/**
* Rollback 3.
*/
@SneakyThrows
@MethodTask(invoke = @Invoke(rollback = "rool1"), config = @MethodConfig(callback = true))
public void rollback3() {
System.out.println("rollback3");
Thread.sleep(1000);
System.out.println(1 / 0);
}
/**
* Roo 1.
*/
public void rool1() {
System.out.println("rool1 start ....");
}
/**
* Roo 2.
*/
public void rool2() {
System.out.println("rool2 start ....");
}
}