4、通用打包方式

1、背景

任何从main方法启动的工程,比如:spring-java,spring-boot,sparing-web-jetty这种直接从main方法启动的,都可以使用如下方式打包

这种工程完全可以通过

maven-compiler-plugin ==> 指定jdk版本

maven-jar-plugin ==> 自定义自己工程,剔除一些配置信息

maven-assembly-plugin ==> 将自己工程的jar和其他依赖的jar组装起来,打包成bin、 config、 lib、 version的标准格式

2、原理

只要是可以从main方法启动,就可以使用如下方式来启动

java $JAVA-OPTS -classpath $CLASS_PATH $MAIN_CLASS 参数

其中

JAVA-OPTS就是一些jvm启动的一些参数,比如:堆、JMX、GC等
CLASS_PATH 就是将lib(包含本工程的jar)下的jar包通过  “:” 拼接起来
MAIN_CLASS 是需要运行的主类(main方法)

这里的要点是:assmebly插件能够把依赖的jar包自动的放到了lib中,需要在start.sh脚本中把它们添加到-classpath 就解决了jar依赖问题。

3、打包主要文件

  • 1、pom.xml中通用的build

      <build>
          <!--
              本工程的jar包名字,默认就是下面这个
              但是assembly插件提取依赖时,即使下面设置为aaa,抽取dependencySets时一定是${project.artifactId}-${project.version}
          -->
          <finalName>${project.artifactId}-${project.version}</finalName>
    
          <plugins>
              <!-- java编译插件 -->
              <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-compiler-plugin</artifactId>
                  <version>3.2</version>
                  <configuration>
                      <source>1.8</source>
                      <target>1.8</target>
                      <encoding>UTF-8</encoding>
                  </configuration>
              </plugin>
    
              <!--设置jar插件,将需要修改的配置文件从jar中删除-->
              <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-jar-plugin</artifactId>
                  <configuration>
                      <!--
                          对于文件,直接用文件名即可
                          对于文件夹:
                          如果要删除文件夹下的某个文件/mybatis/XXXMapper.xml
                          如果要删除整个文件夹db/ 注意:/不能少,否则会被认为是文件,而不是文件夹
                                  注意:不要写成db/*  这样还是会有一个db空文件夹
                      -->
                      <excludes>
                          <exclude>db/db.properties</exclude>
                          <exclude>quartz/job.properties</exclude>
                          <exclude>caiwutong.properties</exclude>
                          <exclude>logback.xml</exclude>
                          <exclude>notice.txt</exclude>
                      </excludes>
    
                      <!--指定主类,一般都不需要指定,只需要在Java命令启动的时候指定即可-->
                      <!--除非是在window下双击执行-->
                      <!--<archive>-->
                          <!--<manifest>-->
                              <!--<addDefaultImplementationEntries>true</addDefaultImplementationEntries>-->
                              <!--<addClasspath>true</addClasspath>-->
                              <!--<mainClass>com.surfilter.pscms.timer.Timer</mainClass>-->
                          <!--</manifest>-->
                          <!--<manifestEntries>-->
                              <!--<Class-Path>.</Class-Path>-->
                          <!--</manifestEntries>-->
                      <!--</archive>-->
    
                  </configuration>
              </plugin>
    
              <!--
                  配置assembly插件,默认的版本是pom4.0里面的2.2-beta-5
                  但是这个版本对dependencyManagement的传递依赖在dependencySets抽取依赖时有bug
                  总是使用dependencyManagement中的依赖,而不是额外指定的版本
                  这个bug在2.3以上的版本修复了,一般使用2.6,如下
              -->
              <plugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-assembly-plugin</artifactId>
                  <version>2.6</version>
                  <configuration>
                      <!-- 这个是最终打包出来的压缩文件名字,${maven.build.timestamp}是加上一个时间戳 -->
                      <finalName>${project.finalName}</finalName>
                      <descriptor>assembly/assembly.xml</descriptor>
                      <!--最终zip包名是否拼接assemblyID名称,默认是加上的-->
                      <!--加上后就变成:  spring-mvcweb-jetty-1.0-assembly.zip-->
                      <appendAssemblyId>false</appendAssemblyId>
                  </configuration>
                  <executions>
                      <execution>
                          <phase>package</phase> <!-- 绑定到package生命周期阶段上 -->
                          <goals>
                              <goal>single</goal>  <!-- 只运行一次 -->
                          </goals>
                      </execution>
                  </executions>
              </plugin>
          </plugins>
      </build>
    
  • 2、assembly.xml文件

      <!--
          - 1、任何从main方法启动的工程,都可以使用assembly进行打包,形成: bin   config  lib  version 的标准格式
    
               在java -classpath 中拼接上config,这样就可以直接使用
               classpath:/db/db.properties
               xxx.class.getResourceAsStream("/db/db.properties")
    
          - 2、路径是相对于工程根目录的,直接写即可。比如:bin 和 src/main/resources
    
          - 3、依赖打包,默认使用pom4.0的2.2-beta-5版本assembly插件
               但是此版本对传递依赖有bug,比如如果dependencyManagement里面包含了某依赖,总是会使用dependencyManagement中的依赖,没法额外指定
               同时对于下面的文件权限无效,即使设置了0755,还是会设置为777
               这些问题在2.3及以后版本修复了,一般打包都是用2.6版本
      -->
      <assembly>
          <id>assembly</id>
          <formats>
              <format>zip</format>
          </formats>
          <!--如果为false,那么解压后就是bin 、 config、 lib、 version。外面没有工程名称-->
          <includeBaseDirectory>true</includeBaseDirectory>
    
          <fileSets>
              <!--bin配置-->
              <fileSet>
                  <directory>bin</directory>
                  <outputDirectory>bin</outputDirectory>
                  <fileMode>0755</fileMode>
              </fileSet>
    
              <!--sbin配置-->
              <fileSet>
                  <directory>sbin</directory>
                  <outputDirectory>sbin</outputDirectory>
                  <fileMode>0755</fileMode>
              </fileSet>
    
              <!--config设置-->
              <fileSet>
                  <directory>src/main/resources</directory>
                  <outputDirectory>config</outputDirectory>
                  <!--
                      对于文件,直接用文件名即可
                      对于文件夹:
                      如果要删除文件夹下的某个文件mybatis/XXXMapper.xml
                      如果要删除整个文件夹mybatis/ 注意:/不能少,否则会被认为是文件,而不是文件夹
                              注意:不要写成mybatis/*  这样还是会有一个mybatis空文件夹
                  -->
                  <excludes>
                      <exclude>db/*.xml</exclude>
                      <exclude>db/*.sql</exclude>
                      <exclude>mybatis/</exclude>
                      <exclude>quartz/*.xml</exclude>
                      <exclude>spring/</exclude>
                      <exclude>notice.txt</exclude>
                  </excludes>
              </fileSet>
    
              <!--version设置-->
              <fileSet>
                  <directory>src/main/resources</directory>
                  <outputDirectory>version</outputDirectory>
                  <includes>
                      <include>notice.txt</include>
                  </includes>
              </fileSet>
    
              <!-- 抽取webapp,包括html和WEN-INF以及下面的web.xml (这些是jetty容器需要设置的)-->
              <fileSet>
                  <directory>src/main/webapp</directory>
                  <outputDirectory>webapp</outputDirectory>
              </fileSet>
          </fileSets>
    
          <!--lib配置,把工程放在根目录下,其他依赖包放在lib下-->
          <dependencySets>
              <dependencySet>
                  <outputDirectory>.</outputDirectory>
                  <includes>
                      <include>:*${project.artifactId}*:</include>
                  </includes>
              </dependencySet>
              <dependencySet>
                  <outputDirectory>lib</outputDirectory>
                  <excludes>
                      <exclude>:*${project.artifactId}*:</exclude>
                  </excludes>
              </dependencySet>
          </dependencySets>
      </assembly>
    
  • 3、启动脚本(通过DEPLOY_DIR)

      #!/bin/bash
    
      # 获取关键路径:BIN_DIR 和 DEPLOY_DIR
      cd `dirname $0`
      BIN_DIR=`pwd`
      cd ..
      DEPLOY_DIR=`pwd`
    
      # 创建logs文件夹
      mkdir -p $DEPLOY_DIR/logs
      STDOUT_FILE=$DEPLOY_DIR/logs/stdout.log
    
      # main类,程序入口 并且 从conf.properties中获取程序名和端口
      MAIN_CLASS=com.yuanmei.caiwutong.JettyServiceStarter
      APPLICATION_NAME="JettyServiceStarter"
      APPLICATION_PORT=`cat config/caiwutong.properties | grep 'application.port=' | cut -d '=' -f2- | tr -d '\r'`
    
      # 先判断此应用程序是否已经启动了以及端口是否被占用
      PIDS=`jps | grep $APPLICATION_NAME | awk '{print $1}'`
      if [ -n "$PIDS" ]; then
          echo "ERROR: The $APPLICATION_NAME already started!"
          echo "PID: $PIDS"
          exit 1
      fi
      if [ -n "$APPLICATION_PORT" ]; then
          SERVER_PORT_COUNT=`netstat -tln | grep $APPLICATION_PORT | wc -l`
          if [ $SERVER_PORT_COUNT -gt 0 ]; then
              echo "ERROR: The $APPLICATION_NAME port $APPLICATION_PORT already used!"
              exit 1
          fi
      fi
    
      # 将config文件夹和lib下jar拼接到--classpath中。
      # config 放在前面,是因为如下方式顺序查找--classpath,找到就返回
      #   classpath:/db/db.properties
      #   xxx.class.getResourceAsStream("/db/db.properties")
      # 将config拼接到--classpath中,那么logger使用class.getResource("logback.xml")能够找到
      # tr 表示将前面的那个值替换为后面的那个值
      CLASS_PATH=$DEPLOY_DIR/config
      CLASS_PATH=$CLASS_PATH:`ls $DEPLOY_DIR/lib/*.jar | tr "\n" ":"`
      CLASS_PATH=$CLASS_PATH:`ls $DEPLOY_DIR/*.jar`
    
      # jvm参数
      JAVA_OPTS=" -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true "
      # 开启debug
      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
      # 开启远程jmx,也就是可以使用jconsole进行连接
      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
      #内存以及gc的配置
      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 "
    
      # 启动应用程序
      echo -e "Starting the $APPLICATION_NAME ...\c"
      nohup java $JAVA_OPTS $JAVA_DEBUG_OPTS $JAVA_JMX_OPTS $JAVA_MEM_OPTS -classpath $CLASS_PATH $MAIN_CLASS $APPLICATION_PORT $1> $STDOUT_FILE 2>&1 &
    
      # 循环判断是否有对应的pid(也就是是否启动成功)
      while true; do
          sleep 1
          echo -e ".\c"
          PIDS=`jps | grep $APPLICATION_NAME | awk '{print $1}'`
          if [ -n PIDS ]; then
              break
          fi
      done
    
      echo "OK!"
      echo "PID: $PIDS"
      echo "STDOUT: $STDOUT_FILE"
    
      # 每次调用启动脚本都把之前的监控脚本干掉,然后再启动
      monitorPidArr=($(ps aux | grep $BIN_DIR/monitorRestart.sh | awk '{print $2}'))
      if [ ${#monitorPidArr[*]} -gt 1 ]; then
          ps -f | grep monitorRestart.sh | grep -v "grep" | awk '{print $2}' | xargs kill -9
      fi
      nohup sh $BIN_DIR/monitorRestart.sh $1> /dev/null 2>&1 &
    
  • 4、停止脚本(通过DEPLOY_DIR)

      #!/bin/bash
    
      # 先获取关键位置BIN_DIR和DEPLOY_DIR
      cd `dirname $0`
      BIN_DIR=`pwd`
      cd ..
      DEPLOY_DIR=`pwd`
    
      # 给定应用名字(和start.sh配置一样)
      APPLICATION_NAME="JettyServiceStarter"
    
      #  通过应用名字来获取pid,最后kill(下面是通用的,不用改了,只要配置上面的APPLICATION_NAME即可)
      PIDS=`jps | grep $APPLICATION_NAME | awk '{print $1}'`
      if [ -z "$PIDS" ]; then
          echo "ERROR: The $APPLICATION_NAME does not started!"
          exit 1
      fi
    
      echo -e "Stopping the $APPLICATION_NAME ...\c"
      while true; do
          echo -e ".\c"
          sleep 1
          PIDS=`jps | grep $APPLICATION_NAME | awk '{print $1}'`
          if [ -n "$PIDS" ]; then
              for PID in $PIDS ; do
                  kill -9 $PID > /dev/null 2>&1
              done
          else
              break;
          fi
      done
    
      echo "OK!"
      echo "PID: $PIDS"
    

4、总结

  • 1、只要能够从java main方法启动的工程,比如:spring-java,spring-boot,sparing-web-jetty这种直接从main方法启动的,都可以使用上面的打包方式

  • 2、如果是war这种基于Tomcat的运行方式,那么只需要利用Tomcat插件进行打包即可。

转载于:https://my.oschina.net/liufukin/blog/2221432

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值