[原创] 介绍java maven项目的多种打包方式

maven项目开发完成后,我们需要部署到线上,这时候我们希望将我们的整个项目或者单个模块打包起来,形成可以部署的包,方便我们进行部署.

最近在整理一个跟spring boot无关的项目,整个项目就是在main方法中创建了一个线程池然后开始run...;

所以这篇文章主要是用来针对类似的传统maven项目(非spring 非spring boot).

spring boot这种约定优于配置的方式用起来是真香啊!

一. 常用的几种打包方式和比较通用的demo

基本打包命令:
  • 进入单独模块并打包

    cd ${module_name} && mvn clean install -Dmaven.test.skip=true
  • 在项目中直接打包指定模块

    mvn clean install -Dmaven.test.skip=true -pl ${moudle_name} -am

    install会往本地仓库也丢一份,单纯打包 package 命令即可

常用的四种打包方式
  1. maven compiler plugin----单纯的jar

    一般maven项目基本都会配置这个plugin,用于进行项目模块的打包

   <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>

这种打包方式只会打包当前项目的所有文件,依赖的jar包及其文件不会被打包;

  1. maven jar plugin----jar包和lib目录
   <!-- 打包jar文件时,配置manifest文件,加入lib包的jar依赖 -->
   <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-jar-plugin</artifactId>
       <version>3.1.1</version>
       <configuration>
           <classesDirectory>target/classes/</classesDirectory>
           <archive>
               <manifest>
                   <!-- 主函数的入口 -->
                   <mainClass>com.kris.TestApplication</mainClass>
                   <!-- 打包时 MANIFEST.MF文件不记录的时间戳版本 -->
                   <useUniqueVersions>false</useUniqueVersions>
                   <addClasspath>true</addClasspath>
                   <classpathPrefix>lib/</classpathPrefix>
               </manifest>
               <manifestEntries>
                   <Class-Path>.</Class-Path>
               </manifestEntries>
           </archive>
       </configuration>
   </plugin>

这种打包方式会生成一个只包含当前项目文件的jar包,依赖的jar被放置在classpathPrefix指定的文件夹中,所以启动时必须要有专门的lib文件夹来管理相关的依赖,否则无法正常启动;

需要在manifest里面指定启动类;

由于不是单独可以运行的jar,局限性较大;

  1. maven assembly plugin----项目及其依赖项打包成一个jar包
   <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-assembly-plugin</artifactId>
       <version>2.5.5</version>
       <configuration>
           <appendAssemblyId>false</appendAssemblyId>
           <descriptorRefs>
               <descriptorRef>jar-with-dependencies</descriptorRef>
           </descriptorRefs>
           <archive>
               <manifest>
                   <addClasspath>true</addClasspath>
                   <classpathPrefix>lib/</classpathPrefix>
                   <mainClass>com.kris.TestApplication</mainClass>
               </manifest>
           </archive>
       </configuration>
       <executions>
           <execution>
               <phase>package</phase>
               <goals>
                   <goal>single</goal>
               </goals>
           </execution>
       </executions>
   </plugin>

通过phase指定在打包的时候运行插件,构建成独立的jar包;

需要在manifest指定启动类,不然没办法直接启动;

  1. maven shard plugin----项目及其依赖项打包成一个jar包,并支持修改/屏蔽指定jar/class
   <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-shade-plugin</artifactId>
       <version>3.2.0</version>
       <configuration>
           <!-- put your configurations here -->
       </configuration>
       <executions>
           <execution>
               <phase>package</phase>
               <goals>
                   <goal>shade</goal>
               </goals>
               <configuration>
                   <transformers>
                       <transformer
                            implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                           <mainClass>com.kris.TestApplication</mainClass>
                       </transformer>
                   </transformers>
                   <filters>
                       <filter>
                           <artifact>org.elasticsearch:elasticsearch</artifact>
                           <excludes>
                               <exclude>org/elasticsearch/action/bulk/*
                               </exclude>
                           </excludes>
                       </filter>
                       <filter>
                           <artifact>com.kris.test:test-core
                           </artifact>
                           <includes>
                               <include>**</include>
                           </includes>
                       </filter>
                   </filters>
               </configuration>
           </execution>
       </executions>
   </plugin>

将本地模块打包成jar,指定了启动类;

通过filter中的exclude功能将elasticsearch依赖下的org/elasticsearch/action/bulk/这个包下面的所有class屏蔽掉,这样我们在本地复写的类就能出现在我们打包好的jar包中,实现替换的目标;

总结:

  • 目前大部分场景都是将本地项目及其依赖打包成一个可执行的jar包然后进行部署;

  • maven-assembly-plugin的主要局限性在于当有多个同名的class出现在不同的包的时候,他只会根据pom.xml文件中的依赖顺序添加类到jar包中,后续的同名类会被直接跳过,所以如果存在同名类,需要谨慎处理;

  • 当你需要对某些类或者库进行特殊处理时,maven-shade-plugin可以提供一些过滤等方面的配置功能,方便用户进行个性化的配置;

  • 个人踩坑记录(仅个人本地环境):

  <dependency>
      <groupId>org.elasticsearch</groupId>
      <artifactId>elasticsearch</artifactId>
      <version>6.8.1</version>
  </dependency>

我在本地要打包的模块复写了一些elasticsearch的一些代码,本地运行时是正常的,类加载顺序是本地优先;

但是使用maven-assembly-plugin进行构建时,发现打包好的jar包中复写的类都没有生效,class文件反编译出来还是elasticsearch原生代码,没有生效,经过仔细观察整个生成的过程,发现最开始maven-compiler-plugin会将本地模块打包一次,这时候是正确的,等到maven-assembly-plugin执行时,发现模块又被打包了一次,并且使用了elasticsearchjar包中的原生代码,最终导致复写的类没有生效;

后面尝试使用了maven shard plugin,发现遵循的原则时本地优先,并且通过filter这样的过滤功能可以做一些个性化的配置,用起来比较方便点.

版权声明:
作者:Zad
链接:https://www.techfm.club/p/311.html
来源:TechFM
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>