FlowContext
介绍
FlowContext 是业务框架 action 流程处理的上下文,生命周期存在于这一次的 action 请求。 如果你之前只接触过 web 开发,可以暂时将其理解为 Cookie。
FlowContext 功能包括但不限于如下:
- userId 的获取。
- 具备动态属性能力。
- 提供通信能力,为各通信方式提供了同步、异步、异步回调 ...等便捷 api, 并具备全链路调用日志跟踪特性。
- 支持元信息-附加信息的扩展(开发者可扩展用户数据的存储)。
- 支持自定义扩展 (开发者可定制符合团队、符合业务的使用 API)。
- 得到当前 FlowContext 对应的线程执行器,可轻松实现无锁高并发。
由于 FlowContext 具备了通信能力,并且提供了同步、异步、异步回调 ...等便捷 api, 并具备全链路调用日志跟踪特性。 所以你可以使用简洁的代码编写跨服访问,或给自己发送数据。
业务框架流程简图
下图是关于 action 的处理流程 ,FlowContext 会经过图中的每个环节。
如何获取 FlowContext
只需要在 action 的方法参数中定义该变量即可,框架会自动识别。
@ActionController(1)
public class DemoAction {
@ActionMethod(1)
public void demo(FlowContext flowContext) {
}
}
userId
用户登录后,可以通过 flowContext 来获取 userId。
long userId = flowContext.getUserId();
自定义 FlowContext
框架提供了 FlowContext 的扩展,如果 FlowContext 现有的功能无法满足你现有的业务, 可以通过扩展的方式增强 FlowContext。 该小节我们自定义一个 FlowContext,并添加一些自定义的方法。
@Setter
public class MyFlowContext extends DefaultFlowContext {
public String getNickname() {
return "Michael Jackson";
}
}
设置自定义的 FlowContext
static void main() {
CoreGlobalConfig.setting.flowContextFactory = MyFlowContext::new;
}
在 action 中的使用
自定义的 MyFlowContext 与框架默认提供的 FlowContext 使用方式是一样的
@ActionController(MyCmd.cmd)
public class MyAction {
@ActionMethod(MyCmd.nickname)
private String getNickname(MyFlowContext flowContext) {
return flowContext.getNickname();
}
}
线程执行器 - 无锁高并发
FlowContext 提供了获取与用户所关联线程执行器,包括用户虚拟线程执行器和用户线程执行器。 框架提供了优雅、独特的线程执行器设计。通过该特性,开发者能轻易的编写出无锁高并发的代码。
具体可阅读线程相关内容。
UserThreadExecutorRegion 是用户线程执行器,也是消费 action 业务的线程执行器。 开发者可以将任务提交到该执行器中执行,能避免并发问题。
- code 2,使用用户线程执行任务,该方法具备全链路调用日志跟踪。
- code 6,提交任务到用户线程执行器中。
void executor() {
flowContext.execute(() -> {
// your code
});
flowContext.getExecutor().execute(() -> {
// your code
});
}
UserVirtualThreadExecutorRegion 是用户虚拟线程执行器, 开发者可以将带有 IO 或阻塞的任务提交到该执行器中执行。
- code 2,使用虚拟线程执行任务,该方法具备全链路调用日志跟踪。
- code 6,提交任务到虚拟线程执行器中。
void executeVirtual() {
flowContext.executeVirtual(() -> {
// your code
});
flowContext.getVirtualExecutor().execute(() -> {
// your code
});
}
通信能力
FlowContext 内部整合了通信模型, 并提供了同步、异步、异步回调的便捷使用方式。 更多使用示例,请阅读 Examples Communication
除了整合广播 API 外,还支持广播给自己,api 名字以 broadcastMe 打头。
@ActionController(FlowContextBroadcastCmd.cmd)
public class FlowContextBroadcastAction {
AtomicInteger inc = new AtomicInteger();
@ActionMethod(triggerBroadcastMe)
private void triggerBroadcastMe(FlowContext flowContext) {
// ---------- empty ----------
flowContext.broadcastMe(broadcastMeEmpty);
// ---------- int ----------
int dataInt = inc.getAndIncrement();
flowContext.broadcastMe(broadcastMeInt, dataInt);
// ---------- boolean ----------
boolean dataBool = inc.getAndIncrement() % 2 == 0;
flowContext.broadcastMe(broadcastMeBool, dataBool);
// ---------- long ----------
long dataLong = inc.getAndIncrement();
flowContext.broadcastMe(broadcastMeLong, dataLong);
// ---------- string ----------
String dataString = "ionet-" + inc.getAndIncrement();
flowContext.broadcastMe(broadcastMeString, dataString);
// ---------- object ----------
BookMessage dataObject = new BookMessage();
dataObject.authorName = "ionet";
dataObject.bookName = "book-" + inc.getAndIncrement();
flowContext.broadcastMe(broadcastMeObject, dataObject);
// ---------- list int ----------
List<Integer> dataListInt = List.of(inc.getAndIncrement(), inc.getAndIncrement());
flowContext.broadcastMeListInt(broadcastMeIntList, dataListInt);
// ---------- list boolean ----------
List<Boolean> dataListBool = List.of(
inc.getAndIncrement() % 2 == 0,
inc.getAndIncrement() % 2 == 0
);
flowContext.broadcastMeListBool(broadcastMeBoolList, dataListBool);
// ---------- list long ----------
List<Long> dataListLong = List.of(
(long) inc.getAndIncrement(),
(long) inc.getAndIncrement()
);
flowContext.broadcastMeListLong(broadcastMeLongList, dataListLong);
// ---------- list string ----------
List<String> dataListString = List.of(
"ionet-" + inc.getAndIncrement(),
"ionet-" + inc.getAndIncrement()
);
flowContext.broadcastMeListString(broadcastMeStringList, dataListString);
// ---------- list object ----------
BookMessage message1 = new BookMessage();
message1.authorName = "ionet";
message1.bookName = "book-" + inc.getAndIncrement();
BookMessage message2 = new BookMessage();
message2.authorName = "ionet";
message2.bookName = "book-" + inc.getAndIncrement();
List<BookMessage> dataList = List.of(message1, message2);
flowContext.broadcastMe(broadcastMeObjectList, dataList);
}
}
小结
FlowContext 是当前 action 的请求上下文,通过 FlowContext 几乎可以拿到当前逻辑服的所有信息,这些信息包括:逻辑服、业务框架等。 框架提供了 FlowContext 的扩展,如果 FlowContext 现有的功能无法满足你现有的业务,可以通过扩展的方式增强 FlowContext。
FlowContext 整合了一些常用的 api
- 通信相关的有:
- 内部请求时的同步、异步、异步回调的便捷使用方式。
- Broadcast 广播。
- EventBus。
- OnExternal。
- 元信息相关的有:
- updateAttachment 同步更新。
- updateAttachmentAsync 异步更新。
- 线程执行器相关的有:
- 用户虚拟线程执行器。
- 用户线程执行器。