Maven高级

目录

[1. 分模块设计与开发](#1. 分模块设计与开发)

[1.1 介绍](#1.1 介绍)

1). 未分模块设计的问题. 未分模块设计的问题)

2). 分模块设计. 分模块设计)

[1.2 实践](#1.2 实践)

[1.2.1 分析](#1.2.1 分析)

[1.2.2 实现](#1.2.2 实现)

[1.3 总结](#1.3 总结)

[2. 继承与聚合](#2. 继承与聚合)

[2.1 继承](#2.1 继承)

[2.1.1 继承关系](#2.1.1 继承关系)

[2.1.1.1 思路分析](#2.1.1.1 思路分析)

在Maven当中,常见的打包方式到底有哪些?它们之间又有什么样的区别呢?

继承关系实现的三步骤:

[2.1.1.2 实现](#2.1.1.2 实现)

注意:

[2.1.2 Maven的版本锁定功能](#2.1.2 Maven的版本锁定功能)

[2.1.2.1 场景](#2.1.2.1 场景)

[2.1.2.2 介绍](#2.1.2.2 介绍)

面试题:与的区别是什么?

[2.1.2.3 实现](#2.1.2.3 实现)

[2.1.2.4 属性配置](#2.1.2.4 属性配置)

我们自己来实现自定义属性以及属性引用:

[2.2 Maven的聚合](#2.2 Maven的聚合)

[2.2.1 介绍](#2.2.1 介绍)

[2.2.2 聚合实现](#2.2.2 聚合实现)

注意:

[2.3 继承与聚合对比](#2.3 继承与聚合对比)

[3. Maven的私服](#3. Maven的私服)

[3.1 场景](#3.1 场景)

[3.2 介绍](#3.2 介绍)

[3.3 资源上传与下载](#3.3 资源上传与下载)

[3.3.1 步骤分析](#3.3.1 步骤分析)

[3.3.2 具体操作](#3.3.2 具体操作)


Maven 是一款构建和管理 Java 项目的工具。

我们掌握了 Maven 工具的基本使用之后,其实对于一些简单的项目的构建及管理基本上就没什么问题了。但是如果我们需要开发一些中大型的项目,此时仅凭我们前面所学习的 Maven 的基础知识就比较难以应对了。所以我们接下来还需要学习 Maven 提供的一些高级的功能,这些功能在构建和管理 Java 项目的时候用的也是非常多的。

Maven高级内容包括:

  • 分模块设计与开发

  • 继承与聚合

  • 私服

1. 分模块设计与开发

1.1 介绍

所谓分模块设计,顾名思义指的就是我们在设计一个 Java 项目的时候,将一个 Java 项目拆分成多个模块进行开发。

提问:项目开发为什么要分模块设计?

1). 未分模块设计的问题

如果项目不分模块,也就意味着所有的业务代码是不是都写在这一个 Java 项目当中。随着这个项目的业务扩张,项目当中的业务功能可能会越来越多

假如我们开发的是一个大型的电商项目,里面可能就包括了商品模块的功能、搜索模块的功能、购物车模块、订单模块、用户中心等等。这些所有的业务代码我们都在一个 Java 项目当中编写。

此时大家可以试想一下,假如我们开发的是一个大型的电商网站,这个项目组至少几十号甚至几百号开发人员,这些开发人员全部操作这一个 Java 项目。此时大家就会发现我们项目管理和维护起来将会非常的困难。而且大家再来看,假如在我们的项目当中,我们自己定义了一些通用的工具类以及通用的组件,而公司还有其他的项目组,其他项目组也想使用我们所封装的这些组件和工具类,其实是非常不方便的。因为 Java 项目当中包含了当前项目的所有业务代码,所以就造成了这里面所封装的一些组件会难以复用。

总结起来,主要两点问题:不方便项目的维护和管理、项目中的通用组件难以复用。

2). 分模块设计

分模块设计我们在进行项目设计阶段,就可以将一个大的项目拆分成若干个模块,每一个模块都是独立的。

比如我们可以将商品的相关功能放在商品模块当中,搜索的相关业务功能我都封装在搜索模块当中,还有像购物车模块、订单模块。而为了实现组件的复用,我们也可以将项目当中的实体类、工具类以及我们定义的通用的组件都单独的抽取到一个模块当中

如果当前这个模块,比如订单模块需要用到这些实体类以及工具类或者这些通用组件,此时直接在订单模块当中引入工具类的坐标就可以了,按需依赖,项目当中的核心代码不会被轻易依赖,保证了项目的安全!这样我们就将一个项目拆分成了若干个模块儿,这就是分模块儿设计

分模块儿设计之后,大家再来看。我们在进行项目管理的时候,我就可以几个人一组,几个人来负责订单模块儿,另外几个人来负责购物车模块儿,这样更加便于项目的管理以及项目的后期维护

而且分模块设计之后,如果我们需要用到另外一个模块的功能,我们直接依赖模块就可以了。比如商品模块、搜索模块、购物车订单模块都需要依赖于通用组件当中封装的一些工具类,我只需要引入通用组件的坐标就可以了。

分模块设计就是将项目按照功能/结构拆分成若干个子模块,方便项目的管理维护、拓展,也方便模块间的相互调用、资源共享。

1.2 实践

1.2.1 分析

好,我们明白了什么是分模块设计以及分模块设计的优势之后,接下来我们就来看一下我们之前所开发的案例工程。

我们可以看到在这个项目当中,除了我们所开发的部门管理以及员工管理、登录认证等相关业务功能以外,我们是不是也定义了一些实体类也就是pojo包下存放的一些类,像分页结果的封装类PageBean统一响应结果Result,我们还定义了一些通用的工具类,像Jwts、阿里云OSS操作的工具类等等。

如果在当前公司的其他项目组当中,也想使用我们所封装的这些公共的组件,该怎么办?大家可以思考一下。

  • 方案一:直接依赖我们当前项目 tlias-web-management ,但是存在两大缺点:

    • 这个项目当中包含所有的业务功能代码,而想共享的资源,仅仅是pojo下的实体类,以及 utils 下的工具类。如果全部都依赖进来,项目在启动时将会把所有的类都加载进来,会影响性能

    • 如果直接把这个项目都依赖进来了,那也就意味着我们所有的业务代码都对外公开了,这个是非常不安全的。

  • 方案二:分模块设计

    • 将pojo包下的实体类,抽取到一个Maven模块中 tlias-pojo

    • 将utils包下的工具类,抽取到一个Maven模块中 tlias-utils

    • 其他的业务代码,放在tlias-web-management这个模块中,在该模块中需要用到实体类pojo、工具类utils,直接引入对应的依赖即可。

注意:分模块开发需要先针对模块功能进行设计,再进行编码。不会先将工程开发完毕,然后进 行拆分。

  • 实际中都是分模块设计,然后再开发的

1.2.2 实现

思路我们分析完毕,接下来,我们就根据我们分析的思路,按照如下模块进行拆分:

1. 创建maven模块 tlias-pojo,存放实体类

A. 创建一个正常的纯Maven模块,模块名tlias-pojo

B. 然后在tlias-pojo中创建一个包 com.gch.pojo (和原来案例项目中的pojo包名一致)

C. 将原来案例项目 tlias-web-management 中的pojo包下的实体类,复制到tlias-pojo模块中

D. 在 tlias-pojo 模块的pom.xml文件中引入依赖

注意:由于是纯Maven模块,在添加依赖时要记得指定版本号!

XML 复制代码
  <dependencies>
        <!-- lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
<!--            <optional>true</optional>-->
            <version>1.18.28</version>
        </dependency>
    </dependencies>

E. 删除原有案例项目tlias-web-management的pojo包【直接删除不要犹豫,我们已经将该模块拆 分出去了】,然后在pom.xml中引入 tlias-pojo的依赖

XML 复制代码
<!-- 引入talis-pojo依赖-->
        <dependency>
            <groupId>com.gch</groupId>
            <artifactId>tlias-pojo</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

2. 创建纯Maven模块 tlias-utils,存放相关工具类

A. 创建一个正常的Maven模块,模块名tlias-utils

B. 然后在 tlias-utils 中创建一个包 com.gch.utils (和原来案例项目中的utils包名一致)

C. 将原来案例项目 tlias-web-management 中的utils包下的实体类,复制到tlias-utils模块中

D. 在 tlias-utils 模块的pom.xml文件中引入依赖

XML 复制代码
<dependencies>
       <!-- web起步依赖-->
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
           <version>2.7.5</version>
       </dependency>

       <!-- 阿里云OSS Java SDK-->
       <dependency>
           <groupId>com.aliyun.oss</groupId>
           <artifactId>aliyun-sdk-oss</artifactId>
           <version>3.15.1</version>
       </dependency>
       <!-- jaxb相关依赖-->
       <dependency>
           <groupId>javax.xml.bind</groupId>
           <artifactId>jaxb-api</artifactId>
           <version>2.3.1</version>
       </dependency>
       <dependency>
           <groupId>javax.activation</groupId>
           <artifactId>activation</artifactId>
           <version>1.1.1</version>
       </dependency>
       <!-- no more than 2.3.3-->
       <dependency>
           <groupId>org.glassfish.jaxb</groupId>
           <artifactId>jaxb-runtime</artifactId>
           <version>2.3.3</version>
       </dependency>

       <!-- lombok-->
       <dependency>
           <groupId>org.projectlombok</groupId>
           <artifactId>lombok</artifactId>
           <version>1.18.28</version>
       </dependency>

       <!-- JWT依赖-->
       <dependency>
           <groupId>io.jsonwebtoken</groupId>
           <artifactId>jjwt</artifactId>
           <version>0.9.1</version>
       </dependency>

       <!-- 配置SpringBoot注解处理器-->
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-configuration-processor</artifactId>
           <version>2.7.5</version>
       </dependency>
   </dependencies>

E. 删除原有案例项目tlias-web-management的utils包【直接删除不要犹豫,我们已经将该模块拆分出去了】,然后在pom.xml中引入 tlias-utils的依赖

XML 复制代码
<!-- 引入tails-utils依赖-->
        <dependency>
            <groupId>com.gch</groupId>
            <artifactId>tlias-utils</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

到此呢,就已经完成了模块的拆分,拆分出了 tlias-pojo、tlias-utils、tlias-web-management ,如果其他项目中需要用到 pojo,或者 utils工具类,就可以直接引入依赖。

启动tails-web-management模块,验证项目是否可以成功运行:

1.3 总结

1). 什么是分模块设计:将项目按照功能拆分成若干个子模块
2). 为什么要分模块设计:方便项目的管理维护、扩展,也方便模块间的相互调用,资源共享
3). 注意事项:分模块设计需要先针对模块功能进行设计,再进行编码。不会先将工程开发完毕,然后进行拆分

2. 继承与聚合

提到继承一词,想必大家都不陌生,因为在Java当中类与类之间就是支持继承关系的,而在Maven当中,工程与工程之间也可以实现继承关系,那么Maven工程之间是如何实现继承关系的呢?继承关系有什么作用呢?

在案例项目分模块开发之后啊,我们会看到tlias-pojo、tlias-utils中都引入了一个依赖 lombok 的依赖。我们在这两个模块中分别配置了一次。

如果是做一个大型的项目,那么模块与模块之间重复的依赖可能会很多很多。如果每一个 Maven 模块里面,我们都来单独的配置一次,功能虽然能实现,但是配置是比较繁琐的。

而接下来我们要学习 Maven 的继承用来解决这问题的。

2.1 继承

我们要使用Maven的继承,我们就需要再创建一个父工程 tlias**-parent**,然后让上述的三个模块 tlias-pojo、tlias-utils、tlias-web-management 都来继承这个父工程。 然后再将各个模块 / 子工程当中都共有的依赖,都提取到父工程 tlias**-parent中进行配置**,只要子工程继承了父工程,依赖它也会继承下来,这样就无需在各个子工程中进行配置了。

  • 概念:Maven当中的继承描述的是两个工程间的关系,与Java中的继承相似,子工程可以继承父工程中依赖的配置信息,常见于依赖关系的继承。

  • 作用:简化子工程的依赖配置、统一管理依赖【在父工程当中进行依赖的统一管理】

  • 实现:在Maven当中,我们要想实现工程与工程之间的这层继承关系,我们就需要在各个子工程当中来通过<parent>标签来指定当前子工程它的父工程是谁<parent>标签当中要来指定的就是父工程的坐标。

XML 复制代码
<parent>
    <groupId>...</groupId>
    <artifactId>...</artifactId>
    <version>...</version>
    <relativePath>....</relativePath>
</parent>

看到<parent>标签好像有些眼熟,有一种似曾相识的感觉,对了,我们之间所创建的所有SpringBoot工程中都继承了一个<parent>父工程,所有的SpringBoot工程都有一个统一的Parent父工程 - spring-boot-starter-parent:

XML 复制代码
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

通过<relativePath>标签来指定父工程的pom文件它的相对路径/位置

2.1.1 继承关系

2.1.1.1 思路分析

我们当前的项目 tlias-web-management,还稍微有一点特殊,因为是一个springboot项目,而所有的springboot项目都有一个统一的父工程,就是spring-boot-starter-parent与Java语言类似,Maven也不支持多继承,一个Maven项目只能继承一个父工程,如果继承了spring-boot-starter-parent,就没法继承我们自己定义的父工程 tlias-parent了。

那我们怎么来解决这个问题呢?

  • 那此时,大家可以想一下,Java虽然不支持多继承,但是可以支持多重继承比如:A 继承 B, B 继承C。 那在Maven中也是支持多重继承的,所以呢,我们就可以让 我们自己创建的三个模块都继承tlias**-parent父工程**,而tlias**-parent父工程 再继承 spring-boot-starter-parent**,就可以了。 具体结构如下:

注意:如果是Maven的父工程,它的打包方式需要设置为pom。

  • 设置打包方式通过<packaging>标签来指定,如果不指定,默认打包方式为Jar包!!!
  • 父工程的职责是不需要写任何Java代码的,它就起到管理依赖的作用!
  • 我们之前所创建的Maven工程好像并没有设置打包方式,原因就是如果你不设置打包方式默认就是Jar包。

在Maven当中,常见的打包方式到底有哪些?它们之间又有什么样的区别呢?

Maven当中常见的三种打包方式:

  • jar:默认的Jar包,普通的Maven模块默认的打包方式,springboot项目基本都是jar包,一个java -jar就将Jar包运行起来了,最终SpringBoot项目就运行在了内嵌的Tomcat服务器 当中(内嵌Tomcat运行)

  • war:早期基于Servlet技术所开发的Web程序,以及基于原始的SpringMVC所开发的Web应用程序的打包方式其实都是War包,打成war包之后,是没有办法Java指令直接运行,它必须要部署在外部的Tomcat服务器当中才能运行。现在的Web应用程序开发,我们基本上都是基于SpringBoot进行开发的,所以War包就比较少见了。

  • pom:pom这种打包方式常见于我们继承关系当中的父工程或聚合关系当中的聚合工程该模块不写代码,仅进行依赖管理

继承关系实现的三步骤:

①. 创建Maven模块 tlias**-parent ,该工程为父工程,并通过<packageing>标签设置打包方式pom(默认jar),然后通过<parent>标签让其继承SpringBoot项目的统一的父工程 - spring-boot-starter-parent**

②. 在子工程的pom.xml文件中,配置继承关系,通过<parent>标签让其继承Parent父工程。如果子工程是SpringBoot项目创建的工程,则把原来SpringBoot项目统一的父工程删掉,让其继承新的父工程。

③. 在Parent父工程中配置各个工程共有的依赖子工程会自动继承父工程的依赖)。

2.1.1.2 实现

1). 创建maven模块 tlias-parent ,该工程为父工程,设置打包方式pom(默认jar)。

通过<parent>标签让其继承SpringBoot的父工程 - spring-boot-starter-parent的XML代码:

XML 复制代码
 <!-- 让其继承SpringBoot项目的父工程-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version>
        <!--该标签指的是父工程的相对路径,如果没有配置任何的属性,代表将会从本地仓库当中来查找这个父工程,因为这个
        父工程不是我们自己创建的,是由官方提供的,所以直接从本地仓库当中查找就可以-->
        <relativePath/>    <!-- lookup parent from repository -->
    </parent>

改造后的父工程tlias-parent的pom.xml文件配置如下:

由于Parent父工程它里面并不会写任何的Java代码,所以直接将src目录删掉:

2). 在子工程的pom.xml文件中,配置继承关系,通过<parent>标签让其继承Parent父工程:

XML 复制代码
    <parent>
        <groupId>com.gch</groupId>
        <artifactId>tlias-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
        <!-- 父工程的pom文件的相对路径-->
        <!-- ../表示往外退一层-->
        <relativePath>../../maven-highlevel-project/tlias-parent/pom.xml</relativePath>
    </parent>

注意:

  • 在子工程中,配置了继承关系之后,坐标中的groupId是可以省略的,因为会自动继承父工程的 。

  • relativePath指定父工程的pom文件的相对路径如果不指定,将从本地仓库/远程仓库查找该工程)。

    • ../ 代表的上一级目录

3). 在父工程中配置各个子工程共有的依赖(子工程会自动继承父工程的依赖)。

XML 复制代码
<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
    </dependency>
</dependencies>

此时,我们已经将各个子工程中共有的依赖(lombok),都定义在了父工程中,子工程中的这一项依赖,就可以直接删除了。删除之后,我们会看到父工程中配置的依赖 lombok,子工程直接继承下来了。

实际项目中,可能还会见到下面的工程结构:

  • 这种层级关系是在Location当中来设置!
  • 在真实的企业开发中,都是先设计好模块之后,再开始创建模块,开发项目。 那此时呢,一般都会先创建父工程tlias**-parent**,然后将创建的各个子模块都放在父工程parent下面这样层级结构会更加清晰一些。 父子工程结构更加清晰、更加直观。
注意:
  • 若父子工程都配置了同一个依赖的不同版本,以子工程的为准!
  • 如果父工程没有直接指定依赖的版本,则子工程当中必须通过<version>标签来手动指定!

2.1.2 Maven的版本锁定功能

  • 通过Maven的继承,我们就可以将所有子工程当中共有的这部分依赖,都统一配置在父工程当中,从而来简化子工程当中的依赖配置,其实这只是Maven继承当中的一个作用。
  • 实现了Maven的继承关系之后,我们还可以在父工程当中统一的来管理依赖的版本,我们也称之为版本锁定。
2.1.2.1 场景

如果项目中各个子模块中都公共的这部分依赖,我们可以直接定义在父工程中,从而简化子工程的依赖配置然而在项目开发中,还有一部分依赖,并不是各个模块都共有的,可能只是其中的一小部分模块中使用到了这个依赖。

比如:在tlias-web-management、tlias-web-system、tlias-web-report这三个子工程中,都使用到了jwt的依赖。 但是 tlias-pojo、tlias-utils中并不需要这个依赖,那此时,这个依赖,我们不会直接配置在父工程 tlias-parent中,而是哪个模块需要,就在哪个模块中配置。

而由于是一个项目中的多个模块,那多个模块中,我们要使用的同一个依赖的版本要一致,这样便于项目依赖的统一管理。比如:这个jwt依赖,我们都使用的是 0.9.1 这个版本。

那假如说,我们项目要升级,要使用到jwt最新版本 0.9.2 中的一个新功能,那此时需要将依赖的版本升级到0.9.2,那此时该怎么做呢 ?

第一步:去找当前项目中所有的模块的pom.xml配置文件,看哪些模块用到了jwt的依赖。

第二步:找到这个依赖之后,将其版本号version,更换为 0.9.2。

问题:如果项目拆分的模块比较多,每一次更换版本,我们都得找到这个项目中的每一个模块,一个一个的更改很容易就会出现,遗漏掉一个模块,忘记更换版本的情况。

那我们又该如何来解决这个问题,如何来统一管理各个依赖的版本呢?

答案:Maven的版本锁定功能

2.1.2.2 介绍

在Maven中,可以在父工程的pom文件中通过**<dependencyManagement>统一管理依赖的版本**。

示例父工程:

XML 复制代码
    <!-- 通过Maven的版本锁定功能,来统一管理各个依赖的版本-->
    <dependencyManagement>
        <dependencies>
            <!-- 声明要管理的依赖-->
            <dependency>
                <groupId>组织名</groupId>
                <artifactId>模块名</artifactId>
                <version>版本号</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

面试题:<dependencyManagement>与<dependencies>的区别是什么?

  • 在父工程中所配置的 <dependencyManagement> 只能统一管理依赖版本,并不会将这个依赖直接引入进来。 这点和 <dependencies> 是不同的。

  • 而<dependencies>用于声明实际引入项目的依赖项,在该元素/标签内部,可以列出项目实际需要的各个<depenency>依赖项,并且可以指定每个依赖的具体版本。

  • 如果子工程要使用这个依赖,还是需要通过<dependency>标签来引入这项依赖,只是此时就无需指定 <version> 版本号了由父工程统一管理该依赖的版本。如果要变更依赖的版本,只需在父工程当中统一变更即可。所以,子工程引入的依赖版本就是父工程当中统一管理的依赖的版本号。

2.1.2.3 实现

接下来,我们就可以tlias-utils模块中单独配置的依赖,将其版本统一交给 tlias-parent 父工程进行统一管理。

具体步骤如下:

1). 将tlias-utils模块当中单独配置的依赖的版本号交给tlias-parent父亲工程中进行统一的管理配置

XML 复制代码
 <!-- 通过Maven的版本锁定功能,来统一管理各个依赖的版本-->
    <dependencyManagement>
        <dependencies>
            <!-- 声明要管理的依赖-->
            <!-- Web开发的起步依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>2.7.5</version>
            </dependency>

            <!-- 阿里云OSS Java SDK-->
            <dependency>
                <groupId>com.aliyun.oss</groupId>
                <artifactId>aliyun-sdk-oss</artifactId>
                <version>3.15.1</version>
            </dependency>
            <!-- jaxb相关依赖-->
            <dependency>
                <groupId>javax.xml.bind</groupId>
                <artifactId>jaxb-api</artifactId>
                <version>2.3.1</version>
            </dependency>
            <dependency>
                <groupId>javax.activation</groupId>
                <artifactId>activation</artifactId>
                <version>1.1.1</version>
            </dependency>
            <!-- no more than 2.3.3-->
            <dependency>
                <groupId>org.glassfish.jaxb</groupId>
                <artifactId>jaxb-runtime</artifactId>
                <version>2.3.3</version>
            </dependency>

            <!-- JWT依赖-->
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>0.9.1</version>
            </dependency>

            <!-- 配置SpringBoot注解处理器-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <version>2.7.5</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

2). tlias-utils中的pom.xml配置

如果依赖的版本已经在父工程进行了统一管理,所以在子工程中就无需再配置依赖的版本了,删除子工程中配置的依赖的版本号!

  • 我们之所以,在SpringBoot项目中很多时候,引入依赖坐标,都不需要指定依赖的版本<version>,是因为在父工程 spring-boot-starter-parent中已经通<dependencyManagement>对依赖的版本进行了统一的管理维护。
2.1.2.4 属性配置

场景:

  • 我们在父工程当中来配置各个依赖的版本的时候,依赖的版本号是在各个依赖坐标当中配置的,如果将来我们配置的依赖比较多,配置了大量的依赖,而这些依赖的版本号是非常零散的分布在各个依赖坐标当中的,此时还是不便于集中的管理和维护的,那怎样来解决这个问题呢?

解决:通过Maven当中给我们提供的自定义属性以及自定义属性引用的功能就可以来解决这个问题!

我们也可以通过自定义属性及属性引用的形式,在父工程中将依赖的版本号进行集中管理维护。

具体语法为:

  • 通过<properties>标签来自定义属性:标签名就是属性名.version - 对应依赖当中的artifactId模块名.version,标签当中所编写的这个值就是属性值,这个属性值对应的就是我们所配置的依赖的版本号。
  • 此时,在对应依赖的<version>标签当中就不用再去编写该依赖的版本号了,可以直接通过${}的形式直接来引用在<properties>标签当中所定义的属性值就可以了。

总结:这样,我们就在<properties>标签当中通过自定义属性的形式来将版本号集中的维护在 <properties>自定义属性当中。

注意:在SpringBoot的父工程当中,已经对Web开发的起步依赖的版本进行了统一的管理,所以我们并不需要维护Web开发的起步依赖的版本。

我们来看一下SpringBoot的父工程 - spring-boot-starter-parent的父工程的源码:

我们自己来实现自定义属性以及属性引用:

XML 复制代码
   <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <lombok.version>1.18.28</lombok.version>
        <aliyun-sdk-oss.version>3.15.1</aliyun-sdk-oss.version>
        <jaxb-api.version>2.3.1</jaxb-api.version>
        <activation.version>1.1.1</activation.version>
        <jaxb-runtime.version>2.3.3</jaxb-runtime.version>
        <jjwt.version>0.9.1</jjwt.version>
        <spring-boot-configuration-processor.version>2.7.5</spring-boot-configuration-processor.version>
    </properties>


 <!-- 通过Maven的版本锁定功能,来统一管理各个依赖的版本-->
    <dependencyManagement>
        <dependencies>
            <!-- 声明要管理的依赖-->

            <!-- Web开发的起步依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>

            <!-- 阿里云OSS Java SDK-->
            <dependency>
                <groupId>com.aliyun.oss</groupId>
                <artifactId>aliyun-sdk-oss</artifactId>
                <version>${aliyun-sdk-oss.version}</version>
            </dependency>
            <!-- jaxb相关依赖-->
            <dependency>
                <groupId>javax.xml.bind</groupId>
                <artifactId>jaxb-api</artifactId>
                <version>${jaxb-api.version}</version>
            </dependency>
            <dependency>
                <groupId>javax.activation</groupId>
                <artifactId>activation</artifactId>
                <version>${activation.version}</version>
            </dependency>
            <!-- no more than 2.3.3-->
            <dependency>
                <groupId>org.glassfish.jaxb</groupId>
                <artifactId>jaxb-runtime</artifactId>
                <version>${jaxb-runtime.version}</version>
            </dependency>

            <!-- JWT依赖-->
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>${jjwt.version}</version>
            </dependency>

            <!-- 配置SpringBoot注解处理器-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <version>${spring-boot-configuration-processor.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

版本集中管理之后,我们要想修改依赖的版本,就只需要在父工程中自定义属性的位置,修改对应的属性值即可。

2.2 Maven的聚合

导学:什么是聚合以及为什么要聚合?Maven项目当中如何来实现聚合功能?

分模块设计与开发之后,我们的项目被拆分为多个模块,而模块之间的关系,可能错综复杂,多个模块之间可能还会存在依赖关系

那就比如我们当前的案例项目,结构如下(相对还是比较简单的):

此时,tlias-web-management 模块的父工程是 tlias-parent,该模块又依赖了tlias-pojo、tlias-utils模块。 那此时,我们要想将 tlias-web-management 模块打包,是比较繁琐的。因为在进行项目打包时,maven会从本地仓库中来查找tlias-parent父工程,以及它所依赖的模块tlias-pojo、tlias-utils,而本地仓库目前是没有这几个依赖的。

所以,我们在打包tlias-web-management 模块前,需要将 tlias-parent、tlias-pojo、tlias-utils分别执行install生命周期安装到maven的本地仓库然后再针对于 tlias-web-management 模块执行package进行打包操作。

那此时,大家试想一下,如果开发一个大型项目,拆分的模块很多,模块之间的依赖关系错综复杂,那此时要进行项目的打包、安装操作,是非常繁琐的

其实通过Maven的聚合就是来解决这个问题的通过Maven的聚合就可以轻松实现项目的一键构建(清理、编译、测试、打包、安装等)。

2.2.1 介绍

  • 聚合:将多个模块组织成一个整体,同时进行项目的构建我们要想实现聚合功能,还必须要提供一个聚合工程。

  • 聚合工程:聚合工程的作用就是将多个模块聚合在一起。聚合工程它是一个不具有业务功能的"空"工程(有且仅有一个pom文件) 【PS:一般来说,继承关系中的父工程与聚合关系中的聚合工程是同一个

  • 聚合的作用:快速构建项目无需根据依赖关系手动构建,直接在聚合工程上构建即可

2.2.2 聚合实现

  • 在Maven中,我们可以在聚合工程中通过<modules>标签设置当前聚合工程所包含的子模块的名称。我们可以在 tlias-parent中,添加如下配置,来指定当前聚合工程,需要聚合的模块:
XML 复制代码
<!-- 指定当前聚合工程需要聚合的其它模块-->
    <modules>
        <module>../tlias-pojo</module>
        <module>../tlias-utils</module>
        <module>../../java_web_project/tlias-web-management</module>
    </modules>

此时,我们要进行编译、打包、安装操作,就无需在每一个模块上操作了。只需要在聚合工程上,统一进行操作就可以了。

注意:
  • 聚合工程中所包含的模块,在构建时,会自动根据模块间的依赖关系设置构建顺序,与聚合工程中模块的配置书写位置无关。

测试:执行在聚合工程 tlias-parent 中执行 package 打包指令

那 tlias-parent 中所聚合的其他模块全部都会执行 package 指令,这就是通过聚合实现项目的一键构建(一键清理clean、一键编译compile、一键测试test、一键打包package、一键安装install等)。

2.3 继承与聚合对比

  • 作用

    • 聚合用于快速构建项目,我们只需要在聚合工程中一键操作,下面所聚合的其它模块全部都会执行。

    • 继承用于简化依赖配置、统一管理依赖的版本

  • 相同点:

    • 聚合与继承的pom.xml文件打包方式均为pom,通常将两种关系制作到同一个pom文件中,也就是Parent既是父工程,也是聚合工程!

    • 聚合与继承均属于设计型模块,并无实际的模块内容,Parent工程仅包含一个pom.xml,连src目录都删除了

  • 不同点:

    • 聚合是在聚合工程当中通过<modules>标签来配置聚合关系的,聚合工程可以感知到参与聚合的模块有哪些

    • 继承是在子模块当中通过<parent>标签来配置继承关系,父模块无法感知哪些子模块 / 子工程继承了自己

3. Maven的私服

前面我们在学习多模块开发的时候,我们谈到我们所拆分的模块是可以在同一个公司各个项目组之间进行资源共享的这个模块的资源共享,就需要通过我们接下来所讲解的 Maven 的私服来实现。

导学:什么是私服,以及它的作用是什么?我们如何将Maven模块打包上传到私服,以及从私服当中来下载依赖。

3.1 场景

在学习什么是私服之前,我们先来分析一下同一个公司,两个项目组之间如何基于私服进行资源的共享。

假设现在有两个团队 / 项目组,A 和 B。 A 开发了一个模块 tlias-utils,模块开发完毕之后,将模块打成jar包,并安装到了A的本地仓库。

那此时,该公司的B团队开发项目时,要想使用 tlias-utils 中提供的工具类,该怎么办呢? 对于Maven项目来说,是不是在pom.xml文件中引入 tlias-utils的坐标就可以了呢?

大家可以思考一下,当B团队在Maven项目的pom.xml配置文件中引入了依赖的坐标之后,Maven是如何查找这个依赖的? 查找顺序为:

1). 本地仓库:本地仓库中是没有这个依赖jar包的。

2). 远程中央仓库:由于该模块是自己公司开发的,远程仓库中也没有这个依赖。

因为目前tlias-utils这个依赖,还在A的本地仓库中的。 B电脑上的Maven项目,是不可能找得到A电脑上Maven本地仓库的jar包的。 那此时,大家可能会有一个想法:因为A和B都会连接中央仓库,我们可以将A本地仓库的jar包,直接上传到中央仓库,然后B从中央仓库中下载tlias-utils这个依赖。

这个想法很美好,但是现实很残酷。这个方案是行不通的,因为中央仓库全球只有一个,不是什么人都可以往中央仓库中来上传Jar包的,我们是没有权限操作的。

那此时,Maven的私服就出场了,私服其实就是架设在公司局域网内部的一台服务器就是一种特殊的远程仓库。

有了私服之后,各个团队就可以直接来连接私服了。 A 连接上私服之后,他就可以把Jar包直接上传到私服当中。我公司自己内部搭建的服务器,我是不是有权限操作呀,把jar包上传到私服之后,我让 B 团队的所有开发人员也连接同一台私服。连接上这一台私服之后,他就会根据坐标的信息,直接从私服当中将对应的jar包下载到自己的本地仓库,这样就可以使用到依赖当中所提供的一些工具类了。这样我们就可以通过私服来完成团队资源的共享

如果我们在项目中需要使用其他第三方提供的依赖,如果本地仓库没有,也会自动连接私服下载,如果私服没有,私服此时会自动连接中央仓库,去中央仓库中下载依赖,然后将下载的依赖存储在私服仓库及本地仓库中。

3.2 介绍

  • 私服:是一种特殊的远程仓库它是架设在局域网内的仓库服务,用来代理位于外部的中央仓库,用于解决团队内部的资源共享与资源同步问题。

  • 依赖查找顺序:

    • 本地仓库

    • 私服仓库

    • 中央仓库

  • 注意事项:私服在企业项目开发中,一个项目/公司,只需要一台即可无需我们自己搭建,会使用即可:如何往私服当中来上传Jar包以及如何从私服当中下载依赖)。

3.3 资源上传与下载

  • 私服是架设在公司局域网内部的仓库服务,可以用于解决团队内部的资源共享问题,所以在一个企业或者是一个大的团队当中,只需要一台私服就可以了。
  • 所以这个私服在企业开发当中并不需要我们自己搭建,我们学习私服就是学习私服的使用,而私服的使用无外乎就两个方面:
  1. 第一个方面:如何将资源上传到私服仓库当中?
  2. 第二个方面:如何从私服的仓库当中来下载资源?

我们这里所说的资源主要指的就是依赖Jar包。

3.3.1 步骤分析

  • 我们要想将模块上传到私服当中,首先得把它安装到本地仓库,然后再将本地仓库当中的Jar包再上传到私服的仓库当中,这里我们要执行一个Maven的指令 -deploy - 发布就是把本地仓库当中的Jar包发布到Maven的私服仓库当中,这个deploy也是Maven的一个生命周期。
  • 要想访问私服必须要有访问权限才可以!

资源上传与下载,我们需要做三步配置,执行一条指令。

  1. 第一步配置: 在Maven的配置文件中来配置访问私服的用户名和密码**。这个用户名和密码就是你的身份凭证,只有用户名和密码是正确的,才允许你将本地仓库当中的Jar包上传到私服的仓库当中。**
  2. 第二步配置:****在Maven的配置文件中配置连接私服的地址(url地址)这个URL地址指的就是私服仓库的地址。
  3. 第三步配置:在项目的pom.xml文件中配置上传资源的位置(url地址),这个URL地址指的就是仓库的URL地址

配置好了上述三步之后,要上传资源到私服仓库,就执行执行Maven生命周期:deploy。

私服当中提供的仓库有很多,这些仓库当中到底存储什么样的内容?它们之间又有什么样的区别呢?

  • Release + Snapshot:这两个仓库当中存放的都是项目组内部共享的资源。也就是说,将来模块上传到私服的仓库当中就会存在这两个仓库当中的某一个里面。

某一个里面,到底是哪个里面呢?为什么项目组共享的资源又会分为两个仓库呢?

  • 其实这个是和我们项目的版本是有关系的

**项目版本说明:**Maven项目版本与私服仓库之间的对应关系

  • **RELEASE(发布 / 发行版本):**功能趋于稳定、当前更新停止,可以用于正式发行/发布的版本,存储在私服中的RELEASE仓库当中

  • **SNAPSHOT(快照版本):**功能不稳定、尚处于开发中的版本,即快照版本,存储在私服的SNAPSHOT仓库当中

私服仓库说明:

  • **RELEASE:**存储自己开发的RELEASE发布版本的资源。

  • **SNAPSHOT:**存储自己开发的SNAPSHOT发布版本的资源。

  • Central:存储的是从中央仓库当中下载下来的依赖Jar包

我们来看一下当前tlias-utils这个模块是属于哪个版本,在该模块的pom.xml文件当中来查看:

当我们在创建Maven模块的时候,默认的版本就是Snapshot,因为当前是正处于开发中的版本,所以,该模块如果将来我们直接上传,将上传到Snapshot这个仓库当中!

如果将<version>标签中的SNAPSHOT改为RELEASE,此时就会上传到RELEASE对应的仓库当中!其实即使后面不加RELEASE,只要不是SNAPSHOT,它都会上传到RELEASE仓库当中。

3.3.2 具体操作

演示:如何将我们所开发的Maven模块上传到私服的仓库当中,以及如何从私服的仓库当中来下载依赖。

1.设置私服的访问用户名/密码(在自己Maven安装目录下的conf/settings.xml中的<servers>标签当中来配置)

配置了两套,一套是RELEASE私服仓库的用户名和密码,另外一套是SNAPSHOT私服仓库的用户名和密码。

XML 复制代码
<server>
    <id>maven-releases</id>
    <username>admin</username>
    <password>admin</password>
</server>
    
<server>
    <id>maven-snapshots</id>
    <username>admin</username>
    <password>admin</password>
</server>

2.设置私服依赖下载的仓库组地址(在自己maven安装目录下的conf/settings.xml中的mirrors、profiles中配置)

在 <mirrors>标签 中只配置我们自己私服的连接地址(如果之前配置过阿里云,需要直接替换掉)

什么是仓库组呢?

  • 我们将来所下载的依赖有可能是我们项目组内部共享的资源,也有可能是第三方提供的依赖,所以我们索要下载的依赖,它有可能是从RELEASE这个仓库当中下载的,也有可能是从SNAPSHOT这个仓库当中下载的,也有可能是从Central中央仓库当中下载的,那我们下载依赖到底连接哪个仓库呢?
  • 其实在私服当中,就给我们提供了一个仓库组,我们可以把若干个仓库划到一个仓库组当中,那我们将来下载依赖,我只需要指定这个仓库组的URL地址就可以了,指定了仓库组的URL地址之后,将来下载依赖它就会自动的从这个仓库组对应的这几个仓库当中来查找这个依赖。
XML 复制代码
<mirror>
    <id>maven-public</id>
    <mirrorOf>*</mirrorOf>
    <url>http://192.168.150.101:8081/repository/maven-public/</url>
</mirror>

需要在 <profiles> 标签中,增加如下配置,来指定snapshot快照版本的依赖,依然允许使用:

  • 需要在<profiles>标签当中来执行无论是RELEASE版本还是SNAPSHOT版本,我们都可以从这个仓库组当中来下载,因为默认情况下SNAPSHOT不稳定的版本,它是不允许从私服当中下载的。
XML 复制代码
<profile>
    <id>allow-snapshots</id>
        <activation>
        	<activeByDefault>true</activeByDefault>
        </activation>
    <repositories>
        <repository>
            <id>maven-public</id>
            <url>http://192.168.150.101:8081/repository/maven-public/</url>
            <releases>
            	<enabled>true</enabled>
            </releases>
            <snapshots>
            	<enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
</profile>

3.IDEA的Maven工程的pom文件中配置上传(发布)地址(直接在tlias-parent聚合工程当中配置发布地址)

这里需要配置两个私服的仓库,一个是RELEASE版本的私服仓库,另外一个是SNAPSHOT版本的私服仓库。

XML 复制代码
<distributionManagement>
    <!-- release版本的发布地址 -->
    <repository>
        <id>maven-releases</id>
        <url>http://192.168.150.101:8081/repository/maven-releases/</url>
    </repository>

    <!-- snapshot版本的发布地址 -->
    <snapshotRepository>
        <id>maven-snapshots</id>
        <url>http://192.168.150.101:8081/repository/maven-snapshots/</url>
    </snapshotRepository>
</distributionManagement>
相关推荐
炸鸡配泡面2 小时前
Qt 12.28 day3
java·开发语言
get_money_2 小时前
代码随想录Day37 动态规划:完全背包理论基础,518.零钱兑换II,本周小结动态规划,377. 组合总和 Ⅳ,70. 爬楼梯(进阶版)。
java·笔记·算法·动态规划
get_money_2 小时前
代码随想录38 322. 零钱兑换,279.完全平方数,本周小结动态规划,139.单词拆分,动态规划:关于多重背包,你该了解这些!背包问题总结篇。
java·开发语言·笔记·算法·动态规划
憶巷4 小时前
设计模式的分类及作用
java·设计模式
向宇it5 小时前
【从零开始入门unity游戏开发之——C#篇36】C#的out协变和in逆变如何解决泛型委托的类型转换问题
java·开发语言·unity·c#·游戏引擎
天空之外1365 小时前
Spring Boot Actuator、Spring Boot Actuator使用、Spring Boot Actuator 监控、Spring程序监控
java·spring boot·spring
baihb10245 小时前
Docker 默认安装位置迁移
java·docker
B1nnnn丶5 小时前
通用导出任何对象列表数据的excel工具类
java·spring boot·excel
陶然同学5 小时前
什么是大数据?2022大数据时代
java·大数据
赛博末影猫5 小时前
SpringBoot(Ⅱ-2)——,SpringBoot版本控制,自动装配原理补充(源码),自动导包原理补充(源码),run方法
java·spring boot·后端