来自不同ClassLoader的Drools KieContainer

Joã*_*ida 5 java weblogic drools kie

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

但是,似乎在生产环境中(通过耳文件部署应用程序)时,有不同的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);
Run Code Online (Sandbox Code Playgroud)

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

小智 3

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

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

不是

// Always create a new container
KieServices.Factory.get().newKieClasspathContainer();
Run Code Online (Sandbox Code Playgroud)

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

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

KieServices.Factory.get().getKieClasspathContainer().dispose();
Run Code Online (Sandbox Code Playgroud)

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

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

<reuseForks>false</reuseForks>
Run Code Online (Sandbox Code Playgroud)

到您的 Surefire 配置。例如:

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <executions>
        <execution>
            <id>default-test</id>
            <configuration>
                 <reuseForks>false</reuseForks>
            </configuration>
        </execution>
       </executions>
  </plugin>
Run Code Online (Sandbox Code Playgroud)

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

KieContainer getKieClasspathContainer(String containerId);
Run Code Online (Sandbox Code Playgroud)

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