场景
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
5.启动/停止服务
- 进入bin目录,执行./start.sh 启动服务
- 执行./stop.sh 停止服务