1 简介
大家都知道java项目可以打包成一个可执行的jar包,当我们指定程序的入口main后,可以利用 java -jar YourApp.jar 命令运行可执行jar。那么它需要什么条件才能运行呢?在eclipse java工程和maven工程该怎么打包和部署呢?下面将一一解答。
1.1 运行java -jar app.jar命令的背后
当我们在命令窗口运行java -jar app.jar时,虚拟机做了什么事呢?其实要解答这个问题,就要深入类加载器机制,这已经超出了本文的范围。我们只需要知道,虚拟机使用多个类加载器加载class文件。其中app CLassLoader会获取jar包中的 META-INF/MANIFEST.MF文件,并加载文件中指定的class文件。MANIFEST.MF文件列出了该jar包需要依赖的jar包、可执行jar的入口程序,版本号等。
MANIFEST.MF如下图所示:
至于MANIFEST.MF的格式和如何编写不在本文的范围。
- ** Manifest-Version ** 清单文件的版本
- ** Main-Class ** 主程序所在class的全路径
- ** Class-Path ** 可执行jar依赖的包路径,所指的路径与可执行文件同一目录路径
1.2 需求
** 目的:可执行JAR在控制台输出字符串,主程序中依赖apache的commons-lang3包对字符串进行拼接**
package com.github.thinwonton.jarstarter;
import org.apache.commons.lang3.StringUtils;
public class JarStarterMain {
public static void main(String[] args) {
String string = StringUtils.join("JarStarterMain--->", "main"); // 合并字符串
System.out.println(string);
}
}
最终jar包和第三方jar所在的目录结构
JarStarter
JarStarter.jar
lib
commons-lang3-3.5.jar
** 运行结果 **
2 eclipse导出可执行jar文件
java工程结构
** 创建自定义MANIFEST.MF文件**
文件内容如下,注意文件最后需要空两行,否则导出jar时,eclipse不会包含Main-Class这行。
Manifest-Version: 1.0
Main-Class: com.github.thinwonton.jarstarter.JarStarterMain
Class-Path: ./lib/commons-lang3-3.5.jar
** 使用eclipse的jar导出功能 **
这时可执行jar已经导出到 f:/JarStarter 文件夹中,我们再把工程所依赖的jar包复制到 f:/JarStarter/lib 文件夹就可用命令jar -jar JarStarter.jar 运行了。
3 maven工程编译可执行jar文件
要编译和打包可执行jar文件,需要借助maven的两个插件:maven-jar-plugin和maven-dependency-plugin。前一个是打包可执行jar文件的,后一个是拷贝依赖包的。下面是它们的具体用法。
pom.xml
<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.github.thinwonton.java</groupId>
<artifactId>jarstarter-maven</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<!-- 工具 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
</dependencies>
<build>
<!-- 输出文件名 -->
<finalName>jarstarter</finalName>
<plugins>
<!-- 资源文件拷贝插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- 打包jar文件时,配置manifest文件,加入lib包的jar依赖 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<classesDirectory>target/classes/</classesDirectory>
<archive>
<manifest>
<!-- 打包时 MANIFEST.MF文件不记录的时间戳版本 -->
<useUniqueVersions>false</useUniqueVersions>
<!-- 添加Class-Path -->
<addClasspath>true</addClasspath>
<!-- Class-Path添加前缀 -->
<classpathPrefix>lib/</classpathPrefix>
<!-- 指定Main-Class -->
<mainClass>com.github.thinwonton.jarstarter.JarStarterMain</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<!-- 拷贝依赖的jar包到lib目录 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
<!-- 拷贝依赖到lib文件夹 -->
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
在工程根目录下运行 mvn clean package ,这时maven构建工具会在target文件夹中生成 jarstarter.jar 文件 和 lib文件夹,lib文件夹包含有工程所依赖的jar包。 这时jarstarter.jar的清单文件内容:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: Administrator
Class-Path: commons-lang3-3.5.jar
Created-By: Apache Maven 3.3.9
Build-Jdk: 1.8.0_102
Main-Class: com.github.thinwonton.jarstarter.JarStarterMain
4 参考资料
本文涉及代码
https://git.oschina.net/thinwonton/java 项目中的jarstarter和jarstarter-maven工程