问题
I have a embedded jetty java application, which starts itself up and serving requests at the mentioned routes. While testing it is working good. Now that I want to deploy this java application via war file it is giving me issues.
While running
java -jar server--1.0-SNAPSHOT.war
: It is giving me error asError: Could not find or load main class com.server.core.App
This one will come after the 1st issue is fixed, how to include all the dependencies into the war file.
Here is my
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>
Where I might have messed up: The classpathPrefix not sure what to set here. My classes goes to target dir as default (Using IDEA Intellij) . The mainClass does exist on the same path.
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();
}
}
}
There are lot of questions similar to this but couldn't find for this use-case.
回答1:
A self executing WAR with Jetty is possible, however its a bit tricky to setup, as the various maven plugins tend to undo the efforts of a Self Executing WAR.
The Jetty Project maintains such an example project.
https://github.com/jetty-project/embedded-jetty-live-war
The key is how its assembled.
The project has 4 main parts:
/thewebapp/
- this is the WAR file, the webapp, as it exists in its native format, with normal maven war and a produced artifact that is just a WAR file that isn't (yet) self-executing./theserver/
- this is the Embedded Jetty Serverjetty.livewar.ServerMain.main(String args[])
which you customize to initialize your Jetty server and its WebApp. This project also is the place where you customize for things like JDBC servers libraries, JNDI, logging, etc. This project produces a uber-jar with all of the dependencies needed to run the server. Special care is taken with the maven-shade-plugin to mergeMETA-INF/services/
files./server-bootstrap/
- this contains 2 small classes that sets up aLiveWarClassLoader
from the content in the live WAR and then runsjetty.livewar.ServerMain.main(String args[])
from this new ClassLoader. This project also contains the liveMETA-INF/MANIFEST.MF
that the live WAR will need/use/livewar-assembly/
- this is the project that ties together the above 3 projects into a Live/Executable WAR file. The artifacts from from the above 3 projects are unpacked by the maven-assembly-plugin and put into place where they will be most functional (and safe). For example, the server classes from/theserver/
are placed in/WEB-INF/jetty-server/
to make them inaccessible from Web Clients accessing the WAR file.
Note: there are 3 files present in your new assembled WAR file that you should be aware of, as these files can be downloaded by a Web Client as static content if you use this setup.
/jetty/bootstrap/JettyBootstrap.class
/jetty/bootstrap/LiveWarClassLoader.class
/META-INF/MANIFEST.MF
The example project is setup in such a way that information present in these bootstrap files should not reveal private or sensitive information about your Server or its operations. Merely that the Webapp can be started as a Live/Executable WAR file.
It might seem strange to have 4 modules result in 1 executable artifact, but you have to understand you are dealing with 3 things to set this environment up.
- The WebApp itself (with all of its classes and jars) - this is
/thewebapp/
- The Classes representing the Server Main, and its requirements. (not to be co-mingled with the WebApp classes) - this is
/theserver/
- The
Main-Class
executable that binds the above 2 together intelligently (so as to not create a security issue for yourself) - this is/server-bootstrap/
The final module, /livewar-assembly/
just ties together the 3 parts into a unified whole.
I know it might be tempting to use maven-shade-plugin
for it all, but you will not be able to accomplish all of the following requirements (you can accomplish some of them, and then attempt to fix for the others, but ultimately break the others, playing an endless game of wack-a-mole) ...
- Placing the Server jars in a place where they cannot be accessed via the Live WebApp.
- Merging Server side (and ONLY the server side)
META-INF/services
intelligently. - Adding the BootStrap classes to the root of the WAR.
- Using a custom
META-INF/MANIFEST.MF
meant for the bootstrap (without also getting a merged copy of theMETA-INF/MANIFEST.MF
files from all of the Server dependencies)
回答2:
Update:: This is obsolete now. As I have went ahead with what @joakim-erdfelt suggested.
As mentioned by @Jens in the comments I have changed the packaging from war to jar and using maven-shaded-plugin I am able to run the application without any issues.
This is the modified version of the 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>
Note that I have removed maven-jar-plugin from the plugin list as well.
来源:https://stackoverflow.com/questions/32689892/error-could-not-find-or-load-main-class