一、命令模式、责任链模式
命令模式与责任链模式
命令模式
阐义:
- 命令模式属于行为型模式,它把一个请求或者操作封装到命令对象中,这些请求或者操作的内容包括接受者信息,然后将该命令对象交由执行者执行,执行者不需要关心命令的接收人或者命令的具体内容, 因为这些信息均被封装到命令对象中。
命令模式中涉及的角色及其作用如下:
- 命令接口【Command】:声明执行操作的接口。
- 接口实现【ConcreteCommand 】: 命令接口实现,需要保存接收者的相应操作 ,并执行相应的操作 。
- 命令执行者【Invoker 】:要求命令执行此次请求 。
- 命令接收人【 Receiver 】: 由命令接口的实现类来维护Receiver实例,并在命令执行时处理相应的任务 。
- 命令接口【Command】:声明执行操作的接口。
UML
时序图
责任链模式
- 阐义:
- 责任链模式属于行为型模式,该设计模式让多个对象都有机会处理请求,从而避免了请求发送者和请求接收者之间的稿合。这些请求接收者将组成一条链,并沿着这条链传递请求,直到有一个对象处理这个请求为止,这就形成了一条责任链 。
- 责任链模式有以下参与者:
- 请求处理者接口【Handler】:定义一个处理请求的接口,可以实现后继链。
- 请求处理者实现【ConcreteHandler】:请求处理接口的实现, 如果它可以处理请求就处理, 否则就将该请求转发给它的后继者 。
- 阐义:
二、Activiti的拦截器
Activiti 的拦截器就是结合这两种设计模式 来达到拦截器效果的。每次 Activiti 进行业务操作,都会将其封装为一个 Command 放到责任 链中执行。
拦截器的配置方式
- customPreCommandInterceptors:配置在默认拦截器之前
- customPostCommandInterceptors:配置在默认拦截器之后
- commandInvoker:配置最后的执行器
Activit的拦截器
三、具体实现
自定义拦截器:DurationCommandInterceptor
javapackage com.laogoubi.interceptor; import org.activiti.engine.impl.interceptor.AbstractCommandInterceptor; import org.activiti.engine.impl.interceptor.Command; import org.activiti.engine.impl.interceptor.CommandConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @ClassName DurationCommandInterceptor * @Description 执行时间 * @Author eastern * @Date 2020/7/1 上午10:26 * @Version 1.0 **/ public class DurationCommandInterceptor extends AbstractCommandInterceptor { private static final Logger logger = LoggerFactory.getLogger(DurationCommandInterceptor.class); @Override public <T> T execute(CommandConfig config, Command<T> command) { // 开始时间,去毫秒数 long start = System.currentTimeMillis(); try { return this.getNext().execute(config, command); } finally { long duration = System.currentTimeMillis() - start; logger.info(" {} 执行时长 {} 毫秒", command.getClass().getSimpleName(), duration); } } }
测试入口代码
javapackage com.laogoubi.config; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; import org.activiti.engine.test.ActivitiRule; import org.activiti.engine.test.Deployment; import org.junit.Rule; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @ClassName ConfigMDCTest * @Description 拦截器测试 * @Author eastern * @Date 2020/6/28 上午11:49 * @Version 1.0 **/ public class ConfigInterceptorTest { private static final Logger logger = LoggerFactory.getLogger(ConfigInterceptorTest.class); @Rule public ActivitiRule activitiRule = new ActivitiRule("activiti_interceptor.cfg.xml"); @Test @Deployment(resources = {"com/laogoubi/my-process.bpmn20.xml"}) public void test() { ProcessInstance processInstance = activitiRule.getRuntimeService().startProcessInstanceByKey("my-process"); Task task = activitiRule.getTaskService().createTaskQuery().singleResult(); activitiRule.getTaskService().complete(task.getId()); } }
配置:activiti_interceptor.cfg.xml
xml<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration"> <!--是否展现执行过程中的日志--> <property name="enableVerboseExecutionTreeLogging" value="true"></property> <!-- <property name="customPreCommandInterceptors">--> <!-- <list>--> <!-- <bean class="com.laogoubi.interceptor.DurationCommandInterceptor"></bean>--> <!-- </list>--> <!-- </property>--> <property name="customPostCommandInterceptors"> <list> <bean class="com.laogoubi.interceptor.DurationCommandInterceptor"></bean> </list> </property> </bean> </beans>
配置:my-process.bpmn20.xml
xml<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test"> <process id="my-process"> <startEvent id="start" /> <sequenceFlow id="flow1" sourceRef="start" targetRef="someTask" /> <userTask id="someTask" name="Activiti is awesome!" /> <sequenceFlow id="flow2" sourceRef="someTask" targetRef="end" /> <endEvent id="end" /> </process> </definitions>