Assembly打包Spring Boot

168 阅读2分钟

场景

springboot + maven 支持spring-boot-maven-plugin插件打包,当我们打完包之后,想要修改application.properties,log4j2.xml等文件,就要重新打包。那么我们可以加maven-assembly-plugin插件来把项目的数据源、日志、缓存路径等配置application.properties放在打完的jar包外面。这样打出来的包,可以随时修改application .properties,log4j2.xml等配置文件。

1.添加maven配置

<!-- 指定启动类,将依赖打成外部jar包 -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>${maven-jar-plugin.version}</version>
    <configuration>
        <archive>
            <!-- 生成的jar中,不要包含pom.xml和pom.properties这两个文件 -->
            <addMavenDescriptor>false</addMavenDescriptor>
            <manifest>
                <!-- 是否要把第三方jar加入到类构建路径 -->
                <addClasspath>true</addClasspath>
                <!-- 外部依赖jar包的最终位置 -->
                <classpathPrefix>./lib</classpathPrefix>
                <!-- 项目启动类 -->
                <mainClass>com.f.Application</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>${maven-assembly-plugin.version}</version>
    <configuration>
        <descriptors>
            <descriptor>src/main/assembly/assembly.xml</descriptor>
        </descriptors>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

2.创建文件 src/main/assembly/assembly.xml

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
    <!--
        必须写,否则打包时会有 assembly ID must be present and non-empty 错误
        这个名字最终会追加到打包的名字的末尾,如项目的名字为f-boot-1.0.0,
        则最终生成的包名为 f-boot-1.0.0-bin.zip
     -->
    <id>bin</id>
    <formats>
        <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>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>src/main/resources</directory>
            <outputDirectory>/conf</outputDirectory>
            <includes>
                <include>**/*.xml</include>
                <include>**/*.txt</include>
                <include>./favicon.ico</include>
                <include>**/*.yml</include>
            </includes>
            <!-- 是否进行属性替换 -->
            <filtered>true</filtered>
        </fileSet>

        <!-- 将项目启动jar打包到boot目录中 -->
        <fileSet>
            <directory>${basedir}/target</directory>
            <outputDirectory>.</outputDirectory>
            <fileMode>0755</fileMode>
            <includes>
                <include>${project.build.finalName}.jar</include>
            </includes>
        </fileSet>
    </fileSets>
</assembly>

3.服务启动/停止脚本

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

#!/bin/bash

cd `dirname $0`
BIN_DIR=`pwd`
cd ..
DEPLOY_DIR=`pwd`
CONF_DIR=$DEPLOY_DIR/conf

SERVER_NAME="${project.artifactId}"
JAR_NAME="${project.build.finalName}.jar"
SERVER_PORT=`sed -nr '/port: [0-9]+/ s/.*port: +([0-9]+).*/\1/p' conf/application.yml`

VM_ARGS_METASPACE_SIZE='MetaspaceSize'

PIDS=`ps -ef | grep java | grep -v grep | grep "$CONF_DIR" |awk '{print $2}'`
if [ -n "$PIDS" ]; then
    echo "ERROR: The $SERVER_NAME already started!"
    echo "PID: $PIDS"
    exit 1
fi

if [ -n "$SERVER_PORT" ]; then
    SERVER_PORT_COUNT=`netstat -tln | grep $SERVER_PORT | wc -l`
    if [ $SERVER_PORT_COUNT -gt 0 ]; then
        echo "ERROR: The $SERVER_NAME port $SERVER_PORT already used!"
        exit 1
    fi
fi

JAVA_OPTS=" -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true "
JAVA_DEBUG_OPTS=""
if [ "$1" = "debug" ]; then
    JAVA_DEBUG_OPTS=" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n "
fi

# set jvm args by different java version
VM_ARGS=${VM_ARGS_METASPACE_SIZE}

JAVA_MEM_OPTS=" -server -Xmx2g -Xms2g -Xmn256m -XX:${VM_ARGS}=128m -Xss512k -XX:LargePageSizeInBytes=128m -XX:+DisableExplicitGC -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8 -XX:G1ReservePercent=15 "

echo -e "Starting the $SERVER_NAME ...\c"
nohup java $JAVA_OPTS $JAVA_MEM_OPTS $JAVA_DEBUG_OPTS -classpath $CONF_DIR -jar $JAR_NAME >/dev/null 2>&1 &

COUNT=0
while [ $COUNT -lt 1 ]; do    
    echo -e ".\c"
    sleep 1 
    COUNT=`ps -ef | grep java | grep -v grep | grep "$DEPLOY_DIR" | awk '{print $2}' | wc -l`
    if [ $COUNT -gt 0 ]; then
        break
    fi
done

echo "OK!"
PIDS=`ps -ef | grep java | grep -v grep | grep "$DEPLOY_DIR" | awk '{print $2}'`
echo "PID: $PIDS"

然后创建一个 stop.sh 文件,这个是 linux 环境下的停止脚本

#!/bin/bash

cd `dirname $0`
BIN_DIR=`pwd`
cd ..
DEPLOY_DIR=`pwd`

SERVER_NAME=${project.artifactId}
JAR_NAME="${project.build.finalName}.jar"

PIDS=`ps -ef | grep java | grep -v grep | grep "$JAR_NAME" |awk '{print $2}'`
if [ -z "$PIDS" ]; then
    echo "ERROR: The $SERVER_NAME does not started!"
    exit 1
fi

if [ "$1" != "skip" ]; then
    $BIN_DIR/dump.sh
fi

echo -e "Stopping the $SERVER_NAME ...\c"
for PID in $PIDS ; do
    kill $PID > /dev/null 2>&1
done

COUNT=0
while [ $COUNT -lt 1 ]; do    
    echo -e ".\c"
    sleep 1
    COUNT=1
    for PID in $PIDS ; do
        PID_EXIST=`ps -f -p $PID | grep java`
        if [ -n "$PID_EXIST" ]; then
            COUNT=0
            break
        fi
    done
done

echo "OK!"
echo "PID: $PIDS"

然后创建一个 dump.sh 文件,这个是 linux 环境下的dump脚本

#!/bin/bash

cd `dirname $0`
BIN_DIR=`pwd`
cd ..
DEPLOY_DIR=`pwd`
CONF_DIR=$DEPLOY_DIR/conf

SERVER_NAME="${project.artifactId}"
LOGS_FILE='./logs'

PIDS=`ps -ef | grep java | grep -v grep | grep "$CONF_DIR" |awk '{print $2}'`
if [ -z "$PIDS" ]; then
    echo "ERROR: The $SERVER_NAME does not started!"
    exit 1
fi

LOGS_DIR=""
if [ -n "$LOGS_FILE" ]; then
 LOGS_DIR=`dirname $LOGS_FILE`
else
 LOGS_DIR=$DEPLOY_DIR/logs
fi
if [ ! -d $LOGS_DIR ]; then
 mkdir $LOGS_DIR
fi
DUMP_DIR=$LOGS_DIR/dump
if [ ! -d $DUMP_DIR ]; then
 mkdir $DUMP_DIR
fi
DUMP_DATE=`date +%Y%m%d%H%M%S`
DATE_DIR=$DUMP_DIR/$DUMP_DATE
if [ ! -d $DATE_DIR ]; then
 mkdir $DATE_DIR
fi

echo -e "Dumping the $SERVER_NAME ...\c"
for PID in $PIDS ; do
 jstack $PID > $DATE_DIR/jstack-$PID.dump 2>&1
 echo -e ".\c"
 jinfo $PID > $DATE_DIR/jinfo-$PID.dump 2>&1
 echo -e ".\c"
 jstat -gcutil $PID > $DATE_DIR/jstat-gcutil-$PID.dump 2>&1
 echo -e ".\c"
 jstat -gccapacity $PID > $DATE_DIR/jstat-gccapacity-$PID.dump 2>&1
 echo -e ".\c"
 jmap $PID > $DATE_DIR/jmap-$PID.dump 2>&1
 echo -e ".\c"
 jmap -heap $PID > $DATE_DIR/jmap-heap-$PID.dump 2>&1
 echo -e ".\c"
 jmap -histo $PID > $DATE_DIR/jmap-histo-$PID.dump 2>&1
 echo -e ".\c"
 if [ -r /usr/sbin/lsof ]; then
 /usr/sbin/lsof -p $PID > $DATE_DIR/lsof-$PID.dump
 echo -e ".\c"
 fi
done

if [ -r /bin/netstat ]; then
/bin/netstat -an > $DATE_DIR/netstat.dump 2>&1
echo -e ".\c"
fi
if [ -r /usr/bin/iostat ]; then
/usr/bin/iostat > $DATE_DIR/iostat.dump 2>&1
echo -e ".\c"
fi
if [ -r /usr/bin/mpstat ]; then
/usr/bin/mpstat > $DATE_DIR/mpstat.dump 2>&1
echo -e ".\c"
fi
if [ -r /usr/bin/vmstat ]; then
/usr/bin/vmstat > $DATE_DIR/vmstat.dump 2>&1
echo -e ".\c"
fi
if [ -r /usr/bin/free ]; then
/usr/bin/free -t > $DATE_DIR/free.dump 2>&1
echo -e ".\c"
fi
if [ -r /usr/bin/sar ]; then
/usr/bin/sar > $DATE_DIR/sar.dump 2>&1
echo -e ".\c"
fi
if [ -r /usr/bin/uptime ]; then
/usr/bin/uptime > $DATE_DIR/uptime.dump 2>&1
echo -e ".\c"
fi

echo "OK!"
echo "DUMP: $DATE_DIR"

4.打包测试

使用 mvn clean package 命令对项目进行打包

打包后会生成web-1.0.0-bin.zip

web.png

5.启动/停止服务

  • 进入bin目录,执行./start.sh 启动服务
  • 执行./stop.sh 停止服务

6.参考项目地址