首页 > 编程语言 >Java 应用部署包优化经验分享

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

时间:2024-01-26 16:32:16浏览次数:25  
标签:依赖 Java 项目 部署 jar 模块 home 分享 优化

背景

最近接手了一个 2018 年的老项目,因为太久远了,功能上的代码不敢乱动。但是这个项目还有一个问题,打包模块打出的全量包部署不起来。拿到这个项目的部署包,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 应用部署包优化经验分享_jar

这些都可以清理掉。

相同 jar 的不同版本

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

比如 netty 的低版本和 netty-all 高版本,如果引用了 netty-all ,就可以清理掉 netty 低版本了,netty-moduleX 开头的低版本=netty-all 高版本,都引入就存在冗余了:

Java 应用部署包优化经验分享_依赖包_02

还有 JDK 的 tools 包:

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

这些都是磁盘蛀虫,项目部署包中没有,而且两个文件都是一样的只是版本不同。 JDK 中已经有了,如果真的要用,用 JDK/jre/ext 下的就可以了。

有冲突的包

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

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

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

比如项目没有用到 websocket 功能,但是使用的容器自带了这些包:

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

清理掉,积少成多,能少则少!

多模块公共 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 应用部署包优化经验分享_依赖包_05

整个应用的依赖包放在一起集中管理,目录清晰,更新方便。目录结构规划好之后了,就需要优化启动脚本了,应用通过 -cp 参数将依赖包目录下所有的 jar 文件拼接起来、然后启动的,很多 Java 工程都是用这个方式启动的,比如 Kafka、IDEA 启动某个主类。

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

这种设置 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 从第一个版本到最新版本,大小几乎翻了一倍;随便下一个应用都大几百兆。但也值得思考,我们发布的应用是不是可以更紧凑呢,里面真的这个应用需要的文件吗?

标签:依赖,Java,项目,部署,jar,模块,home,分享,优化
From: https://blog.51cto.com/u_12386157/9434688

相关文章

  • Java web 应用程序的部署方式有哪些
    当我们开发完一个JavaWeb应用程序后,接下来需要将其部署到服务器上,以便用户可以通过浏览器访问。本文将介绍几种常见的JavaWeb应用程序的部署方式。一、独立容器独立容器是最常见的部署方式之一,它是指将JavaWeb应用程序打包成一个独立的WAR文件,然后将该WAR文件部署到独立的Servle......
  • 使用Java读取Excel文件数据
    通过编程方式读取Excel数据能实现数据导入、批量处理、数据比对和更新等任务的自动化。这不仅可以提高工作效率还能减少手动处理的错误风险。此外读取的Excel数据可以与其他系统进行交互或集成,实现数据的无缝传输和共享,满足特定项目的需求。本文将从以下三个方面介绍如何通过Java......
  • IDEA基于maven创建Java web项目
    idea:2022.2.3 IDEA新建项目,更改项目名称,有需要的可以更改项目地址,将Buidsystem从intelliJ更改到Maven 在pom.xml中添加依赖<dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><......
  • 网站SEO优化有什么注意事项?
    网站上线后,需要从多方面进行SEO优化,提高网站的权重排名和流量,使网站更加成熟,增加访客与转化。那么,在SEO优化中需要考虑什么呢?景安虚拟主机小编与大家分享下SEO优化需要考虑的内容,一起看看吧!首先百度推出了微风算法来点击标题关键词是否有堆砌,然后在推出熊掌之后,对原来的保......
  • 将关键词优化到搜索引擎首页的方法?
    将关键词优化到搜索引擎首页的方法?下面跟北京wordpress建站公司小编一起来了解详细内容:新手在做网站SEO优化时,如何提高网站首页的关键词排名?其实这也很简单,就是优化用户喜欢的内容到搜索引擎首页,这样网站才能有更好的排名,并吸引更多准确的用户流量。在资金充足的情况下......
  • 通达信极品MACD优化版副图指标公式源码
    该指标,简单实用,看盘必备指标金叉在点阵下方时,尽量不要参与 仅在点阵上方时,可大胆介入 在点阵上方金叉的,涨势会非常顺滑DIFF:=EMA(CLOSE,12)-EMA(CLOSE,26);DIF:EMA(CLOSE,12)-EMA(CLOSE,26),LINETHICK2;DEA:EMA(DIF,9),COLORWHITE;MACD:(DIF-DEA)*2,NODRAW;DRAWBAND(......
  • Java_5 字符串
    Java字符串title:(在线学习平台)link:(https://www.acwing.com/)cover:(https://cdn.acwing.com/media/activity/surface/log.png)1.字符与整数的联系——ASCII码每个常用字符都对应一个-128~127的数字,二者之间可以相互转化。注意:目前负数没有与之对应的字符。import......
  • Sublime Text使用技巧分享
    本文档会不断更新有关字体打开Preferences->Settings,可以在右侧文件中自定义设置字体设置使用font_face属性设置示例:"font_face":"Menlo"提示:SublimeText目前不支持多字体设置,所以理论上不能像vscode那样为中文、英文分别准备一种字体。只能通过字体合并工具来解决取......
  • javascript replaceall 正则表达式
    varstr="dogdogdog";varstr2=str.replace(/dog/g,"cat");console.log(str2);参考:https://www.jb51.net/article/23762.htm?tdsourcetag=s_pcqq_aiomsgstr="dogdogdog12";str=str.replace(newRegExp("[d]","g......
  • 深度解析Java8社招面试题:Lambda序列化到底行不行?
    大家好,我是小米,一个热爱技术分享的小伙伴。今天,我们来聊一个关于Java8的话题,一个颇具技术深度的问题:“社招面试题:Java8中的Lambda表达式可以序列化吗?”废话不多说,让我们一起揭开这个技术的神秘面纱!Lambda表达式的崛起在Java8之前,我们编写代码时常常要依赖匿名内部类,这使得代码显得......