点击关注上方蓝字,阅读更多干货~
缦图导读
本期介绍基于Java平台的项目管理和整合工具——Maven。作者将结合项目应用带领大家更为全面的认识与使用Maven,主要围绕Maven项目实战展开详细介绍。下面我们就如何配置Maven、如何分模块、如何解决冲突、如何配置私服、如何多环境配置等问题进行解答。希望大家通过阅读本文能有所帮助或者启发。
前言
自Java诞生以来,打包、测试、部署Java工程就一直是困扰Java程序员的枷锁。即使Ant出现,程序员仍深受困扰,并且Ant中Xml格式的Build文件的方式也再次加重了程序员的负担,直到有了Maven的出现。
图1 Maven模型图
如果jar包都到官方网站进行下载,会浪费很多时间,而且jar包可能不全
针对以上问题,目前最流行的解决方式就是maven,那么下面我们一起来具体看看。
validate(校验):校验项目是否正确并且所有必要的信息可以完成项目的构建过程
initialize(初始化):初始化构建状态,比如:设置属性值
compile(编译) :编译项目的源代码
test(测试):使用合适的单元测试框架运行测试(Juint是其中之一)
package(打包):将编译后的代码打包成可分发格式的文件,比如JAR、WAR或者EAR文件
install(安装):安装项目包到本地仓库,这样项目包可以用作其他本地项目的依赖
Maven构建项目生命周期描述的是一次构建过程经历了多少个事件
Maven对项目构建的生命周期划分为3套
clean:清理工作
default:核心工作,例如编译、测试、打包、安装等
site:产生报告、发布站点等
坐标是什么
Maven中的坐标是资源的唯一标识
使用坐标来定义项目或引入项目中需要的依赖
Maven坐标主要组成
groupId:定义当前Maven项目隶属组织名称(通常是域名反写,例如:com.test)
artifactId:定义当前Maven项目名称(通常是模块名称,例如 order-service、goods-service)
version:定义当前项目版本号
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.22.RELEASE</version>
</dependency>
依赖指当前项目运行所需的jar,一个项目可以设置多个依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.22.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.3.12</version>
<scope>test</scope>
</dependency>
通过设置坐标的依赖范围(scope),可以设置对应jar包的作用范围:编译环境、测试环境、运行环境
<scope>默认值:compile
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
直接依赖:在当前项目中通过依赖配置建立的依赖关系
间接依赖:被依赖的资源如果依赖其他资源,当前项目间接依赖其他资源
路径优先:当依赖中出现相同的资源时,层级越深,优先级越低,层级越浅,优先级越高
声明优先:当资源在相同层级被依赖时,配置顺序靠前的覆盖配置顺序靠后的
特殊优先:当同级配置了相同资源的不同版本,后配置的覆盖先配置的
图5 依赖原则图
可选依赖指对外隐藏当前所依赖的资源——不透明
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<!--可选依赖是隐藏当前工程所依赖的资源,隐藏后对应资源将不具有依赖传递性>
<optional>true</optional>
</dependency>
optional是Maven依赖jar时的一个选项,表示该依赖是可选的,项目之间依赖不传递。假设有两个项目A和B,其中A为父项目,B为子项目,在父项目中引入了Junit的依赖:
optional元素默认值(false)
optional元素为true
排除依赖指主动断开依赖的资源,被排除的资源无需指定版本——不需要
<dependency>
<groupId>springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>1.2.6</version>
<exclusions>
<exclusion>
<groupId>springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
排除依赖资源仅指定groupId,artifactId即可,无需指定version
排查依赖冲突的常用方法:
常用工具idea中下载插件Maven Helper后在pom文件中可以查看依赖分析
可以通过命令行的方式查看依赖树:mvn dependency:tree
我们现在的项目体量往往比较大,这样会出现分工不明确,划分不清晰,后期不易维护的问题。以我们公司项目中一个卡券中心为例:
立减券
产品体验券
实体礼品卡
卡券中心有多种类型的券,上面是目前最常用的三种券,如果非要把三个场景的代码放入到一个模块,那么当其中某一个模块代码出现问题,就会导致整个项目无法正常启动,从而导致公司的多个业务都无法正常运行,所以我们会按照功能将项目进行拆分。
聚合工程中所包含的模块在进行构建时会根据模块间的依赖关系设置构建顺序,与聚合工程中模块的配置书写位置无关
参与聚合的工程无法向上感知是否参与聚合,只能向下配置哪些模块参与本工程的聚合
<modules>
<module>test-admin</module>
<module>test-facade</module>
</modules>
概念:继承描述的是两个工程间的关系,与java中的继承相似,子工程可以继承父工程中的配置信息,常见于依赖关系的继承
作用:简化配置,减少版本冲突
创建Maven模块,设置打包类型为pom
在父工程的pom文件中配置依赖关系(子工程将沿用父工程中的依赖关系)
配置子工程中可选的依赖关系
在子工程中配置当前工程所继承的父工程
在子工程中配置使用父工程中可选依赖的坐标
作用:
聚合用于快速构建项目
继承用于快速配置
相同点:
聚合与继承的pom.xml文件打包方式均为pom,可以将两种关系制作到同一个pom文件中
聚合与继承均属于设计型模块,并无实际的模块内容
不同点:
聚合是在当前模块中配置关系,聚合可以感知到参与聚合的模块有哪些
继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己
定义属性
<properties>
<spring.mybatis.version>2.2.2</spring.mybatis.version>
</properties>
引用属性
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${spring.mybatis.version}</version>
</dependency>
方便公司内部不同团队或者项目共享jar包,当需要共享jar包时,可以上传到私服,通过私服共享
本地仓库:自己计算机上的一个目录
中央仓库:由Maven团队维护的全球唯一的仓库
地址:https://repo1.maven.org/maven2/
远程仓库(私服):一般由公司团队搭建的私有仓库,当项目中使用坐标引入对应依赖jar包后,首先会查找本地仓库中是否有对应的jar包
如果有,则在项目直接引用;
如果没有,则去中央仓库中下载对应的jar包到本地仓库
还可以搭建远程仓库,将来jar包的查找顺序则变为:本地仓库->远程仓库->中央仓库
图9 仓库分类图
私服权限配置
<servers>
<server>
<id>java</id>
<username>admin</username>
<password>test</password>
</server>
<server>
<id>releases</id>
<username>admin</username>
<password>test</password>
</server>
<server>
<id>snapshots</id>
<username>admin</username>
<password>test</password>
</server>
</servers>
私服地址设置
<mirrors>
<mirror>
<!--配置仓库组的ID-->
<id>java</id>
<!--repo代表repo仓库从私服获取-->
<mirrorOf>repo</mirrorOf>
<!--镜像名称-->
<name>java-public</name>
<url>镜像url</url>
</mirror>
</mirrors>
需要注意的是,server的id需要和配置的发布仓库Id保持一致,发布仓库和验证信息是通过id进行匹配的。
* 表示拦截所有请求,使用该仓库
external:* 表示本地仓库的中没有的依赖才会使用该镜像仓库
central 表示拦截去中央仓库的请求,使用该镜像仓库
*,!repo 除repo这个仓库外,其他依赖都是用该镜像仓库
repo 表示只有repo的仓库才会使用该镜像仓库
<mirrors>
<mirror>
<!--配置仓库组的ID-->
<id>java</id>
<!--repo代表repo仓库从私服获取-->
<mirrorOf>repo</mirrorOf>
<!--镜像名称-->
<name>java-public</name>
<url>镜像url</url>
</mirror>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
<distributionManagement>
<!-- 定义releases库的坐标 -->
<repository>
<id>releases</id>
<name>Nexus Release Repository</name>
<url>仓库java-releases的访问路径</url>
</repository>
<!-- 定义snapshots库 -->
<snapshotRepository>
<id>snapshots</id>
<name>Nexus Snapshot Repository</name>
<url>仓库java-snapshots的访问路径/</url>
</snapshotRepository>
</distributionManagement>
<!--定义多环境-->
<profiles>
<!--定义具体的环境:开发环境-->
<profile>
<!--定义环境对应的唯一名称-->
<id>test</id>
<!--定义环境中专用的属性值-->
<properties>
<test-version>1.0.0-SNAPSHOT</test-version>
<rely-jar-suffix>-SNAPSHOT</rely-jar-suffix>
<deploy-repository-id>仓库的ID</deploy-repository-id>
<deploy-url>仓库的url</deploy-url>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<!--定义具体的环境:生产环境-->
<profile>
<id>prod</id>
<properties>
<test-version>1.0.0</test-version>
<rely-jar-suffix></rely-jar-suffix>
<deploy-repository-id>仓库的ID</deploy-repository-id>
<deploy-url>仓库的url</deploy-url>
</properties>
</profile>
</profiles>
本文作者
蜘蛛侠,来自缦图互联网中心后端团队。
--------END--------
也许你还想看