使用maven和fat jar/war运行应用程序的对比

简介

上篇文章我们介绍了Spring boot的fat jar/war包,jar/war包都可以使用 java -jar 命令来运行,而maven也提供了mvn spring-boot:run 命令来运行应用程序,下面我们看看两者有什么不同。

Spring Boot Maven Plugin

上篇文章我们提到了Spring Boot Maven Plugin,通过使用该插件,可以有效的提高部署效率,并打包成为fat jar/war包。

在打包成fat jar/war包的时候,背后实际上做了如下的事情:

  1. 管理了classpath的配置,这样我们在运行java -jar的时候不用手动指定-cp 。
  2. 使用了自定义的ClassLoader来加载和定位所有的外部jar包依赖。并且所有的依赖jar包已经被包含在这个fat包里面了。
  3. 通过manifest自动查找main() ,这样我们就不需要在java -jar中手动指定main方法。

使用Maven命令来运行应用程序

要使用maven命令来运行应用程序可以在程序的根目录下面执行:

mvn spring-boot:run

它会自动下载所需要的依赖,并运行,运行日志如下:

mvn spring-boot:run
[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< com.flydean:springboot-fatjar >--------------------
[INFO] Building springboot-fatjar 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:2.2.2.RELEASE:run (default-cli) > test-compile @ springboot-fatjar >>>
[INFO]
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ springboot-fatjar ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ springboot-fatjar ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ springboot-fatjar ---
[INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO]
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ springboot-fatjar ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] <<< spring-boot-maven-plugin:2.2.2.RELEASE:run (default-cli) < test-compile @ springboot-fatjar <<<
[INFO]
[INFO]
[INFO] --- spring-boot-maven-plugin:2.2.2.RELEASE:run (default-cli) @ springboot-fatjar ---
[INFO] Attaching agents: []

作为fat jar/war包运行应用程序

如果想打包成fat jar/war, 需要使用Maven Spring Boot plugin,如下所示,否则打包出来的jar包并不包含外部依赖:

<build>
<plugins>
...
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
...
</plugins>
</build>

如果我们的代码包含了多个main class, 需要手动指定具体使用哪一个, 有两种设置方式:

<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<configuration>
<mainClass>com.flydean.FatJarApp</mainClass>
</configuration>
</execution>
</executions>
</plugin>

或者设置star-class属性:

<properties>
<start-class>com.flydean.FatJarApp</start-class>
</properties>

使用 mvn clean package 即可打包程序,然后使用java -jar target/springboot-fatwar-0.0.1-SNAPSHOT.war

即可运行。

详解War文件

将打包好的war文件解压,我们看下War文件的结构:

里面有三部分:

  • META-INF, 里面包含有自动生成的MANIFEST.MF
  • WEB-INF/classes, 包含了编译好的class文件
  • WEB-INF/lib,包含了war的依赖jar包和嵌入的Tomcat jar包。
  • WEB-INF/lib-provided,包含了embedded模式运行所需要但是在部署模式不需要的额外的依赖包。
  • org/springframework/boot/loader,里面是Spring boot自定义的类加载器,这些类加载器负责加载外部依赖,并且使他们在运行时可用。

我们再看下MANIFEST.MF文件的内容:

Manifest-Version: 1.0
Implementation-Title: springboot-fatwar
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: com.flydean.FatWarApp
Spring-Boot-Classes: WEB-INF/classes/
Spring-Boot-Lib: WEB-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.2.2.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.WarLauncher

主要关注两行:

Start-Class: com.flydean.FatWarApp
Main-Class: org.springframework.boot.loader.WarLauncher

一个是启动类就是我们自己写的,一个是main类这个是Spring boot自带的。

详解jar文件

我们再来看下jar文件:

jar文件和war文件有一点不同,没有WEB-INF,改成了BOOT-INF。

  • 我们所有的自己的class都在BOOT-INF/classes下面。
  • 外部依赖在BOOT-INF/lib下。

我们再看下MANIFEST.MF文件有什么不同:

Manifest-Version: 1.0
Implementation-Title: springboot-fatjar
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: com.flydean.FatJarApp
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.2.2.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.PropertiesLauncher

我们可以看到Start-Class还是一样的,但是Main-Class是不一样的。

如何选择

既然有两种方式来运行应用程序,一种是使用mvn命令,一种是使用fat jar/war文件,那我们该怎么选择呢?

通常情况下,如果我们是在线下的开发环境,可以直接使用mvn命令,mvn命令需要依赖于源代码,我们可以不断的修改源代码,方便开发。

如果是在线上环境,那么我们就需要使用fat jar/war了,这样的外部依赖比较小,我们不需要在线上环境部署maven环境,也不需要源代码,只要一个java的运行时环境就可以了。

本文的代码请参考https://github.com/ddean2009/learn-springboot2/tree/master/springboot-fatwar

更多教程请参考 flydean的博客

spring boot 使用maven和fat jar/war运行应用程序的对比的更多相关文章

  1. Spring Boot 使用maven打包成jar

    1.application.properties加入如下配置 server.port= 2.修改pom.xml <?xml version="1.0" encoding=&q ...

  2. Spring Boot 的Maven多模块开发web项目使用外部容器进行部署

    Spring Boot中自带有Tomcat容器,因此Spring Boot项目只需要运行main函数,就可以运行,但是以往的web项目,我们习惯于使用自己安装的Tomcat运行或者使用Tomcat.J ...

  3. Spring Boot的Maven插件Spring Boot Maven plugin详解

    Spring Boot的Maven插件(Spring Boot Maven plugin)能够以Maven的方式为应用提供Spring Boot的支持,即为Spring Boot应用提供了执行Mave ...

  4. spring boot和maven的约定大于配置体现在哪些方面

    spring boot和maven的约定大于配置体现在哪些方面? 两者都遵从了约定大于配置的路线 约定优于配置体现点: 1.maven的目录文件结构 1)默认有resources文件夹,存放资源配置文 ...

  5. Spring boot项目maven的profile多环境配置不自动替换变量的问题解决

    Spring boot项目maven的profile多环境配置不自动替换变量的问题解决   在网上找了好久,配置都很简单,可是我的程序就是不能自动替换变量,最终单独测试,发现原来是引用spring b ...

  6. Spring Boot使用Maven打包替换资源文件占位符

    在Spring Boot开发中,通过Maven构建项目依赖是一件比较舒心的事,可以为我们省去处理冲突等大部分问题,将更多的精力用于业务功能上.近期在项目中,由于项目集成了其他外部系统资源文件,需要根据 ...

  7. spring Boot + MyBatis + Maven 项目,日志开启打印 sql

    在 spring Boot + MyBatis + Maven 项目中,日志开启打印 sql 的最简单方法,就是在文件 application.properties 中新增: logging.leve ...

  8. [Java] Spring boot 的maven设置阿里云仓库

    Spring boot 的maven设置阿里云仓库 打开根目录下的 pom.xml 文件,在对应为止出加入如下 红色 代码: <build> <plugins> <plu ...

  9. Spring Boot 项目 Maven 配置

    在配置基于Maven的Spring Boot项目的过程中,打包运行出现了一系列错误. 比如: mvn 中没有主清单属性.java.lang.NoClassDefFoundError: org/spri ...

随机推荐

  1. NKOJ3765 k个最小和

    问题描述 有k个整数数组,各包含k个元素,从每个数组中选取一个元素加起来,可以得到k^k个和,求这些和中最小的k个值. 输入格式 第一行,一个整数k(k<=500)接下来k行,每行k个正整数(& ...

  2. 探秘 RocketMQ 消息持久化机制

    我们知道 RocketMQ 是一款高性能.高可靠的分布式消息中间件,高性能和高可靠是很难兼得的.因为要保证高可靠,那么数据就必须持久化到磁盘上,将数据持久化到磁盘,那么可能就不能保证高性能了. Roc ...

  3. VirtualBox 安装 Arch Linux 并配置桌面环境

    最近无聊,就找来 Arch Linux 来玩一玩,去 archlinux wiki上看了一下教程.以下是操作过程. 1. 下载镜像,下载地址; 2. 启动 Archlinux 并选择 Boot Arc ...

  4. 《Three.js 入门指南》3.1.2 - 一份整齐的代码结构以及使用ORBIT CONTROLS插件(轨道控制)实现模型控制

    3.1.2 正式代码结构 & ORBIT CONTROLS插件(轨道控制) 说明 本节内容属于插入节,<Three.js入门指南>这本书中,只是简单的介绍了一些概念,是一本基础的入 ...

  5. linux系统部署安装过程

    1. 虚拟环境安装 1.新建虚拟机   2.虚拟机设置 2.系统历程 1.进入系统引导界面进行配置 引导项说明:            1.安装centos 系统                    ...

  6. go For-range结构

    For结构: for 初始化;条件语句;修饰语句{ 输出 } 一.For-range结构是可以怎么用? 这种构建方法可以应用于数组和切片: for ix, value := range slice1 ...

  7. PAT 链表倒序的算法优化

    之前的答案错误问题已经解决了,现在还有运行超时的问题,先贴上之前的代码 1 #include <iostream> 2 #include <string.h> 3 using ...

  8. "一号标题"组件:<h1> —— 快应用组件库H-UI

     <import name="h1" src="../Common/ui/h-ui/text/c_h1"></import> < ...

  9. editplus 怎么替换为换行

    到editplus 的搜索 菜单中,选择替换,记住 这边如果是简单的一些 通用字符 替换可以直接替换,如果是一些特殊的字符 那必须选择 替换框左下中间的 “正则表达式”,即把这个“正则表达式” 前边的 ...

  10. CVPR2020|3D-VID:基于LiDar Video信息的3D目标检测框架

    作者:蒋天园 Date:2020-04-18 来源:3D-VID:基于LiDar Video信息的3D目标检测框架|CVPR2020 Brief paper地址:https://arxiv.org/p ...