使用 CDI 在流口水规则中注入事实
Using CDI to inject a fact in a drools rule
我想在 Drools 规则引擎中插入一个 CDI bean 事实。要在正常 java 中做到这一点,我会
@Inject
MyBean myBean;
是否可以在规则引擎中@Inject
?我需要 weld 作为它的依赖项吗?
例如,我有一个规则,目前有以下结果(没有 CDI):
insert(new MyLibraryClass())
MyLibraryClass
已更新,现在包含 cdi 注入,因此需要注入 class 才能正常运行。因为我想在规则中灵活地插入这个 class 作为事实或不插入以及在什么时间点,我想在规则引擎中插入和创建对象。
只需将其注入调用规则的class(普通Java),并在调用规则时将实例传递到工作内存中。
因此,如果您有一个 class,例如调用规则的 RuleInvoker ...
public class RuleInvoker {
@Inject
MyBean myBean;
public void invokeRules() {
KieSession kieSession = ...;
kieSession.insert( myBean ); // insert into working memory like any other fact
// insert other facts, etc here, then fire rules
kieSession.fireAllRules();
// ... etc
}
}
我已经使用 Spring 完成了这样的依赖注入。不需要您尚未使用的额外依赖项。
为了澄清,这里有一些玩具示例。
假设最初我有一些 class 税,我最初在规则中创建一个新实例,然后在后续规则中使用:
rule "Insert Tax"
when
not (Tax())
then
insert(new Tax())
end
rule "Apply Tax to Alcohol"
when
$tax: Tax()
$purchase: Purchase( includesAlcohol == true )
then
$purchase.apply(tax, TaxType.ALCOHOL);
end
// Other rules eg. apply tax to lottery tickets, apply tax to groceries, etc.
现在我必须更改我的设计以支持两个不同地区的不同税收方案。这些税收计划将被注入;在这种情况下,我将使用 Spring 的 @Autowired
注释,但 @Inject
是相似的。
对于我设计的示例,我会将 Tax
转换为一个接口,然后让不同的税收方案简单地实现该接口。由于规则都是针对税收写的,因此规则不需要更改。
public interface Tax {
String getRegion();
// other methods previously on Tax class
}
public class RegionATax implements Tax { ... }
public class RegionBTax implements Tax { ... }
public class RegionCTax implements Tax { ... }
由于我无法再更新我的税务实例,我需要通过手动将它们放入工作内存来将它们放入上下文中。
public class RuleInvoker {
@Autowired
List<Tax> taxSchemes; // injects all tax schemes (implementors of Tax interface)
public void invokeRules(Purchase purchase) {
KieSession kieSession = ...;
for (Tax tax : taxSchemes) {
kieSession.insert( tax ); // insert into working memory like any other fact
}
// insert other facts, etc here, then fire rules
kieSesion.insert(purchase);
kieSession.fireAllRules();
// ... etc
}
}
最后,"Insert Tax" 规则需要替换为决定适用哪种税收方案的规则。在这个特别人为的示例中,由于我没有为自己提供任何实用方法,所以我将撤回与购买区域不匹配的所有不兼容的 Tax。
rule "Filter incompatible tax regions"
salience 1
when
Purchase( $region: region )
$incompatibleTaxRegion: Tax( region != $region )
then
retract( $incompatibleTaxRegion )
end
// Other rules remain the same since they're referencing the Tax interface
我选择使用显着性来确保过滤规则在常规规则之前被调用。更好的设计可能包括有一个单独的议程组来执行此操作。
归根结底,您无法直接注入规则上下文,因为您使用的任何 CDI 库都无法控制工作内存/规则上下文的生命周期。相反,解决方案是将对象传递到规则中,其生命周期 是 由您的 CDI 库控制。
执行此操作的最简单方法通常是将 bean 作为事实或全局变量直接传递到工作内存。我见过的其他解决方案是 "injector" classes 被传入。我曾经不得不管理一个规则集,其中 Spring 应用程序上下文整体被传递到规则中(有点处理 tbh 的噩梦。)
如果不想直接传递bean,可以创建某种"injector" class作为bean holder,注入that进入你的规则调用器 class,然后让规则整理出它们需要的东西。我一点也不熟悉 Weld,但是如果它提供了一个可以注入的应用程序上下文,您也可以将其传递到规则中。但是所有这些解决方案都需要您以某种方式调整规则,至少要删除或更新您原来的 insert( new MyLibraryClass())
规则。
我想在 Drools 规则引擎中插入一个 CDI bean 事实。要在正常 java 中做到这一点,我会
@Inject
MyBean myBean;
是否可以在规则引擎中@Inject
?我需要 weld 作为它的依赖项吗?
例如,我有一个规则,目前有以下结果(没有 CDI):
insert(new MyLibraryClass())
MyLibraryClass
已更新,现在包含 cdi 注入,因此需要注入 class 才能正常运行。因为我想在规则中灵活地插入这个 class 作为事实或不插入以及在什么时间点,我想在规则引擎中插入和创建对象。
只需将其注入调用规则的class(普通Java),并在调用规则时将实例传递到工作内存中。
因此,如果您有一个 class,例如调用规则的 RuleInvoker ...
public class RuleInvoker {
@Inject
MyBean myBean;
public void invokeRules() {
KieSession kieSession = ...;
kieSession.insert( myBean ); // insert into working memory like any other fact
// insert other facts, etc here, then fire rules
kieSession.fireAllRules();
// ... etc
}
}
我已经使用 Spring 完成了这样的依赖注入。不需要您尚未使用的额外依赖项。
为了澄清,这里有一些玩具示例。
假设最初我有一些 class 税,我最初在规则中创建一个新实例,然后在后续规则中使用:
rule "Insert Tax"
when
not (Tax())
then
insert(new Tax())
end
rule "Apply Tax to Alcohol"
when
$tax: Tax()
$purchase: Purchase( includesAlcohol == true )
then
$purchase.apply(tax, TaxType.ALCOHOL);
end
// Other rules eg. apply tax to lottery tickets, apply tax to groceries, etc.
现在我必须更改我的设计以支持两个不同地区的不同税收方案。这些税收计划将被注入;在这种情况下,我将使用 Spring 的 @Autowired
注释,但 @Inject
是相似的。
对于我设计的示例,我会将 Tax
转换为一个接口,然后让不同的税收方案简单地实现该接口。由于规则都是针对税收写的,因此规则不需要更改。
public interface Tax {
String getRegion();
// other methods previously on Tax class
}
public class RegionATax implements Tax { ... }
public class RegionBTax implements Tax { ... }
public class RegionCTax implements Tax { ... }
由于我无法再更新我的税务实例,我需要通过手动将它们放入工作内存来将它们放入上下文中。
public class RuleInvoker {
@Autowired
List<Tax> taxSchemes; // injects all tax schemes (implementors of Tax interface)
public void invokeRules(Purchase purchase) {
KieSession kieSession = ...;
for (Tax tax : taxSchemes) {
kieSession.insert( tax ); // insert into working memory like any other fact
}
// insert other facts, etc here, then fire rules
kieSesion.insert(purchase);
kieSession.fireAllRules();
// ... etc
}
}
最后,"Insert Tax" 规则需要替换为决定适用哪种税收方案的规则。在这个特别人为的示例中,由于我没有为自己提供任何实用方法,所以我将撤回与购买区域不匹配的所有不兼容的 Tax。
rule "Filter incompatible tax regions"
salience 1
when
Purchase( $region: region )
$incompatibleTaxRegion: Tax( region != $region )
then
retract( $incompatibleTaxRegion )
end
// Other rules remain the same since they're referencing the Tax interface
我选择使用显着性来确保过滤规则在常规规则之前被调用。更好的设计可能包括有一个单独的议程组来执行此操作。
归根结底,您无法直接注入规则上下文,因为您使用的任何 CDI 库都无法控制工作内存/规则上下文的生命周期。相反,解决方案是将对象传递到规则中,其生命周期 是 由您的 CDI 库控制。
执行此操作的最简单方法通常是将 bean 作为事实或全局变量直接传递到工作内存。我见过的其他解决方案是 "injector" classes 被传入。我曾经不得不管理一个规则集,其中 Spring 应用程序上下文整体被传递到规则中(有点处理 tbh 的噩梦。)
如果不想直接传递bean,可以创建某种"injector" class作为bean holder,注入that进入你的规则调用器 class,然后让规则整理出它们需要的东西。我一点也不熟悉 Weld,但是如果它提供了一个可以注入的应用程序上下文,您也可以将其传递到规则中。但是所有这些解决方案都需要您以某种方式调整规则,至少要删除或更新您原来的 insert( new MyLibraryClass())
规则。