Skip to content

打包说明

当你执行

bash
mvn package -p dev -am xxx

会发现打出来的jar是个压缩包。这是为什么呢?这是考虑到大多数时候标品都是作为单体项目在运行,每次打出来的包有100多M。 部署传输时,费时费力。可能有时候你就改了某个dto,service代码,便要再次传输100多M就很累,尤其是线上需要紧急修复时,便更加有体会。 基于此,实现了三方lib包、配置分离,形成如下的目录结构:

  • lib 三方包
    • xxx.jar
    • xxx.jar
    • ...
  • config 配置文件
    • yml
    • xml
  • xxxx.jar 主包
  • deploy.sh 启动脚本

在没有借助外部构建工具时,为了实现增量发布,可以手动选择要发布的jar,配置文件等等。通过这样一种方式,便实现了增量发布。但每次手动发布还是比较麻烦。为此我们可以借助CI工具jenkins来帮助我们快速构建。

那这个生成压缩包是如何做的呢?我们以framework-admin模块为例讲解下。在pom.xml里面定义了三个插件:

xml
<properties>
    <scripts_bootMain>com.wmeimob.mall.web.AdminStartApplication</scripts_bootMain>
</properties>
<build>
  <plugins>
      <!-- 基于maven-jar-plugin插件实现把依赖jar定义写入输出jar的META-INFO/MANIFEST文件 -->
      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-jar-plugin</artifactId>
          <version>2.6</version>
          <configuration>
              <archive>
                  <manifest>
                      <addClasspath>true</addClasspath>
                      <classpathPrefix>lib/</classpathPrefix>
                      <useUniqueVersions>false</useUniqueVersions>
                      <!--这里需要修改为你的项目的主启动类-->
                      <mainClass>${scripts_bootMain}</mainClass>
                  </manifest>
              </archive>
          </configuration>
      </plugin>
      <!-- 拷贝项目所有依赖jar文件到构建lib目录下 -->
      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>2.8</version>
          <executions>
              <execution>
                  <id>copy-dependencies</id>
                  <phase>package</phase>
                  <goals>
                      <goal>copy-dependencies</goal>
                  </goals>
                  <configuration>
                      <outputDirectory>${project.build.directory}/lib</outputDirectory>
                      <excludeTransitive>false</excludeTransitive>
                      <stripVersion>false</stripVersion>
                      <silent>true</silent>
                  </configuration>
              </execution>
          </executions>
      </plugin>
      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.4</version>
          <configuration>
              <!-- 打包后的包名是否包含assembly的id名 -->
              <appendAssemblyId>false</appendAssemblyId>
              <!-- 指定最后tar或者zip包的名字 -->
              <finalName>${project.artifactId}</finalName>
              <!-- tar或者zip包的输出目录 -->
              <outputDirectory>target/</outputDirectory>
              <descriptors>
                  <!-- 引用的assembly配置文件-->
                  <descriptor>../deploy/assembly.xml</descriptor>
              </descriptors>
          </configuration>
          <executions>
              <!-- phase加入package后,则在执行maven package时就可以调用maven-assembly-plugin插件定义的打包方式 -->
              <execution>
                  <!--名字任意 -->
                  <id>make-assembly</id>
                  <!-- 绑定到package生命周期阶段上 -->
                  <phase>package</phase>
                  <goals>
                      <!-- 只运行一次 -->
                      <goal>single</goal>
                  </goals>
              </execution>
          </executions>
      </plugin>
  </plugins>
</build>

assembly.xml 文件如下:

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>package</id>
<formats>
    <format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
    <!--拷贝application.yml文件到jar包的外部config目录下面-->
    <fileSet>
        <directory>${basedir}/src/main/resources</directory>
        <includes>
            <include>application.yml</include>
            <include>application-${activatedProperties}.yml</include>
            <include>bootstrap.yml</include>
            <include>*.xml</include>
        </includes>
        <filtered>true</filtered>
        <outputDirectory>${project.artifactId}-${activatedProperties}/config</outputDirectory>
    </fileSet>

    <!--拷贝lib包到jar包的外部lib下面-->
    <fileSet>
        <directory>${project.build.directory}/lib</directory>
        <outputDirectory>${project.artifactId}-${activatedProperties}/lib</outputDirectory>
        <!-- 打包需要包含的文件 -->
        <includes>
            <include>*.jar</include>
        </includes>
    </fileSet>

    <!--启动脚本打包进zip文件-->
    <fileSet>
        <directory>../deploy</directory>
        <outputDirectory>${project.artifactId}-${activatedProperties}/</outputDirectory>
        <includes>
            <include>*.sh</include>
        </includes>
        <!-- 文件文件权限为777 -->
        <fileMode>777</fileMode>
        <!-- 目录权限为777  -->
        <directoryMode>777</directoryMode>
        <!--脚本中参数变量为pom中的值 关键-->
        <filtered>true</filtered>
    </fileSet>

    <!--项目编译出来的jar打包进zip文件-->
    <fileSet>
        <directory>${project.build.directory}</directory>
        <outputDirectory>${project.artifactId}-${activatedProperties}/</outputDirectory>
        <includes>
            <include>*.jar</include>
        </includes>
    </fileSet>
</fileSets>
</assembly>

通过这么一种方式便可以实现了。

这里有个细节,zip 包里面包含一个 deploy.sh 启动脚本文件。其中

bash
#!/usr/bin/env bash
#参数值由pom文件传递
activeProfile=${activatedProperties}
baseZipName=${project.artifactId}
fileName=${project.artifactId}-${activeProfile}
jarName=${project.artifactId}

这四个变量值是动态传递进去的,在assembly.xml文件里实现。这样的好处就是我们的服务启动名称跟着项目来走,且进行环境区分,对于在同一台部署多个服务的服务器来说,无需担心服务名会重复,只需要保证项目名称唯一即可保证服务唯一。

当然了,不生成zip包也是可以的,注释掉pom.xml plugin的配置,使用下面的配置即可还原成单个 jar 100M+

xml
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
            <configuration>
                <mainClass>${scripts_bootMain}</mainClass>
            </configuration>
        </execution>
    </executions>
</plugin>