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

2018-05-30  本文已影响0人  touch_The_Sky

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的阻塞方式

上一篇下一篇

猜你喜欢

热点阅读