
🌈 个人主页: Hygge_Code
🔥 热门专栏:从0开始学习Java | Linux学习| 计算机网络
💫 个人格言: "既然选择了远方,便不顾风雨兼程"

文章目录
- Maven高级特性:分模块、聚合继承与多环境配置
-
- 一、分模块开发与设计
-
- [1. 分模块开发的核心目标](#1. 分模块开发的核心目标)
- [2. 模块拆分原则与实战](#2. 模块拆分原则与实战)
-
- (1)项目整体结构
- (2)各模块详细实现
-
- [① 父工程(maven-user)](#① 父工程(maven-user))
- [② 实体类模块(maven-pojo)](#② 实体类模块(maven-pojo))
- [③ 工具类模块(maven-utils)](#③ 工具类模块(maven-utils))
- [④ 数据访问模块(maven-dao)](#④ 数据访问模块(maven-dao))
- [⑤ 业务逻辑模块(maven-service)](#⑤ 业务逻辑模块(maven-service))
- [⑥ Web控制模块(maven-servlet)](#⑥ Web控制模块(maven-servlet))
- 二、聚合与继承
-
- [1. 聚合:一键构建所有模块](#1. 聚合:一键构建所有模块)
- [2. 继承:复用配置,避免冗余](#2. 继承:复用配置,避免冗余)
-
- [(1)父工程优化:使用 dependencyManagement](#(1)父工程优化:使用 dependencyManagement)
- (2)子模块引用依赖(无需写版本)
- [3. 聚合与继承对比](#3. 聚合与继承对比)
- 三、属性与版本管理
-
- [1. 自定义属性:统一版本维护](#1. 自定义属性:统一版本维护)
- [2. 版本管理](#2. 版本管理)
- [3. 配置文件引用 POM 属性](#3. 配置文件引用 POM 属性)
-
- (1)在`maven-dao`中定义属性:
- (2)在`maven-dao`的`user.properties`中加载这些属性值
- [(3)开启属性过滤(POM 配置)](#(3)开启属性过滤(POM 配置))
- 四、多环境配置
- 五、Maven私服
-
- Maven私服搭建(以Nexus为例)
-
- [1. 安装nexus(自行安装,跳过)](#1. 安装nexus(自行安装,跳过))
- [2. 私服资源获取](#2. 私服资源获取)
- [3. 登录私服后创建仓库](#3. 登录私服后创建仓库)
- [4. 向仓库上传资源](#4. 向仓库上传资源)
- IDEA环境中资源上传与下载
- nexus代理阿里云仓库
Maven高级特性:分模块、聚合继承与多环境配置
一、分模块开发与设计
1. 分模块开发的核心目标
图例:

从 左边单体 → 右边聚合工程 的优点:
- 代码臃肿、职责混乱(分包 != 模块化,没有强制的隔离机制) → 按功能 / 分层拆分模块(如用户模块、订单模块、通用工具模块)
- 依赖版本混乱、冲突频发 → 父工程统一管理所有依赖版本
- 构建效率低(改一行代码需全量构建)→ 支持单独构建某个子模块
- 团队协作冲突多 → 不同团队维护不同子模块,降低代码冲突概率
- 配置重复 → 父工程统一配置插件、编译版本等,子模块自动继承
2. 模块拆分原则与实战
分模块遵循「高内聚、低耦合」,优先按技术分层拆分(中小型项目首选),大型项目可结合业务功能拆分。以下是基于用户管理项目的完整拆分案例:
(1)项目整体结构
maven-user(父工程,pom打包)
├─ maven-pojo(实体类模块,jar打包)
├─ maven-utils(工具类模块,jar打包)
├─ maven-dao(数据访问模块,jar打包)
├─ maven-service(业务逻辑模块,jar打包)
└─ maven-servlet(Web控制模块,war打包)
(2)各模块详细实现
① 父工程(maven-user)
无业务代码,仅负责统一依赖、插件配置,打包方式为 pom:
xml
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.xq</groupId>
<artifactId>maven-user</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging> <!-- 父工程必须为pom打包 -->
<!-- 统一管理依赖(后续通过dependencyManagement优化) -->
<<dependencies>
<!-- Servlet依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- 数据库相关依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- 工具类依赖 -->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
</</dependencies>
<!-- Tomcat插件配置 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8088</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
② 实体类模块(maven-pojo)
映射数据库表,仅包含实体类与 get/set 方法,无依赖:
java
package com.xq.pojo;
public class User {
private Integer id;
private String name;
private String username;
private String password;
// 其他属性(gender/age/address等)
// get/set方法与toString方法
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
// 其余get/set方法省略
}
模块 pom.xml 仅需继承父工程:
xml
<project>
<parent>
<groupId>com.xq</groupId>
<artifactId>maven-user</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>maven-pojo</artifactId>
</project>
③ 工具类模块(maven-utils)
在父工程上,右键,新建模块(使用maven构建,不使用骨架创建)。然后创建工具类类封,装通用工具,如数据库连接工具:
java
package com.xq.utils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class DataSourceConfig {
// 加载c3p0-config.xml配置
private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 获取数据源
public static DataSource getDataSource() {
return dataSource;
}
// 获取数据库连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
模块 pom.xml 继承父工程,无需额外依赖(父工程已统一引入)。
④ 数据访问模块(maven-dao)
负责数据库 CRUD,依赖 maven-pojo 与 maven-utils:
java
// UserDao接口
package com.xq.dao;
import com.xq.pojo.User;
import java.util.List;
public interface UserDao {
List<User> findAll(); // 查询所有用户
}
// UserDao实现类
package com.xq.dao.impl;
import com.xq.dao.UserDao;
import com.xq.pojo.User;
import com.xq.utils.DataSourceConfig;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.sql.SQLException;
import java.util.List;
public class UserDaoImpl implements UserDao {
private QueryRunner runner = new QueryRunner(DataSourceConfig.getDataSource());
@Override
public List<User> findAll() {
String sql = "select * from user";
try {
return runner.query(sql, new BeanListHandler<>(User.class));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
模块 pom.xml 引入依赖:
xml
<project>
<parent>
<groupId>com.xq</groupId>
<artifactId>maven-user</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>maven-dao</artifactId>
<<dependencies>
<!-- 依赖实体类模块 -->
<dependency>
<groupId>com.xq</groupId>
<artifactId>maven-pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 依赖工具类模块 -->
<dependency>
<groupId>com.xq</groupId>
<artifactId>maven-utils</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</</dependencies>
</project>
⑤ 业务逻辑模块(maven-service)
在父工程上,右键,新建模块(使用maven构建,不使用骨架创建):处理业务逻辑,依赖 maven-dao(需要dao模块里面的数据):
java
// UserService接口
package com.xq.service;
import com.xq.pojo.User;
import java.util.List;
public interface UserService {
List<User> findUser();
}
// UserService实现类
package com.xq.service.impl;
import com.xq.dao.UserDao;
import com.xq.dao.impl.UserDaoImpl;
import com.xq.pojo.User;
import com.xq.service.UserService;
import java.util.List;
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public List<User> findUser() {
return userDao.findAll(); // 调用DAO层方法
}
}
模块 pom.xml 依赖 maven-dao 模块。
⑥ Web控制模块(maven-servlet)
在父工程上,右键,新建模块(使用maven构建,使用骨架创建)。然后创建servle:接收前端请求,依赖 maven-service(servlet模块需要调用service模块里面的数据),打包方式为 war:
java
package com.xq.servlet;
import com.xq.pojo.User;
import com.xq.service.UserService;
import com.xq.service.impl.UserServiceImpl;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet("/showUserList")
public class UserServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html;charset=utf-8");
List<User> userList = userService.findUser();
request.setAttribute("list", userList);
// 转发到JSP页面
try {
request.getRequestDispatcher("/list.jsp").forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
模块 pom.xml 依赖 maven-service 模块,并继承父工程的 Tomcat 插件。
二、聚合与继承
1. 聚合:一键构建所有模块
我们思考一个问题:
上面的各个模块是分开独立开发的,彼此互相独立,互补影响。假设如果现在maven-dao模块更新升级了,那么其他模块是如何感知dao模块发生了变化的?

解决方案:
会不会有一个工程,专门对这些模块进行管理。对这些模块进行统一的编译、测试、打包等操作。一旦一个模块发生了变化,会同时对其他模块也进行编译、测试、打包。此时就需要用到聚合的思想。
聚合的作用:用于快速构建maven工程,一次性管理多个模块
(1)父工程配置聚合
在父工程 pom.xml 中添加 <modules> 标签,声明子模块:
xml
<modules>
<module>maven-pojo</module>
<module>maven-utils</module>
<module>maven-dao</module>
<module>maven-service</module>
<module>maven-servlet</module>
</modules>
(2)聚合特性
- 执行
mvn clean compile时,Maven 按依赖顺序 自动编译所有模块(如先编译pojo,再构建dao); - 支持增量构建,仅重新构建修改过的模块及其依赖模块。
我们的父工程为maven-user,专门用来管理其他的子模块,我们测试一下:

2. 继承:复用配置,避免冗余
继承让子模块复用父工程的依赖、插件配置(类似于java中的继承关系),核心优化是通过 <dependencyManagement> 统一版本,避免子模块继承无用依赖:
(1)父工程优化:使用 dependencyManagement
xml
<dependencyManagement>
<dependencies>
<!--管理自己的依赖-->
<!-- 子模块共享依赖,统一版本 -->
<dependency>
<groupId>com.xq.service</groupId>
<artifactId>maven-service</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xq.dao</groupId>
<artifactId>maven-dao</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 子模块间依赖 -->
<dependency>
<groupId>com.xq.pojo</groupId>
<artifactId>maven-pojo</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xq.utils</groupId>
<artifactId>maven-utils</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xq.servlet</groupId>
<artifactId>maven-servlet</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- servlet依赖的jar包start -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<!-- <scope>provided</scope>-->
</dependency>
<!-- servlet依赖的jar包start -->
<!-- jsp依赖jar包start -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
<!-- <scope>provided</scope>-->
</dependency>
<!-- jsp依赖jar包end -->
<!--jstl标签依赖的jar包start -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
<!--<scope>provided</scope>-->
</dependency>
<!-- JSTL实现包 -->
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>
<!--jstl标签依赖的jar包end -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!--beanUtils的依赖-->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
</dependency>
<!--dbutils组件 封装了原生的jdbc-->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
<!--logging-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 插件版本管理 -->
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8088</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
(2)子模块引用依赖(无需写版本)
在子模块中按照自己的需求,引入对应的依赖,此时不需要加依赖的版本号了,
因为在父工程里面已经定义好了:
xml
<!-- maven-utils模块示例 -->
<dependencies>
<!--dbutils组件 封装了原生的jdbc-->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
</dependency>
<!--logging-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--c3p0-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
</dependency>
</dependencies>
<!-- maven-servlet模块示例 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8088</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
3. 聚合与继承对比
| 特性 | 聚合(Aggregation) | 继承(Inheritance) |
|---|---|---|
| 核心作用 | 统一构建子模块,控制构建顺序 | 统一配置,复用依赖/插件版本 |
| 配置位置 | 父工程 pom.xml 的 <modules> |
子模块 pom.xml 的 <parent> |
| 依赖感知 | 父工程知道所有子模块 | 父工程不知道哪些子模块继承自己 |
| 打包要求 | 父工程必须为 pom 打包 |
子模块按功能为 jar/war 打包 |
三、属性与版本管理
1. 自定义属性:统一版本维护
在定义依赖的版本的时候,我们可以使用属性来描述,方便维护管理。
定义格式:

调用格式:

改造我们的父工程:
xml
<properties>
<javax.servlet-api>3.1.0</javax.servlet-api>
<javax.servlet.jsp-api>2.3.1</javax.servlet.jsp-api>
<jstl>1.2</jstl>
<taglibs-standard-impl>1.2.5</taglibs-standard-impl>
<c3p0>0.9.1.2</c3p0>
<commons-beanutils>1.8.3</commons-beanutils>
<commons-dbutils>1.6</commons-dbutils>
<commons-logging>1.1.1</commons-logging>
<mysql>5.1.18</mysql>
</properties>
在pom.xml我们如下定义:

2. 版本管理
(1)版本类型
- 快照版本(SNAPSHOT):开发中版本,如
1.0-SNAPSHOT,每次构建自动更新 - 发布版本(RELEASE):稳定版本,如
1.0.RELEASE,发布后不再修改
测试
我们在maven-pojo上面自定义版本:

然后打包:

观察本地仓库:

(2)版本号规范(并不是所有的都严格遵循)

3. 配置文件引用 POM 属性
在配置文件中直接引用 POM 定义的属性,实现配置动态化:
(1)在maven-dao中定义属性:
xml
<!-- maven-dao模块 -->
<properties>
<user.name>admin</user.name>
<user.age>25</user.age>
</properties>
(2)在maven-dao的user.properties中加载这些属性值
properties
user.name=${user.name}
user.age=${user.age}
(3)开启属性过滤(POM 配置)
xml
<build>
<resources>
<resource>
<!--从任意子模块的根目录开始加载,不管任何子模块都可以加载-->
<directory>${project.basedir}/src/main/resources</directory>
<!-- 开启配置属性的读取,取值false就不能读取 -->
<filtering>true</filtering>
</resource>
</resources>
</build>
打包后配置文件会自动替换为:user.name=admin、user.age=25。
四、多环境配置
在实际开发中,生产环境的配置和开发环境的配置是不一样的。比如生产环境使用的数据库和开发环境的数据库就不一样。那么在项目由开发环境切换到生产环境的时候,配置应该如何更改?

在maven-dao中我们定义不同的数据库连接信息:
xml
<profiles>
<!--生产环境的数据库信息-->
<profile>
<!--环境名称,自定义-->
<id>pro-env</id> <!--product-->
<properties>
<jdbc.url>jdbc:mysql://127.1.1.1:3306/ssm_db</jdbc.url>
</properties>
</profile>
<!--开发环境的数据库信息-->
<profile>
<id>dev-env</id> <!--develop-->
<properties>
<jdbc.url>jdbc:mysql://127.1.1.1:3308/ssm_db</jdbc.url>
</properties>
</profile>
</profiles>
在properties文件中指定:
properties
jdbc.url=${jdbc.url}
那么如何根据指定的开发环境进行运行呢:
格式: 指令 --P 环境名称

运行打包之后,我们在本地仓库看看配置信息:

五、Maven私服
我们的项目都是协同开发的,并不是一个人开发所有的模块。如果每个人开发不同的模块,当我们需要别人的模块时,怎么获取?用硬盘拷贝吗?很显然不可取。
应该怎么办? -> 可不可以把大家开发的模块都放在一个公共的服务器上,大家需要别人的模块时,只需要从这个公共的服务器去获取就可以。
Maven私服搭建(以Nexus为例)
1. 安装nexus(自行安装,跳过)
2. 私服资源获取

仓库的分类:

3. 登录私服后创建仓库
点击 sign in,输入指定的用户和密码登录之后,创建仓库:


点击创建仓库后,选择maven2(hosted),点击进入仓库

点击创建,创建之后:

将创建的仓库加入到仓库组里面来(添加到maven-public这个组),点击maven-public这个组,进入到添加页面:


添加后,点击保存
4. 向仓库上传资源
点击进入仓库后点击上传组件:


最后点击upload按钮,完成的效果:

IDEA环境中资源上传与下载

- 配置maven客户端的settings配置文件
xml
<!--配置访问xq-mixed的仓库名称、用户名、密码-->
<server>
<id>xq-mixed</id>
<username>admin</username>
<password>admin</password>
</server>
- 配置私服的地址(也是在maven的settings中)
xml
<!--私服-->
<mirror>
<id>nexus-xq</id> <!--(这个名字无所谓)-->
<mirrorOf>*</mirrorOf>
<url>http://localhost:8081/repository/maven-public/</url>
</mirror>
- 配置当前项目访问私服上传资源保存的位置(在
pom.xml中配置)
xml
<distributionManagement>
<repository>
<id>xq-mixed</id>
<url>http://localhost:8081/repository/xq-mixed/</url>
</repository>
</distributionManagement>
- 发布资源到私服的命令 mvn deploy

查看控制台效果:

最后在私服上面查看是否上传成功:

nexus代理阿里云仓库
为了提高资源的下载速度,我们也可以在nexus官方仓库中添加国内阿里云maven仓
库。具体操作如下:
- 第一步:点击repositories

- 点击 create repository,选中maven(proxy)

- 设置阿里云
阿里云仓库url:http://maven.aliyun.com/nexus/content/groups/public

- 将创建的仓库添加到仓库组maven-public,并把阿里云代理仓库设置为第一位

- 设置maven的setting.xml文件
xml
<!-- 使用nexus 配置镜像 -->
<mirror>
<id>nexus-central</id>
<mirrorOf>*</mirrorOf>
<name>Nexus Central</name>
<url>http://localhost:8081/repository/maven-public/</url>
</mirror>
或者在项目的pom.xml里面指定仓库路径:
xml
<repositories>
<repository>
<id>nexus-central</id>
<name>nexus-central</name>
<url>http://localhost:8081/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
作用:
配置后,所有依赖请求都会先发给我的 Nexus 私服:
✅ 私服里有缓存的依赖 → 直接从私服下载(局域网速度,毫秒级);
✅ 私服里没有的依赖 → 私服自动从阿里云 / 中央仓库下载并缓存,后续团队所有人再用都不用重复下载
如果我的内容对你有帮助,请 点赞 , 评论 , 收藏 。创作不易,大家的支持就是我坚持下去的动力!

