一、简单理解责任链模式概念
网上关于责任链模式的介绍很多,菜鸟教程上是这样说的:责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
这个概念术语比较抽象。
我曾经在 深入理解Spring Security授权机制原理 一文中提到Spring Security在授权过程中有使用到过滤器的概念,过滤器链就像一条铁链,中间的每个过滤器都包含对另一个过滤器的引用,从而把相关的过滤器链接起来,像一条链的样子。这时请求线程就如蚂蚁一样,会沿着这条链一直爬过去-----即,通过各过滤器调用另一个过滤器引用方法chain.doFilter(request, response),实现一层嵌套一层地将请求传递下去,当该请求传递到能被处理的的过滤器时,就会被处理,处理完成后转发返回。通过过滤器链,可实现在不同的过滤器当中对请求request做处理,且过滤器之间彼此互不干扰。
整个流程大致如下:
这个过滤器链的概念,其实就是责任链设计模式在Spring Security中的体现。
摘录一段网上关于职责链模式介绍,其主要包含以下角色:
抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
二、Activiti工作流里责任链模式的创建
最近在研究Activiti工作流框架,发现其所有实现都是采用命令模式实现,而命令模式当中的Invoker角色又是采用拦截器链式模式,即类似上面提到的过滤器链,即设计模式里的责任链模式。
这里的Activiti工作流版本是6.0。
CommandInterceptor是一个拦截器接口,包含三个方法:
setNext()方法是在初始化时,设置每个拦截器对象中包含了下一个拦截器对象,最后形成一条拦截器链;
getNext()可在每个拦截器对象中调用下一个拦截器对象;
execute()是每个拦截器对请求的处理。若在上一个拦截器链式里不能处理该请求话,就会通过next.execute(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() { return this.next; } public void setNext(CommandInterceptor next) { this.next = next; } }接下来,将会分析拦截器链是如何初始化与工作的。
SpringBoot集成Activiti配置如下:
@Configuration public class SpringBootActivitiConfig { @Bean public ProcessEngine processEngine() { ProcessEngineConfiguration pro = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration(); pro.setJdbcDriver("com.mysql.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。