Activiti⼯作流学习笔记(四)——⼯作流引擎中责任链模式的
建⽴与应⽤原理
原创/朱季谦
本⽂需要⼀定责任链模式的基础与Activiti⼯作流知识,主要分成三部分讲解:
⽹上关于责任链模式的介绍很多,菜鸟教程上是这样说的:责任链模式(Chain of Responsibility Pattern)为请求创建了⼀个接收者对象的链。在这种模式中,通常每个接收者都包含对另⼀个接收者的引⽤。如果⼀个对象不能处理该请求,那么它会把相同的请求传给下⼀个接收者,依此类推。
这个概念术语⽐较抽象。
我曾经在 ⼀⽂中提到Spring Security在授权过程中有使⽤到过滤器的概念,过滤器链就像⼀条铁链,中间的每个过滤器都包含对另⼀个过滤器的引⽤,从⽽把相关的过滤器链接起来,就像⼀条链的样⼦。这时请求线程如蚂蚁⼀样,会沿着这条链⼀直爬过去-----即,通过各过滤器调⽤另⼀个过滤器引⽤⽅法chain.doFilter(request, response),实现⼀层嵌套⼀层地将请求传递下去,当该请求传递到能被处理的过滤器时,就会被处理,处理完成后转发返回。通过过滤器链,可实现在不同的过滤器当中对请求request做拦截增加,且过滤器之间彼此互不⼲扰。
整个流程⼤致如下:
这个过滤器链的概念,其实就是责任链设计模式在Spring Security中的体现。
摘录⼀段⽹上关于职责链模式介绍,其主要包含以下⾓⾊:
1. 抽象处理者(Handler)⾓⾊:定义⼀个处理请求的接⼝,包含抽象处理⽅法和⼀个后继连接。
2. 具体处理者(Concrete Handler)⾓⾊:实现抽象处理者的处理⽅法,判断能否处理本次请求,如果可以处理请求则处理,否则将该
请求转给它的后继者。
3. 客户类(Client)⾓⾊:创建处理链,并向链头的具体处理者对象提交请求,它不关⼼处理细节和请求的传递过程。
最近在研究Activiti⼯作流框架,发现其所有实现都是采⽤命令模式实现,⽽命令模式当中的Invoker⾓⾊⼜是采⽤链式模式,即类似
上⾯提到的过滤器链,即设计模式⾥的责任链模式。
这⾥的Activiti⼯作流版本是6.0。
CommandInterceptor是⼀个接⼝,包含三个⽅法:
setNext()⽅法是在初始化时,设置每个对象中包含了下⼀个对象,最后形成⼀条链;
getNext()可在每个对象中调⽤下⼀个对象;
execute()是每个对请求的处理。若在上⼀个链式⾥不能处理该请求话,就会通过ute(CommandConfig var1, Command var2)将请求传递到下⼀个做处理,类似上⾯过滤器⾥调⽤下⼀个过滤器的chain.doFilter(request,
response)⽅法,将请求进⾏传递;
public interface CommandInterceptor {
<T> T execute(CommandConfig var1, Command<T> var2);
CommandInterceptor getNext();
void setNext(CommandInterceptor var1);
}
抽象类AbstractCommandInterceptor实现了CommandInterceptor接⼝,在责任链模式当中充当抽象处理者(Handler)⾓⾊。该类最主要的属性是 protected CommandInterceptor next,在同⼀包下,直接通过next即可调⽤下⼀个对象。
public abstract class AbstractCommandInterceptor implements CommandInterceptor {
protected CommandInterceptor next;
public AbstractCommandInterceptor() {
}
public CommandInterceptor getNext() {
;
}
public void setNext(CommandInterceptor next) {
< = next;
}
}
接下来,将会分析链是如何初始化与⼯作的。
SpringBoot集成Activiti配置如下:
@Configuration
public class SpringBootActivitiConfig {
@Bean
public ProcessEngine processEngine() {
ProcessEngineConfiguration pro = ateStandaloneProcessEngineConfiguration();
pro.setJdbcDriver("sql.jdbc.Driver");
pro.setJdbcUrl("xxxx");
pro.setJdbcUsername("xxxx");
pro.setJdbcPassword("xxx");
//避免发布的图⽚和xml中⽂出现乱码
pro.setActivityFontName("宋体");
pro.setLabelFontName("宋体");
pro.setAnnotationFontName("宋体");
//数据库更更新策略
pro.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
return pro.buildProcessEngine();
}
}
这时,启动项⽬后,pro.buildProcessEngine()这⾏代码会初始化Activiti框架,进⼊⾥⾯,会发现它有三种实现,默认是第⼆种,即ProcessEngineConfigurationImpl。
点进去,Activiti框架具体构建buildProcessEngine⽅法如下,其中 this.init()的作⽤是环境初始化,包括配置设置、JDBC连接、bean装载等的:
public ProcessEngine buildProcessEngine() {
this.init();
ProcessEngineImpl processEngine = new ProcessEngineImpl(this);
if (this.isActiviti5CompatibilityEnabled && this.activiti5CompatibilityHandler != null) {
Context.ProcessEngineConfiguration());
RawProcessEngine();
}
this.postProcessEngineInitialisation();
return processEngine;
}
在this.init()⽅法⾥,涉及到责任链模式初始化的⽅法是this.initCommandExecutors(),⾥⾯详情如下:
public void initCommandExecutors() {
this.initDefaultCommandConfig();
this.initSchemaCommandConfig();
//初始化命令调⽤器
this.initCommandInvoker();
//List存放进涉及到的
this.initCommandInterceptors();
//初始化命令执⾏器
this.initCommandExecutor();
}
这⾥只需要关注最后三个⽅法——
1. this.initCommandInvoker()
initCommandInvoker()初始化构建了⼀个CommandInvoker,它继承上边提到的抽象类
AbstractCommandInterceptor。这个在整条过滤器链中是最重要和关键,它排在了整条链的最后,其实,它才是最终执⾏请求的,前边⼏个都是传递请求⽽已。
public void initCommandInvoker() {
if (thismandInvoker == null) {
if (ableVerboseExecutionTreeLogging) {
thismandInvoker = new DebugCommandInvoker();
} else {
//初始化执⾏该⾏代码
thismandInvoker = new CommandInvoker();
}
}
}
这⾥ new CommandInvoker()⼀个对象,然后将地址复制给thismandInvoker对象引⽤,注意,该引⽤将会⽤在接下来的initCommandInterceptors()⽅法⾥——
2. this.initCommandInterceptors();
initCommandInterceptors⽅法主要作⽤是创建⼀个List集合,然后将需要⽤到的都保存到该List集合⾥——
public void initCommandInterceptors() {
if (thismandInterceptors == null) {
thismandInterceptors = new ArrayList();
if (this.customPreCommandInterceptors != null) {
//⽤户⾃定义前置
thismandInterceptors.addAll(this.customPreCommandInterceptors);
}
//框架⾃带默认的
thismandInterceptors.DefaultCommandInterceptors());
if (this.customPostCommandInterceptors != null) {
thismandInterceptors.addAll(this.customPostCommandInterceptors);
}
//命令调⽤器,在链最后⼀个
thismandInterceptors.add(thismandInvoker);
}
}
public Collection<? extends CommandInterceptor> getDefaultCommandInterceptors() {
List<CommandInterceptor> interceptors = new ArrayList();
//⽇志
interceptors.add(new LogInterceptor());
CommandInterceptor transactionInterceptor = ateTransactionInterceptor();
if (transactionInterceptor != null) {
interceptors.add(transactionInterceptor);
}
//
if (thismandContextFactory != null) {
interceptors.add(new CommandContextInterceptor(thismandContextFactory, this));
}
//事务
if (ansactionContextFactory != null) {
interceptors.add(new ansactionContextFactory));
}
return interceptors;
}
可见,⽅法⾥的 thismandInterceptors 就是⼀个专门储存对象的List集合——
protected List<CommandInterceptor> commandInterceptors;
这⾥只需要重点关注thismandInterceptors.add(thismandInvoker)这⾏代码,就是将上边创建的CommandInvoker对象存储到List⾥,它是放在initCommandInterceptors()⽅法最后,某种程度也就意味着,这个在整条链当中处在最后⾯的位置。
执⾏完该this.initCommandInterceptors()⽅法后,就可获取到所有的对象,到这⼀步时,各还是互相独⽴的,仍⽆法通过next()来进⾏调⽤传递,那么,究竟是如何将它们串起来形成⼀条链呢?
接下来的this.initCommandExecutor()⽅法,就是实现将各串起来形成⼀条长链。
3. this.initCommandExecutor();
该⽅法有两个作⽤,⼀个是⽣成Interceptor链,⼀个是创建命令执⾏器commandExecutor。
public void initCommandExecutor() {
if (thismandExecutor == null) {
CommandInterceptor first = this.initInterceptorChain(thismandInterceptors);
thismandExecutor = new DefaultCommandConfig(), first);
}
}
this.initInterceptorChain(thismandInterceptors)是将集合⾥的初始化⽣成⼀条链,先循环获取List集合⾥的对象(i),然后通过setNext()⽅法在该对象(i)⾥设置下⼀个引⽤,这样,就可实现责任链⾥所谓每个接收者都包含对另⼀个接收者的引⽤的功能。
public CommandInterceptor initInterceptorChain(List<CommandInterceptor> chain) {
if (chain != null && !chain.isEmpty()) {
for(int i = 0; i < chain.size() - 1; ++i) {
(((i)).setNext(((i + 1));
}
return ((0);
} else {
throw new ActivitiException("invalid command interceptor chain configuration: " + chain);
}
}
那么,这条链当中,都有哪些呢?
直接debug到这⾥,可以看到,总共有4个对象,按照顺序排,包括
LogInterceptor,CommandContextInterceptor,TransactionContextInterceptor,CommandInvoker(在命令模式⾥,该类相当Invoker⾓⾊)。这四个对象在责任链模式当中充当了具体处理者(Concrete Handler)⾓⾊。
责任链模式⾥剩余客户类(Client)⾓⾊应该是命令执⾏器thismandExecutor。
因此,⼯作流引擎当中的责任链模式结构图如下:
组成⼀条链如下图所⽰——
springboot和过滤器
⽣成链后,会返回⼀个((0),即LogInterceptor,为什么只返回第⼀个呢,这是⼀个很巧妙的地⽅,因为该⾥已经⼀层⼀层地嵌套进其他了,因此,只需要返回第⼀个,赋值给first即可。
接下来,就会创建命令执⾏器——
thismandExecutor = new DefaultCommandConfig(), first);
这个命令执⾏器是整个引擎的底层灵魂,通过它,可以实现责任链模式与命令模式——
链初始化介绍完成后,接下来开始介绍链在引擎⾥的应⽤⽅式。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。