Drools 启动Optaplanner应用程序时,异常子服务没有父服务

Drools 启动Optaplanner应用程序时,异常子服务没有父服务,drools,optaplanner,kie,Drools,Optaplanner,Kie,我有一个使用optaplanner的测试程序。KIE API没有直接使用,但看起来它们是在幕后被调用的。这可能与我使用DROOLS计算分数有关。该程序可以从IDE或通过maven工作,但我想创建一个不需要maven的独立jar。 我使用maven assembly插件构建了一个fat jar,其中包含了独立运行的所有依赖项 当我运行java-jar target/OptaPlannerTest-1.4-SNAPSHOT-jar-with-dependencies.jar时,我得到: Except

我有一个使用optaplanner的测试程序。KIE API没有直接使用,但看起来它们是在幕后被调用的。这可能与我使用DROOLS计算分数有关。该程序可以从IDE或通过maven工作,但我想创建一个不需要maven的独立jar。 我使用maven assembly插件构建了一个fat jar,其中包含了独立运行的所有依赖项

当我运行java-jar target/OptaPlannerTest-1.4-SNAPSHOT-jar-with-dependencies.jar时,我得到:

Exception in thread "main" java.lang.ExceptionInInitializerError
        at org.kie.api.internal.utils.ServiceRegistry.getInstance(ServiceRegistry.java:27)
        at org.kie.api.KieServices$Factory$LazyHolder.<clinit>(KieServices.java:332)
        at org.kie.api.KieServices$Factory.get(KieServices.java:339)
        at org.optaplanner.core.config.score.director.ScoreDirectorFactoryConfig.buildDroolsScoreDirectorFactory(ScoreDirectorFactoryConfig.java:460)
        at org.optaplanner.core.config.score.director.ScoreDirectorFactoryConfig.buildScoreDirectorFactory(ScoreDirectorFactoryConfig.java:331)
        at org.optaplanner.core.config.solver.SolverConfig.buildSolver(SolverConfig.java:220)
        at org.optaplanner.core.impl.solver.AbstractSolverFactory.buildSolver(AbstractSolverFactory.java:61)
        at com.github.wshackle.optaplannertest.Main.main(Main.java:38)
Caused by: java.lang.RuntimeException: Child services [org.kie.api.internal.assembler.KieAssemblers] have no parent
        at org.kie.api.internal.utils.ServiceDiscoveryImpl.buildMap(ServiceDiscoveryImpl.java:186)
        at org.kie.api.internal.utils.ServiceDiscoveryImpl.getServices(ServiceDiscoveryImpl.java:97)
        at org.kie.api.internal.utils.ServiceRegistryImpl.<init>(ServiceRegistryImpl.java:36)
        at org.kie.api.internal.utils.ServiceRegistryImpl$LazyHolder.<clinit>(ServiceRegistryImpl.java:32)

运行“mvn依赖项:树”,您将看到optaplanner核心依赖于kie api、kie内部api、drools核心和drools编译器。其中一个会在你的脂肪罐中丢失。

我对以下pom也有同样的问题

    <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
..
    <dependencies>
        <dependency>
            <groupId>org.optaplanner</groupId>
            <artifactId>optaplanner-core</artifactId>
            <version>${optaPlanner.version}</version>
        </dependency>    
...
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>${jar.plugin.version}</version>
                <configuration>
                    <archive>
                        <addMavenDescriptor>false</addMavenDescriptor>
                        <compress>false</compress>                
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>libs/</classpathPrefix>
                            <mainClass>${mainClass}</mainClass>
                        </manifest> 
                        <index>true</index>
                        <manifestEntries>
                            <impl-version>${project.version}</impl-version>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
           <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>${dependency.plugin.version}</version>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/libs</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>${assembly.plugin.version}</version>
                <configuration>
                    <descriptors>
                        <descriptor>assembly/release.xml</descriptor>
                    </descriptors>
                    <finalName>${distribution.file.name}</finalName>
                    <outputDirectory>${project.build.directory}/dist</outputDirectory>
                    <workDirectory>${project.build.directory}/assembly/work</workDirectory>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

4.0.0
..
org.optaplanner
optaplanner核心
${optaPlanner.version}
...
org.apache.maven.plugins
maven jar插件
${jar.plugin.version}
假的
假的
真的
自由基/
${mainClass}
真的
${project.version}
org.apache.maven.plugins
maven依赖插件
${dependency.plugin.version}
复制依赖项
包裹
复制依赖项
${project.build.directory}/libs
org.apache.maven.plugins
maven汇编插件
${assembly.plugin.version}
assembly/release.xml
${distribution.file.name}
${project.build.directory}/dist
${project.build.directory}/assembly/work
组装
包裹
单一的
移除

<index>true</index>
true

解决了我的问题。希望这对其他人也有帮助。

问题是以下jar文件都包含不同版本的
META-INF/kie.conf

optaplanner-core-7.3.0.Final.jar
kie-internal/7.3.0.Final/kie-internal-7.3.0.Final.jar 
drools-core-7.3.0.Final.jar
drools-compiler-7.3.0.Final.jar
当maven assembly插件将它们放在一起时,只能包含一个版本的
META-INF/kie.conf
。在构建解算器时,Optaplanner库将在当前线程上下文类加载器上间接调用
getResources(“META-INF/kie.conf”)
。如果类路径上有多个JAR,那么将找到所有JAR,并且生成的配置将是解析所有JAR的结果。为了在单个胖uber jar中实现这一点,需要将kie.conf文件移动到不同的文件名,并重载一个类加载器,以指示库在新名称处使用它们。(也可以将它们合并到一个kie.conf文件中)

提取并移动kie.conf文件:

 jar -xf ~/.m2/repository/org/optaplanner/optaplanner-core/7.3.0.Final/optaplanner-core-7.3.0.Final.jar META-INF/kie.conf
 mv META-INF/kie.conf src/main/resources/optaplanner-core-kie.conf
 jar -xf ~/.m2/repository/org/kie/kie-internal/7.3.0.Final/kie-internal-7.3.0.Final.jar META-INF/kie.conf
 mv META-INF/kie.conf src/main/resources/kie-internal-kie.conf
 jar -xf ~/.m2/repository/org/drools/drools-core/7.3.0.Final/drools-core-7.3.0.Final.jar META-INF/kie.conf
 mv META-INF/kie.conf src/main/resources/drools-core-kie.conf
 jar -xf ~/.m2/repository/org/drools/drools-compiler/7.3.0.Final/drools-compiler-7.3.0.Final.jar META-INF/kie.conf
 mv META-INF/kie.conf src/main/resources/drools-compiler-kie.conf
然后重载并设置线程上下文加载器

    ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
    URL[] localKieConfUrls = new URL[]{
        ClassLoader.getSystemResource("optaplanner-core-kie.conf"),
        ClassLoader.getSystemResource("kie-internal-kie.conf"),
        ClassLoader.getSystemResource("drools-core-kie.conf"),
        ClassLoader.getSystemResource("drools-compiler-kie.conf")
    };
    ClassLoader newClassLoader = new ClassLoader(oldClassLoader) {

        private final URL[] kieConfUrls = localKieConfUrls;
        @Override
        public Enumeration<URL> getResources(String name) throws IOException {
            if ("META-INF/kie.conf".equals(name)) {
                return new Enumeration<URL>() {
                    int index;
                    @Override
                    public boolean hasMoreElements() {
                        return index < kieConfUrls.length;
                    }

                    @Override
                    public URL nextElement() {
                        return kieConfUrls[index++];
                    }
                };
            }
            return super.getResources(name);
        }

    };
    Thread.currentThread().setContextClassLoader(newClassLoader);
ClassLoader oldClassLoader=Thread.currentThread().getContextClassLoader();
URL[]localkiefolls=新URL[]{
getSystemResource(“optaplanner core kie.conf”),
getSystemResource(“kie internal kie.conf”),
getSystemResource(“drools core kie.conf”),
getSystemResource(“drools编译器kie.conf”)
};
ClassLoader newClassLoader=新类加载器(旧类加载器){
私有最终URL[]kieConfUrls=localKieConfUrls;
@凌驾
公共枚举getResources(字符串名称)引发IOException{
if(“META-INF/kie.conf.equals(name)){
返回新枚举(){
整数指数;
@凌驾
公共布尔值hasMoreElements(){
返回指数
对于使用maven shade插件的用户,这里有一个建议的修复程序,它将使用AppendingTransformer将META-INF/kie.conf复制到单个文件中

我同意问题如@WillSchackleford所述:


问题是以下jar文件都包含不同版本的META-INF/kie.conf:

   optaplanner-core-7.3.0.Final.jar
   kie-internal/7.3.0.Final/kie-internal-7.3.0.Final.jar 
   drools-core-7.3.0.Final.jar
   drools-compiler-7.3.0.Final.jar
当maven汇编插件将它们放在一起时,只能包含一个版本的META-INF/kie.conf

组合所有这些kie.conf文件的最佳技巧是在maven配置中使用
转换器,如下所示:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <!-- get all project dependencies -->
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <!-- MainClass in mainfest make a executable jar -->
        <archive>
            <manifest>
                <mainClass>com.paconsulting.powerpeers.PowerPeersDemo</mainClass>
            </manifest>
        </archive>
        <transformers>
            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                <resource>META-INF/kie.conf</resource>
            </transformer>
        </transformers>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <!-- bind to the packaging phase -->
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

org.apache.maven.plugins
maven汇编插件
带有依赖项的jar
com.paconsulting.powerpeers.PowerPeersDemo
META-INF/kie.conf
 jar -xf ~/.m2/repository/org/optaplanner/optaplanner-core/7.3.0.Final/optaplanner-core-7.3.0.Final.jar META-INF/kie.conf
 mv META-INF/kie.conf src/main/resources/optaplanner-core-kie.conf
 jar -xf ~/.m2/repository/org/kie/kie-internal/7.3.0.Final/kie-internal-7.3.0.Final.jar META-INF/kie.conf
 mv META-INF/kie.conf src/main/resources/kie-internal-kie.conf
 jar -xf ~/.m2/repository/org/drools/drools-core/7.3.0.Final/drools-core-7.3.0.Final.jar META-INF/kie.conf
 mv META-INF/kie.conf src/main/resources/drools-core-kie.conf
 jar -xf ~/.m2/repository/org/drools/drools-compiler/7.3.0.Final/drools-compiler-7.3.0.Final.jar META-INF/kie.conf
 mv META-INF/kie.conf src/main/resources/drools-compiler-kie.conf
    ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
    URL[] localKieConfUrls = new URL[]{
        ClassLoader.getSystemResource("optaplanner-core-kie.conf"),
        ClassLoader.getSystemResource("kie-internal-kie.conf"),
        ClassLoader.getSystemResource("drools-core-kie.conf"),
        ClassLoader.getSystemResource("drools-compiler-kie.conf")
    };
    ClassLoader newClassLoader = new ClassLoader(oldClassLoader) {

        private final URL[] kieConfUrls = localKieConfUrls;
        @Override
        public Enumeration<URL> getResources(String name) throws IOException {
            if ("META-INF/kie.conf".equals(name)) {
                return new Enumeration<URL>() {
                    int index;
                    @Override
                    public boolean hasMoreElements() {
                        return index < kieConfUrls.length;
                    }

                    @Override
                    public URL nextElement() {
                        return kieConfUrls[index++];
                    }
                };
            }
            return super.getResources(name);
        }

    };
    Thread.currentThread().setContextClassLoader(newClassLoader);
   optaplanner-core-7.3.0.Final.jar
   kie-internal/7.3.0.Final/kie-internal-7.3.0.Final.jar 
   drools-core-7.3.0.Final.jar
   drools-compiler-7.3.0.Final.jar
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <!-- get all project dependencies -->
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <!-- MainClass in mainfest make a executable jar -->
        <archive>
            <manifest>
                <mainClass>com.paconsulting.powerpeers.PowerPeersDemo</mainClass>
            </manifest>
        </archive>
        <transformers>
            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                <resource>META-INF/kie.conf</resource>
            </transformer>
        </transformers>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <!-- bind to the packaging phase -->
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-dependency-plugin</artifactId>
 <executions>
   <execution>
    <id>copy-dependencies</id>
    <phase>prepare-package</phase>
    <goals>
     <goal>copy-dependencies</goal>
    </goals>
    <configuration>
     <outputDirectory>${project.build.directory}/lib</outputDirectory>
     <overWriteReleases>false</overWriteReleases>
     <overWriteSnapshots>false</overWriteSnapshots>
     <overWriteIfNewer>true</overWriteIfNewer>
    </configuration>
   </execution>
  </executions>
 </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
  <configuration>
   <archive>
    <manifest>
     <addClasspath>true</addClasspath>
     <classpathPrefix>lib/</classpathPrefix>
     <mainClassMain-Class</mainClass>
    </manifest>
   </archive>
  </configuration>
</plugin>