maven聚合工程(深度剖析)

Posted 一宿君

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了maven聚合工程(深度剖析)相关的知识,希望对你有一定的参考价值。

聚合的意义:

  • 对于一个大型的项目,如果我们直接作为一个工程开发,由于相互之间的依赖我们只能从头到尾由一组人开发,否则就会出现一个类好多人开发,相互更改的混乱局面,这个时候我们就将项目进行了横向纵向的拆分。

  • 横向拆分

    所谓的横向的拆分就是我们平常说的三层架构,将每个功能模块分成三层去开发
    即web层(表现层),service层(业务逻辑层)、dao层(数据访问层、持久层),
    可以理解为将一个功能模块的不同调用过程(三层的调用)进行了水平方向的拆分。

  • 纵向拆分

    所谓的纵向拆分就是将一个项目根据多个功能模块进行拆分,可以理解为,为了完成一个系统,深度(纵向)分析需要有哪些功能,然后将这些功能独立出来(独立为模块),进行了(纵向)拆分。

  • 横向和纵向拆分后,对每层架构和功能模块进行单独的开发,项目整合的时候就需要有一个能够整合这些架构或者模块的工程,这就是所谓聚合工程的意义。

创建聚合工程的要点(重点理解):

  1. 该聚合项目(父级项目、顶级项目)本身也是一个maven项目,它必须有自己的pom
  2. 它的打包方式必须是:pom
  3. 引入新的元素:modules—module(模块:每个模块其实也是一个项目
  4. 版本:聚合模块的版本要和被聚合模块的版本一致
  5. relative path:每个module名称都是一个当前pom的相对目录
  6. 目录名称:为了方便快速定位,模块所处的目录应当与其artifactId一致(maven约定而不是硬性要求),总之,模块所处的目录必须要和聚合模块中的模块目录保持一致。
  7. 聚合模块减少的内容:聚合模块的内容仅仅是一个pom.xml文件,它不包含src/main/java和src/test/java等目录,因为他只是用来将其他模块整合构建成一个整体的工具,本身并没有实质的内容。
  8. 聚合模块和子模块的目录:它们可以是父子级,也可以是平行结构(推荐)。默认是父子级结构,但是不建议使用,因为父子级是一种嵌套关系,子模块要建在父模块里面,维护起来很容易紊乱;推荐使用平行结构,是因为维护起来一目了然,条理比较清晰,当然同时要在pom文件的中修改相应的目录路径配置。
  9. 如果聚合模块对某一个子模块进行了删除操作,那么一定要在聚合模块的pom.xml文件中的modules选项中将对应的子模块删除掉。

继承的意义:

  • 我们知道 maven工程之间可以完成依赖的传递性,实际上就是各个jar包和war包之间存在依赖的传递性,但是必须是compile范围的依赖才具有传递性,才可以根据传递性统一管理一个依赖的版本。
  • 而对于test范围的依赖,只是孤零零的存在于某个项目中,各个项目中的依赖版本可能不同,容易造成问题,所以test范围依赖的统一版本的问题,通过依赖的传递性是无法解决的,所以我们使用继承这个概念来处理。

继承(要点):

1、说到继承肯定是一个父子结构,首先要创建一个parent project;
2<packaging>:作为父模块的pom,其打包类型必须是pom;
3、结构:父模块本身就是为了消除子模块中依赖的冗余性,所以不需要src/main/java和src/test/java等目录;
4、新的元素:<parent>,是在子模块中用来继承父模块的;
5<parent>元素的属性:<relativePath>表示父模块中pom的相对路径,在构建的时候maven会先根据<relativePath>检查父模块pom,如果找不到,再从本地仓库中查找;
6<relativePath>的默认值:../pom.xml;
7、子模块省略groupId和version:在子模块中可以不声明groupId和version两个元素,子模块将隐式的继承父模块中的groupId和version元素。
8、继承能够提高代码的复用性,还可以让项目更加安全。

总结:

  • 对于聚合模块来说,它知道有哪些被聚合的模块,而对于被聚合的模块来说,它们不知道被谁聚合了,也不知道它的存在
  • 对于继承关系的父POM来说,它不知道自己被哪些子模块继承了,对于子POM来说,它必须知道自己的父POM是谁
  • 在一些最佳实践中我们会发现:一个POM既是聚合POM,又是父POM,这么做主要是为了方便。

我们就用如下图来演示maven聚合工程:

在这里插入图片描述

1、创建聚合工程整体架构

1.1、首先在idea创建一个空项目

在这里插入图片描述

在这里插入图片描述

1.2、创建ebuy-parent模块(管理项目所需依赖)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 然后在ebuy-parent模块中添加如下版本控制和相关依赖
    	<!-- properties:统一管理版本号 -->
        <properties>
            <junit.version>4.12</junit.version>
            <jstl.version>1.2</jstl.version>
            <servlet-api.version>2.5</servlet-api.version>
            <jsp-api.version>2.0</jsp-api.version>
        </properties>
        <dependencyManagement>
            <dependencies>
                <!-- 单元测试 -->
                <dependency>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                    <!-- version:引用上面properties中配置的版本号 -->
                    <version>${junit.version}</version>
                    <scope>test</scope>
                </dependency>
                <!-- JSP相关 -->
                <dependency>
                    <groupId>jstl</groupId>
                    <artifactId>jstl</artifactId>
                    <version>${jstl.version}</version>
                </dependency>
                <dependency>
                    <groupId>javax.servlet</groupId>
                    <artifactId>servlet-api</artifactId>
                    <version>${servlet-api.version}</version>
                    <scope>provided</scope>
                </dependency>
                <dependency>
                    <groupId>javax.servlet</groupId>
                    <artifactId>jsp-api</artifactId>
                    <version>${jsp-api.version}</version>
                    <scope>provided</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    

在这里插入图片描述

1.3、创建ebuy-main模块(聚合工程的父级项目)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.4、分层创建模块(横向拆分)

1.4.1、创建ebuy-pojo模块

在这里插入图片描述
在这里插入图片描述

1.4.2、创建ebuy-dao模块

在这里插入图片描述
在这里插入图片描述

1.4.3、创建ebuy-service模块

在这里插入图片描述
在这里插入图片描述

1.4.4、创建ebuy-servlet模块(maven-web项目)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.5、查看ebuy-main模块中pom.xml文件

在这里插入图片描述

2、测试聚合工程

  • 首先分析多层依赖关系:

2.1、首先是dao层引用pojo层

在这里插入图片描述

2.2、service层引用dao层

在这里插入图片描述

2.3、servlet层引用service层

在这里插入图片描述

2.4、简单测试

  • 首先在ebuy-pojo模块中创建com.ebuy.pojo包,其次创建UsersInfo类
    -在这里插入图片描述

    package com.ebuy.pojo;
    
    /**
     * @author 一宿君(CSDN:qq_52596258)
     * @date 2021年05月23日 16时40分04秒
     * 用户信息实体类
     */
    public class UsersInfo {
        private int userid;
        private String username;
        private String userpwd;
    
        public int getUserid() {
            return userid;
        }
    
        public void setUserid(int userid) {
            this.userid = userid;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getUserpwd() {
            return userpwd;
        }
    
        public void setUserpwd(String userpwd) {
            this.userpwd = userpwd;
        }
    
        @Override
        public String toString() {
            return "UsersInfo{" +
                    "userid=" + userid +
                    ", username='" + username + '\\'' +
                    ", userpwd='" + userpwd + '\\'' +
                    '}';
        }
    }
    
  • 然后在ebuy-dao模块中创建com.ebuy.dao包,在下面创UsersInfoDao接口,在接口定义方法getUsers()
    在这里插入图片描述

    package com.ebuy.dao;
    
    import com.ebuy.pojo.UsersInfo;
    
    /**
     * @author 一宿君(CSDN : qq_52596258)
     * @date 2021-05-23 16:52:20
     */
    public interface UsersInfoDao {
        /*用于获取UsersInfo用户信息*/
        public UsersInfo getUsers();
    }
    
  • 然后在ebuy-service模块中创建com.ebuy.service包,然后在下面创建UsersInfoDao接口的实现类UsersInfoService,然后重写方法getUsers()
    在这里插入图片描述

    package com.ebuy.service;
    
    import com.ebuy.dao.UsersInfoDao;
    import com.ebuy.pojo.UsersInfo;
    
    /**
     * @author 一宿君(CSDN : qq_52596258)
     * @date 2021-05-23 16:55:09
     */
    public class UsersInfoService implements UsersInfoDao {
    
        public UsersInfo getUsers() {
                UsersInfo usersInfo = new UsersInfo();
                usersInfo.setUserid(1001);
                usersInfo.setUsername("张三");
                usersInfo.setUserpwd("123456");
                return usersInfo;
        }
    }
    
  • 然后在ebuy-servlet模块中创建com.ebuy.servlet包,继承HttpServlet类,重写doGet()和doPost()方法。

  • 首先要将有关jsp的相关依赖引入到ebuy-servlet的pom.xml文件中,在此处引用的全是ebuy-parent中的依赖,version版本是通过jstl标签的形式获取的。

    <dependencies>
            <!--servlet层依赖service层-->
            <dependency>
                <groupId>com.ebuy</groupId>
                <artifactId>ebuy-service</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>
    
            <!-- JSP相关 -->
            <dependency>
                <groupId>jstl</groupId>
                <artifactId>jstl</artifactId>
                <version>${jstl.version}</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>${servlet-api.version}</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jsp-api</artifactId>
                <version>${jsp-api.version}</version>
                <scope>provided</scope>
            </dependency>
            <!-- 单元测试 -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <!-- version:引用上面properties中配置的版本号 -->
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    

    在这里插入图片描述

    package com.ebuy.servlet;
    
    import com.ebuy.service.UsersInfoService;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * @author 一宿君(CSDN : qq_52596258)
     * @date 2021-05-23 16:57:11
     */
    public class UsersInfoServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            UsersInfoService usersInfoService = new UsersInfoService();
            System.out.println(usersInfoService.getUsers());
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            super.doGet(req, resp);
        }
    }
    
  • 最后还需在web.xml文件中配置下servlet

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
      
      <servlet>
        <servlet-name>usersinfo</servlet-name>
        <servlet-class>com.ebuy.servlet.UsersInfoServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>usersinfo</servlet-name>
        <url-pattern>/usersinfoServlet</url-pattern>
      </servlet-mapping>
      
    </web-app>
    
  • 配置tomcat服务器
    在这里插入图片描述

在这里插入图片描述

  • 然后启动个tomcat发现报如下错误(版本问题):
    在这里插入图片描述
  • 将如下版本控制代码写入到所有模块项目的pom.xml文件中:
    <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>1.9</maven.compiler.source>
            <maven.compiler.target>1.9</maven.compiler.target>
    </properties>
    
  • 然后在启动tomcat服务器:
    在这里插入图片描述
  • 最后测试usersInfoServlet:
    在这里插入图片描述
    在这里插入图片描述

3、maven聚合工程的优点

在项目中使用Maven可以大大简化开发及构建的过程,一旦产品线庞大,包含的项目及模块繁多时,各模块间版本管理就会产生不一致现象,从而给维护及开发带来了不少难题。Maven的聚合特性可以帮助我们把项目的多个模块聚合在一起,使用一条命令完成构建。

以上是关于maven聚合工程(深度剖析)的主要内容,如果未能解决你的问题,请参考以下文章

关于使用maven打包如何聚合资源文件

maven 聚合工程中排除依赖为啥无效

Maven聚合工程怎么变回普通的Maven工程

Maven聚合开发实例详解---5555字

06 Maven拆分聚合项目

maven maven项目构建ssh工程(父工程与子模块的拆分与聚合)