Maven Exec插件,ClassLoader ClassNotFoundException

时间:2016-12-27 09:40:36

标签: eclipse hibernate maven maven-plugin classnotfoundexception

我已经在StackOverflow上尝试过很多建议,并使用setup和pom.xml的许多组合测试了3天,但没有一个能够正常工作。请帮忙。

我从一个包含大量依赖项,spring-boot,hibernate等的大项目开始。然后我创建了另一个小型控制台项目,它导入并使用大项目中的一些类。他们不是父母和孩子的项目。我所做的就是将<dependency/>添加到子项目pom中,就像这样。 附:这个大项目有一个<parent/> spring-boot-starter-parent,并使用spring-boot-maven-plugin。

<dependency>
    <groupId>myGroup</groupId>
    <artifactId>bigProject</artifactId>
    <version>1.0.1</version>
</dependency>

这适用于带m2e的Eclipse,我只使用&#34; Run as&#34; java应用程序和小项目的工作原理。 但我需要在我的linux VM上上传并运行这些项目,它不使用GUI和Eclipse,只使用终端。

然后经过一些阅读,我尝试使用maven exec插件来运行这个小项目。我的步骤: 1.对大项目执行mvn clean install,确认它出现在我的/.m2本地存储库中。 2.在小项目上运行mvn compile 3.在小项目上运行mvn exec:java 它在第2步失败,小项目抛出包xxx类中的那些import ...不存在。 maven因编译错误而失败。

然后,我尝试简化问题。我创建了两个只有1个类,myLib和HelloWorld控制台应用程序的测试项目,然后我添加了myLib依赖项(pom)。 HelloWorld项目从myLib包中的类打印消息。运行步骤1到3.它有效。

public class App 
{
    public static void main( String[] args )
    {
        //SystemLog from big project, does not work
        //SystemLog log = new SystemLog();
        //log.setValue("test value");
        //System.out.println(log.getValue());

        //CustomMessage from myLib, works fine      
        CustomMessage cm = new CustomMessage();
        cm.setTheMessage("custom message");
        System.out.println(cm.getTheMessage() );
        System.out.println(CustomMessage.defaultMsg);

    }
}

小项目的pom.xml

<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>test</groupId>
    <artifactId>dependOnOthers</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>dependOnOthers</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>test</groupId>
            <artifactId>myLibrary</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com</groupId>
            <artifactId>bigproject</artifactId>
            <version>1.0.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.5.0</version>
                <executions>
                    <execution>

                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <includePluginDependencies>true</includePluginDependencies>
                    <mainClass>test.dependOnOthers.App</mainClass>
                    <!-- <arguments> <argument>argument1</argument> </arguments> -->

                    <!-- <arguments> <argument>-classpath</argument> <argument>target/lib/bigproject-1.0.1.jar</argument> 
                        </arguments> -->
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

然后我添加对big project的引用,尝试使用HelloWorld打印日志消息,它通过第2步,mvn编译,但是当我执行第3步时,mvn exec:java,java.lang.ClassLoader.loadClass()抛出ClassNotFoundException我新建一个SystemLog()实例的行,这是在大项目中定义的类。

概述: 目标:尝试使用Maven exec插件运行控制台应用程序,该插件依赖于另一个项目,安装在本地repo /.m2中 SystemLog类是一个带有hibernate注释的模型类。 1.小项目依赖大项目,mvn编译失败,包不存在。 2. HelloWorld依赖于myLib,工作正常。 3. HelloWorld依赖于大项目,在运行时因ClassNotFoundException而失败。

2 个答案:

答案 0 :(得分:1)

有点晚了,但我遇到了同样的错误,将项目从1.5.3迁移到2.1.4

我找到了解决此问题的方法。

Spring Boot在2.0.0+版本中更改了jar结构,因此您无需将类指定为<mainClass>test.dependOnOthers.App</mainClass>,只需将JarLauncher指向主入口即可。

当插件执行jar时,java将调用主要方法JarLauncher,并在他读取清单并调用Start-Class:中定义的类之后调用spring的几个代码。就您而言test.dependOnOthers.App.

<configuration>
<!-- Since version 2 of spring, the jar is packed in 
another way and has his main method here, don't worry in the MANIFEST file is described which file to boot -->
<mainClass>org.springframework.boot.loader.JarLauncher</mainClass>

Spring 1.0的旧结构是经典的Java方式,因此Java类加载器可以毫无问题地加载它,并在类路径中使用2.0.0+版本引用该类时,它们会复制用户类文件和相关性进入BOOT-INF中,因此java类加载器无法再加载它,您需要使用Spring类加载器来获取类实例。

答案 1 :(得分:0)

我有一个解决方法,知道导致问题的原因,但不知道所有细节,希望有人会对此发表评论,或详细说明答案。

导致此问题的是spring-boot-maven-plugin,我使用mvn spring-boot:run来运行spring-boot嵌入式tomcat服务器。这个插件似乎改变了.jar文件,可能是清单?

解决方法是删除此插件,运行mvn clean install,安装在本地存储库中的.jar将正常运行。在小项目上运行mvn compile。然后将插件添加回大项目,运行mvn spring-boot:run

我不知道插件更改会导致包含不存在的.jar,它是否会更改包名称?

我的解决方法很笨拙,如果有一种方法可以选择使用或不使用spring-boot-maven-plugin进行编译来定义maven目标,这样我就不需要为不同的构建更改pom(使用/不使用插件)。那将是一个更好的解决方案。