[英]How can I set global variable in drools using drools-spring and use same in DRL file
[英]How to make a global variable in the drools file synchronous?
我正在开发一个 Spring Boot 应用程序,我在其中创建了一些 REST API。 有一个阅读实体,警报实体。 我正在通过 POST 方法发送读数,在ReadingsService
类的postReadings
方法中,我正在使用KIE
检查读数是否符合某些标准,并将规则rules.drl
文件。 我正在创建一个 Alert 对象并使用session.setGlobal
方法将其设置为全局对象。 然后我检查警报对象是否为空并将其保存到警报存储库。 在 drools 文件中,我添加了一个打印语句来检查是否所有警报都已正确创建。 所有警报都通过打印语句正确打印,但是,只有其中一些被保存到警报存储库中。 有人可以帮忙吗?
这是阅读服务
@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);
}
这是口水文件
import com.shiva.truckerapi.entity.Readings;
global com.shiva.truckerapi.entity.Alert alert;
rule "EngineCoolantOrCheckEngineLight"
when
readingsObject: Readings(engineCoolantLow || checkEngineLightOn);
then
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;
你的规矩没有错。 但是,您的保存由“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
然后您可以修复您的调用方法,以不关闭非空对象的可空性,而是关闭您是否添加了警报:
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 )
Drools 在同一个(单个)线程中评估规则,除非你进行额外的配置。 因此postReadings()
和 drools then block 将被同一个线程调用。 但是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);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.