【问题标题】:Maven AppAssembler not finding classMaven AppAssembler 找不到类
【发布时间】:2013-03-05 16:04:21
【问题描述】:

尝试按照tutorial 修改现有的 Java/Tomcat 应用程序以在 Heroku 上部署,并遇到 AppAssembler 找不到入口类的一些问题。运行 target/bin/webapp(或部署到 Heroku)会得到Error: Could not find or load main class org.stopbadware.dsp.Main

但是,执行 java -cp target/classes:target/dependency/* org.stopbadware.dsp.Main 可以正常运行。这是 pom.xml 的相关部分:

  <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>appassembler-maven-plugin</artifactId>
      <version>1.1.1</version>
      <configuration>
          <assembleDirectory>target</assembleDirectory>
          <programs>
              <program>
                  <mainClass>org.stopbadware.dsp.Main</mainClass>
                  <name>webapp</name>
              </program>
          </programs>
      </configuration>
      <executions>
          <execution>
              <phase>package</phase>
              <goals>
                  <goal>assemble</goal>
              </goals>
          </execution>
      </executions>
    </plugin>

我的猜测是 mvn package 导致 AppAssembler 没有使用正确的类路径,有什么建议吗?

【问题讨论】:

  • 你能展示一下生成的脚本(.sh/.bat)是什么样子的吗?
  • 生成的脚本可以在pastebin.com/f9gbVMgx看到——未找到的Main类在PROJECTROOT/src/org/stopbadware/dsp/中

标签: java maven appassembler


【解决方案1】:

你的神器的包装必须设置为jar,否则找不到主类。

<pom>
  ...
  <packaging>jar</packaging>
  ...
</pom>

工件本身被添加到类路径的末尾,因此除了 JAR 文件之外没有任何效果。

【讨论】:

    【解决方案2】:

    试试:

    mvn clean package jar:jar appassembler:assemble
    

    【讨论】:

    • 这在我的本地机器上运行良好,但一旦部署到 Heroku 就不行了。据我所知,没有办法将 Heroku 的 maven 命令从默认的 mvn clean install 更改(将 jar:jar appassembler:assemble 添加到 MAVEN_OPTS 没有效果)。
    【解决方案3】:

    可以通过将"$BASEDIR"/classes 添加到生成脚本的 CLASSPATH 行来解决此问题。由于每次调用 mvn package 都会重写脚本,因此我编写了一个简短的脚本来调用 mvn package,然后添加所需的类路径条目。

    显然有点破解,但经过 8 多个小时尝试更“正确”的解决方案后,现在必须这样做。肯定会接受任何更优雅的方式来更正此处建议的类路径。

    【讨论】:

      【解决方案4】:

      前段时间我正在阅读该教程并且遇到了非常相似的问题。我采用了一些不同的方法,对我来说非常有效。

      首先,正如之前提到的,您需要将 POM 的类型保持为 jar (&lt;packaging&gt;jar&lt;/packaging&gt;) - 多亏了这一点,appassembler 插件将从您的类中生成一个 JAR 文件并将其添加到类路径。因此,您的错误将会消失。

      请注意,本教程 Tomcat 是从应用程序源目录中实例化的。在很多情况下这就足够了,但是请注意,使用这种方法,您将无法使用 Servlet @WebServlet 注释,因为源中的 /WEB-INF/classes 是空的,并且 Tomcat 将无法扫描您的 servlet 类。因此,该教程中的HelloServlet servlet 将不起作用,除非您按照here 的描述添加一些额外的 Tomcat 初始化(资源配置)(顺便说一句,您会发现更多关于该资源配置的 SO 问题)。

      我做了一些不同的方法:

      我在package 期间运行org.apache.maven.plugins:maven-war-plugin 插件(exploded 目标)并将生成的目录用作我的应用程序源目录。使用这种方法,我的 Web 应用程序目录将有 /WEB-INF/classes“填充”类。这反过来将允许 Tomcat 正确执行扫描作业(即 Servlet @WebServlet 注释将起作用)。

      我还必须在启动器类中更改应用程序的源代码:

      public static void main(String[] args) throws Exception {
          // Web application is generated in directory name as specified in build/finalName
          // in maven pom.xml
          String webappDirLocation = "target/embeddedTomcatSample/";
          Tomcat tomcat = new Tomcat();
      
          // ... remaining code does not change
      

      我添加的对 POM 的更改 - 包括在 appassembler 插件之前的 maven-war-plugin

      ...
      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-war-plugin</artifactId>
          <version>2.5</version>
          <executions>
              <execution>
                  <phase>package</phase>
                  <goals>
                      <goal>exploded</goal>
                  </goals>
              </execution>
          </executions>
      </plugin>
      ...
      

      请注意,exploded 目标被调用。

      希望小小的改变能帮到你。


      关于该教程和 maven 构建的另一条评论:请注意,编写该教程是为了展示构建应用程序并在 Heroku 中运行它是多么简单。但是,这不是 Maven 构建的最佳方法。

      Maven 建议您应该坚持每个 POM 生成一个工件。在您的情况下,应该有两个工件:

      • Tomcat 启动器
      • Tomcat 网络应用程序

      两者都应该构建为单独的 POM,并作为来自父 POM 的模块引用。如果您查看该教程的复杂性,则将其拆分为两个模块没有多大意义。但是,如果您的应用程序变得越来越复杂(并且启动器获得了一些额外的配置等),那么进行“拆分”将很有意义。事实上,已经创建了一些“Tomcat 启动器”库,因此您也可以使用其中的一个。

      【讨论】:

        【解决方案5】:

        可以设置CLASSPATH_PREFIX环境变量:

        export CLASSPATH_PREFIX=target/classes
        

        这将被添加到生成脚本的类路径中。

        【讨论】:

          【解决方案6】:

          首先你使用的是旧版本的appassembler-maven-plugin,当前版本是1.3。

          我不明白你为什么要定义

          <assembleDirectory>target</assembleDirectory>
          

          文件夹。有一个很好的默认值。所以通常你不需要它。除此之外,您不需要定义绑定到包阶段的显式执行,导致appassembler-maven-plugin is by default bound to the package phase

          此外,您可以使用useWildcardClassPath 配置选项来缩短您的类路径。

             <configuration>
               <useWildcardClassPath>true</useWildcardClassPath>
               <repositoryLayout>flat</repositoryLayout>
               ...
             </configruation>
          

          生成脚本的调用显示错误取决于文件夹中所有依赖项所在的存储库的位置与定义的生成脚本中的位置不同。

          【讨论】:

          • 这是我第一次使用 AppAssembler,所以我使用的是 Heroku 在前面提到的教程中的内容。使用 1.3,删除目录和执行引用,并添加通配符选项没有效果,仍然得到同样的错误。显然,在构建脚本时,它没有创建正确的类路径,遗憾的是 AppAssembler 文档非常有限,似乎没有说明如何显式添加到生成的类路径中。
          • 最好的方法是将示例项目(带有 pom.xml)放到jira 上并创建一个问题,或者私下将 pom.xml 文件发送给我,这样我就可以查看您的问题.
          • 您可以在 pastebin.com/11WmjBmB 看到 pom.xml - appassembler 生成的脚本位于 pastebin.com/f9gbVMgx 并且一旦通过添加 @987654329 修复了类路径中缺少的 PROJECTROOT/target/classes 条目,就可以正常运行@
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-03-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-06
          • 2021-02-18
          相关资源
          最近更新 更多