浅谈java 中构建可执行 jar 包的几种方式
2016-10-13 16:16
239 查看
概述
有时候,由于项目的需要,我们会将源码编译后以工具包(即将class打成jar包)的形式对外提供,此时,你的 jar 包不一定要是可执行的,只要能通过编译,能被别的项目以 import 的方式调用就行了。
但还有的情况是,我们的 jar 包是要可执行的,即能直接在 cmd 下直接通过java -jar的命令运行。
前者的打包很简单,在 eclipse 中,直接选中要打包的 java 文件和其它资源、依赖文件, export → Java → JAR file 即可。需要注意的是,这种方式导出的 jar 包是不可执行的,比如你执行如下的语句:
java -jar test.jar
java -classpath test.jar com.test_maven.App
会直接报错:无法找到主类或者找不到 xxx 依赖包/类,这是由于你没有定义 MANIFEST.MF 资源描述文件所致。另一个原因可能是你直接把依赖的 jar 包打进了你最终的 jar,而这种嵌套的依赖 jar 包是不能直接被程序 import 识别的。
如何构建可执行Jar包
方法1、最简单的还是依赖于 eclipse 的导出功能:
export → java → Runnable JAR file,这种形式的导出可以通过 lanuch configuration 指定一个 MainClass,并会自动生成 MANIFEST.MF ,而且会帮你把依赖的 jar 包解压出来,一并打进最终的
jar 包,这样就能被你的代码 import 引用了。
方法2、利用Eclipse的Fat Jar
上述方法是 eclipse 自带的,此外eclipse 也有个专门的插件叫做 Fat Jar,支持许多定制化的功能,但是这个插件有些缺陷,比如修改源码后如果你不 clean & rebuild project, 它会使用缓存重新打包,这样你的编译代码还是老的,会造成执行错误,而且这样是十分不方便的。用Fat Jar Eclipse Plug-In打包可执行jar文件
方法3、利用Maven的插件
3.1: 基于Maven构建的项目最好的方式:
将项目所支持的所有类库打在一个包中,而不是只将项目编译打包到一个jar中。这样便可以直接拷贝一个jar去执行了。
Xml代码
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.ebay.montage.eventprocessor.collector.CodeRollOutEventDataCollector</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>assembly</goal>
</goals>
</execution>
</executions>
</plugin>
使用命令:
这里就会在target目录下生成 {project}.jar文件,
直接运行jar文件: Java -jar {project}.jar
备注:当然也可以使用mvn clean install -DskipTests 来构建生成jar包。
需要注意的是,这种方式在新版本的Maven或者Spring中很多时候执行jar包会出现类似如下的exception:
Xml代码
Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/context]
其原因是新版本的Maven中推荐使用shade来替代assembly方式,于是可以使用如下的命令来代替上面的命令以解决Spring NamespaceHandler for XML schema namespace的异常问题
Xml代码
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.chuanliu.c11.bootstrap.C11SearcherBootStrap</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
该命令有几点需要注意:
1、MainClass必须要指定,否则在运行打包生成的Jar包后,会报这样一个错误:“没有主清单属性”
Java代码
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.chuanliu.c11.bootstrap.C11SearcherBootStrap</mainClass>
</transformer>
2、执行生成的Jar包的时候,有时候还会出现:SecurityException: Invalid signature file digest
这是由于在在META-INF下会有多余的以SF结尾的文件,用winrar打开jar包并删除META-INF下的SF结尾的文件后,执行就不会出现改问题,但更好的方法就是像上面一样,生成可执行jar包时加入filters命令
Xml代码
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
3.2: 在 maven 工程中,我们也可以很方便的打包成可执行的 jar 包。默认Maven生成的JAR包只包含了编译生成的.class文件和项目资源文件,而要得到一个可以直接在命令行通过java命令运行的JAR文件,还要满足两个条件:
JAR包中的/META-INF/MANIFEST.MF元数据文件必须包含Main-Class信息。
项目所有的依赖都必须在Classpath中,其可以通过 MANIFEST.MF 指定或者隐式设置。
Xml代码
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.ebay.montage.eventprocessor.collector.MySpace</mainClass>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
finalName>eventprocessor</finalName>
<!-- <excludes>
<exclude>**/*.properties</exclude>
<exclude>**/*.xml</exclude>
</excludes> -->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
使用mvn clean install -DskipTests打jar 包。
这样打好jar包后就可以使用:java -jar eventprocessor.jar Myspace,
当然了前提是在Myspace中有一个main方法。这样便可直接去执行Myspace中的main方法了。
但是如果要将jar包放到别的机器上去运行的话,需要将targe中的lib下的内容(上面命令中指定)也同样拷贝过去,因为默认情况下:maven只是将项目编译打包到一个jar中,而其它的类库在上面手动的指定被放到了lib中,所以在执行的时候必须要引用才行。
附:如果对Maven感兴趣,如下文章的几个功能有必要了解一下:关于 Apache Maven 您不知道的 5 件事
http://www.ibm.com/developerworks/cn/java/j-5things13/
有时候,由于项目的需要,我们会将源码编译后以工具包(即将class打成jar包)的形式对外提供,此时,你的 jar 包不一定要是可执行的,只要能通过编译,能被别的项目以 import 的方式调用就行了。
但还有的情况是,我们的 jar 包是要可执行的,即能直接在 cmd 下直接通过java -jar的命令运行。
前者的打包很简单,在 eclipse 中,直接选中要打包的 java 文件和其它资源、依赖文件, export → Java → JAR file 即可。需要注意的是,这种方式导出的 jar 包是不可执行的,比如你执行如下的语句:
java -jar test.jar
java -classpath test.jar com.test_maven.App
会直接报错:无法找到主类或者找不到 xxx 依赖包/类,这是由于你没有定义 MANIFEST.MF 资源描述文件所致。另一个原因可能是你直接把依赖的 jar 包打进了你最终的 jar,而这种嵌套的依赖 jar 包是不能直接被程序 import 识别的。
如何构建可执行Jar包
方法1、最简单的还是依赖于 eclipse 的导出功能:
export → java → Runnable JAR file,这种形式的导出可以通过 lanuch configuration 指定一个 MainClass,并会自动生成 MANIFEST.MF ,而且会帮你把依赖的 jar 包解压出来,一并打进最终的
jar 包,这样就能被你的代码 import 引用了。
方法2、利用Eclipse的Fat Jar
上述方法是 eclipse 自带的,此外eclipse 也有个专门的插件叫做 Fat Jar,支持许多定制化的功能,但是这个插件有些缺陷,比如修改源码后如果你不 clean & rebuild project, 它会使用缓存重新打包,这样你的编译代码还是老的,会造成执行错误,而且这样是十分不方便的。用Fat Jar Eclipse Plug-In打包可执行jar文件
方法3、利用Maven的插件
3.1: 基于Maven构建的项目最好的方式:
将项目所支持的所有类库打在一个包中,而不是只将项目编译打包到一个jar中。这样便可以直接拷贝一个jar去执行了。
Xml代码
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.ebay.montage.eventprocessor.collector.CodeRollOutEventDataCollector</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>assembly</goal>
</goals>
</execution>
</executions>
</plugin>
使用命令:
mvn assembly:assembly -DskipTests
这里就会在target目录下生成 {project}.jar文件,
直接运行jar文件: Java -jar {project}.jar
备注:当然也可以使用mvn clean install -DskipTests 来构建生成jar包。
需要注意的是,这种方式在新版本的Maven或者Spring中很多时候执行jar包会出现类似如下的exception:
Xml代码
Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/context]
其原因是新版本的Maven中推荐使用shade来替代assembly方式,于是可以使用如下的命令来代替上面的命令以解决Spring NamespaceHandler for XML schema namespace的异常问题
Xml代码
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.chuanliu.c11.bootstrap.C11SearcherBootStrap</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
该命令有几点需要注意:
1、MainClass必须要指定,否则在运行打包生成的Jar包后,会报这样一个错误:“没有主清单属性”
Java代码
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.chuanliu.c11.bootstrap.C11SearcherBootStrap</mainClass>
</transformer>
2、执行生成的Jar包的时候,有时候还会出现:SecurityException: Invalid signature file digest
这是由于在在META-INF下会有多余的以SF结尾的文件,用winrar打开jar包并删除META-INF下的SF结尾的文件后,执行就不会出现改问题,但更好的方法就是像上面一样,生成可执行jar包时加入filters命令
Xml代码
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
3.2: 在 maven 工程中,我们也可以很方便的打包成可执行的 jar 包。默认Maven生成的JAR包只包含了编译生成的.class文件和项目资源文件,而要得到一个可以直接在命令行通过java命令运行的JAR文件,还要满足两个条件:
JAR包中的/META-INF/MANIFEST.MF元数据文件必须包含Main-Class信息。
项目所有的依赖都必须在Classpath中,其可以通过 MANIFEST.MF 指定或者隐式设置。
Xml代码
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.ebay.montage.eventprocessor.collector.MySpace</mainClass>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path>
</manifestEntries>
</archive>
finalName>eventprocessor</finalName>
<!-- <excludes>
<exclude>**/*.properties</exclude>
<exclude>**/*.xml</exclude>
</excludes> -->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
使用mvn clean install -DskipTests打jar 包。
这样打好jar包后就可以使用:java -jar eventprocessor.jar Myspace,
当然了前提是在Myspace中有一个main方法。这样便可直接去执行Myspace中的main方法了。
但是如果要将jar包放到别的机器上去运行的话,需要将targe中的lib下的内容(上面命令中指定)也同样拷贝过去,因为默认情况下:maven只是将项目编译打包到一个jar中,而其它的类库在上面手动的指定被放到了lib中,所以在执行的时候必须要引用才行。
附:如果对Maven感兴趣,如下文章的几个功能有必要了解一下:关于 Apache Maven 您不知道的 5 件事
http://www.ibm.com/developerworks/cn/java/j-5things13/
相关文章推荐
- 浅谈java 中构建可执行 jar 包的几种方式
- 浅谈java 中构建可执行 jar 包的几种方式
- java 中构建可执行 jar 包的几种方式
- Dubbo服务的运行方式(使用maven构建dubbo可执行的jar包)
- java命令执行jar包的方式
- Linux下shell与子shell及执行Script的几种方式
- android中执行定时任务的几种方式
- Jar的几种打包方式
- mkdir javac jar clean 不同情况执行构建文件的输出情况
- OSGI加载第三方非bundle化jar包的几种方式
- android 延时执行的几种方式
- maven构建可执行jar包
- JAR转osgi bundle的几种方式
- 在使用spring构建项目中,将db配置与程序jar包分离的一种方式
- 在使用spring构建项目中,将db配置与程序jar包分离的一种方式
- Unix/Linux中后台运行程序(断开shell连接后继续执行)的几种方式
- eclipse中如何加入jar包以及几种加入方式的区别
- maven插件构建可执行jar以及maven插件tip
- Python:脚本的几种执行方式
- OSGI加载第三方非bundle化jar包的几种方式