背景
SpringBoot 为我们快速开发提供了很好的架子,使得我们只需要少量配置就能开始我们的开发工作,但是当我们需要打包上传部署时,却是很神伤的一个问题,因为打出来的 Jar 包少则十几兆,多则一百来兆,我们需要上传至公网服务器时,是非常慢的,这就引出了今天的主题,SpringBoot项目Jar包如何瘦身部署
思路
分析 jar,我们可以看出,jar 包里面分为以下三个模块
分为 BOOT-INF,META-INF,org 三个部分,打开 BOOT-INF
可以看到有 classes,lib 两个文件夹,我们编译好的代码是放在 classes 里面的,而我们所依赖的 jar 包都是放在 lib 文件夹下classes 部分是非常小的(我的是3M左右),lib部分是非常大的(我的是170M+左右),所以上传很慢。
解决方法:如果能把lib部分剥离出来,每次打包时只更新当前项目的更新即可。(如果本项目所依赖有我们当前项目所需要的其他模块,其他模块更新后也需要打一个对应的lib包更新上去即可)
瘦身
正常打包
首先,我们项目的 pom.xml 文件中的打包方式如下:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
这是 SpringBoot 中默认的打包方式,我们先按照这种方式打包出来,得到一个 jar 包,我们将 jar 包解压,如果不能直接解压,则将后缀改为 zip 再进行解压,我们只需要拿到 BOOT-INF 中的 lib 目录即可。
改变打包方式
我们对 SpringBoot 中默认的打包方式做一些配置
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.xxx.XxxApplication</mainClass>
<layout>ZIP</layout>
<includes>
<include>
<groupId>nothing</groupId>
<artifactId>nothing</artifactId>
</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
- mainClass,我们指定了项目的启动类
- layout,我们指定了打包方式为 ZIP,注意:一定是大写的
- includes,有自己的依赖 jar,可以在此导入
- repackage,剔除其它的依赖,只需要保留最简单的结构
再次打包
我们再次点击 maven package,得到一个 jar 包,可以看到此时的 jar 包只有几兆了
上传启动
我们将 lib 目录,以及最后打包的瘦身项目 jar 包,上传至服务器,目录如下
[root@Test tax-expand]# tree -L 1
.
├── 1-start.sh
├── 2-stop.sh
├── lib
├── your-app.jar
└── start.sh
使用命令
nohup java -Dloader.path=./lib -jar ./your-app.jar &
- -Dloader.path,告诉它所依赖的 maven jar 包位置
- your-app.jar,项目 jar 包的名字
- nohup、&,使得 jar 包在服务后台运行
附
[root@Test tax-expand]# cat 1-start.sh
#!/bin/sh
# 脚本参数:
# debug:启用 JVM 远程调试,端口设置在 JAVA_DEBUG 变量中。
# log:打印 Java 进程标准输出内容,默认不打印,输出到 LOG_FILE 变量指定的文件中。
# 其他:带有 -D、-X、-javaagent 的参数,会添加到 JVM 参数中。
cd $(dirname $0)
./start.sh $*
[root@Test tax-expand]# cat 2-stop.sh
#!/bin/sh
# 脚本参数:
# debug:启用 JVM 远程调试,端口设置在 JAVA_DEBUG 变量中。
# log:打印 Java 进程标准输出内容,默认不打印,输出到 LOG_FILE 变量指定的文件中。
# 其他:带有 -D、-X、-javaagent 的参数,会添加到 JVM 参数中。
cd $(dirname $0)
./start.sh stop
[root@Test tax-expand]# cat start.sh
#!/bin/sh
# 脚本参数:
# debug:启用 JVM 远程调试,端口设置在 JAVA_DEBUG 变量中。
# log:打印 Java 进程标准输出内容,默认不打印,输出到 LOG_FILE 变量指定的文件中。
# 其他:带有 -D、-X、-javaagent 的参数,会添加到 JVM 参数中。
export JAR_NAME=your-app.jar
export APP_DIR=your-app
export DEPLOY_PATH=/home/application
export LOG_PATH=/data/logs/$APP_DIR
export LOG_FILE=$LOG_PATH/
export VM_OPTIONS=""
export GC_OPTIONS="-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationConcurrentTime
-XX:+PrintHeapAtGC -XX:+UseGCLogFileRotation -XX:+HeapDumpOnOutOfMemoryError -XX:NumberOfGCLogFiles=5
-XX:GCLogFileSize=5M -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly
-XX:HeapDumpPath=${LOG_PATH}/heapdump.hprof -Xloggc:${LOG_PATH}/gc.log
-XX:HeapDumpPath=${LOG_PATH}/HeapDumpOnOutOfMemoryError/"
export JAVA_DEBUG="-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=127.0.0.1:15005,server=y,suspend=n"
export STOP_TIMEOUT=120
for arg in $*; do
[ "$arg" = debug ] && enable_debug=true;
[ "$arg" = log ] && enable_log=true;
[[ "$arg" =~ -D|-X|-javaagent ]] && export VM_OPTIONS="$VM_OPTIONS $arg"
done;
JAVA="java"
[ -n "$JAVA_HOME" ] && JAVA="$JAVA_HOME/bin/java"
app_process=$(ps -ef | grep java | grep $JAR_NAME | grep -v grep | awk '{ print $2 }')
log () {
echo "$(date '+%Y-%m-%d %H:%M:%S') $*"
}
# Stop app instance.
stop_app() {
[ -z "$app_process" ] && log "Application already stoped." && return
log "Stop Application...."
ps -fp $app_process
kill -9 $app_process
# start=$(date +%s)
# while [ -n "$(ps -hp $app_process)" ]; do
# printf STOP | nc -v 127.0.0.1 $COMMAND_PORT
# log "Application stopping..."
# if [ $(($(date +%s) - $start)) -gt $STOP_TIMEOUT ]; then
# echo "[ ERROR ] Application stop timeout, kill force."
# kill -9 $app_process
# fi
# sleep 3
# done
}
[ "$1" = stop ] && stop_app && exit 0
# check app instance
[ -n "$app_process" ] && log "Application is running. ^_^" && exit 1
# Start app instance
log "Start Application."
mkdir -p $LOG_PATH; touch $LOG_FILE; cd $DEPLOY_PATH/$APP_DIR
# Set execute command line
[ ! "$enable_debug" ] && export JAVA_DEBUG=""
EXEC_CMDLINE="$JAVA -Dloader.path=./lib $VM_OPTIONS $GC_OPTIONS $JAVA_DEBUG -jar $JAR_NAME "
echo "*********************************************"
echo "Execute with the following JAVA command line:"
echo $EXEC_CMDLINE
echo "*********************************************"
# Call command line
nohup $EXEC_CMDLINE >/dev/null 2>&1 &
# Display log
[ "$enable_log" ] && tail -0f $LOG_PATH/process.log
exit 0