使用CDI在drools规则中注入事实

使用CDI在drools规则中注入事实,drools,Drools,我想在Drools规则引擎中插入一个事实,它是CDIBean。要在普通java中实现这一点,我需要 @Inject MyBean myBean; 是否可以在规则引擎中@注入?我需要焊接作为一种依赖吗 例如,我有一个规则,目前有以下结果(没有CDI): insert(新的MyLibraryClass()) MyLibraryClass已经更新,现在包含cdi注入,因此需要注入类才能正常工作。由于我希望在规则中能够灵活地将此类作为事实插入或不作为事实插入,以及在什么时间点插入,我希望在规则引擎中插

我想在Drools规则引擎中插入一个事实,它是CDIBean。要在普通java中实现这一点,我需要

@Inject
MyBean myBean;
是否可以在规则引擎中
@注入
?我需要焊接作为一种依赖吗

例如,我有一个规则,目前有以下结果(没有CDI):

insert(新的MyLibraryClass())


MyLibraryClass
已经更新,现在包含cdi注入,因此需要注入类才能正常工作。由于我希望在规则中能够灵活地将此类作为事实插入或不作为事实插入,以及在什么时间点插入,我希望在规则引擎中插入和创建对象。

只需将其注入调用规则的类(普通Java),并在调用规则时将实例传递到工作内存中即可

所以如果你有一个类,比如说,叫做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做过类似的依赖注入。不需要您尚未使用的额外依赖项


为了澄清,这里有一个玩具的例子

假设我最初有一个类Tax,我最初在规则中创建一个新实例,然后在后续规则中使用它:

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 { ... }
因为我不能再新建我的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
  }
}
我选择使用显著性来确保在常规规则之前调用过滤规则。更好的设计可能需要有一个单独的议程组来完成


最后,您不能直接注入规则上下文,因为您使用的任何CDI库都不能控制工作内存/规则上下文的生命周期。相反,解决方案是将对象传递到由CDI库控制其生命周期的规则中

最简单的方法通常是直接将bean作为事实或全局传递给工作内存。我看到的其他解决方案是传入的“injector”类。我曾经不得不管理一个规则集,其中Spring应用程序上下文全部被传递到规则中(处理tbh有点像噩梦)


如果不想直接传递bean,可以创建某种类型的“注入器”类作为bean持有者,将其注入规则调用器类,然后让规则排序它们需要什么。我对Weld一点也不熟悉,但是如果它提供了一个可以注入的应用程序上下文,那么也可以将其传递到规则中。但所有这些解决方案都需要您以某种方式调整规则,至少要删除或更新原始的
insert(new MyLibraryClass())
规则。

对不起,我应该指定这不是我的选项。事实应该在规则引擎中创建,依赖关系在规则引擎中。您将什么称为“规则引擎”?为什么不能将此bean设置为全局或事实?您的问题没有提到这些限制或它们存在的原因。我更新了我的问题,以包含有关我正在寻找的场景的更多详细信息。当我谈论规则引擎时,我指的是在
fireAllRules()
命令期间。仍然不清楚为什么在调用规则时不能将bean插入工作内存。这就是您最初使用
insert(…)
调用所做的一切,尽管是使用一个新实例。根据一条规则,我决定插入哪个类。对不起,我无法解释得更清楚。你能解释一下你在找什么信息吗?
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