Drools使用注意事项
使用场景:
public void doCustomer() {
//
People people = new People();
people.setName("哒");
people.setSex(1);
people.setDrlType("people");
//
KieServices kieServices = KieServices.Factory.get();
StatelessKieSession kieSession = kieServices.getKieClasspathContainer().newStatelessKieSession("my-test");
List<Command> commands = new ArrayList<>();
KieCommands kieCommands = kieServices.getCommands();
commands.add(kieCommands.newInsert(people, "input"));
ExecutionResults execute = kieSession.execute(kieCommands.newBatchExecution(commands));
}
项目中,有两个地方调用doCustomer方法,一个是rabbitMq的监听类,一个是Controller接口处
这两处的调用,由于当前线程的上下文加载器不同,导致只能有其中一处的调用正常,另外一个报错
异常问题:
抛出异常There's already another KieContainer created from a different ClassLoader
解决方案:
通过分析源码,发现:
// 使用Holder内部类的方式,创建了一个单例对象
KieServices kieServices = KieServices.Factory.get();
// 使用Volatile + Double-Check的方式,创建了一个单例对象;
KieContainer kieContainer = kieServices.getKieClasspathContainer(); 但是,代码中,会校验classLoader != classpathClassLoader ???
前者为当前线程上下文类加载器,后者为第一次创建KieContainer的线程类加载器这么一分析,发现是两处的调用,线程上下文加载器不一致导致的报错。
解决办法之一,就是,在项目启动的时候,初始化 KieServices 和 KieContainer 对象
或者
KieServices kieServices = KieServices.Factory.get();
StatelessKieSession kieSession = kieServices.getKieClasspathContainer(this.getClass().getClassLoader()).newStatelessKieSession("my-test");