Java工程打包tar.gz完整流程

Java工程打成tar包的博文很多, 但是很多都只是给了简单的配置文件demo, 但是作为一项工程, 简单的配置是不能成事的. 大部分开源软件都是tar.gz格式, 很明显非常的工程化, 规范化.
所以仅仅一些随笔性质的博文还是不能够让我掌握, 得以在生产环境中使用.

于是, 自己资料加线上测试探索, 基本掌握一点入门使用.

您将了解到:

  • 打tar包的基本配置
  • 启动/停止脚本
  • shell启动java程序classpath问题
  • shell结束java程序时, java自己在结束进程之前如何做些后续处理工作
  • 分环境打包和assembly插件基本使用

目录结构

|- javapro
    |- bin
    |- conf
    |- logs
    |- lib
    |- README.MD
    ... 
  • lib: 自己的工程打成的jar包以及依赖jar包
  • conf:配置文件
  • logs: 日志
  • bin: 脚本, 如启动,停止脚本

打包配置

通常流行使用assembly插件打包, 包括tar包.
这一步麻烦的是配置, 所以需要整理好模板, 以备不时之需.

pom.xml
引入插件.


   
            org.apache.maven.plugins
                maven-assembly-plugin
             
                2.2.1
                
                    
                        assemble
                        
                            single
                        
                        package
                    
                
                
                    false
                    false
                
  




profile标签配置


 
            release
            
                true

                
                    env
                    release
                
            

            
                
                    
                        maven-assembly-plugin
                        
                            
                            
                                ${basedir}/src/main/assembly/release.xml
                            
                            
                            ${project.artifactId}-${project.version}
                            
                            ${project.parent.build.directory}
                        
                    
                
            
        




上文的 profile可以配置多环境(开发,测试,生成..., 这里仅用一个环境release演示).
可以看到release环境中引入了./src/main/assembly/release.xml文件. 这个文件就是决定了打包的目录结构和文件.

release.xml


    dist
    
        tar.gz
    
    false
    
        
            .
            /
            
                README*
                test.csv
            
        
        
            ./src/main/bin
            bin
            
                **/*
            
            0755
        
        
            ./src/main/conf
            /conf
            
                **/*
            
            0644
        
        
            ./src/main/meta
            /meta
            
                **/*
            
            0644
        
        
            ./src/main/resources
            /
            
                **/*
            
        
        
            target
            logs
            
                **/*
            
        
    
    
        
            lib
            
                junit:junit
            
        
    


可单独了解相关专题: [java分环境打包部署][assembly插件打包]

到此, 最简单的基本配置完成了, 可以达成tar.gz包了. 但是问题是, 部署的时候, 那什么来启动java程序. 请看下文.

启动/关闭脚本

我的shell脚本处于幼儿园水平, 以下脚本都是复制粘贴修改的.
启动脚本: startup.sh

#!/bin/bash



case "`uname`" in
    Linux)
        bin_abs_path=$(readlink -f $(dirname $0))
        ;;
    *)
        bin_abs_path=`cd $(dirname $0); pwd`
        ;;
esac

echo "脚本位置: $bin_abs_path"
base=${bin_abs_path}/..
#base=$(dirname $(cd `dirname $0`;pwd))
echo "base path: $base"
echo "cd to $base"
cd $base


export LANG=en_US.UTF-8
export BASE=$base

echo "cd to: $base"

#can't run repeatedly
if [ -f $base/bin/addr.pid ] ; then
    echo "found bin/addr.pid , Please run stop.sh first ,then startup.sh" 2>&2
    exit 1
fi

## set java path
if [ -z "$JAVA" ] ; then
  JAVA=$(which java)
fi



str=`file $JAVA_HOME/bin/java | grep 64-bit`
if [ -n "$str" ]; then
    JAVA_OPTS="-server -Xms1024m -Xmx1536m -Xmn256m -XX:SurvivorRatio=2 -XX:PermSize=96m -XX:MaxPermSize=256m -Xss256k -XX:-UseAdaptiveSizePolicy -XX:MaxTenuringThreshold=15 -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:+HeapDumpOnOutOfMemoryError"
else
    JAVA_OPTS="-server -Xms1024m -Xmx1024m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:MaxPermSize=128m "
fi

JAVA_OPTS=" $JAVA_OPTS -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8"

for i in $base/lib/*;
    do CLASSPATH=$i:"$CLASSPATH";
done


#$JAVA $JAVA_OPTS -classpath .:$CLASSPATH com.jfai.addr.StartUp 1>>$base/bin/nohup.out 2>&1 &
$JAVA $JAVA_OPTS -classpath .:$CLASSPATH com.jfai.addr.StartUp 1>$base/bin/nohup.out 2>&1 &

echo $! > $base/bin/addr.pid
echo "Process addr is running..., pid=$!"

停止脚本: stop.sh

#!/bin/bash

cygwin=false;
case "`uname`" in
    CYGWIN*)
        cygwin=true
        ;;
esac

get_pid() {
    STR=$1
    PID=$2
    if $cygwin; then
        JAVA_CMD="$JAVA_HOME\bin\java"
        JAVA_CMD=`cygpath --path --unix $JAVA_CMD`
        JAVA_PID=`ps |grep $JAVA_CMD |awk '{print $1}'`
    else
        if [ ! -z "$PID" ]; then
            JAVA_PID=`ps -C java -f --width 1000|grep "$STR"|grep "$PID"|grep -v grep|awk '{print $2}'`
        else
            JAVA_PID=`ps -C java -f --width 1000|grep "$STR"|grep -v grep|awk '{print $2}'`
        fi
    fi
    echo $JAVA_PID;
}


base=`dirname $0`/..
pidfile=$base/bin/addr.pid
if [ ! -f "$pidfile" ];then
    echo "addr.pid is not found, addr is not running? exit"
    exit
fi

pid=`cat $pidfile`
if [ "$pid" == "" ] ; then
    pid=`get_pid "addr"`
fi

echo -e "`hostname`: stopping addr, pid=$pid ... "
kill $pid

LOOPS=0
while (true);
do
    gpid=`get_pid "addr" "$pid"`
    if [ "$gpid" == "" ] ; then
        echo "Oook! cost:$LOOPS"
        `rm $pidfile`
        break;
    fi
    let LOOPS=LOOPS+1
    sleep 1
done

附录

classpath问题

一开始, 笔者在用startup.sh启动时, 碰到:

  • 若在~/bin/目录下执行sh startup.sh时, classpath就是: ~/bin/, 这回导致: new File("conf/xx.properties")(相对路径)找不到文件的, 因为它会将相对路径转成: ~/bin/conf/xx.properties. 这显然不是我想要的.
  • 若在~/路径下执行: sh bin/startup.sh, 能够成功转成: ~/conf/xx.properties
    ('~'代表省略的父路径)

根据问题详情页的解答, 解决了这个问题.

关键是要在脚本的一开始就cd 到项目根路径

停止脚本杀死进程时, 如何让java进程在退出之前做些事情?

Runtime.getRuntime().addShutdownHook(...)可以搞定.

请看演示代码:

    public static void main(String[] args) {

        //Test:
        System.out.println("启动 ...");

        Runtime.getRuntime().addShutdownHook(new Thread(){
            @Override
            public void run() {
                log.info("执行shutdown...");
                //这里演示shutdown线程可以读取到主线程改变的变量
                System.out.println("主线程循环了"+count+"次");
                running = false;
            }
        });

        while (running) {
            System.out.println("Not shutdown, running ...");
            count++;
        }
        //kill pid后, 主线程会停止
        System.out.println("退出循环体, 程序将退出");

        //end test

效果

注意: stop.sh中kill命令不能加-9参数.
加上-9之后, 是不会执行到添加到shutdownhook中的线程任务的.

错误写法

你可能感兴趣的:(Java工程打包tar.gz完整流程)