java项目打包最佳实践

摸索了一晚上外加多年经验终于有了这个最佳实践.

环境

  • assembly
  • springboot
  • idea
  • java8
  • logback

需求

  • jar包要可执行: java -jar jar_name.
  • 依赖分离: 主业务代码独立成可执行jar, 其他所有依赖放到./lib下.
  • 配置文件分离: application.yml, logback.xml等配置文件不在jar内, 而是在项目根目录下. 这样方便中途查看和修改配置.
  • 分环境打包: 我这里分了三个环境dev,test,prod.
  • 脚本启动,停止,重启应用.

配置参考

pom.xml


        
            
            dev
            
                dev
            
            
                true
            
            
        
        
            
            test
            
                test
            
        
        
            
            prod
            
                prod
            
        

    


    
        
        
            
                
                    maven-resources-plugin
                    
                        utf-8
                        true
                    
                
            
        
        ${project.artifactId}-${project.version}
        
            
            
                src/main/resources
                
                
                
                
                true
            
        
        
            
            
            
            
            
                org.apache.maven.plugins
                maven-compiler-plugin
                
                    1.8
                    1.8
                    UTF-8
                
            
            
                org.apache.maven.plugins
                maven-assembly-plugin
                
                
                    
                        src/main/resources/assembly.xml
                    
                
                
                    
                        make-my-jar-with-dependencies
                        package
                        
                            single
                        
                        
                            ${project.artifactId}
                        
                    
                
            
            
                org.apache.maven.plugins
                maven-jar-plugin
                
                    
                    
                        *.xml
                        *.yml
                        *.properties
                        *.sh
                        public
                        conf
                    
                    
                        
                            
                            com.gx.app.GxAppApplication
                            true
                            lib/
                            true
                            
                            false
                        
                        
                            
                            ./
                            
                            
                        
                    
                
            
        
    

assembly.xml


    assembly
    
        dir
    
    
        
            ${project.basedir}
            /
            true
            
                application.yml
                application-${profileActive}.yml
                *.xml
            
        
        
            ${project.build.directory}/site
            docs
        
        
        
        
        
        
        
        
        
        
        
            ${project.basedir}/src/main/resources
            /
            true
            0775
            
                
                **/*
            
        
        
            ${project.basedir}/src/main/resources/conf/${profileActive}
            /
            true
            0755
            
                *.properties
            
        
    
    
        
            /lib
            
                ${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}
            
            true
            runtime
            
                ${project.groupId}:${project.artifactId}:*
            
        
        
            provided
            /
            
                ${project.groupId}:${project.artifactId}:*
            
        
    


logback.xml




    
    

    
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
        
    

    
    
        ${LOG_HOME}/${project.artifactId}.log
        
            ${LOG_HOME}/rolling/${project.artifactId}_%d{yyyy-MM-dd}.%i.log.zip
            
            
             30
            
                100MB
            
        
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
        

    

    
    
        
            ${LOG_HOME}/sql/${project.artifactId}_sql_%d{yyyy-MM-dd}.log
            
            
        
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
        
    




    
        
    
    
        
    
    
        
    

    



    
    
        
            ${LOG_HOME}/dao/${project.artifactId}_dao_%d{yyyy-MM-dd}.log
            
            
        
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
        
    



    
        
    

    

    
        ${LOG_HOME}/error/${project.artifactId}_error.log
        
            ${LOG_HOME}/error/${project.artifactId}_error_%d{yyyy-MM-dd}.log
            
            
        
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
        
        
            ERROR
            ACCEPT
            DENY
        
    


    
    
        
            
             
             
        
    

    
        
            
            
            
        
    

    
    
        
            
            
            
        
    



application.yml

spring:
  application:
    name: GxApp
  profiles:
    active: @profileActive@


logging:
  level:
    root: info
    com.gx: debug

启动脚本

#!/bin/bash

#此脚本为Linux下启动java程序的通用脚本。(包含启动,停止,重启)
#cd 进入脚本执行的bin目录,sh run.sh start(启动) | stop(停止)| restart(重启)
#

#bin目前路径以及相关目录路径
cd `dirname $0`
BIN_DIR=`pwd`
DEPLOY_DIR=`pwd`
#LOG_BACK=-Dlogback.configurationFile=$DEPLOY_DIR/logback.xml
JAVA_DEBUG_OPTS=" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n "
JAVA_JMX_OPTS=" -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false  -Djava.rmi.server.hostname=$ip "
#拼接全路径jar包名, 为了精确匹配jar包, 能确保准确定位pid
JAR_NAME=$BIN_DIR/`ls ${project.artifactId}*.jar`
cmd=$2
echo "$cmd"

start(){
    echo "DEPLOY_DIR=$DEPLOY_DIR"
    PIDS=`ps  --no-heading -C java -f --width 1000 | grep "$DEPLOY_DIR" |awk '{print $2}'`
    if [ -n "$PIDS" ]; then
         echo "ERROR: The $SERVER_NAME already started!"
        echo "PID: $PIDS"
        exit 1
    fi

    echo -e "Starting the $JAR_NAME ...\c"
    nohup java -Xms256M -Xmx1024M -XX:PermSize=128M -XX:+HeapDumpOnOutOfMemoryError -verbose:gc -XX:+PrintGCDetails -Xloggc:./gc.log  -XX:+PrintGCDateStamps -jar $JAR_NAME > /dev/null 2>&1 &
    COUNT=0
    while [ $COUNT -lt 1 ]; do
        echo -e ".\c"
        sleep 1

        COUNT=`ps  --no-heading -C java -f --width 1000 | grep "$JAR_NAME" | awk '{print $2}' | wc -l`

            if [ $COUNT -gt 0 ]; then
                break
            fi
    done
    echo "start OK!"
    PIDS=`ps  --no-heading -C java -f --width 1000 | grep "$JAR_NAME" | awk '{print $2}'`
    echo "PID: $PIDS"
    echo $PIDS > .pid



}

stop(){

        PIDS=`ps  --no-heading -C java -f --width 1000 | grep "$JAR_NAME" |awk '{print $2}'`
        if [ -z "$PIDS" ]; then
            echo "ERROR: The $SERVER_NAME does not started!"
        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 --no-heading -p $PID`
                if [ -n "$PID_EXIST" ]; then
                    COUNT=0
                    break
                fi
            done
        done
        echo "stop OK!"
        echo "PID: $PIDS"
        rm .pid

}

case $1 in
  start)
        start;
    ;;
  stop)
        stop;
    ;;
  restart)
        echo "############ Application of '"$JAR_NAME"' restarting....############"
    stop;
    sleep 2
    start;
    ;;
  *)
    echo "Usage: startup.sh {start|stop|restart}"
    ;;
esac
exit 0

目录结构

java项目打包最佳实践_第1张图片
image.png

打包产物
配置文件, 静态资源都在根下.

java项目打包最佳实践_第2张图片
image.png

主程序执行jar包结构
没有配置文件了.

java项目打包最佳实践_第3张图片
image.png

坑点

如何配置不当:

  1. 打包时配置文件能够隔离. 但IDE里本地运行时, 找不到配置文件, 因为配置文件被排除了.
  2. spring 的devtools 一定要设置成 scope provided, 让它不参与打包. 这样可以避免在设置当前目录加入了classpath, 而日志文件又写入当亲目录内时, 应用不停的重启. (这是因为检测到了classpath内内容变化就会热部署, 就会重启).
  3. 找不到 logback.xml 配置文件. 解决: M1: 加入当前目录到classpath; M2: 启动命令中指定文件.

你可能感兴趣的:(java项目打包最佳实践)