Apache Maven - Java项目管理工具

项目简介

Apache Maven是Apache软件基金会开发的项目管理和构建自动化工具,主要用于Java项目,也可用于C#、Ruby、Scala等语言。Maven基于项目对象模型(POM)的概念,通过一个XML文件来描述项目的构建、依赖关系和文档。

Maven最初由Jason van Zyl创建,旨在简化Jakarta Turbine项目的构建过程。它提供了一个标准的项目布局、一个标准的构建生命周期和一个依赖管理系统,极大地简化了Java项目的开发和维护。

主要特性

  • 标准化项目结构:提供一致的项目布局
  • 依赖管理:自动下载和管理项目依赖
  • 构建生命周期:标准化的构建过程
  • 插件架构:丰富的插件生态系统
  • 中央仓库:全球最大的Java库仓库
  • 多模块支持:管理大型项目的多个模块

项目原理

POM(项目对象模型)

POM是Maven的核心概念,包含项目信息和配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?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>com.example</groupId>
<artifactId>my-project</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>

<!-- 项目信息 -->
<name>My Project</name>
<description>示例项目</description>

<!-- 属性配置 -->
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<!-- 依赖管理 -->
<dependencies>
<!-- 依赖声明 -->
</dependencies>

<!-- 构建配置 -->
<build>
<!-- 插件配置 -->
</build>
</project>

标准目录结构

1
2
3
4
5
6
7
8
9
10
11
12
project/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/ # 主要Java源码
│ │ ├── resources/ # 主要资源文件
│ │ └── webapp/ # Web应用资源(对于WAR项目)
│ └── test/
│ ├── java/ # 测试Java源码
│ └── resources/ # 测试资源文件
├── target/ # 编译输出目录
└── README.md

构建生命周期

Maven定义了三个内置的构建生命周期:

Default生命周期

  1. validate - 验证项目正确性
  2. compile - 编译源代码
  3. test - 运行单元测试
  4. package - 打包成JAR/WAR
  5. verify - 验证包的有效性
  6. install - 安装到本地仓库
  7. deploy - 部署到远程仓库

Clean生命周期

  • pre-clean - 清理前执行
  • clean - 清理构建输出
  • post-clean - 清理后执行

Site生命周期

  • pre-site - 生成站点前执行
  • site - 生成项目站点
  • post-site - 生成站点后执行
  • site-deploy - 部署站点

使用场景

1. Java项目构建

标准化Java项目的编译、测试、打包和部署流程。

2. 依赖管理

自动管理第三方库的下载、版本控制和传递依赖。

3. 多模块项目

管理大型企业级应用的多个子模块。

4. 持续集成

与Jenkins、GitLab CI等CI/CD工具集成,实现自动化构建。

5. 项目文档生成

自动生成项目文档、API文档和测试报告。

具体案例

案例1:Spring Boot项目配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<?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>

<!-- 继承Spring Boot父POM -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/>
</parent>

<groupId>com.example</groupId>
<artifactId>spring-boot-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>

<name>Spring Boot Demo</name>
<description>Spring Boot示例项目</description>

<properties>
<java.version>11</java.version>
<mysql.version>8.0.29</mysql.version>
</properties>

<dependencies>
<!-- Spring Boot Web Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Spring Boot Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>

<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<!-- Spring Boot Maven插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>

<!-- 编译器插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>

<!-- 测试插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>false</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</project>

案例2:多模块项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<!-- 父POM:parent-project/pom.xml -->
<?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>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>

<name>Parent Project</name>

<!-- 子模块声明 -->
<modules>
<module>common</module>
<module>service</module>
<module>web</module>
</modules>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.3.21</spring.version>
<junit.version>5.8.2</junit.version>
</properties>

<!-- 依赖管理 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!-- 子模块:common/pom.xml -->
<?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>

<!-- 继承父POM -->
<parent>
<groupId>com.example</groupId>
<artifactId>parent-project</artifactId>
<version>1.0.0</version>
</parent>

<artifactId>common</artifactId>
<packaging>jar</packaging>

<name>Common Module</name>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

案例3:自定义插件开发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!-- 插件项目POM -->
<project>
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>code-generator-maven-plugin</artifactId>
<version>1.0.0</version>
<packaging>maven-plugin</packaging>

<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.8.6</version>
</dependency>

<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.6.4</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.6.4</version>
</plugin>
</plugins>
</build>
</project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 插件实现类
@Mojo(name = "generate", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
public class CodeGeneratorMojo extends AbstractMojo {

@Parameter(defaultValue = "${project.build.directory}/generated-sources")
private File outputDirectory;

@Parameter(required = true)
private String templatePath;

@Parameter(required = true)
private String packageName;

@Component
private MavenProject project;

public void execute() throws MojoExecutionException {
getLog().info("开始生成代码...");

try {
// 确保输出目录存在
if (!outputDirectory.exists()) {
outputDirectory.mkdirs();
}

// 代码生成逻辑
generateCode();

// 将生成的源码目录添加到编译路径
project.addCompileSourceRoot(outputDirectory.getAbsolutePath());

getLog().info("代码生成完成");

} catch (Exception e) {
throw new MojoExecutionException("代码生成失败", e);
}
}

private void generateCode() throws IOException {
// 实际的代码生成逻辑
File packageDir = new File(outputDirectory, packageName.replace('.', '/'));
packageDir.mkdirs();

File javaFile = new File(packageDir, "GeneratedClass.java");
try (FileWriter writer = new FileWriter(javaFile)) {
writer.write(String.format(
"package %s;\n\n" +
"public class GeneratedClass {\n" +
" public void hello() {\n" +
" System.out.println(\"Hello from generated code!\");\n" +
" }\n" +
"}\n", packageName));
}
}
}

案例4:高级配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<project>
<!-- 项目基本信息 -->

<properties>
<!-- 版本属性 -->
<spring.version>5.3.21</spring.version>
<jackson.version>2.13.3</jackson.version>

<!-- 编码属性 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>

<!-- Profile配置 -->
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<env>dev</env>
<database.url>jdbc:mysql://localhost:3306/dev_db</database.url>
</properties>
</profile>

<profile>
<id>prod</id>
<properties>
<env>prod</env>
<database.url>jdbc:mysql://prod-server:3306/prod_db</database.url>
</properties>
</profile>
</profiles>

<build>
<!-- 资源过滤 -->
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
<include>**/*.yml</include>
</includes>
</resource>
</resources>

<plugins>
<!-- 资源插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>

<!-- 测试覆盖率插件 -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.7</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>

<!-- Docker镜像构建插件 -->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.13</version>
<configuration>
<repository>${project.artifactId}</repository>
<tag>${project.version}</tag>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>

最佳实践

1. 依赖管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- 使用dependencyManagement统一管理版本 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<!-- 排除传递依赖冲突 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

2. 构建优化

1
2
3
4
5
6
7
8
9
10
11
# 并行构建
mvn clean install -T 4

# 跳过测试
mvn clean install -DskipTests

# 离线模式
mvn clean install -o

# 只构建特定模块
mvn clean install -pl module1,module2 -am

3. 仓库配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- settings.xml -->
<settings>
<mirrors>
<mirror>
<id>aliyun</id>
<mirrorOf>central</mirrorOf>
<url>https://maven.aliyun.com/repository/central</url>
</mirror>
</mirrors>

<profiles>
<profile>
<id>jdk-11</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>11</jdk>
</activation>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
</profile>
</profiles>
</settings>

Apache Maven作为Java生态系统的标准构建工具,其简化的项目管理和强大的依赖管理功能极大地提高了Java项目的开发效率。通过标准化的项目结构和生命周期,Maven使得Java项目的构建、测试和部署变得简单而一致。

版权所有,如有侵权请联系我