activiti 动态配置 activiti 监听引擎启动和初始化(高级源码篇)

1.1.1. 前言

用户故事:现在有这样一个需求,第一个需求:公司的开发环境,测试环境以及线上环境,我们使用的数据库是不一样的,我们必须能够任意的切换数据库进行测试和发布,对数据库连接字符串我们需要加密,保证我们的数据库连接不能被发现。必须确保我们的数据库不能暴露出去,第二个需求,我们需要监控activiti 工作流引擎,在流程启动的之前,我们要保证我们的所有属性都注入进去,如果有些属性没有注入进去,我们是不能让流程启动起来的。也就是进行必要饿属性检测,如果没有期望的属性,直接报错,在流程实例化之后,输出log日志,确保我们的属性都是正确的。并且监控引擎中所有的值

 

第一个需求如何解决呢?

我们来看一下常规的数据库配置,程序的配置如下:

 <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">

      <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti"/>

        <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>

        <property name="jdbcUsername" value="root"/>

  <property name="jdbcPassword" value="123"/>

 </bean>

看到上面的配置,是不是似曾相识的感觉,没错就是这么简单,但是如何确保能任意的切换呢,仔细想想还是很简单的,那里变化隔离那里嘛,这个时候我们可以把这些这些变化的东西隔离出去,放到jdbc.properties中,新建jdbc.properties把变化的内容设置进去到jdbc.properties,jdbc.properties内容如下:

jdbcUrl=jdbc:mysql://localhost:3306/activiti

jdbcDriver=com.mysql.jdbc.Driver

jdbcUsername=root

jdbcPassword=123

上面把变化的东西隔离出来,那程序怎么能够使用jdbc.properties中的配置信息呢?这是一个很关键的问题,我们之前用的activiti版本是5.12,所以当时的设计就是修改源码,主要修改org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl类,在init()方法中我们设计一个钩子函数,然后子类负责实现上面的这些功能,主要就修改的类是org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl,修改ProcessEngineConfigurationImpl类中的数据库连接的信息,由于目前最新的版本activiti 5.19版本,这个版本已经支持了这种实现,具体的实现都差不多,只是我们不用修改源码,直接扩展了,这不就是软件设计中的开闭原则。对新增开放对修改关闭。

下面看下activiti 5.19是如何可以实现这种功能需求的。

1.1.2. activiti 源码

首先看一下org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl类中的init()方法哪个可以实现这种需求,了解底层内核实现才能很方便的扩展嘛。

ProcessEngineConfigurationImpl中的init()部分方法如下:

//初始化configurators集合

initConfigurators();

//调用configurator.beforeInit方法

configuratorsBeforeInit();

...

//调用configurator.configure()方法

configuratorsAfterInit();

上面的三个核心方法实现如下所示:

内部ServiceLoader可以参考java.util.ServiceLoader使用http://blog.csdn.net/qq_30739519/article/details/51164954这篇文章

 

protected List<ProcessEngineConfigurator> configurators;
protected List<ProcessEngineConfigurator> allConfigurators;
 protected boolean enableConfiguratorServiceLoader = true; // Enabled by default. In certain environments this should be set to false (eg osgi)
  protected void initConfigurators() {
  //初始化数组集合
  allConfigurators = new ArrayList<ProcessEngineConfigurator>();
  
  // Configurators that are explicitely added to the config
//如果集合存在值就循环添加进去
    if (configurators != null) {
      for (ProcessEngineConfigurator configurator : configurators) {
        allConfigurators.add(configurator);
      }
    }
    
    // Auto discovery through ServiceLoader 默认是true
    if (enableConfiguratorServiceLoader) {
    ClassLoader classLoader = getClassLoader();
    if (classLoader == null) {
    classLoader = ReflectUtil.getClassLoader();
    }
    //循环添加进去
    ServiceLoader<ProcessEngineConfigurator> configuratorServiceLoader
    = ServiceLoader.load(ProcessEngineConfigurator.class, classLoader);
    int nrOfServiceLoadedConfigurators = 0;
    for (ProcessEngineConfigurator configurator : configuratorServiceLoader) {
    allConfigurators.add(configurator);
    nrOfServiceLoadedConfigurators++;
    }
    
    if (nrOfServiceLoadedConfigurators > 0) {
    log.info("Found {} auto-discoverable Process Engine Configurator{}", nrOfServiceLoadedConfigurators++, nrOfServiceLoadedConfigurators > 1 ? "s" : "");
    }
    //如果集合不为空 存在多个值的话就按照升序排列 根据什么作为排序规则呢,很显然根据getPriority中的值进行排序 比如a类getPriority 10 b类getPriority 100 那么排序后就是 a,b现执行a类对的再执行b类的。
    if (!allConfigurators.isEmpty()) {
    
    // Order them according to the priorities (usefule for dependent configurator)
    Collections.sort(allConfigurators, new Comparator<ProcessEngineConfigurator>() {
    @Override
    public int compare(ProcessEngineConfigurator configurator1, ProcessEngineConfigurator configurator2) {
    int priority1 = configurator1.getPriority();
    int priority2 = configurator2.getPriority();
    
    if (priority1 < priority2) {
    return -1;
    } else if (priority1 > priority2) {
    return 1;
    } 
    return 0;
    }
});
    
    // Execute the configurators
    log.info("Found {} Process Engine Configurators in total:", allConfigurators.size());
    for (ProcessEngineConfigurator configurator : allConfigurators) {
    log.info("{} (priority:{})", configurator.getClass(), configurator.getPriority());
    }
    
    }
    
    }
  }
  //循环所有allConfigurators 执行beforeInit方法
  protected void configuratorsBeforeInit() {
  for (ProcessEngineConfigurator configurator : allConfigurators) {
  log.info("Executing beforeInit() of {} (priority:{})", configurator.getClass(), configurator.getPriority());
  configurator.beforeInit(this);
  }
  }
  //循环所有allConfigurators 执行configuratorsAfterInit方法
  protected void configuratorsAfterInit() {
  for (ProcessEngineConfigurator configurator : allConfigurators) {
  log.info("Executing configure() of {} (priority:{})", configurator.getClass(), configurator.getPriority());
  configurator.configure(this);
  }
  }

 

 

 

 

 

1.1.3. activiti 动态配置实战

好了上面说了源码的实现,下面来点干货吧,看看如何使用自定义的类实现修改配置文件。

我们使用两个类看他们的执行过程是否跟上面源码解析的一直:

定义com.daling.ch1.init.MyProcessEngineConfigurator1如下所示:

 

@Service
public class MyProcessEngineConfigurator1 extends  AbstractProcessEngineConfigurator{
public static int DEFAULT_CONFIGURATOR_PRIORITY = 100;
public void beforeInit(
ProcessEngineConfigurationImpl processEngineConfiguration) {
System.out.println("1111111111111");
}
 
public void configure(
ProcessEngineConfigurationImpl processEngineConfiguration) {
}
@Override
public int getPriority() {
return DEFAULT_CONFIGURATOR_PRIORITY;
}
 
}
定义com.daling.ch1.init.MyProcessEngineConfigurator2如下所示:
 
@Service
public class MyProcessEngineConfigurator2 extends  AbstractProcessEngineConfigurator{
public static int DEFAULT_CONFIGURATOR_PRIORITY = 200;
public void beforeInit(
ProcessEngineConfigurationImpl processEngineConfiguration) {
System.out.println("2222222222222222");
}
 
public void configure(
ProcessEngineConfigurationImpl processEngineConfiguration) {
}
@Override
public int getPriority() {
return DEFAULT_CONFIGURATOR_PRIORITY;
}
 
}

 

 

 

 

 

在spring中开启 包的扫描代码: <context:component-scan base-package="com"/> 

activiti 引擎配置如下所示:

 <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">

        <property name="jdbcUrl" value="jdbc:mysql://localhost3306/activiti"></property>

        <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>

        <property name="jdbcUsername" value="root"/>

        <property name="jdbcPassword" value="a"/>

    

    <property name="configurators">

    <list>

   <bean class="com.daling.ch1.init.MyProcessEngineConfigurator2"></bean>

     <bean class="com.daling.ch1.init.MyProcessEngineConfigurator1"></bean>

    </list>

    </property>

<property name="activityFontName" value="宋体"></property>

   </bean>

测试代码如下:

ProcessEnginesDemodemo =new ProcessEnginesDemo();

RepositoryServicerepositoryService2 =demo.getRepositoryService();

先来运行一下程序看输出是否正确,部分输出如下所示:

1111111111111

20:20:18.245 [main] INFO  o.a.e.i.c.ProcessEngineConfigurationImpl - Executing beforeInit() of class com.daling.ch1.init.MyProcessEngineConfigurator2 (priority:200)

2222222222222222

确实说明了程序的执行顺序就是按照getPriority()方法值升序执行的。

ProcessEngineConfigurator类的定义如下:

 

public interface ProcessEngineConfigurator {
/**
 * Called <b>before</b> any initialisation has been done.
 * This can for example be useful to change configuration settings
 * before anything that uses those properties is created.
 *
 * Allows to tweak the process engine by passing the {@link ProcessEngineConfigurationImpl}
   * which allows tweaking it programmatically.
 *
 * An example is the jdbc url. When a {@link ProcessEngineConfigurator} instance
 * wants to change it, it needs to do it in this method, or otherwise
 * the datasource would already have been created with the 'old' value
 * for the jdbc url.
 */
void beforeInit(ProcessEngineConfigurationImpl processEngineConfiguration);
  
  /**
   * Called when the engine boots up, before it is usable, but after
   * the initialisation of internal objects is done.
   *  
   * Allows to tweak the process engine by passing the {@link ProcessEngineConfigurationImpl}
   * which allows tweaking it programmatically.
   *
   * An example is the ldap user/group manager, which is an addition to the engine.
   * No default properties need to be overridden for this (otherwise the {@link #beforeInit(ProcessEngineConfigurationImpl)} 
   * method should be used) so the logic contained in this method is executed
   * after initialisation of the default objects.
   *
   * Probably a better name would be 'afterInit' (cfr {@link #beforeInit(ProcessEngineConfigurationImpl)}),
   * but not possible due to backwards compatibility.
   */
  void configure(ProcessEngineConfigurationImpl processEngineConfiguration);
  
  /**
   * When the {@link ProcessEngineConfigurator} instances are used, they are first
   * ordered by this priority number (lowest to highest).
   * If you have dependencies between {@link ProcessEngineConfigurator}
   * instances, use the priorities accordingly to order them as needed.
   */
  int getPriority();
 
}

 

 

 

 

 

ProcessEngineConfigurator类图关系如下:

 

 

上面的类图AbstractProcessEngineConfigurator类实现了ProcessEngineConfigurator接口,AbstractProcessEngineConfigurator是一个抽象类,所以我们使用的时候继承AbstractProcessEngineConfigurator类复写里面的方法即可(模板方法)。

上面我们自定义的类MyProcessEngineConfigurator1中的方法

public void beforeInit(

ProcessEngineConfigurationImplprocessEngineConfiguration) {

System.out.println("1111111111111");

}

 

public void configure(

ProcessEngineConfigurationImplprocessEngineConfiguration) {

 

}

我们可以拿到ProcessEngineConfigurationImpl这个对象其实就是StandaloneProcessEngineConfiguration的父类,里面有很多的属性我们就可以修改了。

怎么修改呢?只要拿到这个对象我们就很方便修改了。

具体的修改如下:

//伪代码 加载jdbc.properties文件 获取配置的值,进行解密然后设置进去 解密算法后续讲解,当然懂的话可以自己直接修改。

descJdbc(ProperUtils.load());

processEngineConfiguration.setJdbcDriver(jdbcDriver);

processEngineConfiguration.setJdbcPassword(jdbcPassword);

processEngineConfiguration.setJdbcUrl(jdbcUrl);

processEngineConfiguration.setJdbcUsername(jdbcUsername)

 

上面提到的引擎初始化完毕会调用configure()中的方法,所以这里可以自定义实现的功能即可。

 

  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
### 回答1: 在 Activiti 中,结束节点是流程图中的一种特殊节点,它表示流程的终止。如果想要在结束节点添加执行监听器,可以使用以下方法: 1. 在结束节点的 XML 配置文件中添加执行监听配置: ``` <endEvent id="endevent1" name="End"> <extensionElements> <activiti:executionListener event="end" class="com.sample.MyExecutionListener"/> </extensionElements> </endEvent> ``` 2. 在 Java 代码中编写执行监听器类,实现 ActivitiExecutionListener 接口,并覆盖 notifiy 方法,在该方法中编写监听器的具体逻辑。 如果在添加执行监听器后流程没有任何启动信息,可能是因为流程图的配置有误,导致流程无法正常启动。建议检查流程图的配置,确保所有节点和连线都配置正确,并检查是否有遗漏的配置。 ### 回答2: 在Activiti工作流引擎中,可以通过为结束节点添加执行监听器来实现在流程结束时执行一些特定操作。然而,在添加执行监听器后,可能会观察到流程没有启动信息的情况。 首先,我们需要理解结束节点的含义。结束节点是一个流程实例完成的地点,当流程实例到达结束节点时,即表示流程正常结束。因此,完成流程的信息已经被记录下来,不再需要显示启动的相关信息。 其次,监听器的作用是在特定的事件发生时执行一段代码逻辑。如果在结束节点添加了执行监听器,监听器的代码逻辑将在流程实例完成时执行。因此,在结束节点执行监听器之前,流程的启动信息已经被记录下来,执行监听器后不再需要显示启动的相关信息。 最后,需要注意的是,添加执行监听器并不会影响流程的正常执行,只是在流程结束时执行一些额外的操作。如果确实需要在流程启动时显示相关信息,可以在开始节点上添加执行监听器,在监听器的代码逻辑中记录启动相关信息。 总结起来,当在Activiti的结束节点添加执行监听器后,流程没有任何启动信息是正常现象,因为完成流程的信息已经被记录下来,不再需要显示启动的相关信息。如果需要显示启动信息,可以在开始节点添加执行监听器来实现。 ### 回答3: 在Activiti中,流程的结束节点是指流程的最后一个节点,一旦流程到达结束节点,表示该流程已经完成。通常情况下,结束节点不需要添加执行监听器,因为流程已经结束,不再需要执行任何操作。 然而,如果在结束节点上添加了执行监听器,那么在流程到达结束节点时将会执行监听器中定义的逻辑。根据您的描述,当您在结束节点添加了执行监听器后,流程没有任何启动信息。有以下几种可能的原因: 1. 监听器逻辑未正确配置:请检查您在结束节点上添加的执行监听器是否正确配置监听器的类和方法。确保方法中的逻辑是否正确执行了。 2. 监听器逻辑存在异常:如果监听器中的逻辑存在异常,可能会导致流程在执行监听器时出错,从而无法获得启动信息。请检查监听器中的逻辑是否正确,并尝试捕获并处理异常。 3. 流程配置错误:除了监听器的问题外,还要确保流程的其他配置没有问题。请检查整个流程的配置,确保正确配置了所有的节点和流转条件。 综上所述,如果您在结束节点上添加了执行监听器,但流程没有任何启动信息,可能是由于监听配置错误或者流程配置错误所导致的。检查并修复这些问题将有助于解决该问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值