0%

尽管至今为止,仍然处于孵化器阶段(Incubation Phase),但是e4代表了Eclipse的未来。e4提供的新特性包括:
基于EMF的应用模型(Application Model);依赖注入;基于CSS定义外观

Read more »

功能测试的目的首先是为了保证软件功能的正确性,其次是为了保证软件的质量。Spring提供了专门的测试模块用于简化单元测试和集成测试。

Read more »

功能测试的目的首先是为了保证软件功能的正确性,其次是为了保证软件的质量。Spring提供了专门的测试模块用于简化单元测试和集成测试。

Read more »

前面,用JSR330
中规定的annotation定义了对象之间的依赖关系和注入机制,
但是仍然使用了一个xml配置,用于初始化ApplicationContext。

该例子中使用GenericXmlApplicationContext创建应用上下文。实际上,Spring提供了很多种应用上下文:

ApplicationContext

使用其中的AnnotationConfigApplicationContext,可以不依赖xml配置文件,而是用java代码的方式初始化应用上下文。

应用配置类中要记录与xml配置文件中相同的要素。

前面的例子中,xml主要定义了以下内容:

1
2
3
4
<!--启用annotation注册-->
<context:annotation-config/>
<!--扫描指定的包中用annotation定义的bean-->
<context:component-scan base-package="org.example"/>

使用Java类可以实现通用的功能:

1
2
3
4
5
6
7
@Configuration
public class AppConfig {
@Bean
public String message() {
return "You are running JSR330!";
}
}

其中,

  • @configuration表明这个类包含Bean的定义
  • @Bean标记创建bean的函数。其中函数名相当于beanID

此时,可以不依赖xml文件使用bean,前提是使用AnnotationConfigApplicationContext创建应用上下文:

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);

ctx.scan("demo");

MessageRenderer renderer = ctx.getBean("messageRenderer",
MessageRenderer.class);
renderer.render();
ctx.close();
}

同样,在Spring Web应用中也可以使用AnnotationConfigWebApplicationContext来代替XmlWebApplicationContext

关于spring基于Java代码配置容器的更多内容,可以参考官方文档

Java World似乎总会出现一些接口规范,这样做的好处是可以面向接口编程,可以在实现了该接口的产品/组件之间自由切换,避免被厂商绑架。 本文要介绍的JSR330:Dependency Injection for Java,Java依赖注入规范。

Read more »

交易策略在其生命周期中要经历过多次检验。这些检验通常需要经过统计分析。
最基本的检验是不考虑交易成本、指令类型、突发事件、回波效应等外部因素的影响,只考虑操作信号自身的统计分析指标。

Read more »

Drools Fusion既是规则引擎,又可以作为CEP。除了事件定义时间推理之外,对于引擎本身也会有一些不同的使用。主要体现在会话时钟、流模式、滑动窗口和对事件的内存管理。

会话时钟

由于事件的时间性,处理事件时需要一个参考时钟。
这个参考时钟在会话配置(KnowledgeSessionConfiguration)中指定,所以称为会话时钟(Session Clock)。

有很多种场景需要对时钟进行控制,比如:

  • 规则测试

    测试总是需要一个可控的环境,并且当测试包含了带有时间约束的 规则时,不仅需要控制输入规则和事实,而且也需要时间流。

  • 定期(regular)执行

    通常,在运行生产规则时,应用程序需要一个实时时 钟,允许引擎对时间的行进立即作出反应。

  • 特殊环境

    特殊环境可以对时间的控制有特殊的要求。群集环境可能需要在心 跳中的时钟同步,或 JEE 环境可能需要使用一个应用服务器提供的时钟,等 等。

  • 规则重演或模拟

    要重演场景或模拟场景也需要应用程序控制时间流。

Drools中默认使用基于系统时钟的实时时钟(realtime),也可以使用能被应用程序控制的伪时钟(pseudo)。设置伪时钟的方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
KnowledgeSessionConfiguration conf = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
conf.setOption( ClockTypeOption.get( "pseudo" ) );

StatefulKnowledgeSession session =kbase.newStatefulKnowledgeSession( conf, null );

SessionPseudoClock clock = session.getSessionClock();

// then, while inserting facts, advance the clock as necessary:
FactHandle handle1 = session.insert( tick1 );
clock.advanceTime( 10, TimeUnit.SECONDS );
FactHandle handle2 = session.insert( tick2 );
clock.advanceTime( 30, TimeUnit.SECONDS );
FactHandle handle3 = session.insert( tick3 );

流模式

Drools默认运行在云(Cloud)模式下。云模式下没有时间流的概念,引擎知道所有的事实(Fact)和事件(Event)。此时引擎将所有的事实/事件看做是一个无序的云。

由于云模式下引擎没有“现在”的概念,尽管事件具有时间戳、期限等元数据,这些数据也仅仅作为事件的属性,
不代表事件发生的顺序,也不能进行

如果需要处理实时/准实时事件(Event),需要时间推理,Drools必须工作在流(Stream)模式下。
此时要求每个流中的事件必须按照时间顺序插入。

启用流模式

Drools默认运行在云模式下,可以通过以下方式启用流模式:

1
2
3
KnowledgeBaseConfiguration config =
KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( EventProcessingOption.STREAM );

也可以使用属性文件定义:drools.eventProcessingMode = stream

入口点

Drools定义了工作空间的多个入口点(WorkingMemoryEntryPoint),每个入口点可以看做是一个事件流,可以将事件通过不同的入口点插入到工作空间中。

来自同一个入口点的事件通过时间戳被排序。每个流既可以包含单一类型的事件,也可以包含多种类型的事件。

  • 声明入口点

    入口点不需要显式声明,在规则中引用的入口点都会在规则编译期间被自动识别和创建。比如:

1
2
3
4
5
6
7
rule "authorize withdraw"
when
WithdrawRequest($ai : accountId,$am : amount ) from entry-point "ATM Stream"
CheckingAccount( accountId ==$ai, balance >$am )
then
// authorize withdraw
end

规则编译器会识别”ATM Stream”入口点,并在规则库中创建该入口点。

  • 使用入口点

    举例如下:

1
2
3
4
5
6
7
// create your rulebase and your session as usual
StatefulKnowledgeSession session = ...
// get a reference to the entry point
WorkingMemoryEntryPoint atmStream =
session.getWorkingMemoryEntryPoint( "ATM Stream" );
// and start inserting your facts into the entry point
atmStream.insert( aWithdrawRequest );

除了这种手工插入事实的方式之外,Drools还提供了一系列的管道API和适配器,可以将其他流(如JMS、IO流、Socket等)之间接入到入口点上。

滑动窗口

在流模式中,规则的LHS部分
可以使用滑动窗口限定只关注一定范围内的事件。这个范围可以是时间或事件的个数,分别成为滑动时间窗口和滑动长度窗口。

比如:

1
2
3
4
5
6
7
8
9
10
11
StockTick() over window:time( 2m )

Number( doubleValue >$max ) from accumulate(
SensorReading($temp : temperature ) over window:time( 10m ), average($temp )
)

StockTick( company == "IBM" ) over window:length( 10 )

Number( doubleValue >$max ) from accumulate(
SensorReading($temp : temperature ) over window:length( 100 ), average($temp )
)

内存管理

在流模式下,引擎自动执行事件的内存管理。对于不可能再被匹配的事件自动释放。

引擎会关注事件的@expires中指定的到期时间,并分析规则中隐含的到期时间,进行自动释放。

CEP处理复杂事件。宽泛的事件,是指在应用程序域中的状态的一个有意义改变的一条记录。
而复杂事件处理关注事件之间的相关性,以及原子事件组合成的复杂(复合)事件。

Read more »

时间推理(Temporal)是CEP中特有的条件判断(LHS)。本文介绍13种时间推理运算符及其DRL表示。

CEP中的事件(Event)具有两个与时间相关的属性。一个是timestamp,标记事件发生的时间;另一个是duration,标记事件持续的时间间隔。

由这两个时间属性,还可以计算出事件结束的事件。

时间推理(Temporal)是CEP中特有的条件判断(LHS),其判断的要素正是基于事件的上述时间属性。

Allen在《An Interval-based Representation of Temporal Knowledge》中描述了13种时间推理的运算符。

下面用DRL语言介绍这13种运算符。其中,运算符的参数格式均为[#d][#h][#m][#s][#[ms]]。比如3m30s4m等。

After 和 Before(之前和之后)

1
2
3
4
5
 // x∈[a,b]时,满足以下条件
//A发生在B之前
$eventA : EventA( this before[a,b]$eventB )
//B发生在A之后
$eventB : EventB( this after[a,b]$eventA )
  • 如果没有给出参数,则a=1ms, b=+∞
  • 如果只给出一个参数a,则b=+∞

Coincides(同时发生)

1
2
3
 // x∈[0,a],且y∈[0,b]时,满足以下条件
$eventA : EventA( this coincides[a,b]$eventB )
$eventB : EventB( this coincides[a,b]$eventA )
  • 如果只给出一个参数a,则b=a
  • 如果不给出参数,则a=0,b=0

During 和 Includes(包含)

1
2
3
4
5
 // x∈[a,b],且y∈[c,d]时,满足以下条件
//A在B期间发生
$eventA : EventA( this during[a,b,c,d]$eventB )
//B包含A
$eventB : EventB( this includes[a,b,c,d]$eventA )
  • 如果只给出二个参数a,b,则c=a,d=b
  • 如果只给出一个参数b,则a=0,c=0,d=b
  • 如果不给出参数,则a=0,b=+∞, c=0,d=+∞

Finishes 和 Finished by(同时结束)

1
2
3
4
5
 // x∈[0,a]时,满足以下条件
//A在B之后开始,和B同时结束
$eventA : EventA( this finishes[a]$eventB )
//B在A之前开始,和B同时结束
$eventB : EventB( this finishedby[a]$eventA )
  • 如果不给出参数,则a=0

Meets 和 Met by(相邻)

1
2
3
4
5
 // x∈[0,a]时,满足以下条件
//A结束时B开始
$eventA : EventA( this meets[a]$eventB )
//A结束时B开始
$eventB : EventB( this metby[a]$eventA )
  • 如果没有给出参数,则a=0

Overlaps 和 Overlappd by(相交)

1
2
3
4
5
 // x∈[a,b]时,满足以下条件
//A在B之前开始,在B之后结束
$eventA : EventA( this overlaps[a,b]$eventB )
//B在A之后开始,在A之前结束
$eventB : EventB( this overlappedby[a,b]$eventA )
  • 如果只给出一个参数b,则a=0
  • 如果不给出参数,则a=0,b=0

Starts 和 Started by(同时开始)

1
2
3
4
5
 // x∈[0,a]时,满足以下条件
//A和B同时开始,A先结束
$eventA : EventA( this starts[a]$eventB )
//B和A同时开始,B后结束
$eventB : EventB( this startedby[a]$eventA )
  • 如果不给出参数,则a=+∞