【问题标题】:How to tell Maven to build an executable jar如何告诉 Maven 构建一个可执行的 jar
【发布时间】:2011-02-25 05:32:13
【问题描述】:

这似乎应该很简单,但我还没有弄清楚,也没有从阅读文档和搜索网络中获得太多帮助。为了学习在多模块项目中使用 Maven (2.2.1),我使用 Maven 创建了一个简单的项目 P,其中包含一个类 C(包含主类)和子类 S。当我运行 mvn install 时,构建运行并产生一个 BUILD SUCCESSFUL 消息。但是,当我运行生成的 C jar 时,我得到一个异常:“线程中的异常“main”java.lang.NoClassDefFoundError:P/S”

目录结构(不显示src等子目录)为:

P
|--C
|--S

P目录下的pom.xml目前为:

<?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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>P</groupId>
  <artifactId>P</artifactId>
  <packaging>pom</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>P</name>
  <url>http://maven.apache.org</url>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>P</groupId>
        <artifactId>C</artifactId>
        <version>${project.version}</version>
        <scope>compile</scope>
      </dependency>
      <dependency>
        <groupId>P</groupId>
        <artifactId>S</artifactId>
        <version>${project.version}</version>  
        <scope>compile</scope>
      </dependency>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <mainClass>P.C</mainClass>
              <packageName>P.C</packageName>
            </manifest>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <modules>
    <module>C</module>
    <module>S</module>
  </modules>

</project>

C 中的 pom.xml 是:

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <artifactId>P</artifactId>
    <groupId>P</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <groupId>P</groupId>
  <artifactId>C</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>C</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>P</groupId>
      <artifactId>S</artifactId>
      <version>${project.version}</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

而S中的pom.xml是:

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <artifactId>P</artifactId>
    <groupId>P</groupId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  <groupId>P</groupId>
  <artifactId>S</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>S</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

以上都是经过多次尝试的最新版本。

对于这个简单的学习练习,Java 类是:

P/C/src/main/java/P/C.java:

package P;

public class C
{
    public static void main( String[] args )
    {
        System.out.println( "Hello World!" );
        S o = new S();
        o.sayHey();
    }
}

和S/src/main/java/P/S.java:

package P;

public class S
{
    public void sayHey()
    {
        System.out.println("Hey!");
    }
}

那么,如何告诉 Maven 在 C jar 中包含 S 类?

【问题讨论】:

    标签: java maven-2 packages


    【解决方案1】:

    默认情况下,Maven 不会在工件中包含依赖项:要运行 P,您的类路径中仍然需要 S。

    这通常不是问题,因为 maven 本身使用传递依赖:例如,如果您有另一个项目依赖于 P,它会自动将 P 和 S 都放在您的类路径中。

    如果你想创建一个“uber-jar”:一个包含所有依赖项的自包含 jar,请查看“shade”插件:http://maven.apache.org/plugins/maven-shade-plugin/

    【讨论】:

    • 感谢您的回答。正如我的回答所表明的那样,我能够使用 maven-assembly-plugin 而不是 shade。另外,感谢您提醒我查看类路径的内容;在找到解决方案的过程中,我验证了我的代码可以使用java -cp C/target/classes:S/target/classes/ P.C 运行。
    【解决方案2】:

    经过更多研究,我找到了一种方法来告诉 Maven 构建一个包含所有需要的类的 jar 文件。我唯一需要更改的 pom 是在 P 目录中。首先,必须从 build-plugins 部分中删除以下部分:

        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <mainClass>P.C</mainClass>
              <packageName>P.C</packageName>
            </manifest>
          </archive>
        </configuration>
    

    我把它放在了:

        <artifactId>maven-assembly-plugin</artifactId>
        <executions>
          <execution>
            <id>create-executable-jar</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
            <configuration>
              <descriptorRefs>
                <descriptorRef>jar-with-dependencies</descriptorRef>
              </descriptorRefs>
              <archive>
                <manifest>
                  <mainClass>P.C</mainClass>
                  <packageName>P.C</packageName>
                </manifest>
              </archive>
            </configuration>
          </execution>
        </executions>
    

    【讨论】:

      【解决方案3】:

      maven exec 插件可能会解决您的问题。您可以使用它来运行 C.jar,它将管理类路径(并确保包含 S.jar)。

      在你的 P pom.xml 中添加类似的内容:

      <project>
        ...
        <build>
          <plugins>
            <plugin>
              <groupId>org.codehaus.mojo</groupId>
              <artifactId>exec-maven-plugin</artifactId>
              <version>1.1</version>
              <executions>
                <execution>
                  ...
                  <goals>
                    <goal>java</goal>
                  </goals>
                </execution>
              </executions>
              <configuration>
                <mainClass>P.C</mainClass>
              </configuration>
            </plugin>
          </plugins>
        </build>
         ...
      </project>
      

      那么你应该可以像这样运行程序:

      mvn exec:java -Dexec.mainClass="P.C"
      

      【讨论】:

      • 虽然我没有对我的 pom 进行任何更改,但我确实尝试了您建议的命令;然而,这只是给了我更多的例外。你有关于如何配置 pom 以使其工作的详细信息吗?
      猜你喜欢
      • 2010-12-21
      • 2019-05-22
      • 2017-03-19
      • 2018-01-31
      • 2017-08-08
      • 2014-06-06
      • 1970-01-01
      相关资源
      最近更新 更多