例外儿童服务在启动Optaplanner应用程序时没有父项
我有一个使用optaplanner的测试程序。没有直接使用KIE API,但它看起来像在幕后调用。这可能与我使用DROOLS进行分数计算有关。该程序从IDE或maven工作,但我想创建一个独立的jar,不需要maven。 我使用maven程序集插件来构建一个包含所有依赖包的独立运行的胖jar包。例外儿童服务在启动Optaplanner应用程序时没有父项
当我运行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)
线Main.java的38只两行到应用程序中,因此所有它做的加载配置文件,并尝试建立求解。
SolverFactory<Plan> solverFactory = SolverFactory.createFromXmlResource(
"com/github/wshackle/optaplannertest/solverConfig.xml");
Solver<Plan> solver = solverFactory.buildSolver();
solverConfig.xml是:
<solver>
<!-- Domain model configuration -->
<scanAnnotatedClasses>
<packageInclude>com.github.wshackle.optaplannertest.model</packageInclude>
</scanAnnotatedClasses>
<!-- Score configuration -->
<scoreDirectorFactory>
<scoreDrl>com/github/wshackle/optaplannertest/scoreRules.drl</scoreDrl>
</scoreDirectorFactory>
<!-- Optimization algorithms configuration -->
<termination>
<secondsSpentLimit>5</secondsSpentLimit>
</termination>
</solver>
在投是有关我的聚甲醛是这样的:
<?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>
<groupId>com.github.wshackle</groupId>
<artifactId>OptaPlannerTest</artifactId>
<version>1.4-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<optiplanner.version>7.3.0.Final</optiplanner.version>
<main.class>com.github.wshackle.optaplannertest.Main</main.class>
</properties>
<dependencies>
<dependency>
<groupId>org.optaplanner</groupId>
<artifactId>optaplanner-core</artifactId>
<version>${optiplanner.version}</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-api</artifactId>
<version>${optiplanner.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>runtime</scope>
<version>1.2.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
<archive>
<manifest>
<mainClass>${main.class}</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
文件的罐中的完整列表显示在 https://gist.github.com/wshackle/8887aac8a10e8c4b1f862a4bda288e41
我用grep来验证他们似乎包括预期的cl驴每个罐子扶养:
> grep -c org/kie/api jarlisting.txt
391
> grep -c org/kie/internal jarlisting.txt
364
> grep -c org/optaplanner/core jarlisting.txt
841
> grep -c org/drools/core jarlisting.txt
2175
> grep -c org/drools/compiler jarlisting.txt
832
的问题是,下面的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
只有一个版本可以被包括在内。当建立求解器时,Optaplanner库将在当前的线程上下文类加载器上间接调用getResources("META-INF/kie.conf")
。如果类路径中有多个jar,则会找到所有这些jar,并且生成的配置将是解析所有这些jar的产品。为了使这个工作在一个简单的超级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);
运行“命令mvn依赖:树”,你会看到optaplanner核心取决于纪伊的API,纪伊内部的API,流口水核和滴料编译器。其中一个将会在你的胖罐子里失踪。
我添加了问题的文件列表链接。所有的依赖似乎都在那里。 – WillShackleford
我是有以下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>
删除
<index>true</index>
解决我的问题同样的问题。希望这可以帮助其他人。
这从您的IDE工作,对吧?在IDE中它没有做任何胖子的魔法。 –
@GeoffreyDeSmet对。我相信IDE使用一个长类路径,其中包含一个带有裸类文件而不是JAR的目录。不幸的是,要区分JAR中包含的内容和类路径中的内容之间的区别并不容易,或者即使是这个问题也是不容易的。 – WillShackleford
[相关jira](https://issues.jboss.org/browse/DROOLS-1761)链接到其他2个类似的问题。 –