作为
spring beans
的工作流组件
<o:p></o:p>
Spring
的
ApplicationContext
是从接口
BeanFactory
继承的,它被用来作为在
spring
容器内实际的控制实体和容器。用来负责对一组作为
spring beans
的一组
bean
的初始化,配置和生命期管理。我们通过装配在一个基于
XML
的配置文件中的
spring beans
来配置
ApplicationContext
。这个配置文件说明了
spring beans
互相协作的本质特点。这样,用
spring
的术语来说,与其他
spring beans
交互的
spring beans
就被叫着协作者(
collaborators
)。缺省情况下,
spring beans
是作为单例存在于
ApplicationContext
中的,但是,单例的属性能够被设置为
false
,从而有效地改变他们在
spring
中调用原型模式时的行为。如下面的配置文件所示:
<o:p></o:p>
<
bean
id
=
"defaultErrorHandler"
<o:p></o:p>
class
=
"com.gsta.eshore.framework.jcf.JCFErrorHandler"
/>
<o:p></o:p>
<
bean
id
=
"simpleProcessor"
class
=
"com.gsta.eshore.framework.jcf.SequenceProcessor"
>
<o:p></o:p>
<
property
name
=
"activities"
>
<o:p></o:p>
<
list
>
<o:p></o:p>
<
ref
bean
=
"command1"
/>
<o:p></o:p>
<
ref
bean
=
"command2"
/>
<o:p></o:p>
<
ref
bean
=
"command3"
/>
<o:p></o:p>
</
list
>
<o:p></o:p>
</
property
>
<o:p></o:p>
<
property
name
=
"defaultErrorHandler"
>
<o:p></o:p>
<
ref
bean
=
"defaultErrorHandler"
></
ref
>
<o:p></o:p>
</
property
>
<o:p></o:p>
</
bean
>
<o:p></o:p>
|
<o:p> </o:p>
将工作流组件实施成
spring beans
有以下两种作用:
<o:p></o:p>
一是容易进行单元测试和很大程度上可重用能力。
IoC
容器的特点明显地提供了有效的单元测试。使用像
spring
这样的
Ioc
容器,在测试期间,协作者之间的依赖能够容易的用假的替代者替代。
<o:p></o:p>
二是可重用能力是通过像
XSL
转换这样的工作流活动实现的。一个被抽象成工作流活动的
XSL
转换现在能够被任何处理
XSL
转换的工作流所重用。
<o:p></o:p>
Spring
控制了一些操作者以一种工作流的方式交互。关键接口如下:
<o:p></o:p>
Command
:
封装了工作流中一个单步业务逻辑;
<o:p></o:p>
Request
:在工作流活动之间传递具参数的对象。实现了这个接口的对象负责维护对象在工作流转换中从一个活动转换到另一个活动的状态;
<o:p></o:p>
Response
:封装了执行
Command
后返回的结果;
<o:p></o:p>
ErrorHandler
:提供错误处理的回调方法;
<o:p></o:p>
BaseProcessor
:描述一个作为主工作流线程的执行者的
bean
。
<o:p></o:p>
<o:p> </o:p>
SequenceProcessor
类是一个对顺序模式建模的具体子类。有
3
个
Command
被连接到工作流处理器,工作流处理器将顺序执行这
3
个
Command
。同样更多的
BaseProcessor
接口的实现也是可以想象得到的。可以开发其他工作流处理过程子类来控制不同的工作流类型,例如,另一种像并行切割模式那样有着变化的执行路径的工作流。对于简单工作流来说,因为活动的顺序是预先决定了的,所以
SequenceProcessor
是好的选择。
<o:p></o:p>
对于使用基于
spring
的简单工作流的实现来说,排他选择模式是另一个好的选择。例如
RunByResultProcessor
类,根据
Command
执行的结果来决定下一个将要执行的
Command,
例如在执行完
Command1
之后可以决定执行哪一个
Command
。
<o:p></o:p>
下面看看
SequenceProcessor
做了些什么,由于
RunByResultProcessor
与之类似,在此省略介绍。
<o:p></o:p>
public
void
doActivities(Request request,Response resp)
throws
Exception {
<o:p></o:p>
if
(
logger
.isDebugEnabled())
<o:p></o:p>
logger
.debug(getBeanName() +
" SequenceProcessor is running.."
);
<o:p></o:p>
Map response = resp.getValues();
<o:p></o:p>
Map params = request.getValues();
<o:p></o:p>
List activities = getActivities();
<o:p></o:p>
for
(Iterator it = activities.iterator(); it.hasNext();) {
<o:p></o:p>
Component component = (Component) it.next();
<o:p></o:p>
if
(
logger
.isDebugEnabled())
<o:p></o:p>
logger
.debug(
"
正在运行中的活动是
: "
+ component.getBeanName());
<o:p></o:p>
try
{
<o:p></o:p>
component.execute(params, response);
<o:p></o:p>
}
catch
(Throwable th) {
<o:p></o:p>
ErrorHandler errorHandler = component.getErrorHandler();
<o:p></o:p>
if
(errorHandler ==
null
) {
<o:p></o:p>
logger
.info(
"no Errorhandler for Command "
+component.getBeanName() +
", run default error handler and abort Command "
);
<o:p></o:p>
ErrorHandler processorerrorHandler=getDefaultErrorHandler();
<o:p></o:p>
if
(processorerrorHandler ==
null
){
<o:p></o:p>
logger
.info(
"no error handler for this processor, run JCFErrorHandler "
+
"handler and abort processing "
);
<o:p></o:p>
//
执行全局的
default ErrorHandler;
<o:p></o:p>
((ErrorHandler)ContextServiceLocator.getInstance().getBean(
"defaultErrorHandler"
)).handleError(resp, th);
<o:p></o:p>
}
else
{
<o:p></o:p>
//
执行
processor
级的
ErrorHandler;
<o:p></o:p>
processorerrorHandler.handleError(resp, th);
<o:p></o:p>
}
<o:p></o:p>
<o:p></o:p>
}
else
{
<o:p></o:p>
logger
.info(
"run Command Errorhandler and continue"
);
<o:p></o:p>
//
执行
Component
级的
ErrorHandler;
<o:p></o:p>
errorHandler.handleError(resp, th);
<o:p></o:p>
}
<o:p></o:p>
}
<o:p></o:p>
}
<o:p></o:p>
logger
.debug(getBeanName() +
" SequenceProcessor is done."
);
<o:p></o:p>
}
<o:p></o:p>
|
SequenceProcessor
关键代码
<o:p></o:p>
<o:p> </o:p>
由上面的代码可见,
SequenceProcessor
按照顺序执行