使用assembly 插件定制化打包项目

assembly(装配/组装)
对于SpringBoot项目通常我们会使用mavaen提供的普通的打包方式打成一个jar包, 这对于在本地运行似乎没有什么问题, 但是把这种方式在Linux上运行却会出现很多问题,导致无法运行, 而且打包的结构也并不清晰,所以我们需要一个插件来完成打包的工作, 把你的项目打包成一个包含脚本、配置文件、运行时所有依赖的部署包
“assembly”就是把一组文件、目录、依赖元素组装成一个归档文件的插件
官方配置详解:http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html
这里使用SpringBoot + Dubbo 的Server项目进行演示

一. 原始项目是一个最简单的SpringBoot +Dubbo 生产者端的小示例,只发布了一个helloWord服务, 在此基础上拷贝assebly的几个文件到main目录

assembly.jpg

- bin 目录放打包后项目的启动/停止脚本 , 这几个脚本可以到dubbo-2.5.7.jar-->MATA-INF-->assembly.bin
  下去拷,然后根据需要修改一下 主方法类 和配置文件名称 等
- assembly.xml 是maven-assembly-plugin插件对应的配置文件

二, 在maven中添加assembly插件

<build>
        <!--我们自己的文件会打成一个demo-server.jar包,此包中不需要配置文件-->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <excludes>
                    <exclude>**/*.xml</exclude>
                    <exclude>**/*.properties</exclude>
                </excludes>
            </resource>
        </resources>
        <plugins>
            
            <!--assebly插件-->
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.5.5</version>
                <configuration>
                    <finalName>${project.artifactId}</finalName>
                    <skipAssembly>false</skipAssembly>
                    <appendAssemblyId>false</appendAssemblyId>
<!--如果路径长度超过100字符,执行的操作warn" (default), "fail", "truncate", "gnu", or "omit". -->
                    <tarLongFileMode>gnu</tarLongFileMode>
                    <outputDirectory>target</outputDirectory>
                    <!--具体配置文件所在路径-->
                    <descriptors>
                        <descriptor>src/main/assembly/assembly.xml</descriptor>
                    </descriptors>
                </configuration>
                <!--执行的操作-->
                <executions>
                    <execution>
                        <id>assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>

    </build>
<!--profile设置 , 这个跟Assebly打包没关系,根据需要配置 -->
<profiles>
        <profile>
            <id>dev</id>
            <properties>
                <dubbo.application.name>demo-server-dev</dubbo.application.name>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <id>test</id>
            <properties>
                <dubbo.application.name>demo-server-test</dubbo.application.name>
            </properties>
        </profile>
    </profiles>

PS:在使用Assembly打包的时候必须要springboot把默认的打包插件删除掉,否则会报找不到启动类

    <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>

二,配置assembly.xml定制打包过程

<?xml version="1.0" encoding="UTF-8"?>
<assembly>
    <id>prd</id>
    <baseDirectory>${project.artifactId}</baseDirectory>
    <includeBaseDirectory>true</includeBaseDirectory>
    <formats>
        <format>tar.gz</format><!--打包的文件格式:tar.zip war zip等-->
    </formats>
    <fileSets>
        <!-- 将src/main/resources下配置问价打包到conf目录 -->
        <fileSet>
            <directory>src/main/resources</directory>
            <outputDirectory>/conf</outputDirectory>
            <includes>
                <include>**/*.xml</include>
                <include>**/*.properties</include>
            </includes>
            <filtered>true</filtered><!-- 是否进行属性替换 -->
        </fileSet>

        <!-- 打包.sh文件到bin 目录 -->
        <fileSet>
            <directory>src/main/assembly/bin</directory>
            <outputDirectory>/bin</outputDirectory>
            <includes>
                <include>*.*</include>
            </includes>
            <fileMode>0755</fileMode><!--赋予文件权限-->
        </fileSet>
    </fileSets>
    <!--依赖输出-->
    <dependencySets>
        <dependencySet>
            <unpack>false</unpack><!--不解压-->
            <outputDirectory>lib</outputDirectory><!--依赖包输出路径-->
            <useProjectArtifact>true</useProjectArtifact><!--当前项目构件是否包含在这个依赖集合里。-->
            <scope>runtime</scope><!-- 将scope为runtime的依赖包打包到lib目录下。 -->

        </dependencySet>
    </dependencySets>
</assembly>

三,根据需要配置startup.sh/stop.sh等便捷启动/停止项目的脚本,这里给出一个示例:

1.startup.sh

#!/bin/bash
cd `dirname $0`
BIN_DIR=`pwd`
cd ..
DEPLOY_DIR=`pwd`
CONF_DIR=$DEPLOY_DIR/conf
MAIN_CLASS=cn.wolfcode.DemoServerApplication

SERVER_NAME=`sed '/spring.dubbo.application.name/!d;s/.*=//' conf/application.properties | tr -d '\r'`
SERVER_PROTOCOL=`sed '/spring.dubbo.protocol.name/!d;s/.*=//' conf/application.properties | tr -d '\r'`
SERVER_PORT=`sed '/spring.dubbo.protocol.port/!d;s/.*=//' conf/application.properties | tr -d '\r'`
LOGS_FILE=`sed '/dubbo.log4j.file/!d;s/.*=//' conf/application.properties | tr -d '\r'`

if [ -z "$SERVER_NAME" ]; then
    SERVER_NAME=`hostname`
fi

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

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
STDOUT_FILE=$LOGS_DIR/stdout.log

LIB_DIR=$DEPLOY_DIR/lib
LIB_JARS=`ls $LIB_DIR|grep .jar|awk '{print "'$LIB_DIR'/"$0}'|tr "\n" ":"`

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
JAVA_JMX_OPTS=""
if [ "$1" = "jmx" ]; then
    JAVA_JMX_OPTS=" -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false "
fi
JAVA_MEM_OPTS=""
BITS=`java -version 2>&1 | grep -i 64-bit`
if [ -n "$BITS" ]; then
    JAVA_MEM_OPTS=" -server -Xmx2g -Xms2g -Xmn256m -XX:PermSize=128m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 "
else
    JAVA_MEM_OPTS=" -server -Xms1g -Xmx1g -XX:PermSize=128m -XX:SurvivorRatio=2 -XX:+UseParallelGC "
fi

echo -e "Starting the $SERVER_NAME ...\c"
nohup java $JAVA_OPTS $JAVA_MEM_OPTS $JAVA_DEBUG_OPTS $JAVA_JMX_OPTS -classpath $CONF_DIR:$LIB_JARS $MAIN_CLASS > $STDOUT_FILE 2>&1 &


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

stop.sh

#!/bin/bash
cd `dirname $0`
BIN_DIR=`pwd`
cd ..
DEPLOY_DIR=`pwd`
CONF_DIR=$DEPLOY_DIR/conf

SERVER_NAME=`sed '/spring.dubbo.application.name/!d;s/.*=//' conf/application.properties | tr -d '\r'`

if [ -z "$SERVER_NAME" ]; then
    SERVER_NAME=`hostname`
fi

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

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"

四,配置完毕,执行package

到Target目录查看是否生成xxx.tar.gz
生成的xxx.tar.gz包结构:

|
    |-bin
    |-conf
    |-lib

五,部署

拷贝xxx.tar.gz到linux
tar -zxvf xxx.tar.gz
cd xxx/bin
./start.sh
tail -f -n 100 ../logs/stout.log 查看日志是否启动成功

ps: SpringBoot + Dubbo 服务端main方法启动需要在最后阻塞进程, 但是不能使用System.in.read() 这种方式, 请参考Dubbo 官方Main类中使用Lock的阻塞方式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容