Drools Spring 集成已经根据 Drools 6.0 的变化进行了彻底的改造。以下是一些主要的变化:
在本节中,我们将解释kie
命名空间。
<kie:kmodule>
定义一个 KieBase
和关联的 KieSession
的集合。kmodule
标签有一个强制参数id
。
表 98. 示例
属性 | 描述 | 是否必需 |
---|---|---|
id | 从其他Bean引用时所使用的Bean名称。适用于标准 Spring ID 语义。 | 是 |
*kmodule
*只能包含以下子标签:
kie:kbase
kmodule
*的详细解释,请参考 Drools Expert 文档中kmodule.xml
的文档。表 99. 示例
Attribute | Description | Required |
---|---|---|
name | KieBase 的名称。 | Yes |
packages | 要包含在此kbase 中的资源包的逗号分隔列表。 | No |
includes | 要导入的kbase 名称。来自相应 kbase 的所有资源都包含在此 kbase 中。 | No |
default | Boolean (TRUE/FALSE) 。 是否为默认 kbase ,如果不设置,则默认为 FALSE | No |
scope | prototype 或 singleton 。如果不设置则默认为 singleton 。 | No |
eventProcessingMode | 事件处理模式。有效选项为STREAM 、CLOUD | No |
equalsBehavior | 有效选项为 IDENTITY 、EQUALITY | No |
declarativeAgenda | 有效选项为 enabled 、disabled 、true 、false | No |
kbase
标签只能包含以下子标签kmodule可以包含多个 (1…n) kbase
元素。
e.g. kbase 定义
<kie:kmodule id="sample_module"> <kie:kbase name="kbase1" packages="org.drools.spring.sample"> ... </kie:kbase> </kie:kmodule> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
在定义 KieBase
或 KieSession
时,您可以选择声明该 bean
的范围。例如,要强制 Spring
在每次需要时生成一个新的 bean
实例,您应该将 bean
的 scope
属性声明为 prototype
。类似的,如果希望每次需要时返回相同的 bean
实例,您应该将 scope
属性声明为singleton
。
为了正确初始化 kmodule 对象(kbase/ksession),它是强制类型的 beanorg.kie.spring.KModuleBeanFactoryPostProcessor
或被org.kie.spring.annotations.KModuleAnnotationPostProcessor
定义。
e.g. 73. Regular kie-spring post processorbean definition
<bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
e.g. 74. kie-spring post processorbean definition when annotations are used
<bean id="kiePostProcessor" class="org.kie.spring.annotations.KModuleAnnotationPostProcessor"/>
如果没有 org.kie.spring.KModuleBeanFactoryPostProcessor
或 org.kie.spring.annotations.KModuleAnnotationPostProcessor
bean定义,kie-spring
集成将无法工作。
<kie:ksession>
元素定义了 KieSessions
。相同的标签用于定义有状态(org.kie.api.runtime.KieSession
)和无状态(org.kie.api.runtime.StatelessKieSession
)会话。
表 100. 示例
Attribute | Description | Required |
---|---|---|
name | ksession 的名称。 | Yes |
type | session 是有状态还是无状态。如果此属性为空或缺失,则假定会话为有状态类型。 | No |
default | 这是默认session 吗? | no |
scope | prototype 或 singleton 。默认为singleton 。 | no |
clockType | REALTIME 或 PSEUDO | no |
listeners-ref | 设置事件监听器组的引用 (请参考 ‘Defining a Group of listeners’ 部分)。 | no |
例 75. ksession 定义示例
<kie:kmodule id="sample-kmodule"> <kie:kbase name="drl_kiesample3" packages="drl_kiesample3"> <kie:ksession name="ksession1" type="stateless"/> <kie:ksession name="ksession2"/> </kie:kbase> </kie:kmodule> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
在定义 KieBase
或 KieSession
时,您可以选择声明该 bean
的范围。例如,要强制 Spring
在每次需要时生成一个新的 bean
实例,您应该将 bean
的 scope
属性声明为 prototype
。类似的,如果希望每次需要时返回相同的 bean
实例,您应该将 scope
属性声明为singleton
。
表 101. 示例
Attribute | Description | Required |
---|---|---|
id | 从其他Bean引用时所使用的Bean名称。适用于标准 Spring ID 语义。 | Yes |
groupId | Maven GA 的groupId | Yes |
artifactId | Maven GAV 的artifactId | Yes |
version | Maven GAV 的version | Yes |
例 76.releaseId 定义示例
<kie:releaseId id="beanId" groupId="org.kie.spring" artifactId="named-artifactId" version="1.0.0-SNAPSHOT"/>
从 6.2 版开始,kie-spring
允许从在 classpath
上找到的 kjars
导入 kie
对象。目前支持两种导入 kie
对象的模式。
Attribute | Description | Required |
---|---|---|
releaseId | Bean id的引用。适用于标准 Spring ID 语义。 | No |
enableScanner | 启动扫描器。仅当指定了releaseId 时才使用此属性。 | No |
scannerInterval | 扫描间隔,单位:毫秒。仅当指定了releaseId 时才使用此属性。 | No |
import
标签强制自动扫描 classpath
上的所有 jars
,初始化 Kie Objects(Kbase/KSessions
并导入到spring context
。
Global Import
<kie:import />
在导入标签上使用releaseId-ref
属性将初始化特定的 Kie Objects(Kbase/KSessions)
并将这些对象导入到 spring context
中。
使用 releaseId
导入 Kie
对象
<kie:import releaseId-ref="namedKieSession"/> <kie:releaseId id="namedKieSession" groupId="org.drools" artifactId="named-kiesession" version="7.61.0.Final"/>
可以为使用特定 releaseId
导入的 KieBase
启用 Kie
扫描功能。此功能目前不适用于全局导入。
使用 releaseId
导入 Kie
对象 - 启用扫描器
<kie:import releaseId-ref="namedKieSession" enableScanner="true" scannerInterval="1000"/> <kie:releaseId id="namedKieSession" groupId="org.drools" artifactId="named-kiesession" version="7.61.0.Final"/>
如果定义并启用了扫描器,则会创建一个隐式KieScanner
对象并将其插入到 spring context
中。可以从 spring context
中检索它。
从 Spring Context
中检索 KieScanner
// the implicit name would be releaseId#scanner KieScanner releaseIdScanner = context.getBean("namedKieSession#scanner", KieScanner.class); releaseIdScanner.scanNow();
kie-ci
必须在classpath
上可用,releaseId
导入功能才能工作。
@KContainer
、@KBase
和 @KSession
都支持可选的name
属性。Spring
在注入时通常会“get”,所有注入都会收到同一组注解的相同实例。尽管该名称的所有实例都是相同的,'name'
注释为每个实例强制设置唯一的名称。
用于将实例绑定到 KieModule
的特定版本。如果 kie-ci
在 classpath
上,这将自动解析依赖项,从远程存储库下载。
注入classpath KieContainer
@KContainer private KieContainer kContainer;
为动态 KieModule
注入 KieContainer
@KContainer @KReleaseId(groupId = "jar1", artifactId = "art1", version = "1.1") private KieContainer kContainer;
为动态 KieModule
注入命名 KieContainer
@KContainer(name = "kc1") @KReleaseId(groupId = "jar1", artifactId = "art1", version = "1.1") private KieContainer kContainer;
默认参数(如果给定)映射到 value
属性并指定来自 spring xml
文件中的 KieBase
的名称。
从classpath
KieContainer
注入默认 KieBase
@KBase private KieBase kbase;
从动态 KieModule
注入默认 KieBase
@KBase @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.0") private KieBase kbase;
'jar1.KBase1' KieBase
的并列版本加载
@KBase("kbase1") @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.0") private KieBase kbase1v10; @KBase("kbase1") @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.1") private KieBase kbase1v11;
'jar1.ksession1'
KieSession
的并列版本加载
@KSession("ksession1") @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.0") private KieSession ksession11kb2; @KSession("ksession1") @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.1") private KieSession ksession11kb2;
默认参数(如果给定)映射到 value
属性并从 kmodule.xml
或 spring xml
文件指定 KieSession
的名称
从 Classpath KieContainer
注入默认 KieSession
@KSession private KieSession ksession;
从动态 KieModule
注入默认 KieSession
@KSession @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.0") private KieSession ksession;
'jar1.KBase1' KieBase
的并排版本加载
@KSession("ksession1") @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.0") private KieSession ksessionv10; @KSession("ksession1") @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.1") private KieSession ksessionv11;
使用 'name'
属性为 'jar1.KBase1' KieSession
强制新实例
@KSession("ksession1") @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.0") private KieSession ksession1ks1 @KSession("ksession1") @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.0") private KieSession ksession1ks2
默认参数(如果给定)映射到 value
属性并从 kmodule.xml
或 spring xml
文件指定 KieSession
的名称。
从 Classpath KieContainer
注入默认的 StatelessKieSession
@KSession private StatelessKieSession ksession;
从动态 KieModule
注入默认的 StatelessKieSession
@KSession @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.0") private StatelessKieSession ksession;
'jar1.KBase1' KieBase
的并列版本加载
@KSession("ksession1") @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.0") private StatelessKieSession ksessionv10; @KSession("ksession1") @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.1") private StatelessKieSession ksessionv11;
@KSession(value="ksession1", name="ks1") @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.0") private StatelessKieSession ksession1ks1 @KSession(value="ksession1", name="ks2") @KReleaseId( groupId = "jar1", artifactId = "art1", version = "1.0") private StatelessKieSession ksession1ks2
当使用 annotations
时,为了正确初始化 kmodule objects(kbase/ksession)
,必须定义一个org.kie.spring.annotations.KModuleAnnotationPostProcessor
类型的 bean
。
示例 77. kie-spring
注释后处理器 bean
定义
<bean id="kiePostProcessor" class="org.kie.spring.annotations.KModuleAnnotationPostProcessor"/>
示例 78. kie-spring
注释 - 组件扫描
<context:component-scan base-package="org.kie.spring.annotations"/>
当使用注解时,后处理器是不同的。
Drools 支持向 KieSessions
添加 3 种类型的监听器 - AgendaListener
、WorkingMemoryListener
、ProcessEventListener
kie-spring
模块允许您使用 XML 标签将这些侦听器配置到 KieSessions
。这些标签与实际的侦听器接口具有相同的名称,即 <kie:agendaEventListener… .>
、<kie:ruleRuntimeEventListener… .>
和 <kie:processEventListener… .>
。
kie-spring
提供了将侦听器定义为独立(个体)侦听器并将它们定义为一个组的功能。
表 102. 示例
Attribute | Required | Description |
---|---|---|
ref | No | 对另一个声明的 bean 的引用 |
示例 79. 侦听器配置示例 - 使用 bean:ref
。
<bean id="mock-agenda-listener" class="mocks.MockAgendaEventListener"/> <bean id="mock-rr-listener" class="mocks.MockRuleRuntimeEventListener"/> <bean id="mock-process-listener" class="mocks.MockProcessEventListener"/> <kie:kmodule id="listeners_kmodule"> <kie:kbase name="drl_kiesample" packages="drl_kiesample"> <kie:ksession name="ksession2"> <kie:agendaEventListener ref="mock-agenda-listener"/> <kie:processEventListener ref="mock-process-listener"/> <kie:ruleRuntimeEventListener ref="mock-rr-listener"/> </kie:ksession> </kie:kbase> </kie:kmodule> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
示例 80. 侦听器配置示例 - 使用嵌套 bean。
<kie:kmodule id="listeners_module"> <kie:kbase name="drl_kiesample" packages="drl_kiesample"> <kie:ksession name="ksession1"> <kie:agendaEventListener> <bean class="mocks.MockAgendaEventListener"/> </kie:agendaEventListener> </kie:ksession> </kie:kbase> </kie:kmodule> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
ref
且没有嵌套bean的声明当在没有引用实现 bean
并且不包含嵌套 bean
的情况下定义侦听器时,<drools:ruleRuntimeEventListener/>
底层实现会添加 API 中定义的侦听器的调试版本。
调试侦听器将相应的 Event toString
消息打印到 System.err。
示例 81. 侦听器配置示例 - 默认为 Knowledge-API
提供的调试版本。
<bean id="mock-agenda-listener" class="mocks.MockAgendaEventListener"/> <bean id="mock-rr-listener" class="mocks.MockRuleRuntimeEventListener"/> <bean id="mock-process-listener" class="mocks.MockProcessEventListener"/> <kie:kmodule id="listeners_module"> <kie:kbase name="drl_kiesample" packages="drl_kiesample"> <kie:ksession name="ksession2"> <kie:agendaEventListener /> <kie:processEventListener /> <kie:ruleRuntimeEventListener /> </kie:ksession> </kie:kbase> </kie:kmodule> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
drools-spring
模块允许您在同一个 KieSession
中混合和匹配不同的声明样式。下面的示例提供了更清晰的信息。
示例 82. 侦听器配置示例 - ‘ref’/nested-bean/empty 样式的混合和匹配。
<bean id="mock-agenda-listener" class="mocks.MockAgendaEventListener"/> <bean id="mock-rr-listener" class="mocks.MockRuleRuntimeEventListener"/> <bean id="mock-process-listener" class="mocks.MockProcessEventListener"/> <kie:kmodule id="listeners_module"> <kie:kbase name="drl_kiesample" packages="drl_kiesample"> <kie:ksession name="ksession1"> <kie:agendaEventListener> <bean class="org.kie.spring.mocks.MockAgendaEventListener"/> </kie:agendaEventListener> </kie:ksession> <kie:ksession name="ksession2"> <kie:agendaEventListener ref="mock-agenda-listener"/> <kie:processEventListener ref="mock-process-listener"/> <kie:ruleRuntimeEventListener ref="mock-rr-listener"/> </kie:ksession> </kie:kbase> </kie:kmodule> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
为 KieSession
定义多个相同事件侦听器类型的 bean
也是有效的。
示例 83. 侦听器配置示例 - 多个相同类型的侦听器。
<bean id="mock-agenda-listener" class="mocks.MockAgendaEventListener"/> <kie:kmodule id="listeners_module"> <kie:kbase name="drl_kiesample" packages="drl_kiesample"> <kie:ksession name="ksession1"> <kie:agendaEventListener ref="mock-agenda-listener"/> <kie:agendaEventListener> <bean class="org.kie.spring.mocks.MockAgendaEventListener"/> </kie:agendaEventListener> </kie:ksession> </kie:kbase> </kie:kmodule> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
drools-spring
允许对listeners
进行分组。当您定义一组侦听器并希望将它们附加到多个会话时,非常有用。当我们为testing
定义一组侦听器然后想要将它们切换为production
使用时,分组功能也非常有用。
表 103. 示例
Attribute | Required | Description |
---|---|---|
ID | yes | Unique identifier |
kie:agendaEventListener
…kie:ruleRuntimeEventListener
…kie:processEventListener
…上面提到的子元素可以按任何顺序声明。一个组中只允许每种类型的一个声明。
<bean id="mock-agenda-listener" class="mocks.MockAgendaEventListener"/> <bean id="mock-rr-listener" class="mocks.MockRuleRuntimeEventListener"/> <bean id="mock-process-listener" class="mocks.MockProcessEventListener"/> <kie:kmodule id="listeners_module"> <kie:kbase name="drl_kiesample" packages="drl_kiesample"> <kie:ksession name="statelessWithGroupedListeners" type="stateless" listeners-ref="debugListeners"/> </kie:kbase> </kie:kmodule> <kie:eventListeners id="debugListeners"> <kie:agendaEventListener ref="mock-agenda-listener"/> <kie:processEventListener ref="mock-process-listener"/> <kie:ruleRuntimeEventListener ref="mock-rr-listener"/> </kie:eventListeners> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
Drools 支持将两类的日志器添加到 KieSessions
- ConsoleLogger
和FileLogger
。
kie-spring
模块允许您使用 XML 标签将这些日志器配置为 KieSessions
。这些标签与实际的日志器接口具有相同的名称,即 <kie:consoleLogger... .>
和 <kie:fileLogger... .>
。
可以使用 <kie:consoleLogger/>
标签将控制台日志器配置到 KieSession
。此标签没有属性,必须直接出现在 <kie:ksession... .>
元素下。
示例 85. 定义控制台记录器 - 示例
<kie:kmodule id="loggers_module"> <kie:kbase name="drl_kiesample" packages="drl_kiesample"> <kie:ksession name="ConsoleLogger-statefulSession" type="stateful"> <kie:consoleLogger/> </kie:ksession> </kie:kbase> </kie:kmodule> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
可以使用<kie:fileLogger/>
标签将文件记录器附加到 KieSession
。此标签具有以下属性,并且必须直接出现在 <kie:ksession... .>
元素下。
表 104. 示例
Attribute | Required | Description |
---|---|---|
ID | yes | 唯一标识符 |
file | yes | 磁盘上实际文件的路径 |
threaded | no | 默认为false 。有效值为true 或false |
interval | no | 整数。指定将内容从内存刷新到磁盘的时间间隔。 |
示例 86. 定义文件记录器 - 示例
<kie:kmodule id="loggers_module"> <kie:kbase name="drl_kiesample" packages="drl_kiesample"> <kie:ksession name="ConsoleLogger-statefulSession" type="stateful"> <kie:fileLogger id="fl_logger" file="#{ systemProperties['java.io.tmpdir'] }/log1"/> <kie:fileLogger id="tfl_logger" file="#{ systemProperties['java.io.tmpdir'] }/log2" threaded="true" interval="5"/> </kie:ksession> </kie:kbase> </kie:kmodule> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
为防止泄漏,建议以编程方式关闭 _<kie:fileLogger … > _。
LoggerAdaptor adaptor = (LoggerAdaptor) context.getBean("fl_logger"); adaptor.close();
<kie:batch>
可以被用来定义一组批处理命令的对于给定的ksession
. 此标签没有属性,必须直接出现在 <kie:ksession... .>
元素下。支持的命令是:
初始化批处理命令
示例 87. 批处理命令 - 示例
<kie:kmodule id="batch_commands_module"> <kie:kbase name="drl_kiesample" packages="drl_kiesample"> <kie:ksession name="ksessionForCommands" type="stateful"> <kie:batch> <kie:insert-object ref="person2"/> <kie:set-global identifier="persons" ref="personsList"/> <kie:fire-all-rules max="10"/> </kie:batch> </kie:ksession> </kie:kbase> </kie:kmodule> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
持久化配置选项
例 88.ksession JPA 配置示例
<kie:kstore id="kstore" /> <!-- provides KnowledgeStoreService implementation --> <bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="ds" /> <property name="persistenceUnitName" value="org.drools.persistence.jpa.local" /> </bean> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="myEmf" /> </bean> <kie:kmodule id="persistence_module"> <kie:kbase name="drl_kiesample" packages="drl_kiesample"> <kie:ksession name="jpaSingleSessionCommandService"> <kie:configuration> <kie:jpa-persistence> <kie:transaction-manager ref="txManager"/> <kie:entity-manager-factory ref="myEmf"/> </kie:jpa-persistence> </kie:configuration> </kie:ksession> </kie:kbase> </kie:kmodule> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
本节提供有关在与 Drools Expert 集成时利用其他标准 spring 特性的详细信息。
<kie:kmodule id="batch_commands_module"> <kie:kbase name="drl_kiesample" packages="#{packageRepository.packages}"> <kie:ksession name="ksessionForCommands" type="stateful"/> </kie:kbase> </kie:kmodule> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/> <bean id="packageRepository" class="sample.package.class.PackageRepo"> <property name="packages" value="drl_kiesample3"> </bean>
<kie:kmodule id="loggers_module"> <kie:kbase name="drl_kiesample" packages="drl_kiesample"> <kie:ksession name="ConsoleLogger-statefulSession" type="stateful"> <kie:fileLogger id="fl" file="#{ systemProperties['java.io.tmpdir'] }/log1"/> <kie:fileLogger id="tfl" file="#{ systemProperties['java.io.tmpdir'] }/log2" threaded="true" interval="5"/> </kie:ksession> </kie:kbase> </kie:kmodule> <bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>
Spring 3.1 为 spring-beans
模式的 beans
元素引入了一个新的配置文件属性。在不同环境中启用和禁用配置文件时,此属性充当开关。此属性的一个潜在用途是在dev
环境中使用调试日志定义相同的 kbase
,而在prod
环境中不使用日志器。
下面的代码片段说明了profiles
的概念。
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:kie="http://drools.org/schema/kie-spring" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://drools.org/schema/kie-spring http://drools.org/schema/kie-spring.xsd"> <beans profile="development"> <kie:kmodule id="test-kmodule"> <kie:kbase name="drl_kiesample" packages="drl_kiesample"> <kie:ksession name="ksession1" type="stateless"> <kie:consoleLogger /> </kie:ksession> </kie:kbase> </kie:kmodule> ... </beans> <beans profile="production"> <kie:kmodule id="test-kmodule"> <kie:kbase name="drl_kiesample" packages="drl_kiesample"> <kie:ksession name="ksession1" type="stateless"/> </kie:kbase> </kie:kmodule> ... </beans> </beans>
如上所示,Spring XML 包含配置文件的定义。在加载ApplicationContext 时,您必须告诉 Spring 您正在加载哪个配置文件。
有多种方法可以选择您的配置文件,最有用的是使用spring.profiles.active
系统属性。
System.setProperty("spring.profiles.active", "development"); ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
显然,如上所示硬编码并不是一个好习惯,推荐的做法是保持系统属性定义独立于应用程序。
-Dspring.profiles.active="development"
配置文件也可以以编程方式加载和启用
... GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("beans.xml"); ConfigurableEnvironment env = ctx.getEnvironment(); env.setActiveProfiles("development"); ctx.refresh(); ...