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

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

ztj100 2025-02-20 18:55 25 浏览 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模块和它所依赖的模块

相关推荐

其实TensorFlow真的很水无非就这30篇熬夜练

好的!以下是TensorFlow需要掌握的核心内容,用列表形式呈现,简洁清晰(含表情符号,<300字):1.基础概念与环境TensorFlow架构(计算图、会话->EagerE...

交叉验证和超参数调整:如何优化你的机器学习模型

准确预测Fitbit的睡眠得分在本文的前两部分中,我获取了Fitbit的睡眠数据并对其进行预处理,将这些数据分为训练集、验证集和测试集,除此之外,我还训练了三种不同的机器学习模型并比较了它们的性能。在...

机器学习交叉验证全指南:原理、类型与实战技巧

机器学习模型常常需要大量数据,但它们如何与实时新数据协同工作也同样关键。交叉验证是一种通过将数据集分成若干部分、在部分数据上训练模型、在其余数据上测试模型的方法,用来检验模型的表现。这有助于发现过拟合...

深度学习中的类别激活热图可视化

作者:ValentinaAlto编译:ronghuaiyang导读使用Keras实现图像分类中的激活热图的可视化,帮助更有针对性...

超强,必会的机器学习评估指标

大侠幸会,在下全网同名[算法金]0基础转AI上岸,多个算法赛Top[日更万日,让更多人享受智能乐趣]构建机器学习模型的关键步骤是检查其性能,这是通过使用验证指标来完成的。选择正确的验证指...

机器学习入门教程-第六课:监督学习与非监督学习

1.回顾与引入上节课我们谈到了机器学习的一些实战技巧,比如如何处理数据、选择模型以及调整参数。今天,我们将更深入地探讨机器学习的两大类:监督学习和非监督学习。2.监督学习监督学习就像是有老师的教学...

Python教程(三十八):机器学习基础

...

Python 模型部署不用愁!容器化实战,5 分钟搞定环境配置

你是不是也遇到过这种糟心事:花了好几天训练出的Python模型,在自己电脑上跑得顺顺当当,一放到服务器就各种报错。要么是Python版本不对,要么是依赖库冲突,折腾半天还是用不了。别再喊“我...

超全面讲透一个算法模型,高斯核!!

...

神经网络与传统统计方法的简单对比

传统的统计方法如...

AI 基础知识从0.1到0.2——用“房价预测”入门机器学习全流程

...

自回归滞后模型进行多变量时间序列预测

下图显示了关于不同类型葡萄酒销量的月度多元时间序列。每种葡萄酒类型都是时间序列中的一个变量。假设要预测其中一个变量。比如,sparklingwine。如何建立一个模型来进行预测呢?一种常见的方...

苹果AI策略:慢哲学——科技行业的“长期主义”试金石

苹果AI策略的深度原创分析,结合技术伦理、商业逻辑与行业博弈,揭示其“慢哲学”背后的战略智慧:一、反常之举:AI狂潮中的“逆行者”当科技巨头深陷AI军备竞赛,苹果的克制显得格格不入:功能延期:App...

时间序列预测全攻略,6大模型代码实操

如果你对数据分析感兴趣,希望学习更多的方法论,希望听听经验分享,欢迎移步宝藏公众号...

AI 基础知识从 0.4 到 0.5—— 计算机视觉之光 CNN

...

取消回复欢迎 发表评论: