分享到:

开发环境:IntelliJ IDEA,Java 8,Gradle,SpringBoot,Drools。
新建Gradle工程后,配置SpringBoot和Drools的引入:
compile 'org.springframework.boot:spring-boot:1.5.9.RELEASE'
compile 'org.springframework.boot:spring-boot-starter:1.5.9.RELEASE'
compile 'org.springframework.boot:spring-boot-starter-log4j2:1.5.9.RELEASE'

compile 'org.kie:kie-api:7.5.0.Final'
compile 'org.drools:drools-compiler:7.5.0.Final'

配置Main类:
package demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Main {

    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }

}

配置一个Bean类:
package demo;

public class Message {

    public final static int HELLO = 1;
    public final static int GOODBYE = 2;

    private String message;
    private int status;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }
    
}

配置META-INF/kmodule.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<kmodule xmlns="http://www.drools.org/xsd/kmodule">
    <kbase name="demo" packages="rules">
        <ksession name="demo_ksession"/>
    </kbase>
</kmodule>

配置对应packages「rules」下的规则文件:
package rules;

import demo.Message;

rule "rule1"
    salience 1
    when
        $message: Message(status == Message.HELLO)
    then
        System.out.println("Status is 'Hello', set 'Hello World!' to message");
        $message.setMessage("Hello World!");
        System.out.println("Message: " + $message.getMessage());
end

配置Demo运行类:
package demo;

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(1)
public class DroolsDemo implements CommandLineRunner{

    @Override
    public void run(String... args) throws Exception {

        KieServices ks = KieServices.Factory.get();
        KieContainer kieContainer = ks.getKieClasspathContainer();
        KieSession kieSession = kieContainer.newKieSession("demo_ksession");

        Message message = new Message();
        message.setStatus(Message.HELLO);
        kieSession.insert(message);
        kieSession.fireAllRules();
        kieSession.dispose();

    }

}

启动运行,输出:
Status is 'Hello', set 'Hello World!' to message
Message: Hello World!

完成。
把规则文件原有的规则调整一下,再增加一个新规则,如下所示:
package rules;

import demo.Message;

rule "rule1"
    salience 1
    when
        $message: Message(status == Message.HELLO)
    then
        System.out.println("Status is 'Hello', set 'Hello World!' to message");
        $message.setMessage("Hello World!");
        System.out.println("Message: " + $message.getMessage());
        System.out.println("Then set 'Goodbye' to status");
        $message.setStatus(Message.GOODBYE);
        update($message);
end

rule "rule2"
    salience 1
    when
        $message: Message(status == Message.GOODBYE)
    then
        System.out.println("Status is 'Goodbye', set 'Goodbye World!' to message");
        $message.setMessage("Goodbye World!");
        System.out.println("Message: " + $message.getMessage());
end

再次运行,输出:
Status is 'Hello', set 'Hello World!' to message
Message: Hello World!
Then set 'Goodbye' to status
Status is 'Goodbye', set 'Goodbye World!' to message
Message: Goodbye World!

即rule1中的
update($message)
会使$message对象再次经过规则验证。
如果把rule2改成和rule1类似的状况,如下所示:
package rules;

import demo.Message;

rule "rule1"
   salience 1
   when
       $message: Message(status == Message.HELLO)
   then
       System.out.println("Status is 'Hello', set 'Hello World!' to message");
       $message.setMessage("Hello World!");
       System.out.println("Message: " + $message.getMessage());
       System.out.println("Then set 'Goodbye' to status");
       $message.setStatus(Message.GOODBYE);
       update($message);
end

rule "rule2"
   salience 1
   when
       $message: Message(status == Message.GOODBYE)
   then
       System.out.println("Status is 'Goodbye', set 'Goodbye World!' to message");
       $message.setMessage("Goodbye World!");
       System.out.println("Message: " + $message.getMessage());
       System.out.println("Then set 'Hello' to status");
       $message.setStatus(Message.HELLO);
       update($message);
end

输出:
Status is 'Hello', set 'Hello World!' to message
Message: Hello World!
Then set 'Goodbye' to status
Status is 'Goodbye', set 'Goodbye World!' to message
Message: Goodbye World!
Then set 'Hello' to status
Status is 'Hello', set 'Hello World!' to message
Message: Hello World!
Then set 'Goodbye' to status
Status is 'Goodbye', set 'Goodbye World!' to message
Message: Goodbye World!
Then set 'Hello' to status
Status is 'Hello', set 'Hello World!' to message
Message: Hello World!
......

 
这样造成了验证一直在循环。如果需要不让它一直循环的话,需要在rule的开头配置「no-loop 」或「lock-on-active 」。这两个属性在没有配置的情况下,默认为false,即不会阻止循环。
但要注意,「no-loop」只会在rule调用自己的时候才会阻止循环,「lock-on-active」则是其它rule调用该rule的时候也会阻止循环,使该rule只执行一次。
no-loop例子:
package rules;

import demo.Message;

rule "rule1"
   salience 1
   no-loop true
when
       $message: Message(status == Message.HELLO)
   then
       System.out.println("Status is 'Hello', set 'Hello World!' to message");
       $message.setMessage("Hello World!");
       System.out.println("Message: " + $message.getMessage());

        System.out.println("Then create a new Message and set 'Hello' to status");
        Message message2 = new Message();
        message2.setStatus(Message.HELLO);
        insert(message2);
end

当把
no-loop true
一句注释掉时,输出结果为:
Status is 'Hello', set 'Hello World!' to message
Message: Hello World!
Then create a new Message and set 'Hello' to status
Status is 'Hello', set 'Hello World!' to message
Message: Hello World!
Then create a new Message and set 'Hello' to status
Status is 'Hello', set 'Hello World!' to message
......
造成了循环,将注释解开后,输出结果为:
Status is 'Hello', set 'Hello World!' to message
Message: Hello World!
Then create a new Message and set 'Hello' to status

没有出现循环。
lock-on-active例子:
package rules;

import demo.Message;

rule "rule1"
   salience 1
   no-loop true
   lock-on-active true
   when
       $message: Message(status == Message.HELLO)
   then
       System.out.println("Status is 'Hello', set 'Hello World!' to message");
       $message.setMessage("Hello World!");
       System.out.println("Message: " + $message.getMessage());
       System.out.println("Then set 'Goodbye' to status");
       $message.setStatus(Message.GOODBYE);
       update($message);
end

rule "rule2"
   salience 1
   when
       $message: Message(status == Message.GOODBYE)
   then
       System.out.println("Status is 'Goodbye', set 'Goodbye World!' to message");
       $message.setMessage("Goodbye World!");
       System.out.println("Message: " + $message.getMessage());
       System.out.println("Then set 'Hello' to status");
       $message.setStatus(Message.HELLO);
       update($message);
end

当把

lock-on-active true

一句注释掉时,输出结果为:

Status is 'Hello', set 'Hello World!' to message
Message: Hello World!
Then set 'Goodbye' to status
Status is 'Goodbye', set 'Goodbye World!' to message
Message: Goodbye World!
Then set 'Hello' to status
Status is 'Hello', set 'Hello World!' to message
Message: Hello World!
Then set 'Goodbye' to status
Status is 'Goodbye', set 'Goodbye World!' to message
Message: Goodbye World!
Then set 'Hello' to status
Status is 'Hello', set 'Hello World!' to message
Message: Hello World!
......
即rule1中的no-loop true并没有阻止其被rule2调用,仍然造成了循环。当把注释解开后,输出结果则为:
Status is 'Hello', set 'Hello World!' to message
Message: Hello World!
Then set 'Goodbye' to status
Status is 'Goodbye', set 'Goodbye World!' to message
Message: Goodbye World!
Then set 'Hello' to status

rule1执行后调用了rule2,rule2没有再使rule1出现循环,rule1仅执行了一次。


本Demo地址: