Maven
Maven 是一个 Java 生态用的较多的依赖管理工具,其稳定、简单易用,缺点就是如果引入的依赖较多,比较臃肿、啰嗦,和 Java 一样,哈哈哈哈。
Maven 中有 6 种 scope:
-
compile(默认)
这是默认作用域,如果未指定,则使用该 scope。编译依赖项在项目的所有类路径中都可用。此外,这些依赖项将传播到依赖项目,在编译与打包时都会加入。
-
provided
这很像 compile ,但表示您希望 JDK 或容器在运行时提供依赖项。例如,在为 Java Enterprise Edition 构建 Web 应用程序时,您需要将对 Servlet API 和相关 Java EE API 的依赖设置为范围 provided ,因为 Web 容器提供了这些类。具有此作用域的依赖项将添加到用于编译和测试的类路径中,但不添加到运行时类路径中(不参与打包),默认不传递。
-
runtime
此范围表示编译不需要依赖项(不需要它们来编译项目源代码),但执行程序需要依赖。Maven 在运行时和测试类路径中包含此作用域的依赖项,但不包含在编译类路径中。
-
test
此范围指示依赖项不是正常使用应用程序所必需的,并且仅适用于测试编译和执行阶段。此范围不是可传递的。通常,此范围用于测试库,如 JUnit 和 Mockito。它也用于非测试库,如 Apache Commons IO,这些库用于单元测试(src/test/java)但不用于代码(src/main/java)。
-
system
此作用域类似于 provided,但是需要结合 systemPath 提供显式包含它的 JAR,即而从本地文件系统获取依赖项,不会在存储库中查找。
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.30</version> <scope>system</scope> <systemPath>${basedir}/lib/mysql-connector-java.jar</systemPath> </dependency> -
import
此作用域仅支持 POM 文件中的 dependencyManagement 部分。它表示依赖关系将被指定 POM 的 dependencyManagement 部分中的有效依赖关系列表替换。
optional
可选的,可以理解为此依赖可选,如果不需要传递某项功能,可以不引用这个包。一般而言,框架的开发者使用居多,但是随着现在 Spring Boot Starter 的流行,实际项目中我们也可以使用,尤其是有扩展模块/插件机制的项目,插件模块可以使用 true 选项让该依赖不传递出去,同时也不参与最终的打包(只有没被使用的情况下)。如果其它模块需要使用,再次显示声明即可。
自己的 jar 包安装到 maven 仓库
相信很多新手在没用 maven 之前,项目目录中都会单独使用一个文件夹存放项目使用的目录。但是使用 maven 之后就不需要了,使用 maven 管理要方便许多,那么问题来了,如果有的 jar 包在下载失败或者配置的下载源中没有怎么办?
这个时候就可以自己去官网或者 jar 包作者提供的下载方式自己下载,然后使用 maven 提供的安装命令,安装到本地的 maven 仓库,然后项目中引入即可。
比如 Oracle 的 ojdbc8.jar,这个 jar 包当时浪子使用的阿里的下载源就没下载成功。后来去 Oracle 官网下载的 jar 包,在本地安装并引用。
食用方法,把对应的 jar 包放在使用它的项目中(其实这个不是必须的啦,maven 官方文档描述中说明:在目标 jar 包的同级目录中必须要有 pom.xml 文件),然后执行以下命令:
# 安装 jar 包到本地 maven 仓库
mvn install:install-file -Dfile=ojdbc8-23.2.0.0.jar -DgroupId=com.oracle -DartifactId=ojdbc8 -Dversion=23.2.0.0 -Dpackaging=jar
-Dfile:jar 包名称,这里 jar 包是在项目根路径,所以直接写 -DgroupId、-DartifactId:坐标位置 -Dversion:版本号
上面的命令执行成功以后就可以去本地 maven 仓库中根据自己写的坐标位置找到刚才安装的 jar 包啦,这时候就可以使用 maven 引入项目使用了,刚在项目中的 jar 包也可以删除了(如果没用的话)。
settings.xml
Maven 的 settings.xml 中定义的下载源是全局生效的,对于本机的所有项目都会生效,而且会覆盖项目中 pom.xml 文件中定义的仓库。所以如果想要更换下载源,需要在该文件中定义。也可以使用命令行指定配置文件:
# -s 指定使用的配置文件
mvn clean install -s settings.xml
Maven 打 war 包
打包之前推荐先清理(clean)再打包(package)。jar 包比较简单,SpringBoot 默认打的就是 jar 包。这里说一下 war 包的打包方式方式。
-
修改打包方式,去除内嵌的 tomcat 依赖
<packaging>war</packaging> ... <!-- 去除内嵌的 tomcat 依赖 --> <scope>provided</scope> -
如果整合的是 jsp,那么使用打包的插件时,打包插件必须是
1.4.2的版本,另外,在pom文件中加入以下内容,指定 jsp 文件的打包位置:<resources> <!-- 打包时将 jsp 文件拷贝到 META-INF 目录下 --> <resource> <!-- 指定 resources 插件处理那个目录下的资源文件 --> <directory>src/main/webapp</directory> <!-- 指定必须要放在此目录下才能被访问到 --> <targetPath>META-INF/resources</targetPath> <includes> <include>**/**</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/**</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/java</directory> <excludes> <exclude>**/*.java</exclude> </excludes> </resource> </resources> -
在插件中指定入口类:
<configuration> <fork>true</fork> <jvmArgument>-Dfile.encoding=UTF-8</jvmArgument> <mainClass>com.XXX.Application.class</mainClass> </configuration> -
在启动类中,继承
SpringBootServletInitiallizer类,重写configure()方法进行配置:public class xxxApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { return builder.sources(xxxApplication.class); } }
注意: 打成的 war 包使用外部 Tomcat 部署时,项目配置文件中配置的端口和项目名称会失效。 后台方式启动 jar 包:
nohup java -jar jar包名称 &
依赖树查询
很多时候,我们可能无意中引入了一些冲突的版本,比如一个版本高,一个版本低,这时候启动的时候就会冲突,且这些依赖不是直接引入的,而是我们引入的依赖内部包含的,这样很不便于排查,因此我们可以使用下面的方式查询依赖树。
# 命令行输出
mvn dependency:tree
# 输出到一个文件中,如果是多模块,会在各个模块打印输出该模块引入的依赖树
mvn dependency:tree -DoutputFile=dependency-tree.txt
然后我们就可以根据依赖树进行查找,并排除不想使用的依赖版本。
一些常用的插件简介
maven 的插件一般都需要配置 goal,指定该插件什么时候运行。
maven-toolchains-plugin
maven 默认情况下没有使用 wrapper,所以直接使用命令行大概率使用的环境变量中的配置,但是我们很可能想要使用类似 gradle.properties 中那样的功能,此时就可以使用 maven-toolchains-plugin 插件。(如果是 spring boot 项目,那更加的简单,直接在 mvnw 中定义 jdk 路径即可)。
使用该插件的第一步需要先更改 maven 安装目录中的 conf/toolchains.xml 文件:
<toolchain>
<type>jdk</type>
<provides>
<version>24</version>
<!-- <vendor>sun</vendor> -->
</provides>
<configuration>
<jdkHome>D:\xxx\xxx\jdk-24.0.1+9</jdkHome>
</configuration>
</toolchain>
其中 <vendor> 可写可不写,然后在 pom.xml 文件中引用插件(看最后的示例配置),直接定义版本即可,这样项目目录下使用全局的命令行使用的 Java 版本就固定了。
依赖分离插件
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
maven-dependency-plugin 插件可以把项目中使用的依赖都打包到一个文件目录中,这样做的的好处是精简了自己项目的 jar 包,大部分情况下,第三方的依赖很少修改。使用该插件可以把这些依赖上传到服务器,后续更新只需传出自己的业务项目 jar 包,速度较快。
配置分离插件
<!-- 配置文件分离插件 (sprint-boot-maven-plugin 支持指定配置文件目录) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/conf</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
此插件和依赖分离插件很类似,它把项目 resources 下的文件单独打到一个目录中,可以使用 <includes> 标签指定只需要哪些文件。
flatten-maven-plugin
该插件在多模块项目中比较常用,主要解决变量引用问题。例如我们使用自定义的版本占位符时,项目在打包、运行时 maven 本身或 ide 无法识别/识别错误的问题。
原理就是该插件把占位符直接替换为实际定义的值生成一个标准的 pom 文件。
其它插件
编译插件和打包插件在所有的项目中都是必须的,不需要赘述。
maven 插件配置示例
<build>
<plugins>
<!-- 本机有多个 jdk,且默认环境变量的 jdk 版本和项目使用的不一致时使用此插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-toolchains-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>toolchain</goal>
</goals>
</execution>
</executions>
<configuration>
<toolchains>
<jdk>
<version>24</version>
</jdk>
</toolchains>
</configuration>
</plugin>
<!-- 编译插件配置 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<!-- 如果使用了 lombok,需要确保在 jimmer apt 之前添加该内容 -->
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</path>
<path>
<groupId>org.babyfish.jimmer</groupId>
<artifactId>jimmer-apt</artifactId>
<version>${jimmer.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<!-- 依赖分离插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<!-- <overWriteReleases>false</overWriteReleases> -->
<!-- <overWriteSnapshots>false</overWriteSnapshots> -->
<!-- <overWriteIfNewer>true</overWriteIfNewer> -->
</configuration>
</execution>
</executions>
</plugin>
<!-- 配置文件分离插件 (sprint-boot-maven-plugin 支持指定配置文件目录) -->
<!-- <plugin> -->
<!-- <groupId>org.apache.maven.plugins</groupId> -->
<!-- <artifactId>maven-resources-plugin</artifactId> -->
<!-- <executions> -->
<!-- <execution> -->
<!-- <id>copy-resources</id> -->
<!-- <phase>package</phase> -->
<!-- <goals> -->
<!-- <goal>copy-resources</goal> -->
<!-- </goals> -->
<!-- <configuration> -->
<!-- <outputDirectory>${project.build.directory}/conf</outputDirectory> -->
<!-- <resources> -->
<!-- <resource> -->
<!-- <directory>src/main/resources</directory> -->
<!-- <includes> -->
<!-- <include>**/*.yml</include> -->
<!-- <include>**/*.properties</include> -->
<!-- </includes> -->
<!-- </resource> -->
<!-- </resources> -->
<!-- </configuration> -->
<!-- </execution> -->
<!-- </executions> -->
<!-- </plugin> -->
<!-- 将 pom 文件引用的变量解析为实际值 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<configuration>
<!-- 让插件直接修改(覆盖)项目中的 pom.xml 文件为扁平化后的内容。 -->
<updatePomFile>true</updatePomFile>
<!-- 只解析 CI 友好的变量(如 ${revision}、${sha1}、${changelist}),其他变量不做处理。这样可以兼容 CI/CD 场景下的版本变量。 -->
<flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration>
<executions>
<!-- 在 process-resources 阶段执行 flatten,即资源处理阶段就会生成扁平化的 POM。 -->
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<!-- 在 clean 阶段执行 flatten:clean,用于清理扁平化生成的内容。 -->
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

说些什么吧!