osworkflow学习记录

因工作需要,学习了下osworkflow。网络上的资料到是有很多。但很多都是大同小异。而《osworkflow开发指南》说实话,并不适合入门。到是看到另一个入门教程,觉得很好。循序渐进,由浅入深。有兴趣的可以去看下。

http://www.blogjava.net/alex/archive/2006/08/15/63715.html

看完这个教程后,突然有种疑问,例子中是一个请假流程的演示,这个流程应该很好理解,很熟悉。做入门的例子讲解很好。

在不同的调用者执行流程中的步骤时,都是重新创建BaseWorkflow对象,和DefaultConfiguration对象的。

如:send方法,和allow方法中都是这样处理的。这样是不是很耗资源呢?每次创建对象,都会涉及到流程的一些配置文件的加载、解析。

看了下源码,了解了一下大致的流程:

在开始流程的时候,创建完BaseWorkflow对象后,会调用initalize方法进行初始化,

这一步,应该是再数据库建立一些基本信息,存储流程的基本信息,如流程名,状态等。同时返回一个流程Id值,

这个值很关键,相当于流程实例的句柄。

在其后的流程执行中基本就是对流程实例对象的doAction()方法的调用了。该方法的参数中有个就是前面说的:流程Id值--workflowId。

通过workflowId到数据库中查询对应的workflowName。这个workflowName也就是workflows.xml中的:

<workflow name="leave" type="resource" location="leave.xml"/>

name属性。这样也就可以确定现在的操作是在哪个流程上进行的。

开始前面的疑问的探讨。在调用BaseWorkflow的initalize和doAction方法时都会调用其父类【AbstractWorkflow】的一个方法getConfiguration(),其他很多地方也调用到该方法。

public Configuration getConfiguration() {
Configuration config = (configuration != null) ? configuration : DefaultConfiguration.INSTANCE;

if (!config.isInitialized()) {
try {
config.load(null);
} catch (FactoryException e) {
log.fatal("Error initialising configuration", e);

//fail fast, better to blow up with an NPE that hide the error
return null;
}
}

return config;
}

由源码可以看到,在不调用BaseWorkflow的setConfiguration方法时,AbstractWorkflow的configuration属性一直是空的。也就会返回DefaultConfiguration.INSTANCE对象。

DefaultConfiguration.INSTANCE是一种单例模式的应用。该类只要加载进内存,就有一个DefaultConfiguration实例对象了,只是这个实例对象是没有初始化的,没有加载,解析流程的相关配置文件的。

向后就有对这个config 对象是初始化的判断。如果没有初始化,就进行初始化----config.load()。

load方法中做了两件事(此处以DefaultConfiguration为例):

1.完成对自身的初始化---加载,解析osworkflow.xml配置文件

2.完成对自身的WorkflowFactory类型的属性factory的配置及factory自身的初始化。

如下源码:

Element root = (Element) doc.getElementsByTagName("osworkflow").item(0);
Element p = XMLUtil.getChildElement(root, "persistence");
Element resolver = XMLUtil.getChildElement(root, "resolver");
Element factoryElement = XMLUtil.getChildElement(root, "factory");

以下源码完成对factory的配置:

try {
clazz = factoryElement.getAttribute("class");

if (clazz == null) {
throw new FactoryException("factory does not specify a class attribute");
}

factory = (WorkflowFactory) ClassLoaderUtil.loadClass(clazz, getClass()).newInstance();

factory 默认的实例类型为URLWorkflowFactory,在此处就被换成osworkflow.xml配置文件中指定的具体类型了---XMLWorkflowFactory。

<factory class="com.opensymphony.workflow.loader.XMLWorkflowFactory">
<property key="resource" value="workflows.xml" />
</factory>

XMLWorkflowFactory,URLWorkflowFactory都是实现了WorkflowFactory接口的具体类。

在第二个任务中:factory的配置及factory自身的初始化。看以下源码:

factory.init(properties); //properties存储有 <property key="resource" value="workflows.xml" />节点信息
factory.initDone();

在factory.initDone()方法中完成对workflows.xml文件的,加载,解析。并存储在自身的缓存中(一个Map对象),

key值就是workflows.xml中的name属性值。

<workflow name="leave" type="resource" location="leave.xml"/>

value值就是对该节点的解析完后生产的一个对象WorkflowConfig

以下为解析workflows.xml的源码

Element root = (Element) doc.getElementsByTagName("workflows").item(0);
workflows = new HashMap();

String basedir = getBaseDir(root);

List list = XMLUtil.getChildElements(root, "workflow");

for (int i = 0; i < list.size(); i++) {
Element e = (Element) list.get(i);
WorkflowConfig config = new WorkflowConfig(basedir, e.getAttribute("type"), e.getAttribute("location"));
workflows.put(e.getAttribute("name"), config);

注:此时还没有完成对具体流程定义文件的加载解析。

前面说到很多地方调用了getConfiguration(),而调用完后,会接着调用Configuration的getWorkflow(workflwoName)方法。

看下这个方法会做些什么。

getWorkflow方法最终是调用的WorkflowFactory中的同名方法。此处也就是XMLWorkflowFactory中的getWorkflow方法

WorkflowConfig c = (WorkflowConfig) workflows.get(name); //@1

if (c == null) {
throw new FactoryException("Unknown workflow name \"" + name + '\"');
}

if (c.descriptor != null) { //@2
if (reload) {
File file = new File(c.url.getFile());

if (file.exists() && (file.lastModified() > c.lastModified)) {
c.lastModified = file.lastModified();
loadWorkflow(c, validate);
}
}
} else {
loadWorkflow(c, validate);
}

c.descriptor.setName(name);

return c.descriptor;

在@1处,先从缓存中取出具体流程定义文件的配置信息。主要就是:类型,名称,路径等。

由前面的分析知道,这个配置信息对象---WorkflowConfig只是存储了流程定义文件的名称,路径等信息,并没有加载,解析具体的流程定义文件。

所以在@2处进行的判断就相当于是判断流程定义文件是否解析了。

如果解析了但需要重新解析,或者根本就没有解析,那就进行解析。

从这也可以看出,新版支持流程文件的热修改。也就是修改了流程定义文件,不需要重启服务器。

整个流程大致就是这样了。

那么前面的疑问也有初步的解释了。

BasicWorkflow 继承 AbstractWorkflow,AbstractWorkflow持有Configuration对象。并拥有getConfiguration方法。而getConfiguration在BasicWorkflow 没有调用

setConfiguration方法时,返回的是一个单例的Configuration对象。

这样多次创建BasicWorkflow 对象的开销,是没有进行多次配置文件的解析的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值