0. 导言

springboot作为现在主流的java开发框架,由于便捷和易上手的特性,深受开发者欢迎。springboot默认以jar包方法,经过java -jar指令运转

但这样的发动方法实际上不是很友爱,咱们常常看到各类组建经过bin目录下的start.sh脚本进行发动,咱们能够在.sh脚本中书写自界说各类发动参数。这样的方法愈加友爱,那么咱们的springboot项目可不能够打包成这样的方法发动呢?

当然能够,今日咱们就来看如何实现

1. assembly-plugin插件

assembly是一个maven插件,专门用于maven项目打包。它的效果便是能够将项目打包成一个能够经过脚本文件发动的项目包

其打包后的项目文件结构如下:

bin 项目发动/中止/重启等脚本文件目录 conf 装备文件目录 lib 依靠包目录

assembly插件需求装备一个.xml装备文件来指定打包设置。该文件常见的标签装备如下:

  • id: 标识符,添加到打包文件称号的后缀符 假如设置为${project.version}则会将项目版本号添加到打包文件名中
  • formats:打包格局,支持zip、tar、tar.gz (or tgz)、tar.bz2 (or tbz2)、jar、dir、war等格局,能够同时指定多种打包方法,经过format标签指定
<formats>
	<format>tar.gz</format>
   <format>jar</format>
</formats>
  • includeBaseDirectory 是否包括打包层目录,当设置false时,所有文件直接打包到根目录下;为true时,打包到${artifactId}目录下
  • dependencySets 设置项目依靠包打包的目录
  • fileSets 设置要包括的文件集,能够界说多个fileSet,单个fileSet标签中又包括如下子标签 directory:要打包的文件夹 outputDirectory:打包出来的文件夹,比方为bin,则表明将directory文件夹下的文本打包到bin目录下 includes: 指定要包括(include)或扫除(exclude)的打包文件 fileMode:指定文件权限,权限的指定参考linux体系文件权限,比较常用的0755,0644。咱们在文末独自解说 directoryMode:指定目录权限
<fileSet>
    <directory>src/main/assembly/bin</directory>
    <outputDirectory>bin</outputDirectory>
    <includes>
       <include>start.sh</include>
       <include>stop.sh</include>
    </includes>
    <fileMode>0755</fileMode>
</fileSet>

2. 实操

1、首要咱们先创立一个springboot项目assembly-plugin-demo,并且引进spring web依靠,模仿一个web项目

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2、创立一个HelloController,并书写一个简单的接口,用于模仿接口

/**
 * @author benjamin_5
 * @Description
 * @date 2022/8/27
 */
@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(){
        return "hello~~";
    }
}

3、在项目src/main下创立bin目录,并声明发动/中止/重启脚本

发动脚本 start.sh

#!/usr/bin/env bash

#source $(dirname $0)/../../env.sh
# 进入当前文件目录
cd `dirname $0`
# 回来上一级
cd ..

# jar包称号
#SERVER_JAR="$SERVER_NAME-$PROJECT_VERSION.jar"
SERVER_JAR="assembly_plugin_demo-0.0.1-SNAPSHOT.jar"
BASE_DIR=`pwd`

# 获取java途径
if [ "$JAVA_HOME" != "" ]; then
 JAVA="$JAVA_HOME/bin/java"
else
 JAVA=java
fi

# 指定日志输出途径
LOGS_DIR=""
if [ -n "$LOGS_FILE" ]; then
    LOGS_DIR=`dirname $LOGS_FILE`
else
    LOGS_DIR=$BASE_DIR/logs
fi
if [ ! -d $LOGS_DIR ]; then
    mkdir $LOGS_DIR
fi
STDOUT_FILE=$LOGS_DIR/stdout.log

# 设置jvm参数
JAVA_OPTS="-server -Xms1G -Xmx2G -Xmn256m -Xss1m \
-XX:SurvivorRatio=4 -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection \
-XX:CMSInitiatingOccupancyFraction=60 -XX:+PrintGCDateStamps \
-XX:+PrintGCDetails -Xloggc:$LOGS_DIR/gc.log"

# 假如项目现已发动则之前中止项目
echo -n "Starting server ..."
 PID=$(ps -ef | grep $SERVER_JAR | grep -v grep |awk '{print $2}')
if [ -z "$PID" ]; then
 echo Application is already stopped
else
 echo kill $PID
 kill -9 $PID
fi

# 以指定参数发动项目
nohup $JAVA $JAVA_OPTS $JAVA_DEBUG_OPT -jar lib/$SERVER_JAR > $STDOUT_FILE 2>&1 &
if [ $? -eq 0 ];then
 # echo -n $! > "$PIDFILE"
 if [ $? -eq 0 ]
 then
 sleep 1
 echo STARTED
 else
 echo FAILED TO WRITE PID
 exit 1
 fi
else
 echo SERVER DID NOT START
 exit 1
fi
PID_NOW=`ps -ef | grep java | grep -v grep | grep "$SERVER_JAR" | awk '{print $2}'`
# 打印参数
echo "进程ID: $PID_NOW"
echo "输出日志:$STDOUT_FILE"

中止脚本 stop.sh

#!/usr/bin/env bash

# jar包称号
SERVER_JAR="assembly_plugin_demo-0.0.1-SNAPSHOT.jar"

# 中止项目
echo -n "Stopping server ..."
    PID=$(ps -ef | grep $SERVER_JAR | grep -v grep |awk '{print $2}')
if [ -z "$PID" ]; then
  echo Application is already stopped
else
  echo kill $PID
  kill -9 $PID
fi
exit 0

4、然后咱们在项目的src/main目录下创立一个assembly目录,并且创立一个assembly插件的装备文件assembly.xml

咱们需求在assembly.xml装备文件中申明bin,conf,lib三个途径

<assembly>
	<id>assembly</id>
	<formats>
		<format>tar.gz</format>
	</formats>
	<includeBaseDirectory>true</includeBaseDirectory>
	<fileSets>
		<fileSet>
			<directory>src/main/assembly/bin</directory>
			<outputDirectory>bin</outputDirectory>
			<fileMode>0755</fileMode>
		</fileSet>
		<fileSet>
			<directory>src/main/resources</directory>
			<outputDirectory>conf</outputDirectory>
			<fileMode>0644</fileMode>
		</fileSet>
	</fileSets>
	<dependencySets>
		<dependencySet>
			<outputDirectory>lib</outputDirectory>
		</dependencySet>
	</dependencySets>
</assembly>

利用assemly插件将springboot项目打包为自定义脚本启动

5、其次咱们在pom.xml中引进assembly-plugin插件

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
    <descriptor>src/main/assembly/assembly.xml</descriptor>
    </configuration>
    <executions>
        <execution>
             <id>make-assembly</id>
             <phase>package</phase>
             <goals>
                 <goal>single</goal>
             </goals>
         </execution>
    </executions>
</plugin>

6、从头加载pom文件,下载assembly插件

7、履行打包指令

利用assemly插件将springboot项目打包为自定义脚本启动

呈现BUILD SUCCESS阐明打包成功

利用assemly插件将springboot项目打包为自定义脚本启动

8、打包文件输出在target目录下,假如有指定输出目录,则在输出目录中查找

利用assemly插件将springboot项目打包为自定义脚本启动

9、咱们将打包出来的’.tar.gz’压缩包文件解压,能够看到其结构便是咱们上述指定的bin、conf、lib目录

利用assemly插件将springboot项目打包为自定义脚本启动

10、进入bin目录,履行start.sh指令发动项目

./start.sh

利用assemly插件将springboot项目打包为自定义脚本启动

11、咱们现已将输出内容指定到logs目录下的stdout.log,咱们能够经过该日志检查发动明细

假如发动失利,也能够经过该日志文件检查报错明细。同时也指定了gc日志gc.log,能够经过该文件检查gc详情

利用assemly插件将springboot项目打包为自定义脚本启动
12、从上述日志看发动成功了,咱们经过访问之前界说的接口来测试

能够看到正常输出了接口数据,证明咱们打包并发动成功了

利用assemly插件将springboot项目打包为自定义脚本启动

如上,咱们的springboot就成功打包成了bin目录发动方法。

2.1 优化【未完善】

上述打包程序并不是最佳的,由于咱们的项目的jar包称号是在start.sh脚本中写死的,假如版本晋级,或者复用到其他模块中时,就需求修改脚本了,非常的不方便

所以咱们做出优化,希望能够自动获取这个jar包称号

能够看到咱们的jar包称号是:assembly_plugin_demo-0.0.1-SNAPSHOT.jar

这个称号由两部分组成:服务名,版本号

于是咱们就要想办法获取这两个特点

1、首要服务名直接在application.properties装备文件中经过spring.application.name特点获取。

2、装备文件是会一同打包到conf文件夹下的,但咱们怎么在shell脚本中获取装备文件中的指定装备项呢?

答案是能够经过sed指令,如下所示

PROJECT_VERSION=`sed '/^project.version=/!d;s/.*=//' conf/application.properties`

3、其次便是版本号,咱们知道版本号是界说在pom.xml文件中的,打包后是没有pom文件的,那么咱们的思路便是在application.properties装备文件中获取到版本号

这儿就要考验我们的springboot常识积累了,如安在装备文件中获取到pom特点呢?

4、首要咱们要在pom.xml文件中,添加resource标签,设置filtering=true,让装备文件能够读取pom特点

<build>
	<resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
	</resources>
</build>

5、设置完成后记住从头加载pom文件!!!

6、然后在application,properties装备文件中经过@xxx@获取pom特点”project.version”

application.version=@project.version@

7、在start.sh脚本中再声明版本号和jar包名变量

PROJECT_VERSION=`sed '/^application.version=/!d;s/.*=//' conf/application.properties`
SERVER_JAR="$SERVER_NAME-$PROJECT_VERSION.jar"

8、从头打包即可,stop.sh脚本中处理类似

9、这儿存在一个问题没有处理,上述说的@xxx@的方法读取pom特点,在idea中打包,能够看到自身的打包插件现已加载了pom中的特点,如下图

利用assemly插件将springboot项目打包为自定义脚本启动

但是assembly插件打包的conf目录中的装备文件中却没能加载pom的值,初步怀疑是加载次序的问题,仍在研究中,这儿也抛出问题点,我们一同评论处理。有思路的同学,能够留言评论

利用assemly插件将springboot项目打包为自定义脚本启动

演示代码见文末

3. 弥补内容

fileMode/directoryMode权限

assembly中的权限表明与linux体系一致,经过4位数值表明权限

其间第一位0表明选用十进制,第二位表明用户权限,第三位组用户权限,第四位表明其他用户权限,而十进制表明的权限等级如下:

十进制 linux权限 阐明
0 无任何权限
1 –x 履行权限
2 –w 可写权限
3 -wx 可写、履行权限
4 r– 只读权限
5 r-x 可读、可履行权限
6 rw- 读写权限
7 rwx 悉数权限

则0755表明用户具有读/写/履行权限,组用户和其它用户具有读写权限;0644表明用户具有读写权限,组用户和其他用户具有只读权限

4. 演示源码

git地址