Maven高级
分模块开发
分模块开发设计
按照功能拆分项目:可以解决因为一个功能有问题导致整个项目无法运行的问题。
按照模块拆分项目:可以解决代码重复的问题。
将原始模块按照功能拆分成若干个子模块,方便模块间的相互调用,接口共享,同时还可以很方便的被他人使用。
分模块开发实现
前面我们已经完成了SSM整合,接下来,我们就基于SSM整合的项目来实现对项目的拆分。
以下是SSM整合项目的目录结构:
抽取domain层
具体步骤如下:
-
创建新模块
创建模块名为maven_03_domain
-
项目中创建domain包并创建pojo类
-
删除原先项目中的domain包
略 -
建立依赖关系
在maven_02_ssm的pom.xml中添加如下依赖:
<dependency>
<groupId>com.itheima</groupId>
<artifactId>maven_03_domain</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
-
将domain项目安装到本地仓库
-
编译运行maven_02_ssm项目
代码依旧可以正常运行,说明成功将domain模块拆分,接下来抽取dao模块
抽取Dao层
-
创建新模块
-
新模块中创建Dao包并编写dao接口
-
在pom.xml中导入所需的坐标
<dependencies>
<dependency>
<groupId>com.itheima</groupId>
<artifactId>maven_03_domain</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
- 删除原先项目中的Dao层
略 - 建立依赖关系
在maven_02_ssm的pom.xml中添加如下依赖:
<dependency>
<groupId>com.itheima</groupId>
<artifactId>maven_04_dao</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
- 将dao模块Install到本地仓库
略(和抽取domain时的情况一致) - 编译运行maven_02_ssm项目
成功!
接下来还可以继续将service层、controller层等继续抽取成单独模块,步骤和上面差不多,所以不再演示。
聚合和继承
在通过前面的分模块开发操作,我们发现当模块前存在依赖关系,必须先将被依赖的模块Install到本地仓库才可以使用依赖这个模块的模块。
这样就存在一个问题,当存在比较多且复杂的项目依赖,我们一个个操作起来很容易遗漏或者重复操作。
在maven中我们可以使用聚合的方式解决以上问题。
聚合
概念:
- 聚合:将多个模块组织成一个整体,同时进行项目构建的过程称为聚合。
- 聚合工程:通常是一个不具有业务功能的空工程(有且仅有一个pom.xml)
- 作用:使用聚合工程可以将多个工程编组,通过对聚合工程进行构建,实现对所包含的模块进行同步构建。
实现步骤:
-
创建一个空的maven项目
-
将项目的打包方式改为pom
<packaging>pom</packaging>
- pom.xml中添加所要管理的项目
<modules>
<module>../maven_02_ssm</module>
<module>../maven_03_domain</module>
<module>../maven_04_dao</module>
</modules>
- 使用聚合统一管理项目
至此,我们可以使用聚合工程对多个模块统一进行clean,compile,install等操作,非常方便!
继承
通过上面使用聚合工程去管理项目,聚合工程进行某一个构建操作,其他被其管理的项目也会执行相同的构建操作。那么接下来我们再来分析下,多模块开发中存在的另一个问题,重复配置的问题。
当我们根据功能分模块时,模块间可能不存在依赖关系,但是它们所依赖的jar包可能是差不多甚至是相同的。这样就出现了重复的内容。并且,如果后期我们想要升级spring的版本,所有与spring相关的jar包都需要修改,涉及到模块越多,维护成本就越高。
我们可以通过继承的方式解决上述问题。
概念
- 继承:描述的是两个工程间的关系,与java中的继承类似,子工程可以继承父工程中的配置信息,常见于依赖关系的继承。
- 继承的作用:简化配置和减少版本冲突
实现步骤:
- 创建一个空的maven项目并将其打包方式设置为pom
- 在父工程的pom文件中配置依赖关系(子工程将沿用父工程中的依赖关系),一般只抽取子项目中公共的jar包。
<dependencies>
<dependency>
<groupId>com.itheima</groupId>
<artifactId>maven_04_dao</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
....
</dependencies>
- 在父工程中配置子工程中的可选依赖
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
- 在子项目中配置使用父工程中的坐标
<parent>
<groupId>com.itheima</groupId>
<artifactId>maven_01_parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../maven_01_parent/pom.xml</relativePath>
</parent>
- 优化子项目依赖版本问题
在domain模块下的pom.xml中添加如下内容:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
子项目中可选依赖的版本和父项目中依赖版本一致。
父工程主要是用来快速配置依赖jar包和管理项目中所使用的资源。
聚合和继承的区别
两者之间的作用:
- 聚合:用于快速构建项目,对项目进行管理
- 继承:用于快速配置和管理子项目中所使用jar包的版本
聚合与继承的相同点:
- 聚合与继承的pom.xml文件的打包方式均为pom,可以将两种关系制作到同一个pom文件中。
- 聚合和继承均属于设计型模块,并无实际的模块内容
聚合和继承的不同点:
- 聚合是在当前模块中配置关系,聚合可以感知到参与聚合的模块有哪些
- 继承在子模块中配置关系,父模块无法感知哪些模块继承了自己
属性
在前面的聚合与继承章节中,我们发现父工程中可以为子工程提供依赖,从而减少代码重复量。因此大量的依赖放在父工程的pom.xml中。
这时我们会发现一个问题,比如我们想更新Spring的版本,我们需要更新多个jar包的版本,像是spring-context,spring-mybaits,spring-jdbc…这样的话不仅麻烦而且可能因为漏改导致程序出现问题。
我们可以参考java基础中的变量。将变量申明在一起,在其他地方调用变量,通过修改变量的值,所有使用变量值的地方都会发生改变。而申明在pom中的变量被称为属性。
配置属性
使用步骤
- 父工程中定义属性
<properties>
<spring.version>5.2.10.RELEASE</spring.version>
<junit.version>4.12</junit.version>
<mybatis-spring.version>1.3.0</mybatis-spring.version>
</properties>
- 修改依赖的version
使用${属性名}
的方式在version标签中使用属性中的版本
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
至此,我们便可以通过继承和属性轻松完成对jar包版本的统一管理。这样我们可以方便地对项目中的jar包版本进行统一维护。
配置文件加载属性
通过属性,我们可以轻松的管理jar包版本。既然属性像变量一样可以统一的完成值的设定。我们希望它的管理范围能够更大一些,实现更多的功能。像是使用maven来配置jdbc.properties中的属性。
要实现以上功能,步骤如下:
- 父工程定义属性
<properties>
<spring.version>5.2.10.RELEASE</spring.version>
<junit.version>4.12</junit.version>
<mybatis-spring.version>1.3.0</mybatis-spring.version>
<jdbc.url>jdbc.mysql://localhost:8080/spring_db?useSSL=false&allowPublicKeyRetrieval=true</jdbc.url>
<jdbc.driver>com.mysql.jdbc.Driver</jdbc.driver>
<jdbc.username>root</jdbc.username>
<jdbc.password>root</jdbc.password>
</properties>
- jdbc.properties文件引用属性
jdbc.driver=${jdbc.driver}
jdbc.url=${jdbc.url}
jdbc.username=${jdbc.username}
jdbc.password=${jdbc.password}
- 扩大maven属性的影响范围,设置maven过滤文件范围
<build>
<resources>
<!--设置资源目录-->
<!--
${project.basedir}:当前项目所在目录,
子项目继承了父项目,相当于所有的子项目都添加资源目录的过滤
-->
<resource>
<directory>${project.basedir}/src/main/resources</directory>
<!--设置能够解析${},默认是false-->
<filtering>true</filtering>
</resource>
</resources>
</build>
- 测试是否生效,查看target中的jdbc.properties文件
版本管理
在我们jar包的版本定义中,有两个工程版本用的比较多:
- SNAPSHOT(快照版本):项目开发过程中的临时版本,随着开发的进展不断更新。
- RELEASE(发布版本):稳定的版本,即使进行功能的后续开发也不会改变当前发布版本的内容。
除了以上的工程版本,我们还经常能看到一些发布版本:
- alpha版:内测版
- beta版:公测版,不稳定
- 纯数字版
多环境配置与应用
多环境开发
我们平时开发的时候使用的是开发环境,测试人员则需要使用测试环境,项目通过测试后还需要部署到生产环境。不同的环境的配置是不相同的,如不可能让三个环境都用一个数据库,所以就会有三个数据库的url配置。
如何实现不同环境之间的配置切换?
maven提供配置多环境的设置,帮助开发者在使用过程中快速切换环境。具体实现步骤:
- 父工程中配置多个环境,并指定激活默认环境
<profiles>
<!--开发环境-->
<profile>
<id>env_dep</id>
<properties>
<jdbc.url>jdbc:mysql://127.1.1.1:3306/ssm_db</jdbc.url>
</properties>
<!--设定是否为默认启动环境-->
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<!--生产环境-->
<profile>
<id>env_pro</id>
<properties>
<jdbc.url>jdbc:mysql://127.2.2.2:3306/ssm_db</jdbc.url>
</properties>
</profile>
<!--测试环境-->
<profile>
<id>env_test</id>
<properties>
<jdbc.url>jdbc:mysql://127.3.3.3:3306/ssm_db</jdbc.url>
</properties>
</profile>
-
执行Install(安装)查看env_dep环境是否生效
-
切换默认环境为生产环境
<!--生产环境-->
<profile>
<id>env_pro</id>
<properties>
<jdbc.url>jdbc:mysql://127.2.2.2:3306/ssm_db</jdbc.url>
</properties>
<!--设定是否为默认启动环境-->
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
-
执行安装并查看env_pro环境是否生效
-
命令行实现环境切换
-
执行安装并查看env_test环境是否生效
跳过测试
前面在执行Install指令的时候,maven都会按照顺序从上往下执行,每次都会执行test,对于test来说有它存在的意义:可以确保每次打包或者安装的时候,程序的正确性。但是也存在一些缺点。
- 程序正确的情况下再次执行打包或者安装,测试还会被执行,浪费事件。
- 功能开发过程中有部分模块还没开发完毕,测试无法通过,但是想要把其中一部分进行快速打包
遇到上面这些情况的时候,我们就想跳过过测试执行下面的构建命令,具体实现的方式有很多:
- 使用IDEA工具实现跳过测试
图中的按钮为Toggle ‘Skip Tests’ Mode,点击按钮则可以跳过测试。但是使用此方法,会把所有的测试都跳过,如果我们想更精细的控制跳过哪些测试,就需要使用配置插件的方式。
- 配置插件实现跳过测试
在父工程中的pom.xml中添加测试插件配置
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<skipTests>false</skipTests>
<!--排除掉不参与测试的内容-->
<excludes>
<exclude>**/BookServiceTest.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
- skipTests:如果为true,则跳过所有测试,如果为false,则不跳过测试
- excludes:哪些测试类不参与测试,即除名,针对skipTests为false来设置
- includes:哪些测试类不参与测试,即除名,针对skipTests为true来设置
================================
- 命令行跳过测试
使用maven的命令行,mvn 指令 -D skipTests
需要注意:该命令可以不借助IDEA,直接使用cmd命令行进行跳过测试,主要注意的是cmd要在pom.xml所在目录下进行执行。
私服
私服介绍
当团队内部不同的人需要其他人编写的模块时,使用直接拷贝的方式,将会导致团队之间的jar包管理会非常混乱且容易出错。我们肯定是希望能够像使用中央仓库中的资源一样来调用其他人的模块。
不过很可惜,maven的中央仓库不允许私人上传自己的jar包。因此只能自己搭建一个类似中央仓库的东西,把自己的资源上传,同时可以下载其他人的资源,而这个东西就是私服。
私服:公司内部搭建的用于存储maven资源的服务器。
私服是一台独立服务器,用于解决团队内部的资源共享和资源同步问题。
搭建maven私服的方式有很多,我们使用其中比较流行的搭建方式:Nexus
私服安装
Nexus是Sonatype公司的一款maven私服产品
Nexus下载地址
-
下载解压
注意:解压后的两个文件夹都是有用的!!!
-
启动Nexus
使用cmd进入到解压目录下的nexus-3.30.1-01\bin,执行如下命令:nexus.exe /run nexus
看到如上图所示内容,则表明启动成功。 -
浏览器访问
访问地址为localhost:8081
-
首次登陆重置密码
输入用户名和密码进行登陆。
点击下一步,需要重新输入新密码,为了和后面的保持一致,密码修改为admin
设置允许(Enable)运行匿名访问
点击完成
至此私服就已经安装成功,如果还想修改一些基础配置信息,可以使用:
修改基础配置信息:安装路径下etc目录中nexus-default.properties文件保存有nexus基础配置信息,例如默认访问端口。
修改服务器运行信息:安装路径下bin目录中的nexus.vmoptions文件保存有nexus服务器启动对应的配置信息,例如默认占用内存空间。
私服仓库分类
- 在没有私服的情况下,我们自己创建的服务都是安装在Maven的本地仓库中
- 私服中也有仓库,我们需要把自己的资源上传到私服,最终也是放在私服的仓库中
- 其他人想要使用你所上传的资源,就需要从私服的仓库中获取
- 当我们所使用的资源不是自己写的,是远程中央仓库的第三方jar包,这个时候就需要从远程中央仓库狭隘,每个开发者都去远程中央仓库下载速度比较慢(中央仓库服务器在国外)
- 私服就再准备一个仓库,用来专门存储从远程中央仓库下载的第三方jar包,第一次访问没有就去远程中央仓库下载,下次再访问就直接走私服下载
- 前面在介绍版本管理1时候提到过有SNAPSHOT和RELEASE,如果把这两类都放到同一个仓库,比较混乱,所以私服就把这两种jar包放入不同的仓库
- 上面我们已经介绍了有三种仓库,一种是存放SNAPSHOT的,一种是存放RELEASE,还有一种是存放从远程仓库下载的第三方jar包,那么我们在获取资源的时候要从哪个仓库获取呢?
- 为了方便获取,我们将所有的仓库编成一个组,我们只需要访问仓库组去获取资源。
所有私服仓库总共分为三大类:
- 宿主仓库hosted
保存无法从中央仓库获取的资源(自足研发,第三方非开源项目) - 代理仓库proxy
代理远程仓库,通过nexus连接中央仓库 - 仓库组group
将若干个仓库组成一个群组,简化配置
仓库组不能保存资源,属于设计型仓库
仓库类别 | 英文名称 | 功能 | 关联操作 |
---|---|---|---|
宿主仓库 | hosted | 保存自主研发+第三方资源 | 上传 |
代理仓库 | proxy | 代理接连中央仓库 | 下载 |
仓库组 | group | 为仓库编组简化下载操作 | 下载 |
本地仓库访问私服配置
- 我们通过IDEA将开发的模块上传到私服,中间是需要经过本地maven
- 本地maven需要知道私服的访问地址以及私服的访问的用户名和密码
- 私服的仓库很多,maven最终要把资源上传到哪个仓库?
- maven下载的时候,又需要携带用户名和密码到私服上找对应的仓库组进行下载,然后再给IDEA。
上面所说的这些内容,我们需要在本地maven的配置文件settings.xml中进行配置
-
私服上配置仓库
点击Repositories然后点击Create repository,如下图:
接着选择创建maven2(hosted)的仓库分别创建itheima_snapshot以及itheima_release
-
配置本地maven对私服的访问权限
在maven的conf包下的settings.xml进行配置
<servers>
<server>
<id>itheima-snapshot</id>
<username>admin</username>
<password>admin</password>
</server>
<server>
<id>itheima-release</id>
<username>admin</username>
<password>admin</password>
</server>
</servers>
- 配置私服的访问路径
</mirrors>
<mirror>
<!--配置仓库组的ID-->
<id>maven-public</id>
<!--*代表所有的内容都从私服获取-->
<mirrorOf>*</mirrorOf>
<!--私服仓库组maven-public的访问路径-->
<url>http://localhost:8081/repository/maven-public</url>
</mirror>
</mirrors>
为了避免阿里云Maven私服地址的影响,建议先将之前配置的阿里云Maven私服镜像地址注释掉,等练习完,再将其恢复。
至此,本地仓库就能与私服进行交互了。
4.
私服资源上传与下载
本地仓库与私服已经建立了连接,接下来我们就需要往私服上上传和下载资源,具体的实现步骤为:
- 配置工程上传私服的具体位置
在父项目的pom.xml中添加如下内容:
<!--配置当前工程保存在私服中的具体位置-->
<distributionManagement>
<repository>
<!--和maven/conf/settings.xml中的id一致,表示使用该id对应的用户名和密码-->
<id>itheima-release</id>
<!--release版本上传仓库的具体位置-->
<url>http://localhost:8081/repository/itheima_release/</url>
</repository>
<snapshotRepository>
<!--和maven/conf/settings.xml中的id一致,表示使用该id对应的用户名和密码-->
<id>itheima-snapshot</id>
<!--snapshot版本上传仓库的具体位置-->
<url>http://localhost:8081/repository/itheima_snapshot/</url>
</snapshotRepository>
</distributionManagement>
- 发布资源到私服
或者执行Maven命令:mvn deploy
注意!!!:要发布的项目都需要配置distributionManagement
标签,要么在自己的pom.xml中配置,要么在父项目中配置,然后子项目中继承父项目即可。
发布成功,在私服中就可以看到:
现在发布是在itheima-snapshot仓库中,如果想发布到itheima-release仓库中只需要将项目的pom.xml中的version修改成RELEASE即可。
如果私服中没有对应的jar,会去中央仓库下载,速度会很慢,可以配置让私服去阿里云中下载依赖
学习总结
本次学习了maven高级部分,其内容包括:分模块开发、聚合与继承、属性、多环境配置与应用以及私服。通过学习这些技术,我发现这些技术的出现主要是用来简化开发、提高开发效率以及减少出错的概率。