[原创] 介绍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 命令即可
常用的四种打包方式
-
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包及其文件不会被打包;
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,局限性较大;
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指定启动类,不然没办法直接启动;
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
执行时,发现模块又被打包了一次,并且使用了elasticsearch
jar包中的原生代码,最终导致复写的类没有生效;
后面尝试使用了maven shard plugin
,发现遵循的原则时本地优先,并且通过filter
这样的过滤功能可以做一些个性化的配置,用起来比较方便点.
共有 0 条评论