当前位置: 代码网 > it编程>编程语言>Java > 使用Assembly打包和部署SpringBoot工程方式

使用Assembly打包和部署SpringBoot工程方式

2024年12月12日 Java 我要评论
1、spring boot项目的2种部署方式目前来说,spring boot 项目有如下 2 种常见的部署方式。1、一种是使用 docker 容器去部署。将 spring boot 的应用构建成一个

1、spring boot项目的2种部署方式

目前来说,spring boot 项目有如下 2 种常见的部署方式。

1、一种是使用 docker 容器去部署。将 spring boot 的应用构建成一个 docker image,然后通过容器去启动镜像。这种方式在需要部署大规模的应用以及对应用进行扩展时,是非常方便的,属于目前工业级的部署方案,但是需要掌握 docker 的生态圈技术。

2、另一种则是使用 fatjar 直接部署启动(将一个 jar 及其依赖的三方 jar 全部打到一个包中,这个包即为 fatjar)。这是很多初学者或者极小规模情况下的一个简单应用部署方式。

2、assembly 的优势

上面介绍的 fatjar 部署方案存在以下缺陷。

1、如果直接构建一个 spring boot 的 fatjar 交由运维人员部署的话,整个配置文件都被隐藏到 jar 中,想要针对不同的环境修改配置文件就变成了一件很困难的事情。

2、如果需要启动脚本启动项目的时候,这种直接通过 jar 的方式后续会需要处理很多工作。

而通过 assembly 将 spring boot 服务化打包,便能解决上面提到的 2 个问题。

1、使得 spring boot 能够加载 jar 外的配置文件。

2、提供一个服务化的启动脚本,这个脚本一般是 shell 或者 windows 下的 bat ,有了 spring boot 的应用服务脚本后,就可以很容易的去启动和停止 spring boot 的应用了。

3、项目配置

3.1、添加插件

编辑项目的 pom.xml 文件,加入 assembly 打包插件。

<build>
    <!-- 指定需要打包编译的文件 -->
    <resources>
        <resource>
            <directory>src/main/resources</directory>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
    <plugins>
        <!-- 指定启动类,将依赖打成外部jar包 -->
        <plugin>
            <groupid>org.apache.maven.plugins</groupid>
            <artifactid>maven-jar-plugin</artifactid>
            <version>2.5</version>
            <configuration>
                <!-- 不打包配置文件 -->
                <excludes>
                    <exclude>*.xml</exclude>
                    <exclude>*.properties</exclude>
                    <exclude>*.yml</exclude>
                </excludes>
                <archive>
                    <!-- 生成的jar中,不要包含pom.xml和pom.properties这两个文件 -->
                    <addmavendescriptor>false</addmavendescriptor>
                    <manifest>
                        <!-- 是否要把第三方jar加入到类构建路径 -->
                        <addclasspath>true</addclasspath>
                        <!-- 外部依赖jar包的最终位置 -->
                        <classpathprefix>../lib</classpathprefix>
                        <!-- 项目启动类 -->
                        <mainclass>com.example.testapplication</mainclass>
                    </manifest>
                    <manifestentries>
                        <!--manifest.mf 中 class-path 加入配置文件目录-->
                        <class-path>../config/</class-path>
                        <implementation-title>${project.artifactid}</implementation-title>
                        <implementation-version>${project.version}</implementation-version>
                        <build-time>${maven.build.timestamp}</build-time>
                    </manifestentries>
                </archive>
            </configuration>
        </plugin>
        <!-- 拷贝配置文件到config目录下 -->
        <plugin>
            <groupid>org.apache.maven.plugins</groupid>
            <artifactid>maven-resources-plugin</artifactid>
            <version>2.7</version>
            <executions>
                <execution>
                    <id>copy-resources</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>
                    <configuration>
                        <resources>
                            <resource>
                                <directory>src/main/resources</directory>
                                <includes>
                                    <include>*.xml</include>
                                    <include>*.properties</include>
                                    <include>*.yml</include>
                                </includes>
                            </resource>
                        </resources>
                     <outputdirectory>${project.build.directory}/config</outputdirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <!-- 将依赖jar包拷贝到lib目录下 -->
        <plugin>
            <groupid>org.apache.maven.plugins</groupid>
            <artifactid>maven-dependency-plugin</artifactid>
            <version>2.8</version>
            <executions>
                <execution>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputdirectory>${project.build.directory}/lib</outputdirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <!-- 打包插件 -->
        <plugin>
            <groupid>org.apache.maven.plugins</groupid>
            <artifactid>maven-assembly-plugin</artifactid>
            <version>2.4.1</version>
            <configuration>
                <finalname>${project.artifactid}</finalname>
                <appendassemblyid>false</appendassemblyid>
                <descriptors>
                    <!--具体的配置文件-->
                    <descriptor>src/main/assembly/assembly.xml</descriptor>
                </descriptors>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <!--绑定到maven操作类型上-->
                    <phase>package</phase>
                    <!--运行一次-->
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <!-- 打包时跳过测试 -->
        <plugin>
            <groupid>org.apache.maven.plugins</groupid>
            <artifactid>maven-surefire-plugin</artifactid>
            <version>2.17</version>
            <configuration>
                <skiptests>true</skiptests>
            </configuration>
        </plugin>
    </plugins>
</build>

从上面代码可以看出,把 assembly 的配置都放在 main/assembly 目录下(具体目录里面的文件接下来会创建)。

3.2、编写服务启动/停止/重启脚本

在 assembly 目录下创建一个 bin 文件夹,然后在该文件夹下创建 start.sh 文件,这个是 linux 环境下的启动脚本,具体内容如下。

tip:开头的项目名称、jar 包名称不用我们手动设置,这里使用参数变量,在项目打包后这些参数自动会替换为 pom 的 profiles 中 properties 的值(assembly 配置文件需要开启属性替换功能),下面另外两个配置文件也同理。

#!/bin/bash

# 项目名称
server_name="${project.artifactid}"
# jar名称
application="${project.build.finalname}"

# 进入bin目录
cd `dirname $0`
# bin目录绝对路径
bin_path=`pwd`

# 返回到上一级项目根目录路径
cd ..
# 打印项目根目录绝对路径
# `pwd` 执行系统命令并获得结果
base_path=`pwd`

# 外部配置文件绝对目录,如果是目录需要/结尾,也可以直接指定文件
# 如果指定的是目录,spring则会读取目录中的所有配置文件
config_path=$base_path/config
log_path=$base_path/logs/${server_name}
java_opt="-server -xms1024m -xmx1024m -xmn512m"
java_opt="${java_opt} -xx:-omitstacktraceinfastthrow"
application_jar=$(ls $base_path/boot/$application.jar)
process_id=$(ps -ef|grep $base_path/boot/$application|grep -v grep|awk '{print $2}')

if [ ! -n "$process_id" ];then
  echo "$server_name服务,进程正在启动中,请稍等..."
  file="nohup.out"
  if [ ! -f "$file" ]; then
    touch "$file"
  fi
  source /etc/profile
  nohup java ${java_opt} -jar ${application_jar} > /dev/null &
  tail -f  "${log_path}/system/info.log"
else
  echo "$server_name服务,进程(id:$process_id)已存在,启动失败"
fi

创建 stop.sh 文件,这个是 linux 环境下的停止脚本,具体内容如下。

#!/bin/bash

# 项目名称
application="${project.artifactid}"

# 项目启动jar包名称
application_jar="${project.build.finalname}.jar"

# 通过项目名称查找到pid,然后kill -9 pid
process_id=$(ps -ef|grep "${application_jar}" |grep -v grep|awk '{print $2}')
if [[ -z "$process_id" ]]
then
    echo "$application服务没有启动,请进一步验证是否需要停止进程"
else
    echo "$application服务,进程已存在,正在kill进程,进程id:$process_id"
    kill -9 ${process_id}
    echo "$application服务,进程$process_id停止成功"
fi

创建 restart.sh 文件,这个是 linux 环境下的重启脚本,具体内容如下。

#!/bin/bash

# 项目名称
application="${project.artifactid}"

# 进入bin目录
cd `dirname $0`
# bin目录绝对路径
bin_path=`pwd`

echo "$application服务正在停止"
sh $bin_path/stop.sh
echo "$application服务正在重启"
sh $bin_path/start.sh

创建 server.sh 文件,这个是 linux 环境下根据指令执行服务启动、停止、重启、查看状态的脚本,具体内容如下。

#!/bin/bash

# 项目名称
server_name="${project.artifactid}"
# jar名称
application=${project.build.finalname}

# 进入bin目录
cd `dirname $0`
# bin目录绝对路径
bin_path=`pwd`

# 返回到上一级项目根目录路径
cd ..
# 打印项目根目录绝对路径
# `pwd` 执行系统命令并获得结果
base_path=`pwd`

# 外部配置文件绝对目录,如果是目录需要/结尾,也可以直接指定文件
config_path=$base_path/config
app_name=$base_path/boot/$application.jar
log_path=$base_path/logs/${server_name}
java_opt="-server -xms512m -xmx1024m -xmn512m"
java_opt="${java_opt} -xx:-omitstacktraceinfastthrow"

#判断用户是否为lbs
loginuser() {
  user=`whoami`
  if [ ${user} != "lbs" ];then
  	echo "please use user 'lbs'"
  	exit 1
  fi
}

loginuser

# 使用说明,用来提示输入参数
usage() {
  echo "usage: sh server.sh [start|stop|restart|status]"
  exit 1
}

# 检查程序是否在运行
is_exist() {
  # 根据关键字过滤进程pid,关键字由业务方自定义
  pid=$(ps -ef | grep $app_name | grep -v grep | awk '{print $2}')
  if [ -z "${pid}" ]; then
    return 1
  else
    return 0
  fi
}

# 启动程序
start() {
  # 启动程序时,可酌情根据各自服务启动条件做出相应的调整
  is_exist
  if [ $? -eq "0" ]; then
    echo "${server_name}服务进程已存在,pid=${pid}"
  else
    if [ ! -f "$log_path" ]; then
          touch "$log_path"
    fi
    source /etc/profile
    nohup java $java_opt -jar $app_name >$log_path 2>&1 &
    # 应以非阻塞方式执行服务启动命令,避免脚本一直阻塞在这里无法退出
    # 业务方应对其服务启动时间进行预估,如果从 命令下发到端口开启并对外提供服务 期间的时长超过了1分钟
    # 那么业务方则需酌情在此处使用sleep来阻塞脚本,避免因启动时间过长导致持续交付系统误判
    # 这个阻塞的时间按照各业务方不同服务自行设定
    # 且执行启动命令后,相关的服务日志应存储到指定的文件
    echo "${server_name}服务进程启动成功"
  fi
}

# 停止程序
stop() {
  # 服务停止方式及具体方法由业务方指定,避免因直接kill掉进程而影响线上业务
  # 并且确保stop函数执行结束后,服务进程不存在,避免影响后续操作
  is_exist
  if [ $? -eq "0" ]; then
    # 如果服务需要平稳的停止,保证业务流无问题,那么可使用不限于循环等方式,保证stop执行后已经停止了该服务
    # 否则后续操作可能会影响相关的业务,务必确保stop函数执行结果的准确性
    kill -9 $pid
    echo "${server_name}服务进程停止成功,pid=$pid"
  else
    echo "${server_name}服务没有启动,请进一步验证是否需要停止进程"
  fi
}

# 程序状态
status() {
  is_exist
  if [ $? -eq "0" ]; then
    echo "${server_name}服务进程正在运行,pid=${pid}"
  else
    echo "${server_name}服务进程没有启动"
  fi
}

# 重启程序
restart() {
  stop
  start
}

# 主方法入口,接收参数可支持start\stop\status\restart\
case "$1" in
"start")
  start
  ;;
"stop")
  stop
  ;;
"status")
  status
  ;;
"restart")
  restart
  ;;
*)
  usage
  ;;
esac

创建 start.bat 文件,这个是 windows 环境下的启动脚本,具体内容如下。

echo off

:: 项目名称
set app_name=${project.artifactid}
:: jar名称
set app_jar=${project.build.finalname}.jar
 
echo "开始启动服务 %app_name%"
java -xms512m -xmx512m -server -jar ../boot/%app_jar%
echo "java -xms512m -xmx512m -server -jar ../boot/%app_jar%"
goto end
 
:end
pause

3.3、创建打包配置文件

最后,我们在 assembly 文件夹下创建一个 assembly.xml 配置文件,具体内容如下。

<assembly>
    <!--
        必须写,否则打包时会有 assembly id must be present and non-empty 错误
        这个名字最终会追加到打包的名字的末尾,如项目的名字为 test-0.0.1-snapshot,
        则最终生成的包名为 test-0.0.1-snapshot-assembly.tar.gz
     -->
    <id>assembly</id>
    <!-- 打包的类型,如果有n个,将会打n个类型的包 -->
    <formats>
        <format>tar.gz</format>
        <!--<format>zip</format>-->
    </formats>
    <includebasedirectory>true</includebasedirectory>
 
    <!--第三方依赖设置-->
    <dependencysets>
        <dependencyset>
            <!-- 不使用项目的artifact,第三方jar不要解压,打包进zip文件的lib目录 -->
            <useprojectartifact>false</useprojectartifact>
            <outputdirectory>lib</outputdirectory>
            <unpack>false</unpack>
        </dependencyset>
    </dependencysets>
 
    <!--文件设置-->
    <filesets>
        <!--
            0755->即用户具有读/写/执行权限,组用户和其它用户具有读写权限;
            0644->即用户具有读写权限,组用户和其它用户具有只读权限;
        -->
        <!-- 将src/main/assembly/bin目录下的所有文件输出到打包后的bin目录中 -->
        <fileset>
            <directory>${basedir}/src/main/assembly/bin</directory>
            <outputdirectory>bin</outputdirectory>
            <filemode>0755</filemode>
            <!--如果是脚本,一定要改为unix.如果是在windows上面编码,会出现dos编写问题-->
            <lineending>unix</lineending>
            <filtered>true</filtered><!-- 是否进行属性替换 -->
        </fileset>

        <!-- 将src/main/resources下配置文件打包到config目录 -->
        <fileset>
            <directory>${basedir}/src/main/resources</directory>
            <outputdirectory>/config</outputdirectory>
            <includes>
                <include>*.xml</include>
                <include>*.properties</include>
                <include>*.yml</include>
            </includes>
            <filtered>true</filtered><!-- 是否进行属性替换 -->
        </fileset>

        <!-- 将第三方依赖打包到lib目录中 -->
        <fileset>
            <directory>${basedir}/target/lib</directory>
            <outputdirectory>lib</outputdirectory>
            <filemode>0755</filemode>
            <includes>
                <include>*.jar</include>
            </includes>
        </fileset>

        <!-- 将项目启动jar打包到boot目录中 -->
        <fileset>
            <directory>${basedir}/target</directory>
            <outputdirectory>boot</outputdirectory>
            <includes>
                <include>${project.build.finalname}.jar</include>
            </includes>
        </fileset>
      </filesets>
  </assembly>

3.4、打包测试

配置修改完毕后,我们对项目进行打包。将生成的压缩包解压后可以发现,boot 文件夹下项目 jar 包和lib文件夹下第三方 jar 分开了,并且项目 jar 体积也十分小巧。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com