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"/>
"/>
</bean>
看到上面的配置,是不是似曾相识的感觉,没错就是这么简单,但是如何确保能任意的切换呢,仔细想想还是很简单的,那里变化隔离那里嘛,这个时候我们可以把这些这些变化的东西隔离出去,放到jdbc.properties中,新建jdbc.properties把变化的内容设置进去到jdbc.properties,jdbc.properties内容如下:
jdbcUrl=jdbc:mysql://localhost:3306/activiti
jdbcDriver=com.mysql.jdbc.Driver
jdbcUsername=root
jdbcPassword=
上面把变化的东西隔离出来,那程序怎么能够使用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()中的方法,所以这里可以自定义实现的功能即可。
activiti 动态配置 activiti 监听引擎启动和初始化(高级源码篇)的更多相关文章
- 深入浅出Mybatis系列(三)---配置详解之properties与environments(mybatis源码篇)
上篇文章<深入浅出Mybatis系列(二)---配置简介(mybatis源码篇)>我们通过对mybatis源码的简单分析,可看出,在mybatis配置文件中,在configuration根 ...
- 深入浅出Mybatis系列三-配置详解之properties与environments(mybatis源码篇)
注:本文转载自南轲梦 注:博主 Chloneda:个人博客 | 博客园 | Github | Gitee | 知乎 上篇文章<深入浅出Mybatis系列(二)---配置简介(mybatis源码篇 ...
- Activiti 流程部署方式 activi 动态部署(高级源码篇)
Activiti的流程 部署方式有很多种方式,我们可以根据activit工作流引擎提供的ap方式进行部署. 当然了实际需求决定你要使用哪一种api操作,后面的总结详细介绍了使用场景. 下面看一下部署方 ...
- 深入浅出Mybatis系列(四)---配置详解之typeAliases别名(mybatis源码篇)
上篇文章<深入浅出Mybatis系列(三)---配置详解之properties与environments(mybatis源码篇)> 介绍了properties与environments, ...
- 深入浅出Mybatis系列四-配置详解之typeAliases别名(mybatis源码篇)
注:本文转载自南轲梦 注:博主 Chloneda:个人博客 | 博客园 | Github | Gitee | 知乎 上篇文章<深入浅出Mybatis系列(三)---配置详解之properties ...
- 配置静态监听解决ORA-12514错误的案例(转)
今天做Linux下DG配置的时候,遇到一个现象,tnsname.ora文件配置都正常,tnsping也正常,监听也正常,但是仍然报ORA-12514错误: SQL> set lin 130 ...
- 配置静态监听解决ORA-12514错误的案例
今天做Linux下DG配置的时候,遇到一个现象.tnsname.ora文件配置都正常,tnsping也正常,监听也正常.可是仍然报ORA-12514错误: SQL> set lin 130 pa ...
- Tomcat介绍、安装jdk、安装Tomcat、配置Tomcat监听80端口
1.Tomcat介绍 2.安装jdk下载:wget -c http://download.oracle.com/otn-pub/java/jdk/10.0.1+10/fb4372174a714e6b8 ...
- 配置Tomcat监听80端口、配置Tomcat虚拟主机、Tomcat日志
6月27日任务 16.4 配置Tomcat监听80端口16.5/16.6/16.7 配置Tomcat虚拟主机16.8 Tomcat日志扩展邱李的tomcat文档 https://www.linuser ...
随机推荐
- Spring Boot 之Hello Word
Spring Boot官网:http://projects.spring.io/spring-boot/ 环境准备:maven 3.3.5.jdk8.Idea 1.创建maven项目工程 2.引入st ...
- 从零开始搭建支持http2的web服务
前段时间开始,公司各项业务开始陆续接入http2,关于http2的优点与所适用的场景网上有很多的文档可以查阅,这里我主要是总结分享一下如何从0到1搭建http2服务. 这里先说明一下,要完成http2 ...
- python 虚拟环境的搭建
1.python3.6 2.MySQL 3.安装虚拟环境 1.pip install virtualenv -i https://pypi.douban.com/simple/ 2.pip ins ...
- python爬虫——爬取小说 | 探索白子画和花千骨的爱恨情仇(转载)
转载出处:药少敏 ,感谢原作者清晰的讲解思路! 下述代码是我通过自己互联网搜索和拜读完此篇文章之后写出的具有同样效果的爬虫代码: from bs4 import BeautifulSoup imp ...
- ●POJ poj 2112 Optimal Milking
●题目大意: 给出K个挤奶机器(编号1~K),C头牛(编号K+1~K+C)(机器和牛各在不同的地方)和每台机器最多可M头牛挤奶: 然后以邻接矩阵告诉各点间的直接距离(不同的地方间若直接距离等于0,则表 ...
- poj 1873 凸包+枚举
The Fortified Forest Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 6198 Accepted: 1 ...
- Unique-paths (动态规划)
题目描述 A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below) ...
- C语言程序设计实验第四次作业
(一)改错题 输出三角形的面积和周长,输入三角形的三条边a.b.c,如果能构成一个三角形,输出面积area和周长perimeter(保留2位小数):否则,输出"These sides do ...
- K-means聚类 的 Python 实现
K-means聚类 的 Python 实现 K-means聚类是一个聚类算法用来将 n 个点分成 k 个集群. 算法有3步: 1.初始化– K 个初始质心会被随机生成 2.分配 – K 集群通过关联到 ...
- Zend引擎探索 之 PHP中前置递增不返回左值
首先来讲,一般我们对"左值"的理解就是可以出现在赋值运算符的左侧的标识符,也就是可以被赋值.这样讲也许并不十分确切,在不同的语言中对左值的定义也不尽相同.在这里我们讨论前置递增(和 ...