无主类时如何用Maven生成可执行Jar包?含Docker部署方案
Hey there! Let's work through your problem together. You've got a Jersey-based web service without a traditional main class, currently building a WAR file that runs fine—but you want either an executable JAR instead, or a way to run that WAR in Docker (since you tried Docker Swarm without luck). Let's cover both solutions clearly.
Since your project uses Jersey, we can leverage its embedded container support to add a tiny, simple main class that boots up your service. This lets Maven package everything into a runnable JAR.
Step 1: Add Embedded Jetty Dependencies
First, add these dependencies to your pom.xml to enable the embedded Jetty server (compatible with your Jersey version):
<dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-jetty-http</artifactId> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> <version>9.4.51.v20230217</version> <!-- Stable version compatible with JDK 1.7 --> </dependency>
Step 2: Add a Minimal Main Class
Create a simple Main class in your project (e.g., com.mycompany.Main) to start the embedded server:
package com.mycompany; import org.glassfish.jersey.jetty.JettyHttpContainerFactory; import org.glassfish.jersey.server.ResourceConfig; import javax.ws.rs.core.UriBuilder; import java.net.URI; public class Main { public static void main(String[] args) { // Define the server URL and port URI baseUri = UriBuilder.fromUri("http://localhost/").port(8080).build(); // Scan your project's packages for Jersey resources ResourceConfig config = new ResourceConfig().packages("com.mycompany"); // Start the server JettyHttpContainerFactory.createServer(baseUri, config); System.out.println("Service running at http://localhost:8080"); } }
Step 3: Configure Maven to Build the Executable JAR
Choose one of these two plugin setups to package your JAR:
Option A: Fat Jar (All Dependencies Included)
Use the maven-shade-plugin to bundle everything into a single runnable JAR:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.mycompany.Main</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
Run mvn clean package, then start the service with:
java -jar target/ProductMicroService.jar
Option B: JAR with Separate Lib Directory
If you prefer keeping dependencies separate, use these two plugins:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.3.0</version> <configuration> <archive> <manifest> <mainClass>com.mycompany.Main</mainClass> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>3.5.0</version> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory> </configuration> </execution> </executions> </plugin>
Run mvn clean package, then start the service from the target directory with:
java -jar ProductMicroService.jar
Running a WAR in Docker is straightforward using the official Tomcat image. Here's how to set it up:
Step 1: Create a Dockerfile
Create a file named Dockerfile in your project root:
# Use Tomcat 7 with JRE 7 (matches your project's JDK version) FROM tomcat:7-jre7 # Copy your WAR file to Tomcat's ROOT webapp (so it's accessible at the root URL) COPY target/ProductMicroService.war /usr/local/tomcat/webapps/ROOT.war # Expose Tomcat's default port EXPOSE 8080 # Start Tomcat CMD ["catalina.sh", "run"]
Step 2: Build and Run the Docker Image
Execute these commands in your project directory:
# First build your WAR file mvn clean package # Build the Docker image docker build -t product-microservice . # Run the container (map host port 8080 to container port 8080) docker run -p 8080:8080 product-microservice
Your service will be accessible at http://localhost:8080.
Docker Swarm Deployment Fix
If you want to deploy to Docker Swarm, first push your image to a registry (Docker Hub or private), then create a docker-compose.yml:
version: '3' services: product-microservice: image: your-registry-username/product-microservice:latest ports: - "8080:8080" deploy: replicas: 2 restart_policy: condition: on-failure
Deploy it with:
docker stack deploy -c docker-compose.yml product-stack
Here's your updated pom.xml with all the necessary changes for the executable JAR option (comment out sections you don't need):
<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>com.mycompany</groupId> <artifactId>ProductMicroService</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>ProductMicroService</name> <build> <finalName>ProductMicroService</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.5.1</version> <inherited>true</inherited> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <!-- Fat Jar setup (uncomment to use) --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.mycompany.Main</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> <!-- Separate JAR + Lib setup (comment out if using shade plugin) --> <!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.3.0</version> <configuration> <archive> <manifest> <mainClass>com.mycompany.Main</mainClass> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>3.5.0</version> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory> </configuration> </execution> </executions> </plugin> --> </plugins> </build> <dependencyManagement> <dependencies> <dependency> <groupId>org.glassfish.jersey</groupId> <artifactId>jersey-bom</artifactId> <version>${jersey.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet-core</artifactId> </dependency> <!-- Embedded Jetty dependencies --> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-jetty-http</artifactId> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> <version>9.4.51.v20230217</version> </dependency> <!-- Original project dependencies --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.0.pr2</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>4.3.1.Final</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.39</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.5.4</version> <type>jar</type> </dependency> <dependency> <groupId>com.owlike</groupId> <artifactId>genson</artifactId> <version>0.99</version> </dependency> </dependencies> <properties> <jersey.version>2.26-b03</jersey.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> </project>
内容的提问来源于stack exchange,提问作者fofoky

