Maven高级:分模块、聚合继承、多环境配置与私服搭建


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

文章目录

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-pojomaven-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-daouser.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=adminuser.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 私服:

✅ 私服里有缓存的依赖 → 直接从私服下载(局域网速度,毫秒级);

✅ 私服里没有的依赖 → 私服自动从阿里云 / 中央仓库下载并缓存,后续团队所有人再用都不用重复下载


如果我的内容对你有帮助,请 点赞 , 评论 , 收藏 。创作不易,大家的支持就是我坚持下去的动力!

相关推荐
程序媛徐师姐1 小时前
Java基于微信小程序的农产品自主供销系统,附源码+文档说明
java·微信小程序·农产品自主供销·农产品自主供销系统·农产品自主供销小程序·java农产品自主供销小程序·农产品自主供销微信小程序
无名-CODING1 小时前
Spring Bean生命周期详解:从入门到精通
java·后端·spring
计算机程序设计小李同学1 小时前
基于JavaServer Pages(JSP)技术开发的食谱分享平台
java·开发语言
阿达King哥2 小时前
hotspot中的Java类对象如何保存虚函数
java·jvm
啦啦啦_99992 小时前
SSE(Server-Sent Events)
java
我是一只小青蛙8882 小时前
C++模板进阶技巧全解析
java·开发语言
组合缺一2 小时前
FastJson2 与 SnackJson4 有什么区别?
java·json·fastjson·snackjson
开开心心_Every2 小时前
无广告输入法推荐:内置丰富词库免费皮肤
服务器·前端·学习·决策树·edge·powerpoint·动态规划
科技林总2 小时前
【系统分析师】4.4 网络工程
学习