maven 打包可运行的 jar 包

本贴最后更新于 2490 天前,其中的信息可能已经时异事殊

目标:

将依赖的第三方 jar 包打进去

方法:

maven-assembly-plugin

环境:

IDEA 2016.3

JDK 1.8

遇到的问题:

此处耗时 2 天时间,遇到过的坑:

1.修改完 pom.xml 后,不生效。

--改 pom.xml 后,代码不生效,是因为对 IDEA 工具不熟,在修改完 xml 后,需要点工具右下角的 import changes 或者直接点 auto-import 就可以一劳永逸了。

2.生成 jar 后,idea 可以执行,但是 java -jar 无法执行,报错 Exception in thread "main" java.lang.NoClassDefFoundError

如果修改 pom.xml 中的 mainClass 生效了,说不定是 mainClass 传入的不对,使用 mvn exec:java -Dexec.mainClass="com.delon.main.Test"可以尝试 main 方法是否正确。

如果想用编译 Test.java 文件,可以使用 mvn clean compile exec:java -Dexec.mainClass="com.delon.main.Test"

3.生成 jar 后,idea 可以执行,java -jar 也可以执行,但是缺少相关依赖,报错 Exception in thread "main" java.lang.NoClassDefFoundError: okhttp3/RequestBody

参考如下解决方式即可。

maven 构建 jar 包的步骤:

1.执行可执行的 class,代码内需要有入口 main 方法

2.通过 mvn package 来构建 jar 包

3.使用 java -jar test.jar 来执行 jar 包

一、包含依赖 jar 包


maven 的 pom.xml 配置文件

xml version="1.0" encoding="UTF-8"?>

4.0.0modelVersion>

<groupId>**com.xxx.delon**groupId> <artifactId>**bugly**artifactId> <version>1.0-SNAPSHOTversion> <dependencies>

    

<dependency> <groupId>junitgroupId> <artifactId>junitartifactId> <version>4.7version> <scope>testscope> dependency> <dependency> <groupId>com.squareup.okhttp3groupId> <artifactId>okhttpartifactId> <version>3.3.0version> dependency> <dependency> <groupId>com.fasterxml.jackson.coregroupId> <artifactId>jackson-databindartifactId> <version>2.2.2version> dependency> dependencies> <build> <plugins> <plugin> <artifactId>maven-assembly-pluginartifactId> <configuration> <appendAssemblyId>falseappendAssemblyId> <descriptorRefs> <descriptorRef>jar-with-dependenciesdescriptorRef> descriptorRefs> <archive> <manifest> <mainClass>**com.xxx.uploadFile**mainClass> manifest> archive> ta configuration> <executions> <execution> <id>make-assemblyid> <phase>packagephase> <goals> <goal>assemblygoal> goals> execution> executions> plugin> plugins> build>

project>

生成 jar 包,会生成在 target 目录下

mvn package

解压缩 bugly-1.0-SNAPSHOT.jar->META-INF->MANIFEST.MF

Manifest-Version: 1.0 Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: delon
Build-Jdk: 1.8.0_112
Main-Class: com.xxx.uploadFile

执行:

运行 jar

java -jar test.jar

也可以通过如下命令

mvn assembly:assembly

#跳过测试
mvn -Dmaven.test.skip=true assembly:assembly

注意:在执行这个命令之前,必须先配置 Maven 的环境变量,检查是否配置可通过命令: mvn -version

如果上面的命令成功执行,那么在项目路径的 target 文件下就会有两个 jar 文件,一个是有 jar 包依赖的,一个是没 jar 包依赖的。

二、不包含依赖 jar 包


如果不想包含依赖的 jar 包,可以把里面的代码替换成如下 code:

<plugin> <groupId>org.apache.maven.pluginsgroupId> <artifactId>maven-jar-pluginartifactId> <configuration> <archive> <manifest> <addClasspath>trueaddClasspath> <classpathPrefix>lib/classpathPrefix> <mainClass>com.xxx.uploadFilemainClass> manifest> archive> configuration> plugin> <plugin> <groupId>org.apache.maven.pluginsgroupId> <artifactId>maven-dependency-pluginartifactId> <executions> <execution> <id>copyid> <phase>packagephase> <goals> <goal>copy-dependenciesgoal> goals> <configuration> <outputDirectory> ${project.build.directory}/lib outputDirectory> configuration> execution> executions> plugin>

三、只包含部分依赖 jar 包


如果想只包含部分依赖 jar 包

比如说,想做一个工具 jar 包,依赖公共 jar 和自己本地 jar 包,本地 jar 包需要解压成 class 打到 jar 包内,而依赖的公共 jar 包则不需要。

剔除公共 jar 包 可以用

的值的含义:
compile,缺省值,适用于所有阶段,会随着项目一起发布。
provided,类似 compile,期望 JDK、容器或使用者会提供这个依赖。如 servlet.jar。
runtime,只在运行时使用,如 JDBC 驱动,适用运行和测试阶段。
test,只在测试时使用,用于编译和运行测试代码。不会随项目发布。
system,类似 provided,需要显式提供包含依赖的 jar,Maven 不会在 Repository 中查找它。

编译的时候采用 compile

log4jgroupId> log4jartifactId> 1.2.17version> compliescope> trueoptional> dependency>

在用 package 打包的时候,改成 test,生成的 jar 包里就不会有该 jar 包的类了。

log4jgroupId> log4jartifactId> 1.2.17version> testscope> trueoptional> dependency>

build 配置项,mainClass 为空因为不是可执行 jar。

maven-assembly-pluginartifactId> jar-with-dependenciesdescriptorRef> descriptorRefs> mainClass> manifest> archive> configuration> make-assemblyid> packagephase> singlegoal> goals> execution> executions> plugin> plugins> build>
==高级 ## 说明

非 web 项目中经常遇到需要将工程打包成一个可执行 jar 包(通过在命令行执行 java 命令进行启动)的情 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 况。
一个可执行的 jar 包,需要满足以下条件:

  • 在 jar 包中的/META-INF/MANIFEST.MF 元数据文件中必须保护 Main-Class 启动入口类信息
  • 项目的所有依赖都必须包含在 Classpath 中。即依赖必须都被描述 MANIFEST 于.MF 文件中的 Class-Path 下

Maven 中可以通过许多插件完成打包任务,如强大的 maven-assembly-plugin 等。具体使用方式,可以参见各插件的说明。

基础概念:maven 的生命周期与插件

Maven 将工程的构建过程分为不同的生命周期(LifeCycle),每个生命周期中又划分为不同的阶段(Phase)。
LifyCycle 之间互相独立,且没有明确的顺序关系,而每个 LifeCycle 中的 Phase 间则存在明确的顺序关系,且必须依序执行。
Maven 内置了三个 LifyCycle,如 default(build)构建,clean 清理, site 生成文档与站点。
以 default 为例,其内置的 phase 主要包含有: validate,compile,test,package,intergration-test,verify,install,deploy.这些 phase 在项目 build 时会依次执行 。

Maven 所定义的 LifeCycle 与 Phase 只是抽象的概念,不涉及具体的功能。而功能的实现则由插件(Plugin)负责。

一个 Plugin 可以实现多个目标(Goal), Goal 可以绑定在多个 Phase 上, 每个 Phase 下也可以包含多个 Goal。可以将 Phase 视为 Goal 的容器。
Goal 是 Maven 里面最小的任务单位,相关于 Ant 的 target。Goal 与 Goal 之间是互相独立的。单独执行某个 Goal 不会导致其他 Goal 被执行。

当我们对一个工程执行打包命令 mvn package 时, maven 将从 validate 阶段开始,一个阶段一个阶段(compile, test)的执行,直至到达 package 阶段。
在执行到 compile 阶段时,插件 maven-compiler-plugin 的 compile goal 会被执行,因为这个 goal 是绑定在 compile 阶段。
同理,当执行到 package 阶段时,插件 maven-dependency-plugin 与 maven-resources-plugin 的相关 goal 都会被执行。

工程打包示例

目录结构示例

project/ + src/main/java/ + com.some.package + src/main/resources/ - settings.properties - applicationContext.xml - startup.bat - pom.xml

打包后的期望结果

target/ + conf/ - settings.properties - applicationContext.xml + lib/ - project.jar - startup.bat

project.jar 中不包含配置文件。

pom 文件中打包相关的配置

<build> <plugins> <!-- 编译插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.6</source> <target>1.6</target> <encoding>UTF-8</encoding> <compilerArguments> <verbose /> <bootclasspath>${java.home}/lib/rt.jar</bootclasspath> </compilerArguments> </configuration> </plugin> <!-- 项目依赖插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory> <excludeTransitive>false</excludeTransitive> <!-- 表示是否不包含间接依赖的包 --> <stripVersion>false</stripVersion> <!-- 去除版本信息 --> </configuration> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <!-- 拷贝项目依赖包到lib/目录下 --> <outputDirectory>${project.build.directory}/lib</outputDirectory> <excludeTransitive>false</excludeTransitive> <stripVersion>false</stripVersion> </configuration> </execution> </executions> </plugin> <!-- 项目资源插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <executions> <execution> <id>copy-resources</id> <phase>package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <encoding>UTF-8</encoding> <!-- 拷贝项目src/main/resources/下,除.bat以外的所有文件到conf/目录下 --> <outputDirectory>${project.build.directory}/conf</outputDirectory> <resources> <resource> <directory>src/main/resources/</directory> <filtering>true</filtering> <excludes> <exclude>*.bat</exclude> </excludes> </resource> </resources> </configuration> </execution> <execution> <id>copy-command</id> <phase>package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <encoding>UTF-8</encoding> <!-- 只拷贝项目src/main/resources/目录下的.bat文件到输出目录下 --> <outputDirectory>${project.build.directory}</outputDirectory> <resources> <resource> <directory>src/main/resources/</directory> <filtering>true</filtering> <includes> <include>*.bat</include> </includes> </resource> </resources> </configuration> </execution> </executions> </plugin> <!-- 打包插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.4</version> <configuration> <archive> <!-- 生成MANIFEST.MF的设置 --> <manifest> <!-- 为依赖包添加路径, 这些路径会写在MANIFEST文件的Class-Path下 --> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <!-- jar启动入口类--> <mainClass>com.some.package.some.class.Main</mainClass> </manifest> <manifestEntries> <!-- 在Class-Path下添加配置文件的路径 --> <Class-Path>conf/</Class-Path> </manifestEntries> </archive> <includes> <!-- 打jar包时,只打包class文件 --> <include>**/*.class</include> </includes> </configuration> </plugin> </plugins> <!-- 解决eclipse下maven插件兼容性问题 --> <pluginManagement> <plugins> <!-- Ignore/Execute plugin execution --> <plugin> <groupId>org.eclipse.m2e</groupId> <artifactId>lifecycle-mapping</artifactId> <version>1.0.0</version> <configuration> <lifecycleMappingMetadata> <pluginExecutions> <!-- copy-dependency plugin --> <pluginExecution> <pluginExecutionFilter> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <versionRange>[1.0.0,)</versionRange> <goals> <goal>copy-dependencies</goal> </goals> </pluginExecutionFilter> <action> <ignore /> </action> </pluginExecution> </pluginExecutions> </lifecycleMappingMetadata> </configuration> </plugin> </plugins> </pluginManagement> </build>

打包命令 mvn clean package

附录 1 启动命令 bat 文件编写

REM 关闭输出 @echo off REM 设置启动时使用的jdk。如果不设置,则使用系统变量中设置的jdk set path=../jdk.1.7.80/bin set classpath=../jdk.1.7.80/jre/lib REM 最基本的jar包启动命令,使用MANIFEST中的入口类启动 java -jar project.jar REM 指定jar包的某个类作为入口启动 java -cp project.jar some.package.some.class.MyClass REM 设置jvm参数并启动jar包 java -Xms256m -Xmx512m -jar project.jar REM 开启输出 echo on

附录 2 maven 打包时的文件拷贝

通常打包外部资源文件时,都使用 maven-dependency-plugin 或是 maven-resources-plugin 插件。但是项目中遇见一个问题,在打包 jnotify 的动态链接库时,使用上面两个插件进行文件拷贝时,程序会无法识别到打包后 dll 文件。
多次尝试后使用了 maven-antrun-plugin 进行拷贝,问题得到解决。其拷贝配置如下:

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <version>1.7</version> <executions> <execution> <id>copy-native-libraries</id> <phase>package</phase> <goals> <goal>run</goal> </goals> <configuration> <target> <echo message="copy native libraries" /> <copy todir="${project.build.directory}/lib"> <fileset dir="${basedir}/lib"></fileset> </copy> </target> </configuration> </execution> </executions> </plugin>

https://www.cnblogs.com/dzblog/p/6913809.html
https://www.jianshu.com/p/afb79650b606

  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    188 引用 • 319 回帖 • 241 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...