如何理解上下文这个概念?
之前在上下文说明这一小章节已经阐述了上下文在LiteFlow框架中是非常重要的概念。
如果有些新手同学对上下文这一概念还不理解,可以看看这小章的说明。
LiteFlow所有的组件process
方法都是无参无返回构造,组件之间的传递参数以及返回的数据都是通过上下文来进行操作的。
# 为什么要这么设计呢?
我们知道在java中调用方法,都是要通过方法名+参数进行调用的,要调用一个方法就必须提供这个方法所需的参数。A方法里调用B方法,等同于A方法强耦合了B方法。
而LiteFlow的核心特性在于编排,如果每个方法名和参数都不一样,就无法做到可替换,可更换顺序。所以必须把组件都设计成一样的模式,消除每个组件的差异性,才能进行编排。
LiteFlow的做法是设计成无参无返回模式,增加了上下文这一概念,业务组件所需要的参数从上下文取,所产出的结果也放到上下文中。
这样设计有两大好处:
- 每一个组件只和上下文发生联系,而无需和其他组件发生联系。这样就消除了组件与组件之间的耦合性。
- 上下文中的数据是共享给当前请求中所有的组件的,我们平时写代码,如果调用关系是: A->B->C,如果A数据要传递给C,那么要一层层的传下去。而在LiteFlow中,如果A把数据放入上下文,则B和C都可以获取到。
每一个请求会产生一个上下文对象,不同请求之间的上下文是隔离开来的。而每个请求结束后,当前的上下文会被销毁回收。
# 上下文和请求参数有什么区别
在LiteFlow中调用一个流程,经常会这么调用:
flowExecutor.execute2Resp("chain1", requestArg, CustomContext.class);
LiteFlow中请求初始参数和上下文不是一个东西。
初始请求参数代表这个流程开始调用时,从这个流程外部传入的参数,这个初始参数也是贯穿整个流程的,任何一个组件都可以用this.getRequestData()
获取到。
上下文是用来存放组件之间产生的数据的,LiteFlow会去初始化这个上下文的class,形成一个全新的实例,在一开始,这个上下文里面是没有任何数据的,组件把执行完的结果数据放入,然后其他组件需要的时候再进行取出,同时链路的最终结果也应该放在上下文中,在组件中用this.getContextBean()
获取。最终流程的response也能通过response.getContextBean()
获取到。
在社区里有一些同学这样写:
CustomContext context = new CustomContext();
context.setName("xxxx");
LiteflowResponse response = flowExecutor.execute2Resp("chain1", context, CustomContext.class);
然后他在组件里这样取:
CustomContext context = this.getContextBean(CustomContext.class);
String name = context.getName();
问我为什么name等于null。
前面说到,LiteFlow中请求初始参数和上下文不是一个东西。
所以,这些同学这么写,是把一个实例context单独作为了requestData,而this.getContextBean
却是另外一个实例。
其实requestData可以是任何对象,只不过这里传的初始参数恰好是CustomContext类型的而已,如果你想取到这个初始参数的CustomContext对象,依然用this.getRequestData()
来获取。
然而有的同学就是想把初始参数包裹在上下文里面,怎么办,难道还专门在第一个组件里,把初始参数set进context里面吗?
LiteFlow其实在文档中也有提到,可以传入已经初始化好的Context。
应该这么写:
CustomContext context = new CustomContext();
context.setName("xxxx");
LiteflowResponse response = flowExecutor.execute2Resp("chain1", null, context);
其实这就是把初始参数和上下文揉到了一起的体现。
LiteFlow的官方建议还是将初始参数和上下文区分开比较好,理由有以下2点:
1.初始参数是不应该被更改的。而上下文里的数据可以随时被更改的。区分开来比较好
2.初始参数可以是任何结构对象,而上下文只是各个组件运行态时所需要的数据对象。如果初始化参数对象被耦合到上下文对象结构里,则从分层理念上来说,是过于耦合了,不利于扩展。
# 上下文中的属性如何保证线程安全
由于组件编排存在着并发性(WHEN),那么上下文的某一个对象可能同时会被多个组件访问,那么这时候如何保证线程安全性以及一致性呢。
由于上下文对象是由使用者定义的,所以这个线程安全性需要由使用者来去处理。在问答中也有解释,跳转到相关问答。
# 多上下文的使用场景
LiteFlow支持在调用时传入多个上下文对象。很多小伙伴不明白这在什么场景使用。
其实这个特性就是为一些通用组件来准备的。
有的时候通用组件会被复用到很多流程中去。而每个流程的上下文又是不一样的。那么你可以为这个通用组件单独定义一个上下文,然后每次调用,你都传入2个上下文,一个为业务上下文,一个为通用组件上下文。使上下文之间的结构分离,完成通用编排。