当前位置: 首页 > news >正文

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.propertiesjdbc.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()中的方法,所以这里可以自定义实现的功能即可。


相关文章:

  • Webview组件和HTML的介绍
  • [一句秒懂]高仿QQ底部小红点弹簧效果
  • 安全关闭多Activity的Application
  • Android自定义控件之日历控件
  • path去除多余“/”和添加“/”正则
  • JS魔法堂:doctype我们应该了解的基础知识
  • CSS3魔法堂:禁止用户改变textarea大小
  • 音效
  • 在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法...
  • ssl证书的对称密钥与非对称密钥
  • Linux LVM硬盘管理及LVM扩容
  • synchronized 补遗
  • 软考信息系统监理师,2016年4月22日作业
  • 使用VMware虚拟机,分别部署2台centos7主机实现,httpd(php模块)+mysql,
  • .NET(C#) Internals: as a developer, .net framework in my eyes
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • CentOS7简单部署NFS
  • es6--symbol
  • ES6系列(二)变量的解构赋值
  • java8-模拟hadoop
  • Otto开发初探——微服务依赖管理新利器
  • SQL 难点解决:记录的引用
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • TypeScript迭代器
  • 百度小程序遇到的问题
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 多线程 start 和 run 方法到底有什么区别?
  • 翻译--Thinking in React
  • 回流、重绘及其优化
  • 解决jsp引用其他项目时出现的 cannot be resolved to a type错误
  • 近期前端发展计划
  • 目录与文件属性:编写ls
  • 漂亮刷新控件-iOS
  • 软件开发学习的5大技巧,你知道吗?
  • 深度学习在携程攻略社区的应用
  • 数据可视化之 Sankey 桑基图的实现
  • 微服务核心架构梳理
  • 一道面试题引发的“血案”
  • Spring第一个helloWorld
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • (cljs/run-at (JSVM. :browser) 搭建刚好可用的开发环境!)
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (一)80c52学习之旅-起始篇
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • .NET 反射的使用
  • .NET 使用 ILMerge 合并多个程序集,避免引入额外的依赖
  • .net经典笔试题
  • @modelattribute注解用postman测试怎么传参_接口测试之问题挖掘
  • @Query中countQuery的介绍
  • @Validated和@Valid校验参数区别
  • [ web基础篇 ] Burp Suite 爆破 Basic 认证密码
  • [ 攻防演练演示篇 ] 利用通达OA 文件上传漏洞上传webshell获取主机权限
  • [Angularjs]asp.net mvc+angularjs+web api单页应用
  • [BUUCTF 2018]Online Tool(特详解)