Activiti7.0进阶学习(四):Activiti的命令拦截器

背景

  1. 《疯狂工作流讲义》:“Activiti提供了命令拦截器功能,外界对Activiti流程中各个实例进行的操作,实际可以看作对数据进行的相应操作,在此过程中,Activiti使用了设计模式中的命令模式,每一个操作数据库的过程,均可被看着一个命令,然后交由命令执行者去完成。除此之外,为了能让使用者可以对这些命令进行相应的拦截(进行个性化处理),Activiti还使用了设计模式中的责任链模式,从而使用者可以添加相应的拦截器(责任链模式中的处理者)”。

  2. 理解了命令模式和责任莲模式,其实就可以大致理解Activiti是怎么工作的。

  3. 命令模式和责任链模式,在很多框架代码中是经常被使用的。在实际开发过程中,也是可以运用命令模式的。

过程

命令模式的实现过程

命令接口

public interface Command {

    void execute(CommandReceiver receiver);
}

命令接收者

public interface CommandReceiver {

    void doSomethingA();

    void doSomethingB();
}

命令接收者的实现

public class CommandReceiverImpl implements CommandReceiver{

    @Override
    public void doSomethingA() {
        System.out.println("命令执行者方法A");
    }

    @Override
    public void doSomethingB() {
        System.out.println("命令执行者方法B");
    }
}

命令执行器

public class CommandExecutor {

    public void execute(Command command) {
        command.execute(new CommandReceiverImpl());
    }
}

命令接口的实现者A

public class CommandA implements Command {
    
    @Override
    public void execute(CommandReceiver receiver) {
        receiver.doSomethingA();
    }
}

命令接口的实现者B

public class CommandB implements Command {

    @Override
    public void execute(CommandReceiver receiver) {
        receiver.doSomethingB();
    }
}

测试代码

  public static void main(String[] args) {
        // 创建命令执行者
        CommandExecutor commandExecutor = new CommandExecutor();
        // 创建命令A,交由命令执行者执行
        Command commandA = new CommandA();
        commandExecutor.execute(commandA);

        // 创建命令B,交由命令执行者执行
        Command commandB = new CommandB();
        commandExecutor.execute(commandB);

    }

理解:通过使用中间层命令接收者,解耦命令和命令执行者。命令执行者只关心命令。而命令的具体执行细节交给命令的接收人。

使用过程理解:需要自定义具体的命令,并选择命令对应的具体方法。而具体方法过程就交给命令接收人的具体实现即可。

此命令在Activiti中扮演的角色: 在Activiti中,每一个数据库的CRUD操作,均为一个命令的实现,然后交给Activiti的命令执行者执行。Activiti使用了一个CommandContext类作为命令接收者,该对象维护一些列的Manager对象,这些Manager对象就像J2EE中的DAO对象。

责任链模式的实现过程

概述:该设计模式让多个对象都有机会处理请求,从而避免了请求发送者和请求接收者之间的耦合。因为,一般理解就是一个请求发送者对应一个请求接收者。如果把请求接收者组成一条链,并沿着这条链传递请求,直到有一个对象处理这个请求为止,这就形成了一条责任链。

处理器接口

public abstract class Handler {
    protected Handler next;

    public void setNext(Handler handler) {
        this.next = handler;
    }

    // 处理请求的方法,交由子类实现
    public abstract void execute(Request request);

}

处理器接口实现A

public class HandlerA extends Handler {

    @Override
    public void execute(Request request) {
        // 处理自己的事,然后交由下一任处理者继续执行请求
        System.out.println("请求处理者A处理请求");
        next.execute(request);
    }
}

处理器接口实现B

public class HandlerB extends Handler {

    @Override
    public void execute(Request request) {
        // 处理自己的事,然后交由下一任处理者继续执行请求
        System.out.println("请求处理者B处理请求");
        next.execute(request);
    }
}

真实任务处理者(并且也宣告链结束了)

public class ActualHandler extends Handler {

    @Override
    public void execute(Request request) {
        // 直接执行请求
        request.doSomething();
    }

}

请求(这里的请求其实也可以换成Command,命令接口,这样两个模式就耦合上了)

public class Request {

    public void doSomething() {
        System.out.println("执行请求");
    }

}

测试

public class Test {

    public static void main(String[] args) {
        // 创建第一个请求处理者集合
        List<Handler> handlers = new ArrayList<Handler>();
        // 添加请求处理者到集合中
        handlers.add(new HandlerA());
        handlers.add(new HandlerB());
        // 将最终的处理者添加到集合中
        handlers.add(new ActualHandler());

        // 处理集合中的请求处理者,按集合的顺序为它们设置下一任请求处理者,并返回第一任处理人
        Handler first = setNext(handlers);
        first.execute(new Request());
    }

    static Handler setNext(List<Handler> handlers) {
        for (int i = 0; i < handlers.size() - 1; i++) {
            Handler handler = handlers.get(i);
            Handler next = handlers.get(i + 1);
            handler.setNext(next);
        }
        return handlers.get(0);
    }

}

理解:运行顺序,请求处理者A处理请求 -> 请求处理者B处理请求 -> 执行请求。根据业务逻辑,每个handler都处理自己的逻辑,然后层层往后传递即可。这个在Netty中有使用,它是双向链表,显示向后传递,这里的显示是指代码主动调用一个往后传递的方法。

编写自定义拦截器的实现过程(activiti)

Activiti的拦截器就是结合这两种设计模式来达到拦截效果的。每次Activiti进行业务操作,都会将其封装为一个Command放到责任链中执行。

定义拦截器A

public class MyCommandInterceptorA extends AbstractCommandInterceptor {

    @Override
        public <T> T execute(CommandConfig config, Command<T> command) {
        System.out.println("拦截器A执行" + command.getClass().getName());
        return this.getNext().execute(config,command);
    }
}

定义拦截器B

public class MyCommandInterceptorB extends AbstractCommandInterceptor {

    @Override
        public <T> T execute(CommandConfig config, Command<T> command) {
        System.out.println("拦截器B执行" + command.getClass().getName());
        return this.getNext().execute(config,command);

    }
}

定义拦截器C

public class MyCommandInterceptorC extends AbstractCommandInterceptor {

    @Override
        public <T> T execute(CommandConfig config, Command<T> command) {
            System.out.println("拦截器C执行" + command.getClass().getName());
            return this.getNext().execute(config,command);
        }
}

在activiti.cfg.xml中配置进去

<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource"/>
        <property name="databaseSchemaUpdate" value="true"/>
        <property name="customPreCommandInterceptors">
            <list>
                <bean class="com.sanding.activiti.interceptor.MyCommandInterceptorC"></bean>
                <bean class="com.sanding.activiti.interceptor.MyCommandInterceptorB"></bean>
                <bean class="com.sanding.activiti.interceptor.MyCommandInterceptorA"></bean>
            </list>
        </property>
    </bean>

拦截器添加的顺序就是执行的顺序。

执行结果

拦截器C执行org.activiti.engine.impl.cmd.GetProcessDefinitionInfoCmd
拦截器B执行org.activiti.engine.impl.cmd.GetProcessDefinitionInfoCmd
拦截器A执行org.activiti.engine.impl.cmd.GetProcessDefinitionInfoCmd

问题记录:按照疯狂工作流讲义的代码,是没有把拦截器添加进去的。原因还没有找到。但是按照上面代码的实现是可以把拦截器添加到activiti中的。

小结

  1. 设计原则多用组合少用继承。而命令模式其实运用的是概念其实是依赖。
  2. 记录命令模式的写作过程和理解。
  3. 记录责任链模式的写作过程和理解。
  4. 学会编写activiti的自定义拦截器。理解这个拦截器底层的工作过程。

你可能感兴趣的:(Activiti)