前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅谈 java 中构建可执行 jar 包的几种方式

浅谈 java 中构建可执行 jar 包的几种方式

作者头像
用户1177713
发布2018-02-24 14:47:55
3.7K0
发布2018-02-24 14:47:55
举报
文章被收录于专栏:数据之美数据之美

        有时候,由于项目的需要,我们会将源码编译后以工具包(class打成jar包)的形式对外提供,此时, 你的 jar 包不一定要是可执行的,只要能通过编译,能被别人以 import 的方式调用就行了。但还有的 情况是,我们的 jar 包是要可执行的,即能直接在 cmd 下直接运行。前者的打包很简单,在 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 识别的。         下面我们看看如何在 eclipse 中构建一个可执行的 jar 包。

(1)最简单的还是依赖于 eclipse 的导出功能:

export → java → Runnable JAR file,这种形式的导出

可以通过 lanuch configuration 指定一个 MainClass,并会自动生成 MANIFEST.MF ,而且会帮你把依赖的 jar 包解压出来,一并打进最终

的 jar 包,这样就能被你的代码 import 引用了。

(2)上述方法是 eclipse 自带的,eclipse 也有个专门的插件叫做 Fat Jar,支持许多定制化的功能,

具体请参见下面的链接。但是这个插件有些缺陷,比如修改源码后如果你不 clean & rebuild project,

 它会使用缓存重新打包,这样你的编译代码还是老的,会造成执行错误,而且这样是十分不方便的。

用Fat Jar Eclipse Plug-In打包可执行jar文件

http://8366.iteye.com/blog/480652

(3)稍微大点的项目都会用 maven 或者 ant 来构建,在 maven 工程中,我们也可以很方便的打包成可执行的 jar 包。默认Maven生成的JAR包只包含了编译生成的.class文件和项目资源文件,而要得到一个可以直接在命令行通过 java命令运行的JAR文件,还要满足两个条件:

  • JAR包中的/META-INF/MANIFEST.MF元数据文件必须包含Main-Class信息。
  • 项目所有的依赖都必须在Classpath中,其可以通过 MANIFEST.MF 指定或者隐式设置。

Maven有好几个插件能帮助用户完成上述任务,不过用起来最方便的还是maven-shade-plugin,它可以让用户配置 Main-Class的值,然后在打包的时候将值填入/META-INF/MANIFEST.MF文件。关于项目的依赖,它很聪明地将依赖 JAR文件全部解压后,再将得到的.class文件连同当前项目的.class文件一起合并到最终的CLI包中,这样,在执行CLI JAR文件的时候,所有需要的类就都在Classpath中了。下面是一个配置样例:

代码语言:javascript
复制
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>1.4</version>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>shade</goal>
        </goals>
        <configuration>
          <transformers>
            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
              <mainClass>com.juvenxu.mavenbook.HelloWorldCli</mainClass>
            </transformer>
          </transformers>
        </configuration>
      </execution>
    </executions>
  </plugin>

上述例子中的,我的Main-Class是com.juvenxu.mavenbook.HelloWorldCli,构建完成后,对应于一个常规的 hello-world-1.0.jar文件,我还得到了一个hello-world-1.0-cli.jar文件。细心的读者可能已经注意到了,这里用的 是cli这个classifier。最后,我可以通过java -jar hello-world-1.0-cli.jar命令运行程序。当然了,如果你需要更加自由 的打包方式,那就用 maven-assembly-plugin 吧。它支持各种打包文件格式,包括zip、tar.gz、tar.bz2等等,通过一个打包 描述文件(例如 src/main/assembly.xml),它能够帮助用户选择具体打包哪些文件集合、依赖、模块、和甚至本地仓库文件,

每个项的具体打包路径用户也能自由控制。比如下面的配置通过设置 assembly 文件的配置节点 dependencySets/includes,来实现 maven build 生成的 jar 包只包含指定的 jar 依赖。 

代码语言:javascript
复制
<assembly ... ooxx>
	<fileSets>
	</fileSets>
	<dependencySets>
        <dependencySet>
        	<unpack>false</unpack> 
            <outputDirectory>lib</outputDirectory>
            <scope>runtime</scope>
		    <includes>  
		        <include>groupId:artifactId</include>  
		    </includes>
        </dependencySet>
    </dependencySets>
</assembly>

具体请参见: Maven实战(九)——打包的技巧

http://www.infoq.com/cn/news/2011/06/xxb-maven-9-package

maven发布 jar类型的工程

http://mengyunshuitian.iteye.com/blog/1759864

maven assembly plugin dependencySet with transitive dependencies

http://stackoverflow.com/questions/22505886/maven-assembly-plugin-dependencyset-with-transitive-dependencies

http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html#dependencySet

(4)可以使用两个 Maven 插件帮助您完成:maven-jar-plugin 和 maven-dependency-plugin。 maven-jar-plugin 可以做很多事情,但在这里,我们只对使用它来修改默认 MANIFEST.MF 文件的内容感兴趣。 在您的 POM 文件的插件部分添加清单 1 所示代码: 清单 1. 使用 maven-jar-plugin 修改 MANIFEST.MF

代码语言:javascript
复制
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>lib/</classpathPrefix>
                <mainClass>com.mypackage.MyClass</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

所有 Maven 插件通过一个 <configuration> 元素公布了其配置,在本例中,maven-jar-plugin 修改它的 archive 属性, 特别是存档文件的 manifest 属性,它控制 MANIFEST.MF 文件的内容。包括 3 个元素: addClassPath:将该元素设置为 true 告知 maven-jar-plugin 添加一个 Class-Path 元素到 MANIFEST.MF 文件,以及在  Class-Path 元素中包括所有依赖项。 classpathPrefix:如果您计划在同一目录下包含有您的所有依赖项,作为您将构建的 JAR,那么您可以忽略它;否则使用  classpathPrefix 来指定所有依赖 JAR 文件的前缀。在清单 1 中,classpathPrefix 指出,相对存档文件,所有的依赖项 应该位于 “lib” 文件夹。 mainClass:当用户使用 lib 命令执行 JAR 文件时,使用该元素定义将要执行的类名。 当您使用这 3 个元素配置好了 MANIFEST.MF 文件之后,下一步是将所有的依赖项复制到 lib 文件夹。为此,使用  maven-dependency-plugin,如清单 2 所示: 清单 2. 使用 maven-dependency-plugin 将依赖项复制到库

代码语言:javascript
复制
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy</id>
            <phase>install</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>
                  ${project.build.directory}/lib
                </outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>

maven-dependency-plugin 有一个 copy-dependencies,目标是将您的依赖项复制到您所选择的目录。本例中,我将依赖项复制到  build 目录下的 lib 目录(project-home/target/lib)。 将您的依赖项和修改的 MANIFEST.MF 放在适当的位置后,您就可以用一个简单的命令启动应用程序: java -jar jarfilename.jar 更多技巧,您可以参考:

关于 Apache Maven 您不知道的 5 件事

http://www.ibm.com/developerworks/cn/java/j-5things13/

(5)当然了,如果你不怕麻烦的话,手动打包,自己建立、维护 MANIFEST.MF 文件也是可以的,你可以参考如下链接:

http://blog.csdn.net/mango_song/article/details/8531389

http://gushuizerotoone.iteye.com/blog/1757002

(6)把包发布到 nexus

项目上右键 → run as → maven build

附:Maven的坐标GAV(groupId, artifactId, version)定义

pom定义了最小的maven元素,允许groupId,artifactId,version。在 POM 中,groupId, artifactId, packaging, version 叫作 maven 坐标,它能唯一的确定一个项目。有了 maven 坐标,我们就可以用它来指定我们的项目所依赖的其他项目,插件,或者父项目。一般 maven 坐标写成如下的格式: groupId:artifactId:packaging:version

  • groupId: 项目或者组织的唯一标志,并且配置时生成的路径也是由此生成,如org.codehaus.mojo生成的相对路径为:/org/codehaus/mojo
  • artifactId: 项目的通用名称
  • version: 项目的版本
  • packaging: 打包的机制,如pom, jar, maven-plugin, ejb, war, ear, rar, par
  • classifier: 分类,它表示在相同版本下针对不同的环境或者jdk使用的jar,如果配置了这个元素,则会将这个元素名在加在最后来查找相应的jar,例如:
代码语言:javascript
复制
<dependency>  
                <groupId>net.sf.json-lib</groupId>   
                <artifactId>json-lib</artifactId>   
                <version>2.2.2</version>  
                <classifier>jdk15</classifier>    
            </dependency>

这样配置即可找到json-lib-2.2.2-jdk15.jar ,其他的就不解释了,应该明白他的用途了吧。 POM关系:

主要为依赖,继承,合成

REF:

使用maven插件对java工程进行打包

http://chenzhou123520.iteye.com/blog/1706242

关于如何从jar包中读取配置、属性文件,请参考:

http://my.oschina.net/leejun2005/blog/95186

Apache Maven 入门篇(下)

http://www.oracle.com/technetwork/cn/community/java/apache-maven-getting-started-2-405568-zhs.html

maven 配置篇 之pom.xml(一)

http://zyl.iteye.com/blog/41754

Maven最佳实践:划分模块

http://juvenshun.iteye.com/blog/305865

在Eclipse中创建Maven多模块工程的例子

http://www.blogways.net/blog/2013/05/13/maven-multi-modules-demo.html

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档