百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

learnMaven系列(一)如何使用Maven构建多模块的项目

ztj100 2025-02-20 18:55 17 浏览 0 评论


Maven目前算是我们后端开发项目管理必不可少的工具了(现在gradle用得也比较多),虽然对开发而言,大部分时候项目是已经搭建好的,个人可能只需要做些clean、package、install等常用操作。但是,如果是作为项目的搭建者,就需要关注下项目构建方面的细节了,毕竟一个好的框架结构,是基石,后续能够更好维护,其他参与你项目的伙伴用起来也比较顺手便捷。当然,另一方面多了解一下maven方面的知识,也有助于自己去更好地参与到他人的项目中,能够更快地让项目“跑”起来,依稀还记得曾经自己新接手项目时,拉到本地一片爆红,被maven支配的恐惧。

现在也是结合自己的一些经历和体会,对遇到过或者觉得比较重要的点进行简要整理和记录吧。

另外,我搭建了简单的示例demo,可以参考这样的模式搭建多模块项目,代码已上传仓库:
https://gitee.com/panda00hi/learnMaven.git

介绍

目前企业级项目因为业务复杂,并且为了方便扩展和维护,同时提高功能代码的复用性,往往会根据功能进行一些模块的拆分,这其实也就带来了一些项目管理上的更高的要求。比如,经常会遇到的情况,对公共组件,如,log4j、logback、sl4j等,如果不做约束,可能会导致每个项目都有依赖类似的组件;而对于模块之间,也可能有依赖,这时又会误引入其他模块引入的组件,总之因为多模块的方式,是需要进行某种规范性约束的,否则随着项目日益复杂,单纯搞依赖配置都要费好大劲。

针对这样的情况,官方也有解决方案,就是pom父子依赖机制,这一点我们应该都有用到,只是可能没有太关注,或者用得不够彻底。

有关于pom的详细介绍和使用案例:https://maven.apache.org/guides/introduction/introduction-to-the-pom.html

Project Inheritance vs Project Aggregation

If you have several Maven projects, and they all have similar configurations, you can refactor your projects by pulling out those similar configurations and making a parent project. Thus, all you have to do is to let your Maven projects inherit that parent project, and those configurations would then be applied to all of them.

And if you have a group of projects that are built or processed together, you can create a parent project and have that parent project declare those projects as its modules. By doing so, you'd only have to build the parent and the rest will follow.

But of course, you can have both Project Inheritance and Project Aggregation. Meaning, you can have your modules specify a parent project, and at the same time, have that parent project specify those Maven projects as its modules. You'd just have to apply all three rules:

Specify in every child POM who their parent POM is.

Change the parent POMs packaging to the value "pom" .

Specify in the parent POM the directories of its modules (children POMs)

创建示例项目

此处使用新建普通maven项目的方式,完成后的项目最为精简,可根据需要自行添加spring boot的相关依赖和启动类。

当然,也可以直接利用spring boot initializer新建项目和模块时,直接生成更丰富的项目模版。

通过继承方式进行管理,只需要应用这三项规则:

  • 在每个子POM中指定其父POM是谁。
  • 将父POM打包更改为值“pom”。
  • 在父POM中指定其模块的目录(子POM)

创建父项目

  1. 新建普通maven项目,作为父项目
  2. pom文件中添加打包方式为

pom

新建完成后

添加打包类型为pom

com.panda00hi.demo
learnMaven
1.0-SNAPSHOT
pom

创建子模块

如,有以下子模块

  • common:一些公共使用的部分,如utils、config、model、mapper等
  • service:抽象的业务服务接口和实现,通过调用dao,各个业务功能,或提供远程调用的方法等
  • web:与前端交互,开放的api、静态资源等
  • task:定时任务或异步相关等一些操作,一般是从web中分离出来,为了方便对一些高耗时的操作进行管理

创建时idea已经可以允许选中基于某模块作为parent创建,创建完成后,子模块自动引入parent,而parent的pom文件中,也会自动添加子模块的标签。

子模块pom文件已引入父模块的parent标签

注意:

1、子模块自己的groupId、version标签无需声明,将通过父模块约束。

2、默认是使用上一级,若需要自己指定,可使用 ../pom.xml


    learnMaven
    com.panda00hi.demo
    1.0-SNAPSHOT

4.0.0

common

父模块pom文件已添加子模块的modules标签


    common
    service
    web
    task

完成后,maven工具栏可看到父模块的root标识


使用spring boot启动项目

1、在父模块,添加spring boot starter parent的parent声明

 

    org.springframework.boot
    spring-boot-starter-parent
    2.6.6
     

2、在web和task模块,由于是web项目,引入web依赖

无需指定版本号,因为父模块依赖的springboot parent已经指定了


    
        org.springframework.boot
        spring-boot-starter-web
    

可以看到,springboot的依赖已经导入了

3、新建启动类和测试controller

启动类

package com.panda00hi.web;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* @author panda00hi
* @date 2022/4/14
*/
// 配置扫描包路径,默认当前模块根目录下及子目录
@SpringBootApplication(scanBasePackages = {"com.panda00hi.web"})
public class WebApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebApplication.class, args);
    }
}

controller

package com.panda00hi.web.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author panda00hi
 * @date 2022/4/14
 */
@RestController
public class TestController {
    
    @GetMapping("/test01")
    public String controller01(Integer id) {
        System.out.println(id);
        return "test01 receive id is :" + id;
    }
}

4、启动项目,验证

启动项目,默认8080端口。浏览器请求localhost:8080/test01?id=1,成功返回。

子模块之间的依赖

如实际工作中,common模块,一般会被其他多个模块依赖,service模块,会被web和task模块所依赖。注意:若service依赖了common,那么web也将获得common依赖,无需重复添加。

操作步骤:

子模块的dependencies标签下,添加需要依赖的其他子模块即可。

注意,添加时GAV三要素中,groupId和version,由于各个子模块均有依赖共同的父模块,且继承了是用来父模块的groupId和version信息,所以,此处依赖其他子模块时,groupId和version使用引用方式即可,如${project.parent.groupId}、${project.parent.version}


  
  
    ${project.parent.groupId}
    service
    ${project.parent.version}
  
  
  
    org.springframework.boot
    spring-boot-starter-web
    
  

父模块进行版本的管理dependencyManagement

为什么springboot项目引用某些依赖时,无需指定版本?

对于添加依赖是需要具备GAV三要素的,但是为什么在springboot项目的pom引入一些依赖的时候不需要指定版本呢?如,spring-boot-starter-web,引用时,并没有声明version信息,这是为什么呢?

原因:实际上,也是通过父模块进行管理的。

依次找到上一级父目录

spring-boot-starter-parent 》spring-boot-dependencies 在dependencyManagement标签下即可看到各个已经声明的依赖,很多都是常见依赖。

实践

采用类似的方式,我们在自己的父模块中,也统一进行依赖的版本管理。

父模块pom



    
        
            ${project.groupId}
            common
            ${project.version}
        
        
            ${project.groupId}
            service
            ${project.version}
        
    

子模块pom,如web模块


    
    
        ${project.parent.groupId}
        service
    

    
        org.springframework.boot
        spring-boot-starter-web
        
    

项目构建

1、使用maven工具,进行mvn package打包操作

注意:若使用父模块进行构建,那么它下面的所有子模块也会构建。

均已构建成功。

2、构建顺序

对于多个模块的项目,尤其是第一次导入新项目,大概率是一片爆红,而且打包命令也是各种执行报错,弄不好心态还崩了,个人也是深有体会。

  • 一般情况会按照父模块的modules标签声明的顺序,进行构建
  • 特殊情况:子模块有先后依赖时,先尝试install被依赖的模块。如,A依赖B和C,那么需要先把B和C打包后,再进行A的打包操作;再就是打包前选中如下图标,跳过单元测试。

3、指定构建的模块

如果只想构建某一模块以及它所依赖的其他模块,可以使用命令操作。如,只打包web模块(其中依赖了service,service依赖了common)

mvn -DskipTests==true package -pk web -am


idea的maven工具执行

修改package的运行配置

添加参数package -pl web -am -f pom.xml。注意:-am参数表示将所依赖的模块也一同打包

保存后,通过启动器运行

构建完成,可以看到打包的操作只有web模块和它所依赖的模块

相关推荐

告别手动操作:一键多工作表合并的实用方法

通常情况下,我们需要将同一工作簿内不同工作表中的数据进行合并处理。如何快速有效地完成这些数据的整合呢?这主要取决于需要合并的源数据的结构。...

【MySQL技术专题】「优化技术系列」常用SQL的优化方案和技术思路

概述前面我们介绍了MySQL中怎么样通过索引来优化查询。日常开发中,除了使用查询外,我们还会使用一些其他的常用SQL,比如INSERT、GROUPBY等。对于这些SQL语句,我们该怎么样进行优化呢...

9.7寸视网膜屏原道M9i双系统安装教程

泡泡网平板电脑频道4月17日原道M9i采用Win8安卓双系统,对于喜欢折腾的朋友来说,刷机成了一件难事,那么原道M9i如何刷机呢?下面通过详细地图文,介绍原道M9i的刷机操作过程,在刷机的过程中,要...

如何做好分布式任务调度——Scheduler 的一些探索

作者:张宇轩,章逸,曾丹初识Scheduler找准定位:分布式任务调度平台...

mysqldump备份操作大全及相关参数详解

mysqldump简介mysqldump是用于转储MySQL数据库的实用程序,通常我们用来迁移和备份数据库;它自带的功能参数非常多,文中列举出几乎所有常用的导出操作方法,在文章末尾将所有的参数详细说明...

大厂面试冲刺,Java“实战”问题三连,你碰到了哪个?

推荐学习...

亿级分库分表,如何丝滑扩容、如何双写灰度

以下是基于亿级分库分表丝滑扩容与双写灰度设计方案,结合架构图与核心流程说明:一、总体设计目标...

MYSQL表设计规范(mysql表设计原则)

日常工作总结,不是通用规范一、表设计库名、表名、字段名必须使用小写字母,“_”分割。...

怎么解决MySQL中的Duplicate entry错误?

在使用MySQL数据库时,我们经常会遇到Duplicateentry错误,这是由于插入或更新数据时出现了重复的唯一键值。这种错误可能会导致数据的不一致性和完整性问题。为了解决这个问题,我们可以采取以...

高并发下如何防重?(高并发如何防止重复)

前言最近测试给我提了一个bug,说我之前提供的一个批量复制商品的接口,产生了重复的商品数据。...

性能压测数据告诉你MySQL和MariaDB该怎么选

1.压测环境为了尽可能的客观公正,本次选择同一物理机上的两台虚拟机,一台用作数据库服务器,一台用作运行压测工具mysqlslap,操作系统均为UbuntuServer22.04LTS。...

屠龙之技 --sql注入 不值得浪费超过十天 实战中sqlmap--lv 3通杀全国

MySQL小结发表于2020-09-21分类于知识整理阅读次数:本文字数:67k阅读时长≈1:01...

破防了,谁懂啊家人们:记一次 mysql 问题排查

作者:温粥一、前言谁懂啊家人们,作为一名java开发,原来以为mysql这东西,写写CRUD,不是有手就行吗;你说DDL啊,不就是设计个表结构,搞几个索引吗。...

SpringBoot系列Mybatis之批量插入的几种姿势

...

MySQL 之 Performance Schema(mysql安装及配置超详细教程)

MySQL之PerformanceSchema介绍PerformanceSchema提供了在数据库运行时实时检查MySQL服务器的内部执行情况的方法,通过监视MySQL服务器的事件来实现监视内...

取消回复欢迎 发表评论: