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的自定義攔截器。理解這個攔截器底層的工作過程。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章