错误无法找到或加载主 class
Error Could not find or load main class
我有一个嵌入式码头 java 应用程序,它会自行启动并在上述路线上为请求提供服务。测试时它运行良好。现在我想通过 war 文件部署这个 java 应用程序,它给我带来了问题。
而 运行 java -jar server--1.0-SNAPSHOT.war
:它给我的错误是 Error: Could not find or load main class com.server.core.App
这个会在第一个问题解决后出现,如何将所有依赖项包含到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 件事来设置此环境。
- WebApp 本身(及其所有 类 和 jar)- 这是
/thewebapp/
- 类 表示服务器主及其要求。 (不要与 WebApp 类 混在一起)- 这是
/theserver/
Main-Class
可执行文件智能地将上述 2 个绑定在一起(以免给您自己造成安全问题)- 这是 /server-bootstrap/
最后一个模块,/livewar-assembly/
只是将这 3 个部分连接成一个统一的整体。
我知道使用 maven-shade-plugin
可能很诱人,但您将无法完成以下所有要求(您可以完成其中一些,然后尝试修复其他人,但最终打破其他人,玩没完没了的怪人游戏)...
- 将服务器 jar 放在无法通过 Live WebApp 访问的地方。
- 智能合并服务器端(并且仅服务器端)
META-INF/services
。
- 将 BootStrap 类 添加到 WAR 的根。
- 使用用于 bootstrap 的自定义
META-INF/MANIFEST.MF
(无需从所有服务器依赖项中获取 META-INF/MANIFEST.MF
文件的合并副本)
我有一个嵌入式码头 java 应用程序,它会自行启动并在上述路线上为请求提供服务。测试时它运行良好。现在我想通过 war 文件部署这个 java 应用程序,它给我带来了问题。
而 运行
java -jar server--1.0-SNAPSHOT.war
:它给我的错误是Error: Could not find or load main class com.server.core.App
这个会在第一个问题解决后出现,如何将所有依赖项包含到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
,然后 运行sjetty.livewar.ServerMain.main(String args[])
来自这个新的类加载器。此项目还包含直播 WAR 将 need/use 的直播 /livewar-assembly/
- 这是将上述 3 个项目绑定到一个 Live/Executable WAR 文件中的项目。来自上述 3 个项目的工件由 maven-assembly-plugin 解包,并放置在它们将发挥最大功能(和安全)的位置。例如,来自/theserver/
的服务器 类 被放置在/WEB-INF/jetty-server/
中,使访问 WAR 文件的 Web 客户端无法访问它们。
META-INF/MANIFEST.MF
注意:新组装的 WAR 文件中有 3 个文件,您应该是其中的一个 war,因为如果您使用 Web 客户端,这些文件可以作为静态内容下载使用此设置。
/jetty/bootstrap/JettyBootstrap.class
/jetty/bootstrap/LiveWarClassLoader.class
/META-INF/MANIFEST.MF
示例项目的设置方式使得这些 bootstrap 文件中的信息不应泄露有关您的服务器或其操作的私人或敏感信息。只是 Webapp 可以作为 Live/Executable WAR 文件启动。
4 个模块产生 1 个可执行工件可能看起来很奇怪,但您必须了解您正在处理 3 件事来设置此环境。
- WebApp 本身(及其所有 类 和 jar)- 这是
/thewebapp/
- 类 表示服务器主及其要求。 (不要与 WebApp 类 混在一起)- 这是
/theserver/
Main-Class
可执行文件智能地将上述 2 个绑定在一起(以免给您自己造成安全问题)- 这是/server-bootstrap/
最后一个模块,/livewar-assembly/
只是将这 3 个部分连接成一个统一的整体。
我知道使用 maven-shade-plugin
可能很诱人,但您将无法完成以下所有要求(您可以完成其中一些,然后尝试修复其他人,但最终打破其他人,玩没完没了的怪人游戏)...
- 将服务器 jar 放在无法通过 Live WebApp 访问的地方。
- 智能合并服务器端(并且仅服务器端)
META-INF/services
。 - 将 BootStrap 类 添加到 WAR 的根。
- 使用用于 bootstrap 的自定义
META-INF/MANIFEST.MF
(无需从所有服务器依赖项中获取META-INF/MANIFEST.MF
文件的合并副本)