从不同的ClassLoader中删除KieContainer

时间:2017-07-06 13:01:10

标签: java weblogic drools kie

我们有一个Java应用程序,在Weblogic上部署了不同的模块。我们在不同的模块上使用drools并尝试通过将它定义为枚举类来使初始化KieContainer的类成为单例。

但是,当我们处于生产环境(通过ear文件部署应用程序)时,似乎有不同的ClassLoader初始化此类,我们得到以下异常:

null    java.lang.IllegalStateException: There's already another KieContainer created from a different ClassLoader; 
at org.drools.compiler.kie.builder.impl.KieServicesImpl.getKieClasspathContainer(KieServicesImpl.java:88); 
at org.drools.compiler.kie.builder.impl.KieServicesImpl.getKieClasspathContainer(KieServicesImpl.java:73);

您对如何解决这个问题有任何建议吗?

2 个答案:

答案 0 :(得分:2)

我们在不同的环境中遇到了同样的问题(Kafka,Weld SE)。虽然反直觉,但仍在调用

// Answer the cuurent container if it exists else create a new container
KieServices.Factory.get().getKieClasspathContainer();

<强>不

// Always create a new container
KieServices.Factory.get().newKieClasspathContainer();

为我们解决了大部分问题。

此外,在容器超出范围之前,请务必调用:

KieServices.Factory.get().getKieClasspathContainer().dispose();

这将从Drools全局单例中释放容器及其资源。

我们在Maven中运行单元测试也遇到了问题,因为Surefire插件默认情况下不会为每个测试重新创建一个JVM,而Drools假定每个JVM调用只创建一个全局单例实例。通过让Surefire在每次测试中重新创建一个干净的JVM环境来解决这个问题。调整你的 的pom.xml 通过添加

<reuseForks>false</reuseForks>

到你的Surefire配置。例如:

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <executions>
        <execution>
            <id>default-test</id>
            <configuration>
                 <reuseForks>false</reuseForks>
            </configuration>
        </execution>
       </executions>
  </plugin>

此外,您可以考虑为每个Java EE模块分配自己的KieContainer

KieContainer getKieClasspathContainer(String containerId);

这将允许每个Java EE模块的生命周期与每个Drools容器模块的生命周期同步。

答案 1 :(得分:0)

drools代码检查您指定的类加载器和当前实例this.getClass()。getClassLoader()是否相同,如果不正确,则KieContainer的错误已经存在eror。如果不指定类加载器,则它使用Thread.currentThread()。getContextClassLoader(),在某些情况下,它与this.getClass()。getClassLoader()不同。简单的解决方法是使用 KieServices.Factory.get()。getKieClasspathContainer(this.getClass()。getClassLoader())