background

With Springboot’s popularity, more and more projects are using JAR packages instead of WAR packages. It’s easy enough to start a jar, but if you need to change a configuration file and you need to change it, you can reprint it into a jar file, or you can use a Linux command to change the JAR file, but that’s not convenient. The Maven Assembly plug-in makes it easy to print the project into a tar.gz package, allowing us to modify the configuration

Packaged project structure

The project structure is shown as follows:

  1. TMP directory we can store temporary files, we can write scheduled tasks scheduled to clear
  2. The run directory stores the ID of the service process that runs the JAR package
  3. The logs directory stores runtime log files
  4. The lib directory stores the JAR package
  5. The bin directory stores executable files
  6. Conf directory stores configuration files

steps

Pom file to add plug-ins

<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 package plugin -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                        <goal>build-info</goal>
                    </goals>
                    <configuration>
                        <! -- main boot file -->
                        <mainClass>com.sun.accsmbly.Application</mainClass>
                        <classifier>with-dependencies</classifier>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <! -- This plugin is key and needs to be placed last, otherwise there may be no jar package in the lib directory -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptors>
                    <! -- This is where the assembly is located -->
                    <descriptor>src/assembly/assembly.xml</descriptor>
                </descriptors>
            </configuration>
            <executions>
                <! -- Configure the actuator -->
                <execution>
                    <id>make-assembly</id>
                    <! -- Bind to the Package lifecycle phase -->
                    <phase>package</phase>
                    <goals>
                        <! -- Run only once -->
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
Copy the code

Create a directory and write a configuration file for the Assembly plug-in

Detailed refer to website: 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">
    <! -- Wrap suffixes -->
    <id>distribution</id>
    <formats>
        <! -- Support zip, tar, tar.gz, tar.bz2, jar, dir, war, etc. -->
        <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>
Copy the code

Write the relevant startup script in the resources/bin directory to enable us to start and stop the configuration service

Here are the scripts I usually use for reference:

  • 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 [email protected]@ [email protected]@ 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 $ERRORCopy the code
  • 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 &Copy the code
  • 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-8Copy the code
  • 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!"Copy the code
  • 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!"Copy the code

Mavan compilation

Wrap up the project as follows

Through this kind of project structure, we deploy, operation and maintenance more easily pull