版本从v7.20更改为v7.21之后,流口水中的无限递归

时间:2019-07-03 11:53:40

标签: drools

当drools-compiler的版本从7.20.0.Final更改为7.21.0.Final时,某些规则将递归循环。

github中的代码:

The working version

The recursively looping version

The change between working and looping version

更多详细信息

当我触发一个规则,该规则的then部分修改了when部分中已经检查过的事实:

rule "rule 1.1"
  when
    $sampleDomain: SampleDomain(instanceVariable2 == "Value of instance variable")
  then
    System.out.println("Rule 1.1 fired");
    modify($sampleDomain){
            setInstanceVariable1(3)
    }
end

它不会递归循环。

但是当我调用另一个从另一个类调用静态函数的规则时:

rule "rule 1.2"
  when
    $sampleDomain: SampleDomain(CoreUtils.anotherFunction())
  then
    System.out.println("Rule 1.2 fired");
    modify($sampleDomain){
            setInstanceVariable1(3)
    }
end

它递归循环。

具有静态功能的类是

import com.drool_issue.domain.SampleDomain;

public class CoreUtils {

    public static boolean anotherFunction() {
        System.out.println("anotherFunction() inside CoreUtils");
        return true;
    }

    public static boolean anotherFunction(SampleDomain sampleDomain) {
        System.out.println("anotherFunction(SampleDomain sampleDomain) inside CoreUtils");
        return true;
    }

}

我的域文件是:

public class SampleDomain {
    private int instanceVariable1;
    private String instanceVariable2;
    private int instanceVariable3;


    public int getInstanceVariable1() {
        return instanceVariable1;
    }
    public void setInstanceVariable1(int instanceVariable1) {
        this.instanceVariable1 = instanceVariable1;
    }
    public String getInstanceVariable2() {
        return instanceVariable2;
    }
    public void setInstanceVariable2(String instanceVariable2) {
        this.instanceVariable2 = instanceVariable2;
    }
    public int getInstanceVariable3() {
        return instanceVariable3;
    }
    public void setInstanceVariable3(int instanceVariable3) {
        this.instanceVariable3 = instanceVariable3;
    }



}

这仅是在版本从7.20.0.Final更改为7.21.0.Final之后引起的。您对问题可能有什么猜测?

当我进一步调查问题时,我也看到了这一点。

当我们将两个函数添加到SampleDomain类中时,即

    public boolean anotherFunction() {
        return true;
    }

    public boolean anotherFunction(SampleDomain sampleDomain) {
        return true;
    }

并在规则中使用它,例如:

rule "rule 1.4"
  when
    $sampleDomain: SampleDomain(anotherFunction())
  then
    System.out.println("Rule 1.4 fired");
    modify($sampleDomain){
            setInstanceVariable1(3)
    }
end

rule "rule 1.5"
  when
    $sampleDomain: SampleDomain(anotherFunction($sampleDomain))
  then
    System.out.println("Rule 1.5 fired");
    modify($sampleDomain){
            setInstanceVariable3(4)
    }
end

这些也会递归循环。

github中的代码:

The recursive looping when using non static methods

The change between working and above version

此外,如果将任何静态方法设为非静态,则即使在规则中指定了静态方法,也会调用域类中的方法。

此处要注意的代码部分为:

Rule where static method is called.

Another rule which also call the static method.

The static access modifier removed from the functions which where previously static.

github中的代码:

Weird behaviour when removing static modifier for the functions.

The change between working and above version

所有这些都是在7.20.0.Final之后的版本中引起的,即7.21.0.Final7.22.0.Final7.23.0.Final

1 个答案:

答案 0 :(得分:1)

基于属性反应性的过滤无法应用于外部功能,因为我们不知道外部功能(静态方法)在内部的作用。

详细说明: 让我们从属性反应性开始;每当我们在规则的结果中使用Modify或update关键字时,就会通知引擎,过滤相似对象类型的规则应再次重新评估该对象。默认情况下,此重新评估发生在整个对象上。只要对象的一个​​属性发生更改,规则就会将其视为要匹配的新对象。当我们不希望对某些更改进行重新评估时,这可能会导致一些问题。循环控制机制(例如无循环和主动锁定)在这些情况下可能会有所帮助。但是,如果我们希望规则仅控制某些属性的更改,则需要编写非常复杂的条件。此外,如果将来由于较大的规则库而模型发生更改,则可能必须修改很多规则,以避免不必要的规则重新执行。幸运的是,Drools提供了一项功能,使引擎可以解决此问题。它允许规则编写者定义bean的属性,如果它们在工作内存中被更新,则应对其进行监视。可以在规则中使用的数据模型(Java类或声明的类型)中定义此功能,该功能称为属性反应Bean。

要使用此功能,我们首先需要用Property Reactive注释标记将在规则中使用的类型。该注释使引擎知道,只要将此类型的对象添加到工作内存中,就需要对其更改进行特殊过滤。可以将该注释添加到Java类(在类级别)或声明的类型(在第一行之后,定义类型名称),如下所示: 在Java类中:

@PropertyReactive public class Customer {     ... }

在声明的类型中:

    declare PropertyReactiveOrder        
        @propertyReactive
        discount: Discount
        totalItems: Integer
        total: Double    
    end 

我们还可以通过向构建器选项添加PropertySpecificOption.ALWAYS来使所有类型的属性具有反应性。

注意:仅在使用Modify关键字的情况下,属性反应Bean的更改才会通知规则引擎。 update关键字将无法分辨正在更改的Bean属性之间的区别。

在Drools 5.4中引入了属性反应性,但是由于在正确性和性能方面都认为使用此功能是一种好的做法,因此在Drools 7.0中已默认启用它。

现在再次解决了我们的问题,尽管随着属性反应的发生,事物已经发生了巨大的变化,并且它的行为就像一个细粒度的属性更改侦听器,使Drools可以了解更多有关我们RHS规则内发生的情况,或至少在modify()操作内部。这些功能仍然是黑匣子,因此会出现此问题。