当前位置: 首页 > news >正文

为什么SpringBoot胖Jar不好

公平地说,我有时会怀念 JavaEE 流行的日子。

当然,当时的情况很复杂,但整个 JavaEE 平台设计合理,符合企业开发的需要。

我可以很轻松地将当时的 JavaEE 应用服务器与现代 Kubernetes 架构进行比较,后者现在也有同样的复杂性、安全性和可维护性问题,甚至可能更糟。而且与 JavaEE 时代不同的是,它没有真正的替代方案。

当时的 JavaEE 和现在的 Kubernetes 都试图(但都失败了)将开发人员从构建可扩展分布式应用的复杂性中解脱出来。

事实上,还有更多的类比,我发现我们现在正在绕一个大圈,先是尝试应用服务器集群,然后是微服务、容器、Kubernetes,现在又回到了模块化单体,而使用类似应用服务器这样允许多个应用/模块并排部署的东西,可能并不是那么疯狂的想法。

考虑到 uber jar 在容器镜像中的效率太低,而将应用程序与其依赖关系分开部署在一个单独的镜像层中更有意义,你就会再次想到单独的应用程序服务器,只不过是在无休止的螺旋式上升的另一个层次上。

JavaEE 规范成功地度过了 Spring 占据主导地位的时代,现在可能会迎来复兴。不知何故,基于 JavaEE 标准的 Quarkus 如今看起来比 Spring 更现代。

欢迎回到新旧 JavaEE 世界。

网友讨论
JEE 背后的许多设计决策都是考虑垂直扩展,容器和微服务有利于水平扩展,不需要应用程序服务器的复杂性。与之互补的是,像 kubernetes 这样的东西使集群充当平台,有可能比大型应用程序服务器规模更大,并且成本更低(许多小型机器与一台大型专用机器)。

==================

如果您想在容器中运行 JVM 应用程序,以获得它能带来的所有好处(可扩展性、声明式方法、自动重启......),那么您绝不会想运行一个完整的应用服务器。

在容器中运行一个完整的应用服务器是没有意义的:它很重,启动速度慢,而且失去了应用服务器的优势。

这不是唯一的原因,因为在容器出现之前,人们就已经开始远离应用服务器了,但这无疑 "扼杀 "了应用服务器。

==================
这其实是个很好的问题,考虑到 Spring Boot 捆绑了Web服务器--我在 Docker 中对捆绑了 Wildfly 服务器的 Jakarta EE 应用程序也做了同样的处理,机制相同,结果相同。

但不管怎么说,Spring Boot 已经过时了,Micronaut、Quarkus 和 GraalVM 的本地可执行文件才是未来的趋势--速度更快,占用内存更少。

=================

应用服务器的最大优点是,你可以用一个 JVM 来管理一切。最大的缺点是只有 1 个 JVM。如果我运行 10 个应用程序,其中一个占用了 JVM 的所有可用内存,那么就会有 10 个应用程序崩溃。而在容器中,尽管内存效率较低,但一个应用程序崩溃也只是该应用程序崩溃。

甚至在容器出现之前,我们公司就遇到过这个问题。我们编写了自己的调度程序和 Java 运行程序,因为这比让大型 tomcat 服务器运行所有程序要简单得多。结果,我们的可靠性大大提高了。

如果 Java 有类似 erlang 的内存空间/进程,那么 EE 模型就会更好用。但是,Java 并不具备这种能力,以后也不会有(太贵了)。

================

可能是因为 Java EE 的最后一次发布是在 2017 年。真实答案为什么你认为它不流行?Jakarta 工作组正在向前推进。你可以在这里看到所有兼容的实现:https://jakarta.ee/compatibility/。很多人正在在 Jakarta EE 上部署应用程序。很抱歉,它在 twitter/tiktok/youtube 上并不流行。

================
不可变容器是一种卓越的部署模式。我们这些多年来一直在管理应用程序/Web 服务器的人再也不想回到那种模式了。先不说容器模式为生产系统管理带来的相对便利,单是开发人员工作效率上的差异就值得我们这样做。

此外,由于部署单元是容器,因此不需要胖 jar。我个人更喜欢使用 Quarkus 的瘦 jar。

在你的容器中,你要么需要一个内嵌有 servlet 容器的胖jar,要么需要一个预部署了应用程序的 servlet 容器。

人们通常会选择带有嵌入式 servlet 容器的 胖jar。

胖 jar 只是一个包含所有依赖项的 jar:当你把应用程序从一个地方复制到另一个地方,或者分发你的应用程序以便在其他地方运行时,它非常方便。

在容器化的世界里,你分发的就是一个容器:在容器中,如果你的应用程序是一个单独的 jar,而它的依赖项在文件系统的其他地方,或者它们作为胖 jar 的一部分包含在 jar 中,那么这并不重要。

我的意思是,如果你要分发一个容器,就真的不需要像 Spring Boot 那样将应用程序及其依赖项打包在一个单一的 jar 中。

Jib 在某种程度上就是这么做的,它不是创建一个胖Jar,而是创建一个多层容器,在不同的层上有不同类别的依赖关系。一个额外的步骤/层可以是网络服务器。

对于这样的应用来说,Jib 就显得有些矫枉过正了。在 Spring Boot 中,spring-boot-thin-launcher 可以生成应用程序的精简 jar 发行版。您必须在容器创建前(或作为创建过程的一部分)将其配置为下载依赖项。否则,它会在您启动容器时下载您的依赖项,这不是好的做法。

Quarkus 默认生成 fast-jar(瘦 jar):

  • 它使用自定义类加载器加载依赖项,速度比系统类加载器快很多。
  • 任何生成瘦 jar 的构建都会将所有依赖项和构建的应用程序 jar 复制到 "target "下的文件夹中。然后,你只需在构建容器时复制该文件夹即可。

这种瘦 jar方式为什么比胖Jar好?
如果你在编译/编辑/运行循环中进行 docker 部署,它就会非常有用。或者,当你在更高的环境中四处奔波,试图让东西正常工作时,它也非常有用。

如果把复制 jar 分成两个 COPY 命令:

  • 第一个复制所有依赖库

  • 第二个复制应用逻辑 jar,

这意味着 docker 会创建两个独立的层。依赖库很少变化,所以 docker 只需要在极少数情况下推送这一层。

对于有大量依赖库的大型项目来说,在网络连接速度较慢的情况下(我在家里工作,网络连接速度很差),大多数情况下,推送操作可以从 2-3 分钟缩短到小于 30 秒。

它还能节省推送到的 docker 仓库的空间。所有使用相同依赖关系的镜像都指向同一层。

因此,在容器环境中,生成胖 jar 是不必要的。瘦 jar 格式是自然的 Java 方式。

生成廋Jar的小技巧
很少有人知道 MANIFEST.MF classpath 条目。Maven 可以自动生成这个条目,例如

${settings.localRepository}

   
org.apache.maven.plugins
maven-jar-plugin


default-jar



true
${exec.mainClass}
${exec.classpathPrefix}
repository
false





这将使 JAR 可以运行,前提是类路径条目是相对或绝对的。

这比 Spring Boot 的 fatjar 启动时间要快得多

基本上,你在开发过程中的运行方式已经发生了变化。由于无需为开发和 CI 打包一个巨大的 jar,构建时间大大缩短。

至于 docker,你可以先构建,然后复制依赖项,更改 classpathprefix 并使用依赖项插件,或者使用 maven 构建插件和 Transitive Deps(~/.m2/),接受一个稍大的镜像......例如,你可以用本地 maven 仓库装运一个容器。

相关文章:

为什么SpringBoot胖Jar不好

公平地说,我有时会怀念 JavaEE 流行的日子。 当然,当时的情况很复杂,但整个 JavaEE 平台设计合理,符合企业开发的需要。 我可以很轻松地将当时的 JavaEE 应用服务器与现代 Kubernetes 架构进行比较,后者现在也有同样…...

Java学习笔记2024/2/6

练习三:验证码 需求: 定义方法实现随机产生一个5位的验证码 验证码格式: 长度为5 前四位是大写字母或者小写字母 最后一位是数字 package com.angus.comprehensiveExercise; ​ import java.util.Random; ​ public class test3 {publ…...

2024 高级前端面试题之 前端安全模块 「精选篇」

该内容主要整理关于 前端安全模块 的相关面试题,其他内容面试题请移步至 「最新最全的前端面试题集锦」 查看。 前端安全模块精选篇 1. 代码注入XSS如何攻击如何防御cookie 如何防范 XSS 攻击 2. 跨站请求伪造CSRF3. 浏览器同源策略 SOP4. 跨域资源共享 CORS5. 密码…...

SpringBoot Security安全认证框架初始化流程认证流程之源码分析

SpringBoot Security安全认证框架初始化流程&认证流程之源码分析 以RuoYi-Vue前后端分离版本为例分析SpringBoot Security安全认证框架初始化流程&认证流程的源码分析 目录 SpringBoot Security安全认证框架初始化流程&认证流程之源码分析一、SpringBoot Security安…...

2024美赛预测算法 | 回归预测 | Matlab基于RIME-LSSVM霜冰算法优化最小二乘支持向量机的数据多输入单输出回归预测

2024美赛预测算法 | 回归预测 | Matlab基于RIME-LSSVM霜冰算法优化最小二乘支持向量机的数据多输入单输出回归预测 目录 2024美赛预测算法 | 回归预测 | Matlab基于RIME-LSSVM霜冰算法优化最小二乘支持向量机的数据多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效…...

test1

1...

远程主机可能不符合 glibc 和 libstdc++ Vs Code 服务器的先决条件

vscode连接远程主机报错,原因官方已经公布过了,需要远程主机 glibc>2.28,所以Ubuntu18及以下版本没法再远程连接了,其他Linux系统执行ldd --version查看glibc版本自行判断。 解决方案建议: 不要再想升级glibc了 问题…...

备战蓝桥杯---数据结构与STL应用(进阶2)

本文将主要围绕有关map的今典应用展开&#xff1a; 下面我用图进行分析&#xff1a; 下面为AC代码&#xff1a; #include<bits/stdc.h> using namespace std; struct Point {int x,y;bool operator < (const Point & r) const {return x < r.x || ( x r.x &a…...

SpringBoot:多环境配置

多环境配置demo代码&#xff1a;点击查看LearnSpringBoot02 点击查看更多的SpringBoot教程 方式一、多个properties文件配置 注意&#xff1a;创建properties文件,命名规则&#xff1a;application-&#xff08;环境名称&#xff09; 示例&#xff1a;application-dev.proper…...

input框中添加一个 X(关闭/清空按钮)

要在输入框&#xff08;<input> 元素&#xff09;中添加一个 X&#xff08;关闭/清空按钮&#xff09;&#xff0c;可以使用 CSS 和 JavaScript 实现。 HTML&#xff1a; <div class"input-container"><input type"text" id"myInput…...

Unity3d Shader篇(三)— 片元半兰伯特着色器解析

文章目录 前言一、片元半兰伯特着色器是什么&#xff1f;1. 片元漫反射着色器的工作原理2. 片元半兰伯特着色器的优缺点优点&#xff1a;缺点&#xff1a; 3. 公式 二、使用步骤1. Shader 属性定义2. SubShader 设置3. 渲染 Pass4. 定义结构体和顶点着色器函数5. 片元着色器函数…...

【vue3学习P5-P10】vue3语法;vue响应式实现

0、vue2和vue3对比 框架版本API方式双向绑定原理domFragmentsTree-Shakingvue2选项式API&#xff08;Options API&#xff09;基于Object.defineProperty&#xff08;监听&#xff09;实现&#xff0c;不能双向绑定对象类型的数据【通过Object.defineProperty里面的set和get做…...

相机图像质量研究(3)图像质量测试介绍

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…...

PaddleDetection学习5——使用Paddle-Lite在 Android 上实现实时的人脸检测(C++)

使用Paddle-Lite在 Android 上实现实时的人脸检测 1 环境准备2. 部署步骤2.1 下载Paddle-Lite-Demo2.2 运行face_detection_demo项目3 使用Opencv对后处理进行优化4 开启手机摄像头进行人脸检测1 环境准备 参考前一篇在 Android 上使用Paddle-Lite实现实时的目标检测功能 2. …...

全套电气自动化样例图纸分享,使用SuperWorks自动化版免费设计软件!

今天给大家分享一套完备的电气自动化样例图纸&#xff0c;结构准确、内容清晰&#xff0c;适合初学者入门操作练习。 整套图纸包含图纸目录、原理图、端子列表、连接列表、元件列表、接线图&#xff0c;具有较高的参考价值&#xff0c;请大家点击自行下载文件&#xff01; 1e8…...

带你实现用自己域名打开Tomcat

文章目录 Tomcat1.1、Tomcat 下载1.2、Tomcat 文件图解1.3、 启动或关闭 Tomcat1.3.1、 启动1.3.2、 关闭程序2.1、 修改端口号2.2、修改主机名称Tomcat 1.1、Tomcat 下载 首先去Tomcat 官网下载找到我们需要下载的版本 1.2、To...

python coding with ChatGPT 打卡第18天| 二叉树:从中序与后序遍历序列构造二叉树、最大二叉树

相关推荐 python coding with ChatGPT 打卡第12天| 二叉树&#xff1a;理论基础 python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历 python coding with ChatGPT 打卡第14天| 二叉树的广度优先遍历 python coding with ChatGPT 打卡第15天| 二叉树&#xff1a;翻转…...

java基础训练题(1)

1.下列代码段中&#xff0c;存在编译错误的语句是(B C D) byte b1 1,b2 2,b3,b6,b8; final byte b4 4,b5 6,b7; b3 (b1 b2);/*语句1*/ b6 b4 b5 ; /*语句2*/ b8 (b1 b4);/*语句3*/ b7 (b2 b5);/*语句4*/ System.out.println(b3 b6);A: 语句2 B: 语句1 C: 语句3…...

【自定义序列化器】⭐️通过继承JsonSerializer和实现WebMvcConfigurer类完成自定义序列化

目录 前言 解决方案 具体实现 一、自定义序列化器 二、两种方式指定作用域 1、注解 JsonSerialize() 2、实现自定义全局配置 WebMvcConfigurer 三、拓展 WebMvcConfigurer接口 章末 前言 小伙伴们大家好&#xff0c;上次做了自定义对象属性拷贝&#x…...

闲聊电脑(5)装个 Windows(一)

​夜深人静&#xff0c;万籁俱寂&#xff0c;老郭趴在电脑桌上打盹&#xff0c;桌子上的小黄鸭和桌子旁的冰箱又开始窃窃私语…… 小黄鸭&#xff1a;冰箱大哥&#xff0c;上次说到硬盘分区和格式化&#xff0c;弄完之后&#xff0c;就该装系统了吧&#xff1f; 冰箱&#x…...

CVPR 2026 手物交互数据生成新SOTA

Project Page: https://gasaiyu.github.io/PAM.github.io/01▪ 在只给定初始姿态、目标姿态和不含外观的物体几何信息的输入下&#xff0c;如何直接生成逼真的手物交互&#xff08;HOI&#xff09;视频&#xff1f;▪ 现有方法存在一系列问题&#xff1a;姿态合成方法只能预测 …...

LiuJuan Z-Image Generator真实案例:为独立音乐人生成专辑封面人像全流程

LiuJuan Z-Image Generator真实案例&#xff1a;为独立音乐人生成专辑封面人像全流程 最近&#xff0c;一位独立音乐人朋友找到我&#xff0c;说他想为自己的新专辑设计一个封面。预算有限&#xff0c;请不起专业画师&#xff0c;但又不想要那些千篇一律的模板。他想要一张能体…...

Qwen3-0.6B-FP8实战案例:为嵌入式系统开发提供代码生成与调试建议

Qwen3-0.6B-FP8实战案例&#xff1a;为嵌入式系统开发提供代码生成与调试建议 最近在折腾一个STM32的小项目&#xff0c;想用PWM调个呼吸灯&#xff0c;结果对着手册和寄存器配置了半天&#xff0c;不是时钟没配对就是占空比算错&#xff0c;一编译还报了一堆警告。相信不少搞…...

毕业季论文救星:深度解析百考通AI如何智能攻克文献综述与开题报告

又到一年毕业季&#xff0c;无数莘莘学子在为自己学术生涯的“终极答卷”——毕业论文而挑灯夜战。其中&#xff0c;文献综述的浩如烟海与开题报告的千头万绪&#xff0c;无疑是横亘在大多数同学面前的两座大山。你是否也曾面对海量文献不知如何筛选梳理&#xff1f;是否为构建…...

别再手动调参了!用C#和Halcon的HSmartWindow控件,5分钟搞定ROI绘制与参数提取

工业视觉开发革命&#xff1a;用C#封装Halcon ROI的智能实践 在半导体检测、精密零件测量等工业场景中&#xff0c;区域兴趣&#xff08;ROI&#xff09;的精准定义直接影响着算法效果。传统开发模式下&#xff0c;工程师需要反复在Halcon脚本与C#界面代码间切换&#xff0c;手…...

WRF风场后处理实战:用Python+Cartopy绘制500hPa风场矢量图(附完整代码)

WRF风场后处理实战&#xff1a;用PythonCartopy绘制500hPa风场矢量图&#xff08;附完整代码&#xff09; 气象数据分析中&#xff0c;风场可视化是理解大气环流特征的关键环节。WRF&#xff08;Weather Research and Forecasting&#xff09;模式输出的数据包含丰富的三维风场…...

雪女-斗罗大陆模型案例分享:多种提示词生成不同风格雪女图

雪女-斗罗大陆模型案例分享&#xff1a;多种提示词生成不同风格雪女图 最近在体验“雪女-斗罗大陆-造相Z-Turbo”这个AI绘画模型时&#xff0c;我发现了一个特别有意思的现象&#xff1a;同样一个模型&#xff0c;用不同的提示词描述&#xff0c;能画出风格迥异的雪女形象。有…...

Ostrakon-VL-8B零基础上手:无需Python基础,通过Chainlit界面完成首次图文问答

Ostrakon-VL-8B零基础上手&#xff1a;无需Python基础&#xff0c;通过Chainlit界面完成首次图文问答 你是不是对AI图文对话很感兴趣&#xff0c;但一看到Python代码、命令行就头疼&#xff1f;是不是觉得部署一个多模态大模型需要专业的技术背景&#xff1f;今天我要告诉你一…...

前端开发者必看:5个提升AI提示词效果的实战技巧(附代码示例)

前端开发者必看&#xff1a;5个提升AI提示词效果的实战技巧&#xff08;附代码示例&#xff09; 当ChatGPT帮你生成React组件却总跑偏&#xff0c;当Copilot给出的代码建议总差那么点意思——作为前端开发者&#xff0c;你可能已经意识到&#xff1a;AI工具的表现力&#xff0c…...

AI编程专栏(三) - Cursor 高级技巧与实战优化

1. Cursor高级功能深度解析 第一次接触Cursor时&#xff0c;你可能觉得它就是个带AI的代码编辑器。但当我真正用它完成一个企业级项目后&#xff0c;才发现那些藏在深处的功能才是真正的生产力神器。比如最近在重构一个老旧的React项目时&#xff0c;通过合理使用MCP协议&#…...