疑问:Spring Boot已经有了 spring-boot-maven-plugin
的打包方式,为什么还要自己重新实现打包方式呢?
答:都各有优势吧,不过本文的方式更加强大。不过SpringBoot打包出来jar文件,没办法进行修改,如果遇到需要简单修改一些系统配置或参数时(一些非配置中心的参数,如日志配置文件中的某个系统参数等),那就必须要重新编译打包才能生效。同时,本文的方式会自动生成各种操作系统(MAC/AIX/Linux/Windows等)的脚本文件,以及一些相关的运维命令(console|start|stop|restart|status|dump),同时可以依赖版本检查、GIT历史记录、远程DEBUG、配置JVM参数、GC参数和JMX参数等。
1 背景
每个JAVA项目开发完成后都会考虑部署至各个环境(DEV、TEST、PRO等)中,选择一种好的打包方式,将会在使用中无形的减少不少工作量,同时也会带来很多方便之处。反之,没有选择好打包方式,则会带来诸多不变之处。 下面我将介绍几种JAVA工厂常见的打包方式,先上效果图:
整体目录结构和物料包 自动生成的脚本目录 自动拷贝的配置目录2 spring-boot-maven-plugin
spring-boot-maven-plugin是Springboot提供的打包插件,直接在POM中添加一下Plugin即可:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>cn.micro.demo.DemoApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
3 自定义打包脚本
如果你的脚本编写能力很高,那完全可以考虑自己编写一套适合自己的打包脚本出来,不过因为难度和复杂度都较大所以不建议自己编写,等常用的方式解决不了你的需求时再考虑。
4 IDEA手动打包
常用的IDEA开发工具都是可以可视化界面打包部署包的,不过这种方式不利于CI/CD流程,所以也不推荐。
5 JSW+Assembly
JSW+Assembly是JAVA工程MAVEN通用打包方式。精简方式则直接使用:appassembler-maven-plugin和maven-assembly-plugin即可完成打包。但为了更好的效果,我将引入几个好用的插件来配合完成打包。
5.1 maven-compiler-plugin
maven-compiler-plugin插件主要用于指定编译时的JDK版本。
<!-- Specify JDK compiler version -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
5.2 maven-jar-plugin
maven-jar-plugin插件主要用于项目打包时,排除配置文件不打包进jar包中(如果配置打入了jar,则每次变更配置,都需要重新打包,很不方便)。
<!-- Specify the configuration files that do not need to be packaged into the jar package -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<!-- The exclusion rule is recommended to be consistent with the import rules in the assembly.xml file -->
<excludes>
<!-- Custom configuration -->
<exclude>*.yml</exclude>
<exclude>*.xml</exclude>
<exclude>*.properties</exclude>
<exclude>static/**</exclude>
<!-- Must be configured -->
<exclude>*.conf</exclude>
<exclude>tools/**</exclude>
</excludes>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
5.3 maven-enforcer-plugin
maven-enforcer-plugin插件主要用于打包时检测各种规范要求,如:检查JDK版本、MAVEN版本、不能依赖快照等功能。
<!-- Use enforcer to mandatory agreement rule: mvn validate -->
<!-- mvn clean install -Denforcer.skip=true -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M2</version>
<executions>
<execution>
<id>default-cli</id>
<goals>
<goal>enforce</goal>
</goals>
<phase>validate</phase>
<configuration>
<rules>
<requireMavenVersion>
<message>
<![CDATA[You are running an older version of Maven. This application requires at least Maven ${maven.version}.]]>
</message>
<version>[3.3.3,)</version>
</requireMavenVersion>
<requireJavaVersion>
<message>
<![CDATA[You are running an older version of Java. This application requires at least JDK ${java.version}.0.]]>
</message>
<version>[1.8.0,)</version>
</requireJavaVersion>
<requireReleaseVersion>
<message>No Snapshots Allowed!</message>
</requireReleaseVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
5.4 git-commit-id-plugin
git-commit-id-plugin用于将当前GIT项目的Commit日志记录打包成一个文件,便于查看当前物料包的历史GIT日志(如使用场景:线上跑的代码,想看看是否提交了某个BUG的修复记录)。
<!-- Git commit change log plugin -->
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<verbose>true</verbose>
<dateFormat>yyyy-MM-dd'T'HH:mm:ssZ</dateFormat>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
<generateGitPropertiesFilename>${project.build.directory}/dist/jsw/app/conf/git.properties</generateGitPropertiesFilename>
</configuration>
</plugin>
5.5 appassembler-maven-plugin
appassembler-maven-plugin用于将当前项目打包成个性化的目录框架,并同时使用JSW(Java Service Wrapper)生成各种操作系统的运维脚本(启动、停止、查看状态、重启等等命令),并且赋予可执行的权限等操作。同时也可以指定JMX端口、远程DEBUG端口、GC配置、GC日志、JVM配置和内存溢出Dump等信息。
<!-- Packing command: mvn clean package appassembler:generate-daemons -Dmaven.test.skip=true -->
<!-- Using JSW services to create scaffolding for target material packages -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>2.0.0</version>
<configuration>
<encoding>UTF-8</encoding>
<binFolder>bin</binFolder>
<tempDirectory>tmp</tempDirectory>
<logsDirectory>logs</logsDirectory>
<repositoryName>lib</repositoryName>
<repositoryLayout>flat</repositoryLayout>
<target>${project.build.directory}/dist</target>
<configurationDirectory>conf</configurationDirectory>
<copyConfigurationDirectory>true</copyConfigurationDirectory>
<configurationSourceDirectory>src/main/resources</configurationSourceDirectory>
<daemons>
<daemon>
<id>app</id>
<!-- Main Class -->
<mainClass>cn.micro.demo.Main</mainClass>
<platforms>
<!-- Java Service Wrapper -->
<platform>jsw</platform>
</platforms>
<generatorConfigurations>
<generatorConfiguration>
<generator>jsw</generator>
<includes>
<include>aix-ppc-32</include>
<include>aix-ppc-64</include>
<include>linux-ppc-64</include>
<include>linux-x86-32</include>
<include>linux-x86-64</include>
<include>windows-x86-32</include>
<include>windows-x86-64</include>
<include>hpux-parisc-64</include>
<include>solaris-x86-32</include>
<include>solaris-sparc-32</include>
<include>solaris-sparc-64</include>
<include>macosx-ppc-32</include>
<include>macosx-universal-32</include>
<include>macosx-universal-64</include>
</includes>
<configuration>
<property>
<name>configuration.directory.in.classpath.first</name>
<value>conf</value>
</property>
<property>
<name>wrapper.ping.timeout</name>
<value>120</value>
</property>
<property>
<name>set.default.REPO_DIR</name>
<value>lib</value>
</property>
<property>
<name>wrapper.logfile</name>
<value>logs/wrapper.log</value>
</property>
</configuration>
</generatorConfiguration>
</generatorConfigurations>
<jvmSettings>
<!-- JMX -->
<systemProperties>
<systemProperty>java.security.policy=conf/policy.all</systemProperty>
<systemProperty>com.sun.management.jmxremote</systemProperty>
<systemProperty>com.sun.management.jmxremote.port=8777</systemProperty>
<systemProperty>com.sun.management.jmxremote.authenticate=false</systemProperty>
<systemProperty>com.sun.management.jmxremote.ssl=false</systemProperty>
</systemProperties>
<!-- https://blog.csdn.net/wo541075754/article/details/75008617 -->
<!-- https://zhaoyanblog.com/archives/440.html -->
<!-- https://www.javadoop.com/post/g1 -->
<extraArguments>
<extraArgument>-server</extraArgument>
<!-- Remote Debug -->
<extraArgument>-Xdebug</extraArgument>
<extraArgument>-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5010</extraArgument>
<!-- Heap Dump -->
<extraArgument>-XX:+HeapDumpOnOutOfMemoryError</extraArgument>
<extraArgument>-XX:HeapDumpPath=logs/heap-dump.hprof</extraArgument>
<!-- GC Config -->
<extraArgument>-XX:+UseG1GC</extraArgument>
<extraArgument>-XX:MaxGCPauseMillis=200</extraArgument>
<extraArgument>-XX:InitiatingHeapOccupancyPercent=45</extraArgument>
<extraArgument>-XX:G1ReservePercent=10</extraArgument>
<extraArgument>-XX:NewRatio=2</extraArgument>
<extraArgument>-XX:SurvivorRatio=8</extraArgument>
<extraArgument>-XX:MaxTenuringThreshold=15</extraArgument>
<!-- GC Log -->
<extraArgument>-Xloggc:logs/gc.log</extraArgument>
<extraArgument>-XX:GCLogFileSize=10M</extraArgument>
<extraArgument>-XX:NumberOfGCLogFiles=10</extraArgument>
<extraArgument>-XX:+UseGCLogFileRotation</extraArgument>
<extraArgument>-XX:+PrintGCDateStamps</extraArgument>
<extraArgument>-XX:+PrintGCTimeStamps</extraArgument>
<extraArgument>-XX:+PrintGCDetails</extraArgument>
<extraArgument>-XX:+PrintHeapAtGC</extraArgument>
<extraArgument>-XX:+PrintGCApplicationStoppedTime</extraArgument>
<extraArgument>-XX:+DisableExplicitGC</extraArgument>
<extraArgument>-verbose:gc</extraArgument>
</extraArguments>
</jvmSettings>
</daemon>
</daemons>
</configuration>
<executions>
<execution>
<id>generate-jsw-scripts</id>
<phase>package</phase>
<goals>
<goal>generate-daemons</goal>
</goals>
</execution>
</executions>
</plugin>
5.6 maven-assembly-plugin
maven-assembly-plugin插件用于将上述appassembler-maven-plugin插件打包后的目录框架,再次打包为压缩包,便于在不同环境中进行拷贝操作。
<!-- Use assembly to package the scaffolding directory into compressed packets -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<descriptors>
<descriptor>src/main/resources/tools/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
完整Plugin如下:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<!-- Specify JDK compiler version -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<!-- Specify the configuration files that do not need to be packaged into the jar package -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<!-- The exclusion rule is recommended to be consistent with the import rules in the assembly.xml file -->
<excludes>
<!-- Custom configuration -->
<exclude>*.yml</exclude>
<exclude>*.xml</exclude>
<exclude>*.properties</exclude>
<exclude>static/**</exclude>
<!-- Must be configured -->
<exclude>*.conf</exclude>
<exclude>tools/**</exclude>
</excludes>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Use enforcer to mandatory agreement rule: mvn validate -->
<!-- mvn clean install -Denforcer.skip=true -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M2</version>
<executions>
<execution>
<id>default-cli</id>
<goals>
<goal>enforce</goal>
</goals>
<phase>validate</phase>
<configuration>
<rules>
<requireMavenVersion>
<message>
<![CDATA[You are running an older version of Maven. This application requires at least Maven ${maven.version}.]]>
</message>
<version>[${maven.version},)</version>
</requireMavenVersion>
<requireJavaVersion>
<message>
<![CDATA[You are running an older version of Java. This application requires at least JDK ${java.version}.0.]]>
</message>
<version>[${java.version}.0,)</version>
</requireJavaVersion>
<!--
<requireReleaseVersion>
<message>No Snapshots Allowed!</message>
</requireReleaseVersion>
-->
</rules>
</configuration>
</execution>
</executions>
</plugin>
<!-- Git commit change log plugin -->
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<verbose>true</verbose>
<dateFormat>yyyy-MM-dd'T'HH:mm:ssZ</dateFormat>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
<generateGitPropertiesFilename>${project.build.directory}/dist/jsw/app/conf/git.properties
</generateGitPropertiesFilename>
</configuration>
</plugin>
<!-- Packing command: mvn clean package appassembler:generate-daemons -Dmaven.test.skip=true -->
<!-- Using JSW services to create scaffolding for target material packages -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>2.0.0</version>
<configuration>
<encoding>UTF-8</encoding>
<binFolder>bin</binFolder>
<tempDirectory>tmp</tempDirectory>
<logsDirectory>logs</logsDirectory>
<repositoryName>lib</repositoryName>
<repositoryLayout>flat</repositoryLayout>
<target>${project.build.directory}/dist</target>
<configurationDirectory>conf</configurationDirectory>
<copyConfigurationDirectory>true</copyConfigurationDirectory>
<configurationSourceDirectory>src/main/resources</configurationSourceDirectory>
<daemons>
<daemon>
<id>app</id>
<!-- Main Class -->
<mainClass>cn.micro.biz.Main</mainClass>
<platforms>
<!-- Java Service Wrapper -->
<platform>jsw</platform>
</platforms>
<generatorConfigurations>
<generatorConfiguration>
<generator>jsw</generator>
<includes>
<include>aix-ppc-32</include>
<include>aix-ppc-64</include>
<include>linux-ppc-64</include>
<include>linux-x86-32</include>
<include>linux-x86-64</include>
<include>windows-x86-32</include>
<include>windows-x86-64</include>
<include>hpux-parisc-64</include>
<include>solaris-x86-32</include>
<include>solaris-sparc-32</include>
<include>solaris-sparc-64</include>
<include>macosx-ppc-32</include>
<include>macosx-universal-32</include>
<include>macosx-universal-64</include>
</includes>
<configuration>
<property>
<name>configuration.directory.in.classpath.first</name>
<value>conf</value>
</property>
<property>
<name>wrapper.ping.timeout</name>
<value>120</value>
</property>
<property>
<name>set.default.REPO_DIR</name>
<value>lib</value>
</property>
<property>
<name>wrapper.logfile</name>
<value>logs/wrapper.log</value>
</property>
</configuration>
</generatorConfiguration>
</generatorConfigurations>
<jvmSettings>
<!-- JMX -->
<!--
<systemProperties>
<systemProperty>java.security.policy=conf/policy.all</systemProperty>
<systemProperty>com.sun.management.jmxremote</systemProperty>
<systemProperty>com.sun.management.jmxremote.port=8777</systemProperty>
<systemProperty>com.sun.management.jmxremote.authenticate=false</systemProperty>
<systemProperty>com.sun.management.jmxremote.ssl=false</systemProperty>
</systemProperties>
-->
<!-- https://blog.csdn.net/wo541075754/article/details/75008617 -->
<!-- https://zhaoyanblog.com/archives/440.html -->
<!-- https://www.javadoop.com/post/g1 -->
<extraArguments>
<extraArgument>-server</extraArgument>
<!-- Remote Debug -->
<extraArgument>-Xdebug</extraArgument>
<!--
<extraArgument>-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5010</extraArgument>
-->
<!-- Heap Dump -->
<extraArgument>-XX:+HeapDumpOnOutOfMemoryError</extraArgument>
<extraArgument>-XX:HeapDumpPath=logs/heap-dump.hprof</extraArgument>
<!-- GC Config -->
<extraArgument>-XX:+UseG1GC</extraArgument>
<extraArgument>-XX:MaxGCPauseMillis=200</extraArgument>
<extraArgument>-XX:InitiatingHeapOccupancyPercent=45</extraArgument>
<extraArgument>-XX:G1ReservePercent=10</extraArgument>
<extraArgument>-XX:NewRatio=2</extraArgument>
<extraArgument>-XX:SurvivorRatio=8</extraArgument>
<extraArgument>-XX:MaxTenuringThreshold=15</extraArgument>
<!-- GC Log -->
<extraArgument>-Xloggc:logs/gc.log</extraArgument>
<extraArgument>-XX:GCLogFileSize=10M</extraArgument>
<extraArgument>-XX:NumberOfGCLogFiles=10</extraArgument>
<extraArgument>-XX:+UseGCLogFileRotation</extraArgument>
<extraArgument>-XX:+PrintGCDateStamps</extraArgument>
<extraArgument>-XX:+PrintGCTimeStamps</extraArgument>
<extraArgument>-XX:+PrintGCDetails</extraArgument>
<extraArgument>-XX:+PrintHeapAtGC</extraArgument>
<extraArgument>-XX:+PrintGCApplicationStoppedTime</extraArgument>
<extraArgument>-XX:+DisableExplicitGC</extraArgument>
<extraArgument>-verbose:gc</extraArgument>
</extraArguments>
</jvmSettings>
</daemon>
</daemons>
</configuration>
<executions>
<execution>
<id>generate-jsw-scripts</id>
<phase>package</phase>
<goals>
<goal>generate-daemons</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Use assembly to package the scaffolding directory into compressed packets -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<descriptors>
<descriptor>src/main/resources/tools/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
assembly.xml文件内容为:
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0
http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>dist</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target/dist/jsw/app/bin</directory>
<outputDirectory>bin</outputDirectory>
<!-- Set executable permissions -->
<fileMode>0755</fileMode>
<directoryMode>0755</directoryMode>
</fileSet>
<fileSet>
<directory>target/dist/jsw/app/conf/tools</directory>
<outputDirectory>bin</outputDirectory>
<fileMode>0755</fileMode>
<directoryMode>0755</directoryMode>
<includes>
<include>**.sh</include>
<include>**.bat</include>
</includes>
</fileSet>
<fileSet>
<directory>target/dist/jsw/app/conf</directory>
<outputDirectory>conf</outputDirectory>
<!-- The import rules here recommend consistency with exclusionary rules in the pom.xml file -->
<includes>
<!-- Custom configuration -->
<include>*.yml</include>
<include>*.xml</include>
<include>*.properties</include>
<include>static/**</include>
<!-- Must be configured -->
<include>*.conf</include>
</includes>
<excludes>
<!-- Must be configured -->
<exclude>tools/**</exclude>
</excludes>
<fileMode>0644</fileMode>
<directoryMode>0744</directoryMode>
</fileSet>
<fileSet>
<directory>target/dist/jsw/app/lib</directory>
<outputDirectory>lib</outputDirectory>
<fileMode>0644</fileMode>
<directoryMode>0744</directoryMode>
</fileSet>
<fileSet>
<directory>target/dist/jsw/app/logs</directory>
<outputDirectory>logs</outputDirectory>
<fileMode>0644</fileMode>
<directoryMode>0744</directoryMode>
</fileSet>
<fileSet>
<directory>target/dist/jsw/app/tmp</directory>
<outputDirectory>tmp</outputDirectory>
<fileMode>0644</fileMode>
<directoryMode>0744</directoryMode>
</fileSet>
</fileSets>
</assembly>
5.7 打包命令
mvn clean package appassembler:generate-daemons -Dmaven.test.skip=true
打包之后的目录结构为:
整体目录结构和物料包 自动生成的脚本目录 自动拷贝的配置目录
网友评论