可运行jar包的几种打包/部署方式
java项目开发中,最终生成的jar,大概可分为二类,一类是一些通用的工具类(不包含main入口方法),另一类是可直接运行的jar包(有main入口方法),下面主要讲的是后者,要让一个jar文件可直接运行,通常有几下三种方式:
动工之前,先搭一个项目架子便于后面分析:
项目结构图:
这是一个gradle项目(当然,也可以换成ant项目或maven项目,这不重要),里面有二个模块,my-jar的DemoApp里提供了main入口方法,通常一个可运行的java项目,都会依赖其它一些jar包,所以另一个模块my-lib模拟工具类的jar包,即:简单来说,my-jar依赖my-lib。
my-lib中DemoLib类的源代码:
package yjmyzz.runnable.lib;
public class DemoLib {
public static void demo() {
System.out.println("我是DemoLib中的demo方法");
}
}
my-jar中DemoApp类的源代码:
package yjmyzz.runnable.jar;
import yjmyzz.runnable.lib.DemoLib;
public class DemoApp {
public static void main(String[] args) {
DemoLib.demo();
}
}
二个项目编译后,会得到二个jar包:my-jar.jar及my-lib.jar
方法一:不借助manifest文件
java -classpath jar1:jar2:jar3... mainClassName
解解一下:
红色的是固定部分,中间蓝色的是jar包的路径(多个jar之间用:号连接),最后绿色的部分是main方法所在的类名,按这个思路
把这二个jar包扔同一个目录下,输入如下命令:
java -classpath my-jar.jar:my-lib.jar yjmyzz.runnable.jar.DemoApp
程序就能跑起来了
方法二:借助manifest文件
想办法在my-jar.jar中添加MANIFEST.MF文件,内容参考下面这样:
Main-Class: yjmyzz.runnable.jar.DemoApp
Class-Path: my-lib.jar
同样,将这二个jar包扔在一起,然后
java -jar my-jar.jar 就能运行了,至于如何在打包里,自动添加MANIFEST.MF文件,gradle下可以这么做:
jar {
manifest {
attributes 'Main-Class': 'yjmyzz.runnable.jar.DemoApp'
attributes 'Class-Path': 'my-lib.jar'
}
}
build.gradle中添加这一段即可,如果是maven项目,请参考 maven: 打包可运行的jar包(java application)及依赖项处理 一文
方法三:借助spring-boot 插件
前面二种方法,主程序的jar包,与依赖的jar包是分开的,这在云环境中,上传部署比较麻烦,得传多个文件(或者上传前,先压缩成一个包,再传到服务器上解压),服务器节点多时,操作起来太累。又到我大Spring出场了,将my-jar项目中的build.gradle改成下面这样:
apply plugin: 'java'
apply plugin: 'spring-boot' buildscript {
repositories {
maven {
url 'http://maven.oschina.net/content/groups/public/'
}
} dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.0.RELEASE")
}
} repositories {
maven {
url 'http://maven.oschina.net/content/groups/public/'
}
} dependencies {
compile project(':my-lib')
}
然后命令行输入 gradle bootRepackage 将在build/libs下生成二个文件my-jar.jar以及my-jar.jar.original(先不用管这个original文件是啥)
直接java -jar my-jar.jar 就能运行了(注意:这种方式下,并不需要my-lib.jar这类依赖的jar文件),其原理在于spring-boot插件把所有依赖的jar包,全都打到一个jar包里了。
基本上,到这里这篇文章就可以完结了,如果有同学对spring-boot这种打包方式比较好奇,想深入研究,可以继续向下看,把my-jar.jar.original改名为my-jar-origin.jar,然后输入jar tf my-jar-origin.jar 即显示这个jar包的内容,会得到以下输出:
META-INF/
META-INF/MANIFEST.MF
yjmyzz/
yjmyzz/runnable/
yjmyzz/runnable/jar/
yjmyzz/runnable/jar/DemoApp.class
即.original文件,其实就是一个普通的jar包,其中的MANIFEST.MF并没有什么实质性内容,只是一个空壳,这样的jar包,跟方法1得到的jar包是一样的。
再输入jar tf my-jar.jar,会得到以下输出:
META-INF/
META-INF/MANIFEST.MF
yjmyzz/
yjmyzz/runnable/
yjmyzz/runnable/jar/
yjmyzz/runnable/jar/DemoApp.class
lib/
lib/my-lib.jar
org/
org/springframework/
org/springframework/boot/
org/springframework/boot/loader/
org/springframework/boot/loader/LaunchedURLClassLoader$Java7LockProvider.class
org/springframework/boot/loader/PropertiesLauncher$ArchiveEntryFilter.class
org/springframework/boot/loader/PropertiesLauncher$PrefixMatchingArchiveFilter.class
org/springframework/boot/loader/ExecutableArchiveLauncher$1.class
org/springframework/boot/loader/PropertiesLauncher.class
org/springframework/boot/loader/LaunchedURLClassLoader$ResourceEnumeration.class
org/springframework/boot/loader/data/
org/springframework/boot/loader/data/ByteArrayRandomAccessData.class
org/springframework/boot/loader/data/RandomAccessDataFile$DataInputStream.class
org/springframework/boot/loader/data/RandomAccessData.class
org/springframework/boot/loader/data/RandomAccessDataFile$FilePool.class
org/springframework/boot/loader/data/RandomAccessDataFile.class
org/springframework/boot/loader/data/RandomAccessData$ResourceAccess.class
org/springframework/boot/loader/util/
org/springframework/boot/loader/util/SystemPropertyUtils.class
org/springframework/boot/loader/util/AsciiBytes.class
org/springframework/boot/loader/LaunchedURLClassLoader$1.class
org/springframework/boot/loader/InputArgumentsJavaAgentDetector.class
org/springframework/boot/loader/Launcher.class
org/springframework/boot/loader/LaunchedURLClassLoader.class
org/springframework/boot/loader/JarLauncher.class
org/springframework/boot/loader/jar/
org/springframework/boot/loader/jar/JarEntryFilter.class
org/springframework/boot/loader/jar/JarURLConnection.class
org/springframework/boot/loader/jar/JarEntry.class
org/springframework/boot/loader/jar/Bytes.class
org/springframework/boot/loader/jar/CentralDirectoryEndRecord.class
org/springframework/boot/loader/jar/JarFile$2.class
org/springframework/boot/loader/jar/ZipInflaterInputStream.class
org/springframework/boot/loader/jar/JarFile.class
org/springframework/boot/loader/jar/JarFile$1.class
org/springframework/boot/loader/jar/JarURLConnection$1.class
org/springframework/boot/loader/jar/Handler.class
org/springframework/boot/loader/jar/JarURLConnection$JarEntryName.class
org/springframework/boot/loader/jar/JarEntryData.class
org/springframework/boot/loader/MainMethodRunner.class
org/springframework/boot/loader/InputArgumentsJavaAgentDetector$1.class
org/springframework/boot/loader/WarLauncher.class
org/springframework/boot/loader/PropertiesLauncher$1.class
org/springframework/boot/loader/ExecutableArchiveLauncher.class
org/springframework/boot/loader/LaunchedURLClassLoader$LockProvider.class
org/springframework/boot/loader/archive/
org/springframework/boot/loader/archive/JarFileArchive$JarFileEntry.class
org/springframework/boot/loader/archive/JarFileArchive.class
org/springframework/boot/loader/archive/FilteredArchive.class
org/springframework/boot/loader/archive/JarFileArchive$1.class
org/springframework/boot/loader/archive/ExplodedArchive.class
org/springframework/boot/loader/archive/FilteredArchive$2.class
org/springframework/boot/loader/archive/Archive$Entry.class
org/springframework/boot/loader/archive/ExplodedArchive$1.class
org/springframework/boot/loader/archive/Archive$EntryFilter.class
org/springframework/boot/loader/archive/FilteredArchive$1.class
org/springframework/boot/loader/archive/ExplodedArchive$FileEntry.class
org/springframework/boot/loader/archive/Archive.class
org/springframework/boot/loader/archive/Archive$EntryRenameFilter.class
org/springframework/boot/loader/archive/ExplodedArchive$FilteredURLStreamHandler.class
org/springframework/boot/loader/archive/ExplodedArchive$FileNotFoundURLConnection.class
org/springframework/boot/loader/JavaAgentDetector.class
很明显,多出了很多内容,注意第8行,可以发现my-lib.jar这个依赖的jar包,已经打包到my-jar.jar内部了,这时的MANIFEST.MF内容为:
Manifest-Version: 1.0
Start-Class: yjmyzz.runnable.jar.DemoApp
Spring-Boot-Version: 1.3.0.RELEASE
Main-Class: org.springframework.boot.loader.JarLauncher
Main-Class被设置成org.springframework.boot.loader.JarLauncher,此外还增加了Start-Class指向我们真正的程序入口yjmyzz.runnable.jar.DemoApp,换句话说,程序运行时,先调用org.springframework.boot.loader.JarLauncher,然后找到Start-Class对应的类,最终运行,运行过程中,会查找内部lib下的依赖jar包my-lib.jar,当然这一切是需要有额外的代码来处理的,所以多出来的org/springframework/boot下的一堆class,就是spring用来干这件事儿的。
第三种方式,很适合云环境的部署,只需要扔一个jar包上去就完事了,这种all-in-one的jar包,也被称为fat-jar。
参考文章:
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#executable-jar
可运行jar包的几种打包/部署方式的更多相关文章
- 可运行jar包的几种打包/部署方式(转)
转自:https://www.cnblogs.com/yjmyzz/p/executable-jar.html java项目开发中,最终生成的jar,大概可分为二类,一类是一些通用的工具类(不包含ma ...
- java打jar包和运行jar包的两种方式
java打jar包和运行jar包的两种方式更详细的打包方式请参考https://www.cnblogs.com/mq0036/p/8566427.html 一.java类不依赖第三方jar包以简单的一 ...
- windows 系统后台运行 jar 包
windows平台下 后台运行 jar 包 1.cmd 下执行方式:后台运行 start /min java -server -Xms1024m -Xmx20480m -jar $JAR_NAME. ...
- windows 下启动运行 jar 包程序
windows 下 运行 jar 包 java -jar XXX.jar java -server -Xms1024m -Xmx20480m -jar $JAR_NAME.jar windows 后台 ...
- maven 打包可运行jar包(转)
目录 1.前提 2.方法一:使用maven-jar-plugin和maven-dependency-plugin插件打包 3.方法二:使用maven-assembly-plugin插件打包 4.方法三 ...
- spring boot maven打包可运行jar包
普通打包之后在程序目录运行,或者编写bat运行时会提示“没有主清单属性”,这是因为并没有找到main()方法,需要我们指明告诉java程序 我bat中的代码 @echo off title mytit ...
- 如何打包/运行jar包,及生成exe文件
关于如何打包/运行jar包,以及生成exe文件.之前各种查询.博客,终于搞明白究竟是咋回事.记得还做过笔记的.今天要打包生成exe用的时候,居然忘了咋怎来着.去查看之前的笔记,死活没找到(好像被删掉了 ...
- 【Maven学习】Maven打包生成普通jar包、可运行jar包、包含所有依赖的jar包
http://blog.csdn.net/u013177446/article/details/54134394 ******************************************* ...
- jar包生制作几种方法,jar包导出三种方法:eclipse导出、jar命令、FatJar插件
Eclipse将引用了第三方jar包的Java项目打包成jar文件的两种方法 方案一:用Eclipse自带的Export功能 步骤1:准备主清单文件 “MANIFEST.MF”, 由于是打包引用了第三 ...
随机推荐
- MUI-最接近原生App体验的前端框架
MUI:让HTML5达到原生体验的高性能开源框架 UI组件 HelloMUI HTML5+开发移动app教程3-mui开发示例
- css3图片模糊过滤效果
css3图片过滤效果,鼠标放上后其它图片模糊,鼠标所在位置的图片是清淅的,有效索引出当前的图片,对图片的模糊处理是本特效的亮点,你完全可以将模糊的效果应用于其它的图片特效中,你同样也可借此代码研究一下 ...
- 彻底解决mysql中文乱码的办法 ???
MySQL会出现中文乱码的原因不外乎下列几点:1.server本身设定问题,例如还停留在latin12.table的语系设定问题(包含character与collation)3.客户端程式(例如p ...
- SVG简介
最近遇到SVG这个名词,于是查阅资料,做个笔记. 前言 图片的数字化.将图片存储为数据有两种方案. 位图.也被称为光栅图.即是以自然的光学的眼光将图片看成在平面上密集排布的点的集合.每个点发出的光有独 ...
- jsonp 演示实例 —— 基于node
序 同源策略是浏览器处于安全考虑,为通信设置了"相同的域.相同的端口.相同的协议"这一限制.这让我们的ajax请求存在跨域无权限访问的问题. 同时我们发现script标签引入脚本的 ...
- Dev TreeList 总结
1.表格的要求:如果要求有父子节点关系,则必须有ID和ParentID字段,并且父节点ParentID字段必须指向ID字段. 2.Access表格在穿入DATATABLE的时候,要想表现出父子节点关系 ...
- IOS客户端实现RSA加密
在IOS的app登陆模块,用户名和密码如果直接传给后台服务器,很容易被截获并伪造网络请求, 如果利用RSA算法在每个客户端利用公钥解密,服务器端进行私钥解密,即使截获了密码也是无法解密的 在这里只介绍 ...
- [Android]对MVC和MVP的总结
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5036289.html 经历过的客户端的架构分为这么几个阶段: ...
- android handler ,message消息发送方式
1.Message msg = Message.obtain(mainHandler) msg.obj=obj;//添加你需要附加上去的内容 msg.what = what;//what消息处理的类 ...
- 分享dubbo.xsd和idubbo.xsd的可用地址
dubbo.xsd和idubbo.xsd的官方地址不可用 http://code.alibabatech.com/schema/dubbo/dubbo.xsd似乎挂了,真是淡淡的忧伤啊,然后就各种报错 ...