溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何建立工作流引擎中責(zé)任鏈模式

發(fā)布時(shí)間:2021-10-14 14:55:42 來(lái)源:億速云 閱讀:166 作者:iii 欄目:編程語(yǔ)言

本篇內(nèi)容介紹了“如何建立工作流引擎中責(zé)任鏈模式”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

一、簡(jiǎn)單理解責(zé)任鏈模式概念

網(wǎng)上關(guān)于責(zé)任鏈模式的介紹很多,菜鳥(niǎo)教程上是這樣說(shuō)的:責(zé)任鏈模式(Chain of Responsibility Pattern)為請(qǐng)求創(chuàng)建了一個(gè)接收者對(duì)象的鏈。在這種模式中,通常每個(gè)接收者都包含對(duì)另一個(gè)接收者的引用。如果一個(gè)對(duì)象不能處理該請(qǐng)求,那么它會(huì)把相同的請(qǐng)求傳給下一個(gè)接收者,依此類推。

這個(gè)概念術(shù)語(yǔ)比較抽象。

我曾經(jīng)在 深入理解Spring Security授權(quán)機(jī)制原理  一文中提到Spring Security在授權(quán)過(guò)程中有使用到過(guò)濾器的概念,過(guò)濾器鏈就像一條鐵鏈,中間的每個(gè)過(guò)濾器都包含對(duì)另一個(gè)過(guò)濾器的引用,從而把相關(guān)的過(guò)濾器鏈接起來(lái),像一條鏈的樣子。這時(shí)請(qǐng)求線程就如螞蟻一樣,會(huì)沿著這條鏈一直爬過(guò)去-----即,通過(guò)各過(guò)濾器調(diào)用另一個(gè)過(guò)濾器引用方法chain.doFilter(request, response),實(shí)現(xiàn)一層嵌套一層地將請(qǐng)求傳遞下去,當(dāng)該請(qǐng)求傳遞到能被處理的的過(guò)濾器時(shí),就會(huì)被處理,處理完成后轉(zhuǎn)發(fā)返回。通過(guò)過(guò)濾器鏈,可實(shí)現(xiàn)在不同的過(guò)濾器當(dāng)中對(duì)請(qǐng)求request做處理,且過(guò)濾器之間彼此互不干擾。

整個(gè)流程大致如下:

如何建立工作流引擎中責(zé)任鏈模式

這個(gè)過(guò)濾器鏈的概念,其實(shí)就是責(zé)任鏈設(shè)計(jì)模式在Spring Security中的體現(xiàn)。

摘錄一段網(wǎng)上關(guān)于職責(zé)鏈模式介紹,其主要包含以下角色:

  1. 抽象處理者(Handler)角色:定義一個(gè)處理請(qǐng)求的接口,包含抽象處理方法和一個(gè)后繼連接。

  2. 具體處理者(Concrete Handler)角色:實(shí)現(xiàn)抽象處理者的處理方法,判斷能否處理本次請(qǐng)求,如果可以處理請(qǐng)求則處理,否則將該請(qǐng)求轉(zhuǎn)給它的后繼者。

  3. 客戶類(Client)角色:創(chuàng)建處理鏈,并向鏈頭的具體處理者對(duì)象提交請(qǐng)求,它不關(guān)心處理細(xì)節(jié)和請(qǐng)求的傳遞過(guò)程。


 

二、Activiti工作流里責(zé)任鏈模式的創(chuàng)建

最近在研究Activiti工作流框架,發(fā)現(xiàn)其所有實(shí)現(xiàn)都是采用命令模式實(shí)現(xiàn),而命令模式當(dāng)中的Invoker角色又是采用攔截器鏈?zhǔn)侥J剑搭愃粕厦嫣岬降倪^(guò)濾器鏈,即設(shè)計(jì)模式里的責(zé)任鏈模式。

這里的Activiti工作流版本是6.0。

CommandInterceptor是一個(gè)攔截器接口,包含三個(gè)方法:

  • setNext()方法是在初始化時(shí),設(shè)置每個(gè)攔截器對(duì)象中包含了下一個(gè)攔截器對(duì)象,最后形成一條攔截器鏈;

  • getNext()可在每個(gè)攔截器對(duì)象中調(diào)用下一個(gè)攔截器對(duì)象;

  • execute()是每個(gè)攔截器對(duì)請(qǐng)求的處理。若在上一個(gè)攔截器鏈?zhǔn)嚼锊荒芴幚碓撜?qǐng)求話,就會(huì)通過(guò)next.execute(CommandConfig var1, Command

    var2)將請(qǐng)求傳遞到下一個(gè)攔截器做處理,類似上面過(guò)濾器里調(diào)用下一個(gè)過(guò)濾器的chain.doFilter(request, response)方法,將請(qǐng)求進(jìn)行傳遞;
public interface CommandInterceptor {
    <T> T execute(CommandConfig var1, Command<T> var2);

    CommandInterceptor getNext();

    void setNext(CommandInterceptor var1);
}

抽象類AbstractCommandInterceptor實(shí)現(xiàn)了CommandInterceptor攔截器接口,在責(zé)任鏈模式當(dāng)中充當(dāng)抽象處理者(Handler)角色。該類最主要的屬性是 protected CommandInterceptor next,在同一包下,直接通過(guò)next即可調(diào)用下一個(gè)攔截器對(duì)象。

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;
    }
}

接下來(lái),將會(huì)分析攔截器鏈?zhǔn)侨绾纬跏蓟c工作的。

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");
          //避免發(fā)布的圖片和xml中文出現(xiàn)亂碼
          pro.setActivityFontName("宋體");
          pro.setLabelFontName("宋體");
          pro.setAnnotationFontName("宋體");
          //數(shù)據(jù)庫(kù)更更新策略
          pro.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
          return pro.buildProcessEngine();
      }
  }

這時(shí),啟動(dòng)項(xiàng)目后,pro.buildProcessEngine()這行代碼會(huì)初始化Activiti框架,進(jìn)入里面,會(huì)發(fā)現(xiàn)它有三種實(shí)現(xiàn),默認(rèn)是第二種,即ProcessEngineConfigurationImpl。

如何建立工作流引擎中責(zé)任鏈模式

點(diǎn)進(jìn)去,Activiti框架具體構(gòu)建buildProcessEngine方法如下,其中 this.init()的作用是環(huán)境初始化,包括配置設(shè)置、JDBC連接、bean裝載等的:

public ProcessEngine buildProcessEngine() {
    this.init();
    ProcessEngineImpl processEngine = new ProcessEngineImpl(this);
    if (this.isActiviti5CompatibilityEnabled && this.activiti5CompatibilityHandler != null) {
        Context.setProcessEngineConfiguration(processEngine.getProcessEngineConfiguration());
        this.activiti5CompatibilityHandler.getRawProcessEngine();
    }

    this.postProcessEngineInitialisation();
    return processEngine;
}

在this.init()方法里,涉及到責(zé)任鏈模式初始化的方法是this.initCommandExecutors(),里面詳情如下:

public void initCommandExecutors() {
    this.initDefaultCommandConfig();
    this.initSchemaCommandConfig();
    //初始化命令調(diào)用器
    this.initCommandInvoker();
    //List存放進(jìn)涉及到的攔截器
    this.initCommandInterceptors();
    //初始化命令執(zhí)行器
    this.initCommandExecutor();
}

這里只需要關(guān)注最后三個(gè)方法——

  1. this.initCommandInvoker()

    initCommandInvoker()初始化構(gòu)建了一個(gè)CommandInvoker攔截器,它繼承上邊提到的攔截器抽象類AbstractCommandInterceptor。這個(gè)攔截器在整條過(guò)濾器鏈中是最重要和關(guān)鍵,它排在了整條鏈的最后,其實(shí),它才是最終執(zhí)行請(qǐng)求的,前邊幾個(gè)攔截器都是傳遞請(qǐng)求而已。

    public void initCommandInvoker() {
        if (this.commandInvoker == null) {
            if (this.enableVerboseExecutionTreeLogging) {
                this.commandInvoker = new DebugCommandInvoker();
            } else {
                //初始化執(zhí)行該行代碼
                this.commandInvoker = new CommandInvoker();
            }
        }
    }


    這里 new CommandInvoker()一個(gè)對(duì)象,然后將地址復(fù)制給this.commandInvoker對(duì)象引用,注意,該引用將會(huì)用在接下來(lái)的initCommandInterceptors()方法里——

  2. this.initCommandInterceptors();

    initCommandInterceptors方法主要作用是創(chuàng)建一個(gè)List集合,然后將需要用到的攔截器都保存到該List集合里——

    public void initCommandInterceptors() {
        if (this.commandInterceptors == null) {
            this.commandInterceptors = new ArrayList();
            if (this.customPreCommandInterceptors != null) {
                //用戶自定義前置攔截器
                this.commandInterceptors.addAll(this.customPreCommandInterceptors);
            }
            //框架自帶默認(rèn)的攔截器
            this.commandInterceptors.addAll(this.getDefaultCommandInterceptors());
            if (this.customPostCommandInterceptors != null) {
                this.commandInterceptors.addAll(this.customPostCommandInterceptors);
            }
            //命令調(diào)用器,在攔截器鏈最后一個(gè)
            this.commandInterceptors.add(this.commandInvoker);
        }
    }


    this.getDefaultCommandInterceptors()的代碼如下:

    public Collection<? extends CommandInterceptor> getDefaultCommandInterceptors() {
        List<CommandInterceptor> interceptors = new ArrayList();
        //日志攔截器
        interceptors.add(new LogInterceptor());
        CommandInterceptor transactionInterceptor = this.createTransactionInterceptor();
        if (transactionInterceptor != null) {
            interceptors.add(transactionInterceptor);
        }
    	//
        if (this.commandContextFactory != null) {
            interceptors.add(new CommandContextInterceptor(this.commandContextFactory, this));
        }
        //事務(wù)攔截器
        if (this.transactionContextFactory != null) {
            interceptors.add(new TransactionContextInterceptor(this.transactionContextFactory));
        }
    
        return interceptors;
    }


    可見(jiàn),方法里的 this.commandInterceptors 就是一個(gè)專門(mén)儲(chǔ)存攔截器對(duì)象的List集合——

    protected List<CommandInterceptor> commandInterceptors;


    這里只需要重點(diǎn)關(guān)注this.commandInterceptors.add(this.commandInvoker)這行代碼,就是將上邊創(chuàng)建的CommandInvoker攔截器對(duì)象存儲(chǔ)到List里,它是放在initCommandInterceptors()方法最后,某種程度也就意味著,這個(gè)攔截器在整條鏈當(dāng)中處在最后面的位置。

    執(zhí)行完該this.initCommandInterceptors()方法后,就可獲取到所有的攔截器對(duì)象,到這一步時(shí),各攔截器還是互相獨(dú)立的,仍無(wú)法通過(guò)next()來(lái)進(jìn)行調(diào)用傳遞,那么,究竟是如何將它們串起來(lái)形成一條鏈呢?

    接下來(lái)的this.initCommandExecutor()方法,就是實(shí)現(xiàn)將各攔截器串起來(lái)形成一條長(zhǎng)鏈。

  3. this.initCommandExecutor();

該方法有兩個(gè)作用,一個(gè)是生成Interceptor攔截器鏈,一個(gè)是創(chuàng)建命令執(zhí)行器commandExecutor。

public void initCommandExecutor() {
    if (this.commandExecutor == null) {
        CommandInterceptor first = this.initInterceptorChain(this.commandInterceptors);
        this.commandExecutor = new CommandExecutorImpl(this.getDefaultCommandConfig(), first);
    }
}

this.initInterceptorChain(this.commandInterceptors)是將集合里的攔截器初始化生成一條攔截器鏈,先循環(huán)獲取List集合里的攔截器對(duì)象chain.get(i),然后通過(guò)setNext()方法在該攔截器對(duì)象chain.get(i)里設(shè)置下一個(gè)攔截器引用,這樣,就可實(shí)現(xiàn)責(zé)任鏈里所謂每個(gè)接收者都包含對(duì)另一個(gè)接收者的引用的功能。

public CommandInterceptor initInterceptorChain(List<CommandInterceptor> chain) {
    if (chain != null && !chain.isEmpty()) {
        for(int i = 0; i < chain.size() - 1; ++i) {
            ((CommandInterceptor)chain.get(i)).setNext((CommandInterceptor)chain.get(i + 1));
        }
        return (CommandInterceptor)chain.get(0);
    } else {
        throw new ActivitiException("invalid command interceptor chain configuration: " + chain);
    }
}

那么,這條攔截器鏈當(dāng)中,都有哪些攔截器呢?

直接debug到這里,可以看到,總共有4個(gè)攔截器對(duì)象,按照順序排,包括LogInterceptor,CommandContextInterceptor,TransactionContextInterceptor,CommandInvoker(在命令模式里,該類相當(dāng)Invoker角色)。這四個(gè)攔截器對(duì)象在責(zé)任鏈模式當(dāng)中充當(dāng)了具體處理者(Concrete Handler)角色。

如何建立工作流引擎中責(zé)任鏈模式

責(zé)任鏈模式里剩余客戶類(Client)角色應(yīng)該是命令執(zhí)行器this.commandExecutor。

因此,工作流引擎當(dāng)中的責(zé)任鏈模式結(jié)構(gòu)圖如下:

如何建立工作流引擎中責(zé)任鏈模式

組成一條攔截器鏈如下圖所示——

如何建立工作流引擎中責(zé)任鏈模式

生成攔截器鏈后,會(huì)返回一個(gè)(CommandInterceptor)chain.get(0),即攔截器LogInterceptor,為什么只返回第一個(gè)攔截器呢,這是一個(gè)很巧妙的地方,因?yàn)樵摂r截器里已經(jīng)一層一層地嵌套進(jìn)其他攔截器了,因此,只需要返回第一個(gè)攔截器,賦值給first即可。

接下來(lái),就會(huì)創(chuàng)建命令執(zhí)行器——

this.commandExecutor = new CommandExecutorImpl(this.getDefaultCommandConfig(), first);

這個(gè)命令執(zhí)行器是整個(gè)引擎的底層靈魂,通過(guò)它,可以實(shí)現(xiàn)責(zé)任鏈模式與命令模式——

攔截器鏈初始化介紹完成后,接下來(lái)開(kāi)始介紹攔截器鏈在引擎里的應(yīng)用方式。


 

三、Activiti工作流里責(zé)任鏈模式的應(yīng)用

Activiti引擎的各操作方法其底層基本都是以命令模式來(lái)實(shí)現(xiàn)的,即調(diào)用上面創(chuàng)建的命令執(zhí)行器this.commandExecutor的execute方法來(lái)實(shí)現(xiàn)的,例如自動(dòng)生成28張數(shù)據(jù)庫(kù)表的方法,就是通過(guò)命令模式去做具體實(shí)現(xiàn)的——

this.commandExecutor.execute(processEngineConfiguration.getSchemaCommandConfig(), new SchemaOperationsProcessEngineBuild());

進(jìn)入到commandExecutor方法里,會(huì)發(fā)現(xiàn)前邊new CommandExecutorImpl(this.getDefaultCommandConfig(), first)建立命令執(zhí)行器時(shí),已將配置對(duì)象和嵌套其他攔截器的LogInterceptor攔截器對(duì)象,通過(guò)構(gòu)造器CommandExecutorImpl(CommandConfig defaultConfig, CommandInterceptor first)生成對(duì)象時(shí),傳參賦值給了相應(yīng)的對(duì)象屬性,其中first引用指向LogInterceptor,即攔截器鏈上的第一個(gè)攔截器——

public class CommandExecutorImpl implements CommandExecutor {
    protected CommandConfig defaultConfig;
    protected CommandInterceptor first;

    public CommandExecutorImpl(CommandConfig defaultConfig, CommandInterceptor first) {
        this.defaultConfig = defaultConfig;
        this.first = first;
    }

    public CommandInterceptor getFirst() {
        return this.first;
    }

    public void setFirst(CommandInterceptor commandInterceptor) {
        this.first = commandInterceptor;
    }

    public CommandConfig getDefaultConfig() {
        return this.defaultConfig;
    }

    public <T> T execute(Command<T> command) {
        return this.execute(this.defaultConfig, command);
    }

    public <T> T execute(CommandConfig config, Command<T> command) {
        return this.first.execute(config, command);
    }
}

當(dāng)引擎執(zhí)行this.commandExecutor.execute(xxx,xxx))類似方法時(shí),其實(shí)是執(zhí)行了this.first.execute(config, command)方法,這里的this.first在構(gòu)建命令執(zhí)行器時(shí)是通過(guò)LogInterceptor傳進(jìn)來(lái)的,因此,執(zhí)行代碼其實(shí)是調(diào)用了LogInterceptor內(nèi)部的execute()方法,也就是說(shuō),開(kāi)始攔截器鏈上的第一個(gè)LogInterceptor攔截器傳遞方法execute()請(qǐng)求——

如何建立工作流引擎中責(zé)任鏈模式

進(jìn)入到攔截器鏈上的第一個(gè)攔截器LogInterceptor。

根據(jù)其內(nèi)部代碼可以看出,這是一個(gè)跟日志有關(guān)的攔截器,內(nèi)部并沒(méi)有多少增強(qiáng)功能,只是做了一個(gè)判斷是否需要debug日志打印。若需要,則進(jìn)行debug打印,若不需要,直接進(jìn)入到 if (!log.isDebugEnabled()) 為true的作用域內(nèi)部,進(jìn)而執(zhí)行this.next.execute(config, command)用以將請(qǐng)求傳遞給下一個(gè)攔截器做處理。

public class LogInterceptor extends AbstractCommandInterceptor {
    private static Logger log = LoggerFactory.getLogger(LogInterceptor.class);
    public LogInterceptor() {
    }
    public <T> T execute(CommandConfig config, Command<T> command) {
        if (!log.isDebugEnabled()) {
            return this.next.execute(config, command);
        } else {
            log.debug("\n");
            log.debug("--- starting {} --------------------------------------------------------", command.getClass().getSimpleName());
            Object var3;
            try {
                var3 = this.next.execute(config, command);
            } finally {
                log.debug("--- {} finished --------------------------------------------------------", command.getClass().getSimpleName());
                log.debug("\n");
            }

            return var3;
        }
    }
}

這里有一個(gè)小地方值得稍微打斷說(shuō)下,就這個(gè) if (!log.isDebugEnabled())判斷。眾生周知,若集成第三方日志插件如logback之類,若其配置里去除debug的打印,即時(shí)代碼里 存在log.debug("xxxxx")也不會(huì)打印到控制臺(tái),那么,這里增加一個(gè)判斷 if (!log.isDebugEnabled())是否多次一舉呢?

事實(shí)上,這里并非多此一舉,增加這個(gè)判斷,是可以提升代碼執(zhí)行效率的。因?yàn)閘og.debug("xxxxx")里的字符串拼接早于log.debug("xxxxx")方法執(zhí)行的,也就是說(shuō),即使該log.debug("xxxxx")不會(huì)打印,但其內(nèi)部的字符串仍然會(huì)進(jìn)行拼接,而拼接,是需要時(shí)間的,雖然很細(xì)微,但同樣屬于影響性能范疇內(nèi)的。因此,增加一個(gè)if判斷,若無(wú)需要打印debug日志時(shí),那么就無(wú)需讓其內(nèi)部的字符串進(jìn)行自動(dòng)拼接。

這是一個(gè)很小的知識(shí)點(diǎn),但面試過(guò)程中其實(shí)是有可能會(huì)遇到這類與日志相關(guān)的面試題的。

接下來(lái),讓我們繼續(xù)回到攔截器鏈的傳遞上來(lái)。

LogInterceptor攔截器調(diào)用this.next.execute(config, command),意味著將請(qǐng)求傳遞到下一個(gè)攔截器上進(jìn)行處理,根據(jù)前邊分析,可知下一個(gè)攔截器是CommandContextInterceptor,根據(jù)代碼大概可知,這個(gè)攔截器內(nèi)主要是獲取上下文配置對(duì)象和信息相關(guān)的,這些都是在工作流引擎初始化時(shí)生成的,它們被保存在Stack棧里,具體都保存了哪些信息暫不展開(kāi)分析——

public class CommandContextInterceptor extends AbstractCommandInterceptor {
    ......
public <T> T execute(CommandConfig config, Command<T> command) {
    CommandContext context = Context.getCommandContext();
    boolean contextReused = false;
    if (config.isContextReusePossible() && context != null && context.getException() == null) {
        contextReused = true;
        context.setReused(true);
    } else {
        context = this.commandContextFactory.createCommandContext(command);
    }

    try {
        Context.setCommandContext(context);
        Context.setProcessEngineConfiguration(this.processEngineConfiguration);
        if (this.processEngineConfiguration.getActiviti5CompatibilityHandler() != null) {
            Context.setActiviti5CompatibilityHandler(this.processEngineConfiguration.getActiviti5CompatibilityHandler());
        }
        //繼續(xù)將命令請(qǐng)求傳遞到下一個(gè)攔截器
        Object var5 = this.next.execute(config, command);
        return var5;
    } catch (Exception var31) {
        context.exception(var31);
    } finally {
     ......
    }

    return null;
}
}

CommandContextInterceptor攔截器沒(méi)有對(duì)命令請(qǐng)求做處理,它繼續(xù)將請(qǐng)求傳遞到下一個(gè)攔截器TransactionContextInterceptor,根據(jù)名字就大概可以猜到,這個(gè)攔截器主要是增加與事務(wù)有關(guān)的功能——

public <T> T execute(CommandConfig config, Command<T> command) {
    CommandContext commandContext = Context.getCommandContext();
    boolean isReused = commandContext.isReused();
    Object var9;
    try {
        if (this.transactionContextFactory != null && !isReused) {
            TransactionContext transactionContext = this.transactionContextFactory.openTransactionContext(commandContext);
            Context.setTransactionContext(transactionContext);
            commandContext.addCloseListener(new TransactionCommandContextCloseListener(transactionContext));
        }
        var9 = this.next.execute(config, command);
    } finally {
    ......
    }
    return var9;
}

TransactionContextInterceptor攔截器同樣沒(méi)有對(duì)命令請(qǐng)求做處理,而是繼續(xù)傳遞到下一個(gè)攔截器,也就是最后一個(gè)攔截器CommandInvoker,根據(jù)名字可以大概得知,這是一個(gè)與命令請(qǐng)求有關(guān)的攔截器,傳遞過(guò)來(lái)的請(qǐng)求將會(huì)在這個(gè)攔截器里處理——

public class CommandInvoker extends AbstractCommandInterceptor {
    ......
    public <T> T execute(CommandConfig config, final Command<T> command) {
        final CommandContext commandContext = Context.getCommandContext();
        commandContext.getAgenda().planOperation(new Runnable() {
            public void run() {
                commandContext.setResult(command.execute(commandContext));
            }
        });
        this.executeOperations(commandContext);
        if (commandContext.hasInvolvedExecutions()) {
            Context.getAgenda().planExecuteInactiveBehaviorsOperation();
            this.executeOperations(commandContext);
        }
        return commandContext.getResult();
    }
}

進(jìn)入到其內(nèi)部,可以發(fā)現(xiàn),這里沒(méi)有再繼續(xù)調(diào)用this.next.execute(config, command)這樣的請(qǐng)求進(jìn)行傳遞,而是直接執(zhí)行command.execute(commandContext),然后將返回值進(jìn)行返回,其中,command是請(qǐng)求參數(shù)當(dāng)中的第二個(gè)參數(shù),讓我們回過(guò)頭看下該請(qǐng)求案例最開(kāi)始的調(diào)用——

this.commandExecutor.execute(processEngineConfiguration.getSchemaCommandConfig(), new SchemaOperationsProcessEngineBuild());

這里的第二個(gè)參數(shù)是new SchemaOperationsProcessEngineBuild(),不妨進(jìn)入到SchemaOperationsProcessEngineBuild類中,是吧,其內(nèi)部同樣有一個(gè)execute方法——

public final class SchemaOperationsProcessEngineBuild implements Command<Object> {
    public SchemaOperationsProcessEngineBuild() {
    }

    public Object execute(CommandContext commandContext) {
        DbSqlSession dbSqlSession = commandContext.getDbSqlSession();
        if (dbSqlSession != null) {
            dbSqlSession.performSchemaOperationsProcessEngineBuild();
        }

        return null;
    }
}

可見(jiàn),CommandInvoker攔截器內(nèi)部執(zhí)行command.execute(commandContext),就相當(dāng)于執(zhí)行了new SchemaOperationsProcessEngineBuild().execute(commandContext),也就是——

 public Object execute(CommandContext commandContext) {
        DbSqlSession dbSqlSession = commandContext.getDbSqlSession();
        if (dbSqlSession != null) {
            dbSqlSession.performSchemaOperationsProcessEngineBuild();
        }
        return null;
    }

這是一種命令模式的實(shí)現(xiàn)。

“如何建立工作流引擎中責(zé)任鏈模式”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI