-
编写 POM:
Maven 项目的核心是 pom.xml 文件. pom 文件中的 groupId, artifactId, version 这三个元素定义了一个项目的基本坐标.- groupId: 定义了项目属于哪个组, 这个组往往和项目所在的组织或公司存在关联.
- artifactId: 定义了当前 Maven 项目在组中的唯一的 ID.
- version: 定义了当前项目的版本
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>study-maven</groupId> <artifactId>chapter5</artifactId> <version>1.0-SNAPSHOT</version> </project>
-
Maven 基本命令使用:
-
mvn clean compile: 在项目目录下运行
mvn clean compile
进行项目代码编译. -
mvn clean test: 在项目目录下运行
mvn clean compile
进行项目代码编译, 并进行测试. -
mvn clean package: 在项目目录下运行
mvn clean package
进行项目代码编译, 并进行测试, 测试通过后将代码打包成默认的 jar 包.Maven 默认打包生成的 jar 是不能支架运行的, 因为带有 main 方法的类信息不回添加到 manifest 中. 这里需要配置 maven-shade-plugin 插件:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>1.2.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation = "org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>HelloWorld</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build>
-
mvn archetype:generate: 生成项目骨架. 在 Maven 项目中, 在项目根目录中放置 pom.xml, 在 src/main/java 目录中放置项目的主代码, 在 src/test/java 中放置项目的测试代码.
-
-
Maven 依赖的配置:
- groupId, artifactId, version: 定义依赖的基本坐标.
- type: 依赖的类型, 对应项目坐标定义的 packaging. 默认为 jar.
- scope: 依赖的范围.
- optional: 标记依赖是否可选.
- exclusions: 用来排除传递性依赖.
<dependencies> <dependency> <groupId></groupId> <artifactId></artifactId> <version></version> <type></type> <scope></scope> <optional></optional> <exclusions> <exclusion> </exclusion> </exclusions> </dependency> </dependencies>
-
依赖的范围:
Maven 在编译项目主代码的时候需要使用一套 classpath, 例如在编译 spring 项目时需要使用 spring-core, 该文件以依赖的方式被引入到 classpath中; 在 Maven 编译和执行测试的时候会使用另外一套 classpath, 例如 JUnit, 该文件也以一俩的方式引入到测试使用的 classpath 中; 在实际运行 Maven 项目的时候, 又会使用一套 classpath.- compile: 编译依赖范围. 默认的依赖范围. 使用此依赖范围的 Maven 依赖, 对于编译, 测试, 运行三种 classpath 都有效. 例如: spring-core.
- test: 测试依赖范围. 只对测试 classpath 有效, 在编译主代码或者运行项目的使用时将无法使用此类依赖. 例如: JUnit.
- provided: 已提供范围依赖. 对于测试和运行 classpath 有效, 但是在运行时无效. 例如: servle-api, 编译和测试项目的时候需要该依赖, 但是在项目运行的时候, 由于容器已经提供, 就不需要重复地引入.
- runtime: 运行时 范围依赖. 对于测试和运行 classpath 有效, 但在编译主代码时无效. 例如: JDBC 驱动视线, 项目主代码的编译只需要 JDK 提供的 JDBC 接口, 只有在执行测试或者运行项目的时候才需要实现上述接口的具体 JDBC 驱动.
- system: 系统依赖范围. 与 provided 依赖范围一致. 但必须通过 systemPath 元素显示地制定依赖文件的路径.
- import: 导入范围依赖.
<dependency> <groupId>javax.sql</groupId> <artifactId>jdbc-stdext</artifactId> <version>2.0</version> <scope>system</scope> <systemPath>${java.home}/lib/rt.jar</systemPath> </dependency>
-
传递性依赖:
项目 A 有一个 compile 范围的 spring-core 依赖, spring-core 有一个 compile 范围的 commons-loggin 依赖. 那么 commons-logging 就会成为项目 A 的 compile 范围依赖. -
依赖调解:
- 假设项目 A 的依赖关系: A -> B -> C -> X(1.0), A -> D -> X(2.0), X 是 A 的传递性依赖. 这时会采用路径最近者优先, 因此 X(2.0) 会被解析使用.
- 假设项目 A 的依赖关系: A -> B -> Y(1.0), A -> B -> Y(2.0), X 是 A 的传递性依赖. 这时会采用第一声明者优先.
-
可选依赖:
假设项目 A 依赖于项目 B, 项目 B 依赖于项目 X 和 Y. B 对于 X 和 Y 的依赖都是可选依赖: A -> B, B -> X(可选), B -> Y(可选). 由于这里 X, Y 是可选依赖, 依赖不会得到传递.项目 B 使用可选依赖可能是因为 B 实现了两个特性, 其中特性一依赖于 X, 特性二依赖于 Y, 而且这两个特性是互斥的, 用户不可能同时使用这两个特性. 例如 B 是一个持久层隔离工具包, 它支持多种数据库, 包括 MySql, SQLServer等. 在构建这个工具包的时候, 需要这两种数据库的驱动程序, 但是在使用这个工具包的时候, 只会依赖一种数据库. 当项目 A 依赖于项目 B 的时候, 必须显示声明 X 或 Y 的一种依赖.
-
排除依赖:
项目 A 依赖于项目 B, 项目 B 依赖于项目 C 的SNAPSHOT版本. 为了使项目 A 依赖于项目 C 的稳定版本, 可在声明依赖项目 B 的时候, 排除依赖项目 C, 然后再显示声明依赖项目 C.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.2.RELEASE</version>
<exclusions>
<!--这里排除掉 spring-core 依赖-->
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--这里重新显示声明 spring-core 依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
-
归类依赖:
<properties> <!--通过定义属性来统一管理版本号--> <spring.framework.version>5.1.2.RELEASE</spring.framework.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.framework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.framework.version}</version> </dependency> </dependencies>
-
优化依赖:
- 已解析依赖: mvn dependency:list 以列表形式展示已解析依赖; mvn dependency:tree 以树形结构展示已解析依赖.
- 依赖分析: mvn dependency:analyze. 分析结果包括: Used undeclared dependencies, 意思是项目中使用到, 但是没有显示声明的依赖. 例如有很多相关的 Java import 声明. 当升级直接依赖的时候, 相关传递性依赖的版本也可能发生变化. 因此需要显示声明任何项目中直接用到的依赖; Unused declared dependencies. 意思是项目中未使用的, 但是显示声明的依赖. 由于 dependency:analyze 只会分析编译主代码和测试代码需要用到的依赖, 一些执行测试和运行时需要的一拉它就发现不了.
-
参考:
[1] : Maven 实战