如何使drools文件中的全局变量同步?

问题描述

我正在使用Spring Boot应用程序,在其中创建了一些REST API。有一个Readings实体,Alert实体。我正在通过POST方法发送读数,并且在postReadings类的ReadingsService方法中,我正在使用KIE检查读数是否符合特定条件,并在{{1 }}文件。我正在创建一个Alert对象,并使用rules.drl方法将其设置为全局对象。然后,我要检查Alert对象是否为null并将其保存到Alert Repository。在drools文件中,我添加了一条打印语句,以检查是否正确创建了所有警报。所有警报都可以通过print语句正确打印,但是,只有其中一部分被保存到警报存储库中。谁能帮忙吗?

这是ReadingsService

session.setGlobal

这是流口水文件

@Service
public class ReadingsServiceImpl implements ReadingsService{

@Autowired
ReadingsRepository repository;

@Autowired
VehicleRepository vehicleRepo;

@Autowired
private KieSession session;

@Autowired
AlertRepository alertRepo;


@Override
public List<Readings> findAll() {
    return repository.findAll();
}

@Override
public Readings postReadings(Readings readings) {
    Alert alert = new Alert();
    session.setGlobal("alert",alert);
    session.insert(readings);
    session.fireAllRules();
    if(!Optional.ofNullable(alert).map(o -> o.getVin()).orElse("").isBlank()) {
        alertRepo.save(alert);
    }
    return repository.save(readings);
}

解决方法

您的规则没有错。但是,您的保存受“ if”语句保护,该语句检查是否存在非空白/非空VIN,因此很可能会导致缺少保存的问题:

if(!Optional.ofNullable(alert).map(o -> o.getVin()).orElse("").isBlank()) {
  alertRepo.save(alert);
}

您可以轻松地编写单元测试来验证此行为-如果警报存在(因为您使用相同的方法更早地实例化了警报,所以一直存在)并且有VIN,则可以保存;并且如果警报存在并且没有VIN,则不会保存该警报。


这是保存规则输出的非常老式的方法。如今,我们通常会在右侧规则中使用具有副作用的动作,或使用对象来传递信息。

您当前的设置甚至存在逻辑缺陷:您将总是具有警报,因为在将其添加到会话之前实例化了它。

如果要使用这样的全局变量,则需要向Alert类本身添加某种指示符,以指示已添加警报。因此,例如,如果您仅添加带有适当的getter的boolean added = false方法,则可以像这样更新规则:

rule "Engine Coolant Or Check Engine Light"
when
    readingsObject: Readings(engineCoolantLow || checkEngineLightOn);
then
    alert.setAdded(true); // Mark the alert as now being added
    alert.setVin(readingsObject.getVin());
    alert.setPriotity("LOW");
    alert.setDescription("Engine Coolant LOW Or Check Engine Light ON");
    alert.setTimestamp(readingsObject.getTimestamp());
    alert.setLatitude(readingsObject.getLatitude());
    alert.setLongitude(readingsObject.getLongitude());
    System.out.println(alert.toString());
end

然后您可以将调用方法固定为 not ,以取消非null对象的可为空性,而改为取消是否已添加警报:

public Readings postReadings(Readings readings) {
    Alert alert = new Alert();
    session.setGlobal("alert",alert);
    session.insert(readings);
    session.fireAllRules();
    if(alert.isAdded()) {
        alertRepo.save(alert);
    }
    return repository.save(readings);
}

(当然,我假设您在“存储库”实例中具有适当的连接和事务处理。)

如果您仍然需要非空VIN,则应在规则的左侧进行检查;像这样的东西:

readingsObject: Readings( vin != null,engineCoolantLow || checkEngineLightOn )

相关问题:How to return the value from Cosequence of drl file to java

,

Drools会在同一(单个)线程中评估规则,除非您进行其他配置。因此postReadings()和drools然后阻塞将由同一线程调用。但是postReadings()可以在并发上下文中执行,并且使用共享的全局对象引用Alert alert(由于共享的会话实例)。 Drools与使ReadingsServiceImpl线程安全的一般问题无关。实现这一目标的方法有很多,第一个反模式是“全局变量” ...不要在drools文件中使用共享对象,而要使用共享线程安全服务参考。您可以使用不同的同步方法,使用线程局部变量来使您的服务以线程安全的方式处理内部事务,但是您是否真的需要共享对象?

import com.shiva.truckerapi.entity.Readings;
import com.shiva.truckerapi.entity.Alert;

global com.shiva.truckerapi.service.ReadingsService readingsService;

rule "EngineCoolantOrCheckEngineLight"
when
    readingsObject: Readings(engineCoolantLow || checkEngineLightOn);
then
    Alert alert = new Alert();
    alert.setVin(readingsObject.getVin());
    alert.setPriotity("LOW");
    alert.setDescription("Engine Coolant LOW Or Check Engine Light ON");
    alert.setTimestamp(readingsObject.getTimestamp());
    alert.setLatitude(readingsObject.getLatitude());
    alert.setLongitude(readingsObject.getLongitude());
    System.out.println(alert.toString());

    readingsService.onAlert(alert);
end;

服务变更

@PostConstruct
private void postConstruct() {
    session.setGlobal("readingsService",this);
}

@Override
public void postReadings(Readings readings) {
    session.insert(readings);
    session.fireAllRules();
    repository.save(readings);
}

@Override
public void onAlert(Alert alert) {
    // this looks ugly. There should not be produced 'invalid' alert,if vin is empty alert should not be generated by the rule itself
    if(!Optional.ofNullable(alert).map(o -> o.getVin()).orElse("").isBlank()) {
        alertRepo.save(alert);
    }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...