Maven插件

2022/4/18 6:13:04

本文主要是介绍Maven插件,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目录
  • 一、maven-compiler-plugin 插件详解
    • 1.maven插件介绍
    • 2.全局配置maven JDK编译版本
    • 3.参考
  • 二、org.apache.maven.plugins系列插件简介
    • 1.插件知识简介
    • 2.官网也建议指定编译的jdk版本
    • 3.POM简介
    • 4.打开Show Effective POM的两种方式
    • 5.常用插件
      • Maven官网插件地址:https://maven.apache.org/plugins/index.html
    • 6.工作机制
    • 7.自定义maven插件
    • 8.参考
  • 三、springboot 打包插件spring-boot-maven-plugin打包机制及内部结构分析
    • 1.前言
      • 1、spring-boot-maven-plugin引入pom
    • 2.执行打包命令
    • 3.jar内部结构
      • 3.1 common.jar目录结构如下:
      • 3.2 common.jar.original目录结构
    • 4.参考
  • 四、springboot增量打包更新--静态资源分离打包
    • 1.前言
    • 2.具体步骤
    • 3.参考

一、maven-compiler-plugin 插件详解

1.maven插件介绍

maven是个项目管理工具,如果我们不告诉它代码要使用什么样的jdk版本编译的话,它就会用maven-compiler-plugin默认的jdk版本来进行编译处理,这样就容易出现编译版本与源代码不匹配,以至于可能导致编译不通过的问题。例如代码中要是使用上了Java 8的新特性,比如函数式编程,但是maven在编译的时候使用的是Java 7,那这一段代码是完全不可能编译成.class文件的,但如果相反maven编译时使用的是java11则可以编译通过,java高版本的jdk可以运行低版本的java语法的,也既是向下兼容的。为了避免出现mvne使用低版本jdk编译高版本java语法这种情况,在构建maven项目的时候,推荐第一步就是配置maven-compiler-plugin插件,指定项目源码的 jdk 版本,编译后的 jdk 版本,以及编码方式。

从 maven-compiler-plugin 3.8.0 之后,默认JDK 版本就由 1.5 改为 1.6 了。但是这仍然跟不上 JDK 的更新速度,目前大多数系统都在使用 JDK 1.8。Apache Maven Project 对 maven-compiler-plugin中compiler:compile有如下关于jdk版本变更的描述:

img

<plugin>
    <!-- 指定maven编译的jdk版本,如果不指定,maven3默认用jdk 1.5 maven2默认用jdk1.3 -->                 
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>                       
        <!-- 一般而言,target与source是保持一致的,但是,有时候为了让程序能在其他版本的jdk中运行
(比如:源代码使用的是1.5的语法,但是想在1.8的jdk环境运行,由低刀高是允许的)
(对于低版本目标jdk,源代码中不能使用低版本jdk中不支持的语法),会存在target不同于source的情况 -->
        <!-- 源代码使用的JDK版本 -->
        <source>1.8</source>
        <!-- 需要生成的目标class文件的编译版本 -->
        <target>1.8</target>
        <!-- 字符集编码 -->
        <encoding>UTF-8</encoding>
        <!-- 跳过测试 -->
        <skipTests>true</skipTests>
        <verbose>true</verbose>
        <showWarnings>true</showWarnings>
        <!-- 要使compilerVersion标签生效,还需要将fork设为true,用于明确表示编译版本配置的可用 -->
        <fork>true</fork>
        <!-- 使用指定的javac命令,例如:<executable>${JAVA_1_4_HOME}/bin/javac</executable> -->
        <executable><!-- path-to-javac --></executable>
        <!-- 指定插件将使用的编译器的版本 -->
        <compilerVersion>1.3</compilerVersion>
        <!-- 编译器使用的初始内存 -->
        <meminitial>128m</meminitial>
        <!-- 编译器使用的最大内存 -->
        <maxmem>512m</maxmem>
        <!-- 这个选项用来传递编译器自身不包含但是却支持的参数选项 -->
        <compilerArgument>-verbose -bootclasspath ${java.home}\lib\rt.jar</compilerArgument>
    </configuration>
</plugin>                             

参考:https://blog.csdn.net/liupeifeng3514/article/details/80236077

2.全局配置maven JDK编译版本

  • 在公司开发时一劳永逸的配置

此种设置方式将影响由maven创建的所有项目。找到maven安装目录的conf文件夹,修改其中的settings.xml文件,profiles标签加入如下配置:

<!-- ${MAVEN_HOME}/conf/settins.xml 文件添加如下profile配置,建立的java项目默认使用java 8/11/13 -->
<profiles>
    <profile>
        <id>jdk-8</id>
        <activation>
            <activeByDefault>true</activeByDefault>
            <jdk>8</jdk>
        </activation>
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
            <maven.compiler.compilerVersion>8</maven.compiler.compilerVersion>
        </properties>
    </profile>
</profiles>

这样全局设置后,项目编译时就会默认使用jdk 13。全局配置的好处就是省事、方便,从而避免对每个项目都去设置。

3.参考

https://www.cnblogs.com/east7/p/13363069.html?utm_source=tuicool

二、org.apache.maven.plugins系列插件简介

1.插件知识简介

  compiler(maven-compiler-plugin)插件3.0之前,默认的Java编译器就的JDK自带的javac。但是从Compiler(maven-compiler-plugin)插件3.0开始(需要JDK1.6),默认的Java编译器 是javax.tools.JavaCompiler。如果仍然希望使用JDK自带的javac编译源代码,就需要为mvn命令配置forceJavacCompilerUse启动参数如:-Dmaven.compiler.forceJavacCompilerUse=true

  Compiler插件编译时和编译后运行的JVM版本目前默认的设置为1.5,默认用此版本,而不是根据你在IDEA项目结构中指定的工程JDK版本编译。如果想改变这些默认设置,应该设置编译源和目标中java编译器的目标,通过设置Java源代码兼容的JVM版本,标明Java源代码开发过程中使用的Java版本,通过设置编译后的类库拟运行的JVM版本,给出编译后的类库将要运行的Java环境(一般都会设置,因为很少有项目再用1.7以下的版本了):

  同时,命令mvn的运行需要依赖JDK,Compiler插件默认使用当前运行mvn命令的JDK去编译Java源代码。如果想使用其他版本的JDK(比如本地java环境的,而非maven自带的)编译Java源代码,则需要设置如下(重点fork 、executable、compilerVersion):

上述配置中,用以编译Java源代码的是JDK 1.8,运行mvn命令时指定maven所使用的是JDK为1.6

Compiler插件提供了如下2个goal,默认都已经绑定到Maven的生命周期阶段,无需单独指出。

compiler:compile,绑定到compile 阶段,用以编译main/路径下的源代码

compiler:testCompile,绑定到test-compile阶段,用以编译test/路径下的源代码

mvn compile:

2.官网也建议指定编译的jdk版本

如果是web项目,就需要打war包,那就需要这个插件:

强制字符集编码:${project.build.sourceEncoding}

platformwar包名字——platform.war

产生war前,用于存放构建war包的目录——target/platform。

${project.build.directory}/platform

使用maven工具链:

使用不同的JDK的最好方法是使用工具链方式。在建立一个项目,如编译java源文件,生成Javadoc,运行单元测试、打包,这些插件中的每一个都需要一个JDK工具来对应操作:Javac、JavaDoc、JaveNeR等。使用Maven工具链插件,您可以为所有相关的Maven插件配置1个默认JDK工具链也可以各自配置不同的jdk,用法略。

配置编译插件:

除工具链方式之外,也可以在编译过程中使用的特定JDK。这样的配置对这个插件是特定的,不会影响其他插件。compilerVersion参数可以用来指定插件使用的编译器版本,但是需要将fork设置为true才能工作,此为非常用配置不做详细了解。

针对不同的编译器设置source和target选项:

有时编译某个项目时需要使用的jdk与当前maven所使用的版本不同。Javac可以使用source和target参数来接受这样的命令。编译器插件也可以被配置为在编译期间提供这些选项。如刚才上述:官网也建议指定编译的jdk版本

传递编译参数:

有时需要传递其他编译器参数,这些编译器参数本身不是插件本身需要处理的,而是需要将编译器参数传递给Javac编译器,如下图

3.POM简介

所有的 POM 都继承自一个父 POM(无论是否显式定义了这个父 POM),父POM包含一些可以被继承的默认设置。Maven 使用 effective pom(Super pom 加上工程自己的配置)来执行相关,目的为了使开发者在pom.xml中做尽可能少的配置,且在子配置中可以被方便的覆盖:

比如不指定packaging时,即默认打jar包时打开effective.pom

再看另一种举例:当指定packaging为war,指定打war包时打开effective pom

所以我们只需要指定packaging打包类型,maven插件可以自动加载并继承父pom相关配置。

如果父pom中的默认配置不符合现有项目要求,而在我们的pom中有没有覆盖,则会报错,如删除pom中的maven-compiler-plugin,使其不覆盖父pom中的maven-compiler-plugin,这样就是使用的父pom中的配置:

上图删除了pom中的maven-compiler-plugin,再看下图effecrive pom中的:

看到这里就使用了默认父pom的maven-compiler-plugin2.3.2版本,此版本默认的jdk是1.5,maven编译时报:

然后修改自己的pom中的maven-compiler-plugin覆盖父pom中的maven-compiler-plugin,使用自定义覆盖默认配置:

上图pom中增加了maven-compiler-plugin,再看下图effecrive pom中的:

则使用jdk1.7编译成功了

4.打开Show Effective POM的两种方式

  • maven 命令行方式:
    mvn help:effective-pom -Doutput=EffectivePom.xml

我们都知道maven是约定大于配置,也就是默认有很多约定好的配置,如果你不改变,那么就使用这些配置,比如java源代码放置在src/main/java下, 资源文件放置在src/main/resources下, 所以当我们把源代码,资源按约定的结构建立起来后,pom.xml配置很少就可以build jar/war/ear 包, 那么如果你想知道pom.xml的默认配置有哪些,分别设置了哪些值,那么你可以通过上面的goal来生成一个完整的EffectivePom.xml文件,这里面有完整的配置.

打开Show Effective POM(最终生效POM配置,包含了继承的内容)

  • IDEA方式:

5.常用插件

Maven官网插件地址:https://maven.apache.org/plugins/index.html

maven的属性值的占位符,类似EL,类似ant的属性,比如${X},可用于pom文件任何赋值的位置。有以下分类:

env.X:操作系统环境变量,比如${env.PATH}

project.x:pom文件中的属性,比如:1.0,引用方式:${project.version}

settings.xml文件中的属性,比如:false,引用方式:${settings.offline}

Java System Properties:java.lang.System.getProperties()中的属性,比如java.home,引用方式:${java.home}

自定义在pom文件中可以:c:/apps/cargo-installs定义属性及属性的值,而引用方式为:${installDir}

6.工作机制

  Maven强大的一个重要的原因是它有一个十分完善的生命周期模型(lifecycle),它有三套相互独立的生命周期,请注意这里说的是“三套”,请别将Maven的生命周期看成一个整体哦,三个生命周期是独立线性执行,分别是:

Clean Lifecycle 在进行真正的构建之前进行一些清理工作。

Default Lifecycle 构建的核心部分,编译,测试,打包,部署等等。

Site Lifecycle 生成项目报告,站点,发布站点。

  每个生命周期包含一些阶段(phase),这些阶段(phase)是有顺序的,每个阶段蕴含一个或多个目标(goal),并且后面的阶段依赖于前面的阶段,我们和Maven最直接的交互方式就是调用这些生命周期阶段。较之于生命周期阶段的前后依赖关系,三套生命周期本身是相互独立的,用户可以仅仅调用clean生命周期的某个阶段,或者仅仅调用default生命周期的某个阶段,而不会对其他生命周期产生任何影响。例如,当用户调用clean生命周期的clean阶段的时候,不会触发default生命周期的任何阶段。其中deault是最重要的生命周期,拥有validate 、compile 、test 、package、integration、verify、install、deploy等等阶段。

  看一下Maven的编译阶段,让maven进行编译代码,使用的是声明的方式来告知Maven如何做的。看似一个简单的命令,但其实它后面执行了一系列的工作。mvn compile如不指定compile阶段的goal,所以complie阶段所有goal,compile和test compile都会执行。

  Maven是如何知道从哪里找到要编译的源文件?并且Maven如何知道将编译好的类文件放到哪里?这里就是由Mave基础工作之一“通过配置进行约定”所解决的问题。一般情况下,源文件放在src/main/java路径下,这种默认设置(虽然在上面的POM文件中并没看到)是从父 POM继承来的,即使最简单的POM也知道源文件的默认位置:

当首次执行compile命令或其它命令时,maven会下载所有插件和相关的文件,而之后再执行同一个命令的时候会发现比第一次快很多,这就为什么首次执行命令时候会比较慢的原因。

7.自定义maven插件

大家有没有想过,如果maven自带的插件满足不了我们的需求时候,该怎么办呢?其实不难办,可以通过自己写插件来实现。下面给大家讲一下如何写插件。

1、首先需要创建一个maven项目tinaproject,然后把pom里的packaging改成maven-plugin

然后把版本改为你自己使用的版本,一般现在都是用maven2

接着添加依赖

2、pom修改完了之后就开始创建mojo类了,maven插件里每一个goal所对应的功能都是一个Mojo,比如说eclipse:clean和eclipse:eclipse就是两个Mojo

写完了一个最简单的mojo类之后就来测试下能否正确运行,把mvn install把它发布到本地maven仓库,然后在pom里再增加一个plugin(上面写的这个)

最后再运行mvn compile 就能看到输出了

8.参考

https://www.jianshu.com/p/3c75b3225724

三、springboot 打包插件spring-boot-maven-plugin打包机制及内部结构分析

1.前言

许多公司都会选择使用springboot作为服务应用开发框架,springboot框架提供了一套自己的打包机制,是通过spring-boot-maven-plugin插件来实现的。

1、spring-boot-maven-plugin引入pom

对于新建的一个springboot项目来说,pom中会加入插件:

img

通过idea可以看到maven中包含了spring-boot-maven-plugin插件:

img

功能说明:

  • build-info:生成项目的构建信息文件 build-info.properties
  • repackage:这个是默认goal,在 mvn package 执行之后,这个命令再次打包生成可执行的 jar,同时将 mvn package 生成的 jar 重命名为 *.origin
  • run:这个可以用来运行 Spring Boot 应用
  • start:这个在 mvn integration-test 阶段,进行 Spring Boot 应用生命周期的管理
  • stop:这个在 mvn integration-test 阶段,进行 Spring Boot 应用生命周期的管理

spring-boot-maven-plugin插件默认在父工程sprint-boot-starter-parent中被指定为repackage,可以点击sprint-boot-starter-parent进入父pom进行查看,如下图:

img

如果需要设置其他属性,需要在当前应用的pom中进行设置去覆盖父pom默认的值去改变行为。

2.执行打包命令

mvn clean package

或者通过开发工具如idea执行clean和package俩命令:

img

执行以上命令时会自动触发spring-boot-maven-plugin插件的repackage目标,完后可以在target目录下看到生成的jar,如下图:

img

这里可以看到生成了两个jar相关文件,其中common.jar是spring-boot-maven-plugin插件重新打包后生成的可执行jar,即可以通过java -jar common.jar命令启动。common.jar.original这个则是mvn package打包的原始jar,在spring-boot-maven-plugin插件repackage命令操作时重命名为xxx.original,这个是一个普通的jar,可以被引用在其他服务中。

3.jar内部结构

对这两个jar文件解压看看里面的结构差异:

3.1 common.jar目录结构如下:

img

其中BOOT-INF主要是一些启动信息,包含classes和lib文件,classes文件放的是项目里生成的字节文件class和配置文件,lib文件是项目所需要的jar依赖。

META-INF目录下主要是maven的一些元数据信息,MANIFEST.MF文件内容如下:

MANIFEST.MF:这个manifest文件定义了与扩展和包相关的数据。单词“manifest”的意思是“显示”。

Manifest-Version: 1.0
Implementation-Title: java-common-utils
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: com.common.util.CommonUtilsApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.1.9.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.JarLauncher

其中Start-Class是项目的主程序入口,即main方法。Springboot-Boot-Classes和Spring-Boot-Lib指向的是生成的BOOT-INF下的对应位置。

Main-Class属性值为org.springframework.boot.loader.JarLauncher,这个值可以通过设置属性layout来控制,如下:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
<!--使用-Dloader.path需要在打包的时候增加<layout>ZIP</layout>,不指定的话-Dloader.path不生效-->
        <layout>ZIP</layout>
        <!-- 指定该jar包启动时的主类[建议] -->
        <mainClass>com.common.util.CommonUtilsApplication</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

设置<layout>ZIP</layout>时Main-Class为org.springframework.boot.loader.PropertiesLauncher,具体layout值对应Main-Class关系如下:

  • JAR,即通常的可执行jar
Main-Class: org.springframework.boot.loader.JarLauncher
  • WAR,即通常的可执行war,需要的servlet容器依赖位于WEB-INF/lib-provided
Main-Class: org.springframework.boot.loader.warLauncher
  • ZIP,即DIR,类似于JAR(打增量包时会使用到)
Main-Class: org.springframework.boot.loader.PropertiesLauncher
  • MODULE,将所有的依赖库打包(scope为provided的除外),但是不打包Spring Boot的任何Launcher
  • NONE,将所有的依赖库打包,但是不打包Spring Boot的任何Launcher

common.jar之所以可以使用java -jar运行,和MANIFEST.MF文件里的配置关系密切

3.2 common.jar.original目录结构

img

可以看到通过mvn package构建的jar是一个普通的jar,包含的都是项目的字节文件和一些配置文件,没有将项目依赖的第三方jar包含进来。再看下MANIFEST.MF文件:

Manifest-Version: 1.0
Implementation-Title: java-common-utils
Implementation-Version: 0.0.1-SNAPSHOT
Build-Jdk-Spec: 1.8
Created-By: Maven Archiver 3.4.0

其中没有包含Start-Class、Main-Class等信息,这个与可执行jar的该文件存在很多差异,而且目录结构也有很大差异。

一般对使用spring-boot-maven-plugin插件打出的可执行jar不建议作为jar给其他服务引用,因为可能出现访问可执行jar中的一些配置文件找不到的问题。如果想让构建出来的原始jar不被重新打包,可以对spring-boot-maven-plugin插件配置classifier属性,自定义一个可运行jar名称,这样该插件就不会对原始的jar重命名操作了。

例如:

<configuration>
    <!-- [建议]指定该jar包启动时的主类 -->
    <mainClass>com.common.util.CommonUtilsApplication</mainClass>
    <!--配置的 classifier 表示可执行 jar 的名字,配置了这个之后,在插件执行 repackage 命令时,
    就不会给 mvn package 所打成的 jar 重命名了,这样就可以被其他项目引用了,classifier命名的为可执行jar-->
    <classifier>myexec</classifier>
</configuration>

效果如下:

img

以上是对spring-boot-maven-plugin插件的打包机制和jar包结构的一些分析。

4.参考

https://blog.csdn.net/iss_jin/article/details/122463390

四、springboot增量打包更新--静态资源分离打包

1.前言

springboot部署打包为jar,一般都是全量打包,生成的jar包因包含大量三方库通常都是超过100M的,并且在进行一般的页面html微调、js修改、img替换、css样式修改时也需要重新打包进行部署;每次微小的调整都需要重新打包就太烦了,一般在项目开发稳定以后项目中引用的jar就不再改变

为了方便进行静态资源管理及增量部署,对项目引用jar包以及静态资源分离打包,提高打包的效率及部分前端微调项修改后及时进行无重启更新;

2.具体步骤

1、初次打包进行全量打包,对打包的jar进行解压,解压后的文件如下图展示:

jar包解压后的目录

2、分离引用的jar包:进入BOOT-INF中,copy文件夹lib到指定目录下,如jar包运行目录;

需要copy引用的jar包文件夹-lib

图-3,最终lib存放的目录

3分离静态文件:在lib同目录下创建resource文件夹,进入classes文件夹内copy文件夹statictemplates文件夹到resource文件下;如图:

copy到resource目录下的静态文件,包括HTML、JS、css、image等静态文件

4、删除jar包及解压文件,当前目录结构如下:

初次完成jar及静态文件分离

5、增量打包,打包不再将引用jar及static文件夹、templates文件夹打到jar包中:首先修改pom.xml文件中打包相关配置,如下图:
打包配置增加了如下代码:

<layout>ZIP</layout>
<includes>
        <include>
                <groupId>non-exists</groupId>
                <artifactId>non-exists</artifactId>
         </include>
</includes>

resource打包配置增加如下过滤:

<exclude>static/**/*</exclude>
<exclude>templates/**/*</exclude>

最终pom.xml中打包配置如下:

<build>
    <finalName>web</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <includeSystemScope>true</includeSystemScope>
                <mainClass>com.XXX.Application</mainClass>
                <!--增量打包配置【start】-->
                <layout>ZIP</layout>
                <includes>
                    <include>
                        <groupId>non-exists</groupId>
                        <artifactId>non-exists</artifactId>
                    </include>
                </includes>
                <!--增量打包配置【end】-->
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.0.4.RELEASE</version>
            <configuration>
                <fork>false</fork>
            </configuration>
        </plugin>
    </plugins>
 
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*</include>
            </includes>
            <excludes>
                <!--【增加静态文件过滤】-->
                <exclude>static/**/*</exclude>
                <exclude>templates/**/*</exclude>
            </excludes>
        </resource>
    </resources>
</build>

6、执行maven clean install,获得最终jar包,如下图所示,只有5M大小;

最终项目打包的目录结构

7、最终运行时,jar的执行命令中增加lib及resource的路径指向,否则项目无法正常运行;

java -Dloader.path=./lib,./resource -jar ./web.jar

8、如上进行增量打包后,如果前端有不涉及到后端的修改时都可以对resource中的文件进行替换进行实时更新,不再进行重启;后端有变动也不用上传100多M的jar到服务器,影响效率;

3.参考

转自:https://blog.csdn.net/qq_35611143/article/details/107083164

参考:https://www.jb51.net/article/186316.htm



这篇关于Maven插件的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程