背景
随着Springboot的流行,越来越多的项目打的都是jar包,而取代了war包。虽然jar包启动已经很简单了,但是如果我们需要修改配置文件某项配置,又需要修改,重新打成jar包,或者直接使用linux命令,修改jar包文件,但是这些都不方便。通过maven assembly插件,可以轻松将项目打成tar.gz包,便于我们修改配置
打包后项目结构
项目结构如图:
- tmp目录我们可以存放临时文件,可以编写定时任务定时清除
- run目录存放jar包运行的服务进程号
- logs目录存放运行时日志文件
- lib目录存放jar包
- bin目录存放可执行文件
- conf目录存放配置文件
步骤
pom文件添加插件
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>static/**</exclude>
<exclude>bin/ci.sh</exclude>
</excludes>
<includes>
<include>mybatis/**</include>
<include>bin/*.sh</include>
<include>*.properties</include>
<include>*.yml</include>
<include>*.yaml</include>
<include>*.xml</include>
<include>*.json</include>
</includes>
</resource>
<!-- fonts file cannot use filter as the data structure of byte file will
be changed via filter -->
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>static/**</include>
<include>templates/**</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<excludes>
<exclude>*.properties</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
<!--source-jar的编译-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!--maven打包插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
<goal>build-info</goal>
</goals>
<configuration>
<!--主启动文件-->
<mainClass>com.sun.accsmbly.Application</mainClass>
<classifier>with-dependencies</classifier>
</configuration>
</execution>
</executions>
</plugin>
<!-- 这个插件是关键,并且需要放在最后,否则可能lib目录下没有jar包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<!-- 这个是assembly 所在位置 -->
<descriptor>src/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<!-- 配置执行器 -->
<execution>
<id>make-assembly</id>
<!-- 绑定到package生命周期阶段上 -->
<phase>package</phase>
<goals>
<!-- 只运行一次 -->
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
创建目录,编写assembly插件的配置文件
详细可参考官网:maven.apache.org/plugins/mav…
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<!--打包的后缀-->
<id>distribution</id>
<formats>
<!--支持 zip,tar,tar.gz,tar.bz2,jar,dir,war 等 -->
<format>tar.gz</format>
<format>dir</format>
</formats>
<moduleSets>
<moduleSet>
<sources>
<excludes>
<exclude>src/main/resources/*.properties</exclude>
<exclude>src/main/resources/*.xml</exclude>
</excludes>
</sources>
</moduleSet>
</moduleSets>
<fileSets>
<fileSet>
<outputDirectory>/sql</outputDirectory>
<directory>sql</directory>
<includes>
<include>*.sql</include>
</includes>
</fileSet>
<fileSet>
<outputDirectory>/tmp</outputDirectory>
<directory>target</directory>
<excludes>
<exclude>**/*</exclude>
</excludes>
</fileSet>
<fileSet>
<outputDirectory>/logs</outputDirectory>
<directory>target</directory>
<excludes>
<exclude>**/*</exclude>
</excludes>
</fileSet>
<fileSet>
<outputDirectory>/run</outputDirectory>
<directory>target</directory>
<excludes>
<exclude>**/*</exclude>
</excludes>
</fileSet>
<fileSet>
<outputDirectory>/lib</outputDirectory>
<directory>target</directory>
<includes>
<include>*-with-dependencies.jar</include>
</includes>
</fileSet>
<fileSet>
<outputDirectory>/bin</outputDirectory>
<directory>target/classes/bin</directory>
<lineEnding>unix</lineEnding>
<fileMode>0744</fileMode>
</fileSet>
<fileSet>
<outputDirectory>conf</outputDirectory>
<directory>target/classes</directory>
<includes>
<include>*.yaml</include>
<include>*.yml</include>
<include>*.properties</include>
<include>*.xml</include>
</includes>
</fileSet>
</fileSets>
</assembly>
在resources/bin目录下编写相关的启动脚本,方便我们启动和停止配置服务
以下是我通常使用的脚本,可供参考:
- ctl.sh
#!/bin/sh
# resolve links - $0 may be a softlink
PRG="$0"
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> (.*)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`/"$link"
fi
done
PRGDIR=`dirname "$PRG"`
# Only set PRG_HOME if not already set
[ -z "$PRG_HOME" ] && PRG_HOME=`cd "$PRGDIR/.." ; pwd`
#echo "PRG_HOME: $PRG_HOME"
if [ -r "$PRG_HOME"/bin/setenv.sh ]; then
. "$PRG_HOME"/bin/setenv.sh
fi
# Some parameters initializaion
[ -z "$FILE_ENCODING" ] && FILE_ENCODING=UTF-8
[ -z "$TMP_DIR" ] && TMP_DIR="$PRG_HOME"/tmp
[ -z "$DATA_DIR" ] && DATA_DIR="$PRG_HOME"/data
[ -z "$RUN_DIR" ] && RUN_DIR="$PRG_HOME"/run
[ -z "$LOG_DIR" ] && LOG_DIR="$PRG_HOME"/logs
[ -z "$CONF_DIR" ] && CONF_DIR="$PRG_HOME"/conf
if [ ! -d "$TMP_DIR" ]; then
mkdir -p $TMP_DIR
fi
PRG_NAME=@project.artifactId@
PRG_VERSION=@project.version@
JAR_FILE=$PRG_HOME/lib/$PRG_NAME-$PRG_VERSION-with-dependencies.jar
PRG_PIDFILE=$RUN_DIR/$PRG_NAME.pid
LIB_PATH="$PRG_HOME/lib"
CONF_PATH=$CONF_DIR
if [ "x$STANDALONE" = "xtrue" ]; then
SPRING_CONFIGS="file:$CONF_PATH/application.properties"
SPRING_CONFIGS="$SPRING_CONFIGS,file:$CONF_PATH/application-dev.properties"
SPRING_CONFIGS="$SPRING_CONFIGS,file:$CONF_PATH/application-prod.properties"
echo "CLUSTER MODE: standalone"
else
SPRING_CONFIGS="$SPRING_CONFIGS,file:$CONF_PATH/bootstrap.properties"
echo "CLUSTER MODE: cluster"
fi
JAVA_OPTS="$JAVA_OPTS -Djava.ext.dirs=$JAVA_HOME/jre/lib/ext:$LIB_PATH"
JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=$FILE_ENCODING"
JAVA_OPTS="$JAVA_OPTS -Djava.tmp.dir=$TMP_DIR"
JAVA_OPTS="$JAVA_OPTS -Djava.io.tmpdir=$TMP_DIR"
JAVA_OPTS="$JAVA_OPTS -Dspring.profiles.active=$PROFILE"
JAVA_OPTS="$JAVA_OPTS -Dspring.config.location=$SPRING_CONFIGS"
PRG_START="java -server $JAVA_OPTS -jar $JAR_FILE"
PRG_STATUS=""
PID=""
ERROR=0
get_pid() {
PID=""
PIDFILE=$1
# check for pidfile
if [ -f "$PIDFILE" ] ; then
PID=`cat $PIDFILE`
fi
}
get_PRG_PID() {
get_pid $PRG_PIDFILE
if [ ! "$PID" ]; then
return
fi
if [ "$PID" -gt 0 ]; then
PRG_PID=$PID
fi
}
is_service_running() {
PID=$1
if [ "x$PID" != "x" ] && kill -0 $PID 2>/dev/null ; then
RUNNING=1
else
RUNNING=0
fi
return $RUNNING
}
is_running() {
get_PRG_PID
is_service_running $PRG_PID
RUNNING=$?
if [ $RUNNING -eq 0 ]; then
PRG_STATUS="$PRG_NAME not running"
else
PRG_STATUS="$PRG_NAME already running"
fi
return $RUNNING
}
start() {
is_running
RUNNING=$?
if [ $RUNNING -eq 1 ]; then
echo "$0 $ARG: $PRG_NAME (pid $PRG_PID) already running"
exit
fi
echo $PRG_START
$PRG_START &
echo $! > $PRG_PIDFILE
COUNTER=40
while [ $RUNNING -eq 0 ] && [ $COUNTER -ne 0 ]; do
COUNTER=`expr $COUNTER - 1`
sleep 3
is_running
RUNNING=$?
done
if [ $RUNNING -eq 0 ]; then
ERROR=1
fi
if [ $ERROR -eq 0 ]; then
echo "$0 $ARG: $PRG_NAME started at port $PORT"
sleep 2
else
echo "$0 $ARG: $PRG_NAME could not be started"
ERROR=3
fi
}
stop() {
NO_EXIT_ON_ERROR=$1
is_running
RUNNING=$?
if [ $RUNNING -eq 0 ]; then
echo "$0 $ARG: $PRG_STATUS"
if [ "x$NO_EXIT_ON_ERROR" != "xno_exit" ]; then
exit
else
return
fi
fi
kill $PRG_PID
COUNTER=40
while [ $RUNNING -eq 1 ] && [ $COUNTER -ne 0 ]; do
COUNTER=`expr $COUNTER - 1`
sleep 3
is_running
RUNNING=$?
done
is_running
RUNNING=$?
if [ $RUNNING -eq 0 ]; then
echo "$0 $ARG: $PRG_NAME stopped"
rm -f $PRG_PIDFILE
else
echo "$0 $ARG: $PRG_NAME could not be stopped"
ERROR=4
fi
}
help(){
echo "--------------------------------------------------"
echo "Usage: ctl.sh help|start|stop|status|cleanpid|deamon|version"
echo -e "\n"
echo "start - start the process"
echo "stop - stop the process"
echo "status - query the process status"
echo "cleanpid - delete the process pid file"
echo "cleanlogs - delete all log files"
echo "cleantmp - delete all temp files"
echo "clean - delete all temp/log/pid files"
echo "deamon - set the process as a deamon"
echo "version - view build version"
echo "help - print help"
}
cleanlogs() {
rm -rf $LOG_DIR/*
}
cleantmp() {
rm -rf $TMP_DIR/*
}
cleanpid() {
rm -f $PRG_PIDFILE
}
clean() {
cleanpid
cleantmp
cleanlogs
}
version() {
jar -xf $JAR_FILE META-INF/build-info.properties
cat META-INF/build-info.properties
rm -rf META-INF
}
if [ "x$1" = "xstart" ]; then
start
elif [ "x$1" = "xstop" ]; then
stop
elif [ "x$1" = "xstatus" ]; then
is_running
echo "$PRG_STATUS"
elif [ "x$1" = "xcleanpid" ]; then
cleanpid
elif [ "x$1" = "xcleantmp" ]; then
cleantmp
elif [ "x$1" = "xcleanlogs" ]; then
cleanlogs
elif [ "x$1" = "xclean" ]; then
clean
elif [ "x$1" = "xversion" ]; then
version
elif [ "x$1" = "xdeamon" ]; then
is_running
RUNNING=$?
if [ $RUNNING -eq 1 ]; then
echo "$0 $ARG: $PRG_NAME (pid $PRG_PID) already running"
else
echo "$0 $ARG: $PRG_NAME (pid $PRG_PID) not running"
start
fi
elif [ "x$1" = "xhelp" ]; then
help
else
help
fi
exit $ERROR
- deamon.sh
#!/bin/sh
# execute commond below to auto startup after startup of computer:
#####################
# resolve links - $0 may be a softlink
#####################
PRG="$0"
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> (.*)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`/"$link"
fi
done
PRGDIR=`dirname "$PRG"`
#####################
# start
#####################
nohup sh "$PRGDIR"/ctl.sh deamon >/dev/null 2>&1 &
- setenv.sh
# Local address default as below, if you have more net-interface, you must specify one
LOCAL_ADDRESS=`/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"`
#echo LOCAL_ADDRESS:$LOCAL_ADDRESS
# Solves the problem of multiple NIC
LOCAL_ADDRESS=`echo $LOCAL_ADDRESS | awk '{print $1}'`
#echo LOCAL_ADDRESS RANDOM:$LOCAL_ADDRESS
JAVA_OPTS="$JAVA_OPTS -Xms8g"
JAVA_OPTS="$JAVA_OPTS -Xmx8g"
JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError"
JAVA_OPTS="$JAVA_OPTS -Duser.timezone=GMT+08"
#JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote"
#JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.port=0"
#JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
#JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
#JAVA_OPTS="$JAVA_OPTS -Dserver.address=$LOCAL_ADDRESS"
# which spring profile will be actived
# PROFILE="dev"
# standalone or cluster? true if standalone, otherwise false as cluster
STANDALONE="true"
#TMP_DIR=/tmp
#FILE_ENCODING=UTF-8
- start.sh
#!/bin/sh
#####################
# resolve links - $0 may be a softlink
#####################
PRG="$0"
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> (.*)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`/"$link"
fi
done
PRGDIR=`dirname "$PRG"`
EXECUTABLE=ctl.sh
CONSOLE_OUT=$PRGDIR/../logs/console.out
if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
echo "Cannot find $PRGDIR/$EXECUTABLE"
echo "The file is absent or does not have execute permission"
echo "This file is needed to run this program"
exit 1
fi
nohup "$PRGDIR"/"$EXECUTABLE" start > "$CONSOLE_OUT" 2>&1 &
echo "Started success!"
- stop.sh
#!/bin/sh
#####################
# resolve links - $0 may be a softlink
#####################
PRG="$0"
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> (.*)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`/"$link"
fi
done
PRGDIR=`dirname "$PRG"`
EXECUTABLE=ctl.sh
CONSOLE_OUT=$PRGDIR/../logs/console.out
if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
echo "Cannot find $PRGDIR/$EXECUTABLE"
echo "The file is absent or does not have execute permission"
echo "This file is needed to run this program"
exit 1
fi
exec "$PRGDIR"/"$EXECUTABLE" stop
echo "Stopped success!"
mavan编译
打包完项目如下
通过这种的项目结构,我们部署、运维就更加简单拉