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 ...
随机推荐
- postgresql 定时任务备份及恢复
编写 脚本文件 如bak.sh,内容如下: ls_date=`date "+%Y%m%d%H%M%S"` pg_dump -U postgres -Ft yourdbname &g ...
- ASP.NET MVC4通过UrlRewriter配置伪静态,支持html后缀
参考文章: ASP.NET MVC4通过UrlRewriter配置伪静态 http://blog.csdn.net/just_shunjian/article/details/51132866 .NE ...
- 实验吧_NSCTF web200&FALSE(代码审计)
挺简单的一个代码审计,这里只要倒序解密就行了,这里给一下python版的wp import codecs import base64 strs = 'a1zLbgQsCESEIqRLwuQAyMwLy ...
- 实验吧_貌似有点难(php代码审计)&头有点大
二话不说先贴代码 <?php function GetIP(){ if(!empty($_SERVER["HTTP_CLIENT_IP"])) $cip = $_SERVER ...
- Event 发布与订阅(一)
前言 主要讲的是发布与订阅在Event中的一个简单实现用来加深理解. C #中的事件(Event)的理解: 事件具有以下属性:(From Events) 发行者确定何时引发事件:订户确定对事件作出何种 ...
- [NOI 2014]起床困难综合症
Description 21 世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳.作为一名青春阳光好少年,atm 一直坚持与起床困难综合症作斗争.通过研究相关文献,他找 ...
- [COGS 2877]老m凯的疑惑
Description Margatroid退役之后沉迷文化课 这天,写完数学作业之后的他脑洞大开,决定出一道比NOIP2017 D1T1<小凯的疑惑math>还要好的题 题面是这样的 $ ...
- [SCOI 2016]背单词
Description Lweb 面对如山的英语单词,陷入了深深的沉思,“我怎么样才能快点学完,然后去玩三国杀呢?”.这时候睿智 的凤老师从远处飘来,他送给了 Lweb 一本计划册和一大缸泡椒,他的计 ...
- HTTPS介绍
超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂 ...
- win10下python环境变量设置
我用的是python_2.7.3.msi,从官网下载之后,一路按照默认进行安装. 安装之后配置环境变量的步骤如下: 1,点“我的电脑”,右键选“属性” 2,选择“高级系统设置”--->选“环境变 ...