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类的源代码:

  1. package yjmyzz.runnable.lib;
  2.  
  3. public class DemoLib {
  4.  
  5. public static void demo() {
  6. System.out.println("我是DemoLib中的demo方法");
  7. }
  8. }

my-jar中DemoApp类的源代码:

  1. package yjmyzz.runnable.jar;
  2.  
  3. import yjmyzz.runnable.lib.DemoLib;
  4.  
  5. public class DemoApp {
  6.  
  7. public static void main(String[] args) {
  8. DemoLib.demo();
  9. }
  10. }

二个项目编译后,会得到二个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文件,内容参考下面这样:

  1. Main-Class: yjmyzz.runnable.jar.DemoApp
    Class-Path: my-lib.jar

同样,将这二个jar包扔在一起,然后

java -jar my-jar.jar 就能运行了,至于如何在打包里,自动添加MANIFEST.MF文件,gradle下可以这么做:

  1. jar {
  2. manifest {
  3. attributes 'Main-Class': 'yjmyzz.runnable.jar.DemoApp'
  4. attributes 'Class-Path': 'my-lib.jar'
  5. }
  6. }

build.gradle中添加这一段即可,如果是maven项目,请参考  maven: 打包可运行的jar包(java application)及依赖项处理 一文

方法三:借助spring-boot 插件

前面二种方法,主程序的jar包,与依赖的jar包是分开的,这在云环境中,上传部署比较麻烦,得传多个文件(或者上传前,先压缩成一个包,再传到服务器上解压),服务器节点多时,操作起来太累。又到我大Spring出场了,将my-jar项目中的build.gradle改成下面这样:

  1. apply plugin: 'java'
  2. apply plugin: 'spring-boot'
  3.  
  4. buildscript {
  5. repositories {
  6. maven {
  7. url 'http://maven.oschina.net/content/groups/public/'
  8. }
  9. }
  10.  
  11. dependencies {
  12. classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.0.RELEASE")
  13. }
  14. }
  15.  
  16. repositories {
  17. maven {
  18. url 'http://maven.oschina.net/content/groups/public/'
  19. }
  20. }
  21.  
  22. dependencies {
  23. compile project(':my-lib')
  24. }

然后命令行输入 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包的内容,会得到以下输出:

  1. META-INF/
  2. META-INF/MANIFEST.MF
  3. yjmyzz/
  4. yjmyzz/runnable/
  5. yjmyzz/runnable/jar/
  6. yjmyzz/runnable/jar/DemoApp.class

即.original文件,其实就是一个普通的jar包,其中的MANIFEST.MF并没有什么实质性内容,只是一个空壳,这样的jar包,跟方法1得到的jar包是一样的。

再输入jar tf my-jar.jar,会得到以下输出:

  1. META-INF/
  2. META-INF/MANIFEST.MF
  3. yjmyzz/
  4. yjmyzz/runnable/
  5. yjmyzz/runnable/jar/
  6. yjmyzz/runnable/jar/DemoApp.class
  7. lib/
  8. lib/my-lib.jar
  9. org/
  10. org/springframework/
  11. org/springframework/boot/
  12. org/springframework/boot/loader/
  13. org/springframework/boot/loader/LaunchedURLClassLoader$Java7LockProvider.class
  14. org/springframework/boot/loader/PropertiesLauncher$ArchiveEntryFilter.class
  15. org/springframework/boot/loader/PropertiesLauncher$PrefixMatchingArchiveFilter.class
  16. org/springframework/boot/loader/ExecutableArchiveLauncher$1.class
  17. org/springframework/boot/loader/PropertiesLauncher.class
  18. org/springframework/boot/loader/LaunchedURLClassLoader$ResourceEnumeration.class
  19. org/springframework/boot/loader/data/
  20. org/springframework/boot/loader/data/ByteArrayRandomAccessData.class
  21. org/springframework/boot/loader/data/RandomAccessDataFile$DataInputStream.class
  22. org/springframework/boot/loader/data/RandomAccessData.class
  23. org/springframework/boot/loader/data/RandomAccessDataFile$FilePool.class
  24. org/springframework/boot/loader/data/RandomAccessDataFile.class
  25. org/springframework/boot/loader/data/RandomAccessData$ResourceAccess.class
  26. org/springframework/boot/loader/util/
  27. org/springframework/boot/loader/util/SystemPropertyUtils.class
  28. org/springframework/boot/loader/util/AsciiBytes.class
  29. org/springframework/boot/loader/LaunchedURLClassLoader$1.class
  30. org/springframework/boot/loader/InputArgumentsJavaAgentDetector.class
  31. org/springframework/boot/loader/Launcher.class
  32. org/springframework/boot/loader/LaunchedURLClassLoader.class
  33. org/springframework/boot/loader/JarLauncher.class
  34. org/springframework/boot/loader/jar/
  35. org/springframework/boot/loader/jar/JarEntryFilter.class
  36. org/springframework/boot/loader/jar/JarURLConnection.class
  37. org/springframework/boot/loader/jar/JarEntry.class
  38. org/springframework/boot/loader/jar/Bytes.class
  39. org/springframework/boot/loader/jar/CentralDirectoryEndRecord.class
  40. org/springframework/boot/loader/jar/JarFile$2.class
  41. org/springframework/boot/loader/jar/ZipInflaterInputStream.class
  42. org/springframework/boot/loader/jar/JarFile.class
  43. org/springframework/boot/loader/jar/JarFile$1.class
  44. org/springframework/boot/loader/jar/JarURLConnection$1.class
  45. org/springframework/boot/loader/jar/Handler.class
  46. org/springframework/boot/loader/jar/JarURLConnection$JarEntryName.class
  47. org/springframework/boot/loader/jar/JarEntryData.class
  48. org/springframework/boot/loader/MainMethodRunner.class
  49. org/springframework/boot/loader/InputArgumentsJavaAgentDetector$1.class
  50. org/springframework/boot/loader/WarLauncher.class
  51. org/springframework/boot/loader/PropertiesLauncher$1.class
  52. org/springframework/boot/loader/ExecutableArchiveLauncher.class
  53. org/springframework/boot/loader/LaunchedURLClassLoader$LockProvider.class
  54. org/springframework/boot/loader/archive/
  55. org/springframework/boot/loader/archive/JarFileArchive$JarFileEntry.class
  56. org/springframework/boot/loader/archive/JarFileArchive.class
  57. org/springframework/boot/loader/archive/FilteredArchive.class
  58. org/springframework/boot/loader/archive/JarFileArchive$1.class
  59. org/springframework/boot/loader/archive/ExplodedArchive.class
  60. org/springframework/boot/loader/archive/FilteredArchive$2.class
  61. org/springframework/boot/loader/archive/Archive$Entry.class
  62. org/springframework/boot/loader/archive/ExplodedArchive$1.class
  63. org/springframework/boot/loader/archive/Archive$EntryFilter.class
  64. org/springframework/boot/loader/archive/FilteredArchive$1.class
  65. org/springframework/boot/loader/archive/ExplodedArchive$FileEntry.class
  66. org/springframework/boot/loader/archive/Archive.class
  67. org/springframework/boot/loader/archive/Archive$EntryRenameFilter.class
  68. org/springframework/boot/loader/archive/ExplodedArchive$FilteredURLStreamHandler.class
  69. org/springframework/boot/loader/archive/ExplodedArchive$FileNotFoundURLConnection.class
  70. org/springframework/boot/loader/JavaAgentDetector.class

很明显,多出了很多内容,注意第8行,可以发现my-lib.jar这个依赖的jar包,已经打包到my-jar.jar内部了,这时的MANIFEST.MF内容为:

  1. Manifest-Version: 1.0
  2. Start-Class: yjmyzz.runnable.jar.DemoApp
  3. Spring-Boot-Version: 1.3.0.RELEASE
  4. 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包的几种打包/部署方式的更多相关文章

  1. 可运行jar包的几种打包/部署方式(转)

    转自:https://www.cnblogs.com/yjmyzz/p/executable-jar.html java项目开发中,最终生成的jar,大概可分为二类,一类是一些通用的工具类(不包含ma ...

  2. java打jar包和运行jar包的两种方式

    java打jar包和运行jar包的两种方式更详细的打包方式请参考https://www.cnblogs.com/mq0036/p/8566427.html 一.java类不依赖第三方jar包以简单的一 ...

  3. windows 系统后台运行 jar 包

    windows平台下 后台运行 jar 包 1.cmd 下执行方式:后台运行  start /min java -server -Xms1024m -Xmx20480m -jar $JAR_NAME. ...

  4. windows 下启动运行 jar 包程序

    windows 下 运行 jar 包 java -jar XXX.jar java -server -Xms1024m -Xmx20480m -jar $JAR_NAME.jar windows 后台 ...

  5. maven 打包可运行jar包(转)

    目录 1.前提 2.方法一:使用maven-jar-plugin和maven-dependency-plugin插件打包 3.方法二:使用maven-assembly-plugin插件打包 4.方法三 ...

  6. spring boot maven打包可运行jar包

    普通打包之后在程序目录运行,或者编写bat运行时会提示“没有主清单属性”,这是因为并没有找到main()方法,需要我们指明告诉java程序 我bat中的代码 @echo off title mytit ...

  7. 如何打包/运行jar包,及生成exe文件

    关于如何打包/运行jar包,以及生成exe文件.之前各种查询.博客,终于搞明白究竟是咋回事.记得还做过笔记的.今天要打包生成exe用的时候,居然忘了咋怎来着.去查看之前的笔记,死活没找到(好像被删掉了 ...

  8. 【Maven学习】Maven打包生成普通jar包、可运行jar包、包含所有依赖的jar包

    http://blog.csdn.net/u013177446/article/details/54134394 ******************************************* ...

  9. jar包生制作几种方法,jar包导出三种方法:eclipse导出、jar命令、FatJar插件

    Eclipse将引用了第三方jar包的Java项目打包成jar文件的两种方法 方案一:用Eclipse自带的Export功能 步骤1:准备主清单文件 “MANIFEST.MF”, 由于是打包引用了第三 ...

随机推荐

  1. java中 try return finally return

    finally块里面的代码一般都是会执行的,除非执行 System.exit(int),停止虚拟机,断电. 1.若try代码块里面有return ,假设要return 的值 是A,A为基本类型或者被f ...

  2. Struts2(3) —— 数据处理

    Struts2框架框架使用OGNL语言和值栈技术实现数据的流转处理. 值栈就相当于一个容器,用来存放数据,而OGNL是一种快速查询数据的语言. 值栈:ValueStack一种数据结构,操作数据的方式为 ...

  3. 【转】js 中导出excel 较长数字串会变为科学计数法

    [转]js 中导出excel 较长数字串会变成科学计数法 在做项目中,碰到如题的问题.比如要将居民的信息导出到excel中,居民的身份证号码因为长度过长(大于10位),excel会自动的将过长的数字串 ...

  4. Centos6_64 rpm打包实践

    安装rpmbuild sudo yum install rpm-build 普通用户的配置 /home/you/rpmbuild/ 假设是要构建rpm的目录 先说说rpmbuild有什么用,给一个例子 ...

  5. UITextField的代理方法:textField:shouldChangeCharactersInRange:replacementString

    原文链接:http://www.cnblogs.com/zhanggui/p/6101813.html 这个我在开发的过程中用到的次数最多,因此这里就简单对其进行分析.先看看Command+点击 弹出 ...

  6. ListView setOnItemClickListener无效原因分析

    前言 最近在做项目的过程中,在使用listview的时候遇到了设置item监听事件的时候在没有回调onItemClick 方法的问题.我的情况是在item中有一个Button按钮.所以不会回调.上百度 ...

  7. jQuery与Zepto的异同

    一,同: Zepto最初是为移动端开发的库,是jQuery的轻量级替代品,因为它的API和jQuery相似,而文件更小.Zepto最大的优势是它的文件大小,只有8k多,是目前功能完备的库中最小的一个, ...

  8. linux 学习随笔-shell简单编写

    脚本最好都放在/usr/local/sbin中 脚本的执行 sh -x 脚本.sh -x可以查看执行过程 1在脚本中使用变量 使用变量的时候,需要使用$符号:  #!/bin/bash  ##把命令赋 ...

  9. 【从零开始学习Hadoop】--1.Hadoop的安装

    第1章 Hadoop的安装1. 操作系统2. Hadoop的版本3. 下载Hadoop4. 安装Java JDK5. 安装hadoop6. 安装rsync和ssh7. 启动hadoop8. 测试had ...

  10. 不同版本SQL SERVER备份还原时造成索引被禁用

    以下测试例子以SQL 2008备份,在SQL2014还原,造成索引被禁用. --备份环境(SQL Server 2008 R2) /* MicrosoftSQL Server 2008 R2 (RTM ...