Spring Boot 和 Drools 整合

4

我正在尝试在Spring Boot 1.2.2.RELEASE中运行drools 6.2.0.Final。根据文档,我已经配置好了drools。我的kie-context.xml配置文件是我保存drools bean的地方,看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:kie="http://drools.org/schema/kie-spring"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                      http://drools.org/schema/kie-spring http://drools.org/schema/kie-spring.xsd">

<kie:kmodule id="sample_module">
    <kie:kbase name="kbase1" packages="composition-rules">
        <kie:ksession name="ksession1" type="stateless"/>
    </kie:kbase>
</kie:kmodule>

<bean id="kiePostProcessor" class="org.kie.spring.KModuleBeanFactoryPostProcessor"/>

当我尝试使用Spring Boot编译应用程序并运行时,出现了以下错误:
java.lang.IllegalStateException: LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6ab6cc3b: startup date [Wed Apr 15 13:57:02 CEST 2015]; root of context hierarchy
at org.springframework.context.support.AbstractApplicationContext.getLifecycleProcessor(AbstractApplicationContext.java:357)
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:877)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.doClose(EmbeddedWebApplicationContext.java:150)
at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:836)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:342)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at skeleton.StorfinoApplication.main(StorfinoApplication.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:53)
at java.lang.Thread.run(Thread.java:745)

java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:53)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.RuntimeException: Unable to get all ZipFile entries: /home/lukasz/dev/skeleton/application/target/application-1.0-SNAPSHOT.jar!
at org.drools.core.util.IoUtils.indexZipFile(IoUtils.java:133)
at org.drools.compiler.kie.builder.impl.ZipKieModule.<init>(ZipKieModule.java:20)
at org.drools.compiler.kie.builder.impl.ClasspathKieProject.createInternalKieModule(ClasspathKieProject.java:186)
at org.kie.spring.KModuleBeanFactoryPostProcessor.createKieModule(KModuleBeanFactoryPostProcessor.java:189)
at org.kie.spring.KModuleBeanFactoryPostProcessor.addKieModuleToRepo(KModuleBeanFactoryPostProcessor.java:162)
at org.kie.spring.KModuleBeanFactoryPostProcessor.postProcessBeanFactory(KModuleBeanFactoryPostProcessor.java:121)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:265)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:177)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:606)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:462)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at skeleton.StorfinoApplication.main(StorfinoApplication.java:23)
... 6 more
Caused by: java.io.FileNotFoundException: /home/user-name/dev/skeleton/application/target/application-1.0-SNAPSHOT.jar! (No such file or directory)
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(ZipFile.java:220)
at java.util.zip.ZipFile.<init>(ZipFile.java:150)
at java.util.zip.ZipFile.<init>(ZipFile.java:164)
at org.drools.core.util.IoUtils.indexZipFile(IoUtils.java:124)
... 21 more

我所用的构建项目的命令是:mvn clean package,然后我将其作为jar文件运行(java -jar application/target/application-1.0-SNAPSHOT.jar)。
有一件事引起了我的注意,即文件路径(未找到的路径)末尾有一个感叹号(这里不应该有)。我还观察到,在IntelijIdea ide中运行该项目时,它成功构建并正常工作。
这种错误的原因可能是什么?

1
有时我会看到这样的“路径”,当他们试图引用JAR/WAR文件内部的文件时,但通常后面还有第二部分,例如app.jar!path/to/file.xml。 JAR和InteliJ之间的区别在于你的“类文件”不在jar中。最好调试KModuleBeanFactoryPostProcessor。 - sodik
1
是的...这可能是由于Spring Boot生成了一个包含依赖项的“fat” jar。我似乎在其他地方听说过与Drools 6类路径扫描相关的错误。可能只涉及到kie-spring,因为我个人不使用它,并且有没有此类问题的Spring Boot项目。例如:https://github.com/gratiartis/buspass-ws - Steve
你可能是对的。我尝试使用依赖于kie-spring的kie-camel,经过进一步调查,我发现它试图从类路径中读取像这样的内容:jar:file:/home/lukasz/dev/skeleton/application/target/application.jar!/(是的 - 感叹号后面没有任何东西)。正如日志之前所说,这都发生在KModuleBeanFactoryPostProcessor中。你认为我可以通过将其部署为非fat jar(war或其他选项)来解决它吗? - gajos
1个回答

10

我尝试过相同的方法,最终创建了一个spring-boot-starter-drools,因为我找不到其他可用的解决方案。我没有使用XML配置,因为最新的Spring配置都是使用Java完成的,我也建议您在这种情况下使用Java配置。

建议:

  1. 只需按照starter或示例项目中所述使用starter。
  2. 使用此工作配置将Drools集成到您的Spring Boot项目中:

    @Configuration
    public class DroolsAutoConfiguration {
    
    private static final String RULES_PATH = "rules/";
    
    @Bean
    public KieFileSystem kieFileSystem() throws IOException {
        KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();
        for (Resource file : getRuleFiles()) {
            kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + file.getFilename(), "UTF-8"));
        }        
        return kieFileSystem;
    }
    
    private Resource[] getRuleFiles() throws IOException {
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        return resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "**/*.*");
    }
    
    @Bean
    public KieContainer kieContainer() throws IOException {
        final KieRepository kieRepository = getKieServices().getRepository();
    
        kieRepository.addKieModule(new KieModule() {
            public ReleaseId getReleaseId() {
                return kieRepository.getDefaultReleaseId();
            }
        });
    
        KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem()); 
        kieBuilder.buildAll();
    
        return getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());
    }
    
    private KieServices getKieServices() {
        return KieServices.Factory.get();
    }
    
    @Bean
    public KieBase kieBase() throws IOException {
        return kieContainer().getKieBase();
    }
    
    @Bean
    public KieSession kieSession() throws IOException {
        return kieContainer().newKieSession();
    }
    
    @Bean
    public KModuleBeanFactoryPostProcessor kiePostProcessor() {
        return new KModuleBeanFactoryPostProcessor();
    }
    }
    
  3. 由于Spring Boot基于Spring 4.x,而kie-spring依赖于Spring 3.2,因此存在版本冲突。我一直遇到很愚蠢的异常,最终在我的pom.xml中排除了所有3.2依赖项。

  4. <dependency>
    <groupId>org.kie</groupId>
    <artifactId>kie-spring</artifactId>
    <version>${drools.version}</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </exclusion>
    </exclusions>
    </dependency>
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接