Maven插件
一、maven-compiler-plugin 插件详解
1.maven插件介绍
maven
是项目构建管理工具,如果不明确指定源代码要使用什么版本的jdk
的话,maven-compiler-plugin
编译插件就使用默认版本进行编译,这就容易出现编译版本与源代码不匹配,甚至导致编译不通过。
例如:如果代码中使用了Java 8 新特性,如函数式编程,但编译时使用Java 7,那就完全不可能编译通过,但如果编译时使用java11则可以编译通过,java高版本jdk的语法是向下兼容的。
为了避免使用低版本jdk编译高版本java语法的情况,在构建项目时就要配置maven-compiler-plugin插件,指定项目源码的 jdk 版本,编译后的 jdk 版本,以及编码方式。
从 maven-compiler-plugin-3.8.0 之后,默认 编译 版本由 1.5 改为 1.6 。但这仍然跟不上 JDK 的更新速度,目前大多数系统都在使用 JDK 1.8。Apache Maven Project 对 maven-compiler-plugin中compiler:compile有如下关于jdk版本变更的描述:
<plugin>
<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,源代码中不能使用低版本jdk中不支持的语法,会存在target不同于source的情况
-->
<source>1.8</source><!-- 源码语法版本 -->
<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>javac路径</executable>
<compilerVersion>1.3</compilerVersion><!-- 指定插件将使用的编译器的版本 -->
<meminitial>128m</meminitial><!-- 编译器使用的初始内存 -->
<maxmem>512m</maxmem><!-- 编译器使用的最大内存 -->
<!-- 这个选项用来传递编译器自身不包含但是却支持的参数选项 -->
<compilerArgument>-verbose -bootclasspath ${java.home}\lib\rt.jar</compilerArgument>
</configuration>
</plugin>
2.全局配置maven JDK编译版本
此种设置方式将影响由maven创建的所有项目。
找到maven的settings.xml配置文件,加入如下配置片段:
<profiles>
<profile>
<id>default-jdk8-env</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>
二、org.apache.maven.plugins系列插件简介
1.插件知识简介
maven-compiler-plugin
插件3.0之前,默认使用 JDK 自带的 javac 进行编译。但从3.0开始(需要JDK1.6),默认使用的 Java 编译器 是javax.tools.JavaCompiler
。如果仍然希望使用 JDK 自带的 javac 编译源代码,需要为 mvn 指定启动参数:-Dmaven.compiler.forceJavacCompilerUse=true
maven-compiler-plugin
插件编译时和编译后运行的JVM版本目前默认的设置为1.5,默认用此版本,而不是根据你在IDEA项目结构中指定的工程JDK版本编译。如果想改变这些默认设置,应该设置编译源和目标中java编译器的目标,通过设置Java源代码兼容的JVM版本,标明Java源代码开发过程中使用的Java版本,通过设置编译后的类库拟运行的JVM版本,给出编译后的类库将要运行的Java环境(一般都会设置,因为很少有项目再用1.7以下的版本了):
同时 mvn 的运行需要依赖 JDK ,maven-compiler-plugin
插件默认使用当前运行 mvn 命令的 JDK 去编译Java源代码。如果想使用其他版本的 JDK (比如本地 java 环境的,而非maven自带的)编译Java源代码,则需要设置如下(重点fork 、executable、compilerVersion):
上述配置中,用于编译 Java 源代码的是 JDK 1.8 ,运行mvn命令时指定maven所使用的是JDK1.6
2.官网也建议指定编译的jdk版本
如果是web项目,就需要打war包,那就需要这个插件:
使用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中的:
编译成功
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}
6.工作机制
Maven强大的一个重要的原因是它有一个十分完善的生命周期模型,它有三套相互独立的生命周期,请注意这里说的是“三套”,请别将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插件
https://blog.csdn.net/qq_34272760/article/details/127148290
三、springboot 打包插件spring-boot-maven-plugin打包机制及内部结构分析
1.前言
许多公司都会选择使用springboot作为服务应用开发框架,springboot框架提供了一套自己的打包机制,是通过spring-boot-maven-plugin插件来实现的。
1、spring-boot-maven-plugin引入pom
对于新建的一个springboot项目来说,pom中会加入插件:
通过idea可以看到maven中包含了spring-boot-maven-plugin插件:
功能说明:
- 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进行查看,如下图:
如果需要设置其他属性,需要在当前应用的pom中进行设置去覆盖父pom默认的值去改变行为。
2.执行打包命令
mvn clean package
或者通过开发工具如idea执行clean和package俩命令:
执行以上命令时会自动触发spring-boot-maven-plugin插件的repackage目标,完后可以在target目录下看到生成的jar,如下图:
这里可以看到生成了两个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目录结构如下:
其中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目录结构
可以看到通过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>
效果如下:
以上是对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进行解压,解压后的文件如下图展示:
2、分离引用的jar包:进入BOOT-INF中,copy文件夹lib到指定目录下,如jar包运行目录;
3分离静态文件:在lib同目录下创建resource文件夹,进入classes文件夹内copy文件夹static
及templates
文件夹到resource文件下;如图:
4、删除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