错误无法找到或加载主 class

Error Could not find or load main class

我有一个嵌入式码头 java 应用程序,它会自行启动并在上述路线上为请求提供服务。测试时它运行良好。现在我想通过 war 文件部署这个 java 应用程序,它给我带来了问题。

  1. 而 运行 java -jar server--1.0-SNAPSHOT.war :它给我的错误是 Error: Could not find or load main class com.server.core.App

  2. 这个会在第一个问题解决后出现,如何将所有依赖项包含到war文件中。

这是我的 pom.xml https://gist.github.com/shadow-fox/24ec2c7d40f4b0e6aae5

<?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.server</groupId>
    <artifactId>server</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>${jetty-version}</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>${jetty-version}</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-util</artifactId>
            <version>${jetty-version}</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet-core</artifactId>
            <version>${jersey-version}</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-server</artifactId>
            <version>${jersey-version}</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-jetty-http</artifactId>
            <version>${jersey-version}</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-moxy</artifactId>
            <version>${jersey-version}</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-client</artifactId>
            <version>${jersey-version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>${jackson-version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson-version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>${jackson-version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j-version}</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit-version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jdk-version>1.8</jdk-version>
        <jetty-version>9.3.3.v20150827</jetty-version>
        <jersey-version>2.21</jersey-version>
        <junit-version>4.12</junit-version>
        <jackson-version>2.6.1</jackson-version>
        <log4j-version>2.3</log4j-version>
        <mvn-compiler>3.3</mvn-compiler>
        <mvn-war>2.6</mvn-war>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${mvn-compiler}</version>
                <configuration>
                    <source>${jdk-version}</source>
                    <target>${jdk-version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>${mvn-war}</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <mainClass>com.server.core.App</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

我可能搞砸了的地方:classpathPrefix 不确定要在此处设置什么。我的 类 默认转到目标目录(使用 IDEA Intellij)。 mainClass 确实存在于同一路径上。

App.java

package com.server.core;

import com.server.core.filters.RequestFilter;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.servlet.ServletContainer;

import java.util.EnumSet;

import javax.servlet.DispatcherType;

public class App {

    private static final Logger logger = LogManager.getLogger(App.class);

    public static void main(String[] args) throws Exception {

        Server server = new Server();
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(8080);
        server.addConnector(connector);

        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        context.addFilter(RequestFilter.class, "/*", EnumSet.of(DispatcherType.INCLUDE,
                DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR,
                DispatcherType.FORWARD));
        server.setHandler(context);

        ServletHolder servletHolder = new ServletHolder(ServletContainer.class);
        servletHolder.setInitOrder(0);
        servletHolder.setInitParameter("jersey.config.server.provider.packages", "com/server/core/endpoints");
        context.addServlet(servletHolder, "/*");

        try {
            server.start();
            logger.debug("Server started");
            logger.debug(server);
            server.join();
        } catch (Throwable t) {
            logger.error(System.err);
        } finally {
            server.destroy();
        }
    }
}

有很多与此类似但找不到此用例的问题。

更新::现在已经过时了。正如我已经按照@joakim-erdfelt 的建议进行的那样。 正如@Jens 在评论中提到的,我已经将包装从 war 更改为 jar 并使用 maven-shaded-plugin 我能够 运行 应用程序而没有任何问题。 这是 pom.xml

的修改版本
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>${mvn-shade}</version>
  <executions>
      <execution>
          <phase>package</phase>
          <goals>
              <goal>shade</goal>
          </goals>
          <configuration>
              <filters>
                  <filter>
                      <artifact>*:*</artifact>
                      <excludes>
                          <exclude>META-INF/*.SF</exclude>
                          <exclude>META-INF/*.DSA</exclude>
                          <exclude>META-INF/*.RSA</exclude>
                      </excludes>
                  </filter>
              </filters>
              <transformers>
                  <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                      <mainClass>com.igp.core.App</mainClass>
                  </transformer>
              </transformers>
          </configuration>
      </execution>
  </executions>
</plugin>

请注意,我也从插件列表中删除了 maven-jar-plugin。

使用 Jetty 自执行 WAR 是可能的,但是设置起来有点棘手,因为各种 maven 插件往往会撤消自执行 WAR 的努力。

Jetty 项目维护了这样一个示例项目。

https://github.com/jetty-project/embedded-jetty-live-war

关键在于它的组装方式。

该项目有 4 个主要部分:

  • /thewebapp/ - 这是 WAR 文件,webapp,因为它以其原生格式存在,具有正常的 Maven war 和一个生成的工件,它只是一个 WAR 不是(还)自执行的文件。
  • /theserver/ - 这是您自定义的嵌入式 Jetty 服务器 jetty.livewar.ServerMain.main(String args[]),用于初始化您的 Jetty 服务器及其 WebApp。该项目也是您自定义 JDBC 服务器库、JNDI、日志记录等内容的地方。该项目生成一个 uber-jar,其中包含 运行 服务器所需的所有依赖项。特别注意使用 maven-shade-plugin 合并 META-INF/services/ 个文件。
  • /server-bootstrap/ - 这包含 2 个小的 类,它们根据实时 WAR 中的内容设置一个 LiveWarClassLoader,然后 运行s jetty.livewar.ServerMain.main(String args[]) 来自这个新的类加载器。此项目还包含直播 WAR 将 need/use
  • 的直播 META-INF/MANIFEST.MF
  • /livewar-assembly/ - 这是将上述 3 个项目绑定到一个 Live/Executable WAR 文件中的项目。来自上述 3 个项目的工件由 maven-assembly-plugin 解包,并放置在它们将发挥最大功能(和安全)的位置。例如,来自 /theserver/ 的服务器 类 被放置在 /WEB-INF/jetty-server/ 中,使访问 WAR 文件的 Web 客户端无法访问它们。

注意:新组装的 WAR 文件中有 3 个文件,您应该是其中的一个 war,因为如果您使用 Web 客户端,这些文件可以作为静态内容下载使用此设置。

/jetty/bootstrap/JettyBootstrap.class
/jetty/bootstrap/LiveWarClassLoader.class
/META-INF/MANIFEST.MF

示例项目的设置方式使得这些 bootstrap 文件中的信息不应泄露有关您的服务器或其操作的私人或敏感信息。只是 Webapp 可以作为 Live/Executable WAR 文件启动。

4 个模块产生 1 个可执行工件可能看起来很奇怪,但您必须了解您正在处理 3 件事来设置此环境。

  1. WebApp 本身(及其所有 类 和 jar)- 这是 /thewebapp/
  2. 类 表示服务器主及其要求。 (不要与 WebApp 类 混在一起)- 这是 /theserver/
  3. Main-Class 可执行文件智能地将上述 2 个绑定在一起(以免给您自己造成安全问题)- 这是 /server-bootstrap/

最后一个模块,/livewar-assembly/只是将这 3 个部分连接成一个统一的整体。

我知道使用 maven-shade-plugin 可能很诱人,但您将无法完成以下所有要求(您可以完成其中一些,然后尝试修复其他人,但最终打破其他人,玩没完没了的怪人游戏)...

  1. 将服务器 jar 放在无法通过 Live WebApp 访问的地方。
  2. 智能合并服务器端(并且仅服务器端)META-INF/services
  3. 将 BootStrap 类 添加到 WAR 的根。
  4. 使用用于 bootstrap 的自定义 META-INF/MANIFEST.MF(无需从所有服务器依赖项中获取 META-INF/MANIFEST.MF 文件的合并副本)