Java 应用部署包优化经验分享

这篇具有很好参考价值的文章主要介绍了Java 应用部署包优化经验分享。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

最近接手了一个 2018 年的老项目,因为太久远了,功能上的代码不敢乱动,虽然是老项目,但最近一年也在持续加功能,功能不稳定,于是我就进入了救火式改 Bug 的状态。

功能不能妄动,但是这个项目还有一个问题,打包模块打出的全量包部署不起来。拿到这个项目的部署包,400 多兆,网速慢的情况下,下载、上传都得好半天。分析了一下部署包,决定先优化一下,本文记录这个 Java 应用的部署包优化过程。

优化主要是清理 Java 依赖,内容有:

  1. 无用依赖
  2. 测试相关的依赖
  3. 相同 jar 的不同版本
  4. 有冲突的 jar
  5. 容器自带、但是项目无用的包
  6. 第三方组件中的无用文件,如 docs、.cmd 、NOTICES、src 源码等

无用依赖包

项目创建初期的 pom 文件大概是从别的旧项目拷贝过来的,没有做过清理,里面有一些引用包但是工程中没有用到的。比如 ,ftpserver-core、sshd-core,注释掉这些引用后,项目编译能通过,打包后生成的 lib 包中也没有这些模块,说明就是无用的,可以清理掉。

此外,项目初期引 jar 的时候,有必要搞明白引入的包是实现什么功能的,项目是否用得到。如果不确定能否用到,可以只在 maven 父工程的依赖管理中定义,子模块需要的时候再引入。

测试相关的依赖包

maven 项目引入模块时,虽然 scope 设置为 test,但是打包的时候,这些 jar 还是会被加入到第三方依赖 lib 目录下。所以在整理项目部署包的时候,需要手动剔除掉各种测试相关的依赖包。

主要有 junit、自动化测试框架、第三方测试工具类等,搜索出来:
Java 应用部署包优化经验分享,项目开发问题,java,经验分享,开发语言
这些都可以清理掉。

相同 jar 的不同版本

部署包中存在一些名称相同、版本号不一样的 jar ,需要手动清理。

比如 netty 的低版本和 netty-all 高版本,如果引用了 netty-all ,就可以清理掉 netty 低版本了,netty-moduleX 开头的低版本=netty-all 高版本,都引入就存在冗余了:
Java 应用部署包优化经验分享,项目开发问题,java,经验分享,开发语言
还有 JDK 的 tools 包:
Java 应用部署包优化经验分享,项目开发问题,java,经验分享,开发语言
这些都是磁盘蛀虫,项目部署包中没有,而且两个文件都是一样的只是版本不同。 JDK 中已经有了,如果真的要用,用 JDK/jre/ext 下的就可以了。

有冲突的包

Java 框架发展过程中,有一些相互冲突的包,是不应该同时引入的。同时引入,而且能正常运行,只能说是幸运。

比如,servlet-api-2.5.jar 和 javax.servlet-api-3.1.0.jar。servlet-api-2.5.jar 这个版本,可以直接清理掉。

容器引用但是项目完全无用的包

比如项目没有用到 websocket 功能,但是使用的容器自带了这些包:
Java 应用部署包优化经验分享,项目开发问题,java,经验分享,开发语言
清理掉,积少成多,能少则少!

多模块公共 jar 共享

这个项目组件比较少,一个后台、一个前端,但是两个模块有公共的 jar ,梳理出来后,公共包有几十兆。而项目源码包也两个模块共同的包,每次发布补丁的时候都要同时更新两个组件的依赖。

所以,彻底的优化方案是,对项目模块的 jar 进行分类,按当前工程分为四个 jar 包目录:

  1. commonLib:所有模块公共引用的包
  2. moduleALib:模块 A 引用的包
  3. moduleBLib:模块 B 引用的包
  4. dynamicLib:应用中支持动态上传的包

计算模块 A 和模块 B 公共依赖的方法,用 Shell 脚本就可以完成:

进入 moduleA 全量包目录,ll|grep -v 总量|awk '{print $NF}' > /home/alib.log
进入 moduleB 全量包目录,ll|grep -v 总量|awk '{print $NF}' > /home/blib.log
file1="/home/alib.log" #第一个文件名
file2="/home/blib2.log" #第二个文件名
#通过comm命令获取公共行 
common_lines=$(comm -12 <(sort "$file1") <(sort "$file2")) 
echo "$common_lines" > /home/commlib.log

计算出公共包后,就可以将模块 A、B 全量包中的公共文件移除到公共目录了

进入 moduleA 全量包目录,cat /home/commlib.log |xargs -I file mv file /home/commonlib
进入 moduleB 全量包目录,cat /home/commlib.log |xargs -I file mv file /home/commonlib

这样就得到了整个应用的最终依赖包:
Java 应用部署包优化经验分享,项目开发问题,java,经验分享,开发语言
整个应用的依赖包放在一起集中管理,目录清晰,更新方便。目录结构规划好之后了,就需要优化启动脚本了,应用通过 -cp 参数将依赖包目录下所有的 jar 文件拼接起来、然后启动的,很多 Java 工程都是用这个方式启动的,比如 Kafka、IDEA 启动某个主类。
Java 应用部署包优化经验分享,项目开发问题,java,经验分享,开发语言
这种设置 Java 类路径的方法,有一个大问题,就是如果依赖包过多时,进程的启动命令会拼接的很长,比如上面这个,一屏都看不到这个进程的全貌。

有三种方法可以改善这个问题:

  1. -cp 拼接路径可以用通配符-cp /xx/lib/*:/lib/*
  2. -Djava.ext.dirs:这是普通 Java 应用的参数。
  3. -Dloader.path:SpringBoot 引用的启动参数。

这个工程是原生的 SpringMVC 项目,尝试了第二种方法,但是找不到主类,最终选择了第一种方法。

修改应用中组件 A、B 的启动脚本,将拼接 -cp 参数的部分直接改为当前应用部署包中 lib 目录:

模块 A 的启动脚本中拼接依赖的地方 moduleALib = moduleALib+commonLib
CLASSPATH=${APP_HOME}/lib/commonLib/*:${APP_HOME}/lib/moduleALib/*
同理修改模块 B 的启动脚本。

第三方组件的无关文件

最后一点可以优化的是第三方组件中的无关文件了,部署包中显然用不上。
主要有:

  1. docs :组件说明文档。
  2. src :源码。
  3. LICENCES 文件。
  4. NOTICES 文件。
  5. cmd 启动脚本,目标是 Linux ,显然用不到 cmd 脚本。
  6. tools ,一些用来调试的工具。

启示录

经过这一些列的操作后,部署包从 400 多兆减少到了 178M,使用精简之后的部署包运行时,如果启动失败,再排查缺什么 jar ,就加上。还是比较顺利的,5轮报错后,程序就正常启动了。没有表面的错误,其他功能有没有影响,还需要继续观察。

最后一步,以精简之后的目录结构调整打包脚本,保证项目源码打出的全量包是可用的,顺手写一个补丁包打包模块。这极大方便了部署包的准备工作,按之前的流程,要拿到第一版的部署包,将项目打包出来的 6个 jar ,逐个替换部署包对应目录的文件。让工程的打包模块真正能打包,能极大减少人工操作。

部署包优化其实是个费力不讨好的事情,中途搞一半有点弄不下去了,担心优化过度后项目跑不起来了怎么办!况且,项目源码存在这么多年、经手人都多少波了,也没有人考虑过这种问题,而且豪横的项目组磁盘资源根本不是事儿,这点优化是否有必要呢?

谁让我碰到了呢!作为一个还算有点工匠精神的超级熟练程序员,真的忍不了这些问题。优化还是有成效的,至少方便自己了,经过一轮改造后,部署、发包就方便多了。

其实本文记录的工作应该是项目开发完成后,发布部署包时就应该做的工作,虽然部署包越来越大是趋势,例如:Kafka 从第一个版本到最新版本,大小几乎翻了一倍;随便下一个应用几百兆。但也值得思考,我们发布的应用是不是可以更紧凑呢,里面真的这个应用需要的文件吗?文章来源地址https://www.toymoban.com/news/detail-811511.html

到了这里,关于Java 应用部署包优化经验分享的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【java】Java项目从开发到部署生产完整流程梳理

    从事Java开发许久,从最初学习的JDK环境变量开始,到如今开发部署发布,已经逐渐形成了自己的一套体系,当然,其中也不少学习了网上各种资料总结,接下来将在本文对Java项目开发到部署发布整个流程进行归纳梳理。 关于开发环境,在之前写的一篇文章里有详细教学,因

    2024年02月03日
    浏览(31)
  • 前端开发者必备:Nginx部署前端项目,让你的Web应用快速、稳定、安全地运行

    Nginx是一个高性能的HTTP和反向代理服务器,它可以用来部署前端项目,提供静态文件服务、负载均衡、缓存等功能。本文将介绍如何使用Nginx部署前端项目。 1. 安装Nginx 首先需要安装Nginx,可以通过源码编译安装,也可以通过包管理器安装,例如Ubuntu下可以使用以下命令安装

    2024年02月13日
    浏览(37)
  • GAMS---典型优化模型和算法介绍、GAMS安装和介绍、GAMS程序编写、GAMS程序调试、实际应用算例演示与经验分享

    优化分析是很多领域中都要面临的一个重要问题,求解优化问题的一般做法是:建立模型、编写算法、求解计算。常见的问题类型有线性规划、非线性规划、混合整数规划、混合整数非线性规划、二次规划等,优化算法包括人工智能算法和内点法等数学类优化方法。算法编写

    2024年02月16日
    浏览(34)
  • 【Java开发】 Spring 11 :Spring Boot 项目部署至云服务器

    Spring Boot 项目开发结束后的工作便是运维,简单来说需要配置 Web 运行参数和项目部署两大工作,本文将尽可能详细地给大家讲全! 目录 1 定制 Web 容器运行参数 1.1 运行参数介绍 1.2 项目搭建 ① 通过 IDEA Spring Initializr 创建项目 ② 添加 Spring Web 等依赖 ③ 编写 controller 层的

    2023年04月23日
    浏览(39)
  • Qt项目开发经验:在Linux平台下使用Qt进行开发

    Qt项目开发经验:在Linux平台下使用Qt进行开发 如今,Qt已成为跨平台应用程序开发中的一大宠儿。在Linux平台下,Qt的应用也是越来越广泛了。今天,我将和大家分享一些我在Linux平台下使用Qt进行开发的经验。 首先,在Linux平台下安装Qt并不复杂。我们可以通过apt-get工具来安

    2024年02月08日
    浏览(47)
  • Java企业级信息系统开发学习笔记(4.2)Spring Boot项目单元测试、热部署与原理分析

    该文章主要为完成实训任务,详细实现过程及结果见【http://t.csdn.cn/pG623】 1. 添加测试依赖启动器和单元测试 修改pom.xml文件,添加依赖 刷新项目依赖 2. 创建测试类与测试方法 在 src/test/java 里创建 cn.kox.boot 包,创建测试类 TestHelloWorld01 给测试类添加测试启动器注解与Spring

    2024年02月10日
    浏览(43)
  • MySql优化经验分享

    我们怎么查看MySQL当前有多少个连接? 可以用show status命令,模糊匹配Thread, Show global status like \\\"Thread%\\\" show global variables like \\\'wait timeout\\\';—非交互式超时时间,如JDBC程序 show global variables like \\\'interactive timeout\\\';\\\"交互式超时时间,如数据库工具默认都是28800秒,8小时。 既然连接消

    2024年02月05日
    浏览(25)
  • Web站点性能优化经验分享

            之前负责IT团队项目管理工作,手里有几套业务站点。其中一个站点被业务吐槽比较严重,主要涉及功能模块缺失、站点性能差会出现卡死的现象,同时也被旁边的项目团队埋怨调用我们的接口会比较慢,甚至超时的情况。         鉴于业务压力,准备对这个

    2024年02月03日
    浏览(38)
  • 【实战项目开发技术分享】谈谈机器人如何进行脱困

    在机器人科学和技术领域,我们经常谈论的是机器人的精密运动、

    2024年02月09日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包