1.maven是什么?
maven是Apache下的一个纯java开发的一个开源项目,它是一款能够抽象构建过程,并且提供依赖管理,中央仓库,自动下载构建等功能的项目构建工具。
2.为什么要使用maven工具构建项目?
假如我们在开发两个Java项目,暂时称之为A,B,这两个项目中对于一些特殊功能会有互相依赖的情况下,该如何做两者之间较好的关联呢?是打算在A,B两边共用一套代码进行关联吗?( 这样的做法会非常难以进行后期的维护 )
如果我们将共用的代码打包成jar引入项目中使用的话,那么后期进行代码更新的话是否又要对所有引入的jar进行更新呢?这样的做法似乎非常繁琐。
回想起以前做开发的时候,由于maven技术还没有出现,使用ssh框架进行开发的时候,所有的jar都需要人为的进行统一导入和维护,导致后期的维护难度极高。
而maven正是可以解决以上所说的这些问题。
3.maven会如何进行jar的管理呢?
在maven这款工具里面,有一个特别的概念叫做坐标。这个坐标可不是我们数学里面说的那个坐标,但是在设定上确实和数学的坐标有一点类似,就是每个坐标都会拥有属于它自己的唯一标识。在maven里面也不例外:
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> 复制代码
例如上边的这段坐标信息,groupId 通常会用于标识该jar所属的实际项目,由于通常一个项目可能会划分为了多个模块,因此artifactId 则是对于该项目的某个模块进行了一个明确的标识。version元素更多的是定义了该构件的真实版本。通常我们会称呼这一段 dependency 为依赖。
对于依赖的读取还有一个叫做scope的配置
scope的分类 | 讲解 |
compile | 默认情况下就是compile类型,意味着该依赖既要参与编译又要参与后期的测试等环节 |
test | 表示该依赖仅仅参加和测试有关的工作 |
provided | 可以参与编译,测试,运行等周期,但是在打包的时候会进行exclude的相应操作,其他方面和compile差异不大 |
runntime | 在编译环节不会参与进来,个人感觉和compile差异不大 |
system | 通常是指不从仓库读取依赖,而是通过本地路径来读取依赖,因此常与systemPath标签结合使用 |
当然如果对于每个依赖我们都进行相应单独的version设置,那么管理起来会有些繁琐,因此可以使用或者标签进行统一的管理,例如下方的这两组案例:
基于parent的依赖管理:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> 复制代码
基于properties的依赖管理,在properties里面我们可以进行整个项目的统一字符集编码管理或者对于一些依赖jar包统一版本号的管理:
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <lombok.version>1.16.6</lombok.version> <aspectj.version>1.8.11</aspectj.version> <common.version>3.4</common.version> <codec.version>1.10</codec.version> <swagger2.version>2.7.0</swagger2.version> <mybatis.version>3.3.0</mybatis.version> <mybatis-spring-boot.version>1.3.1</mybatis-spring-boot.version> <pagehelper.version>1.2.3</pagehelper.version> <springfox-swagger-ui.version>2.7.0</springfox-swagger-ui.version> <mysql.version>5.1.6</mysql.version> <mongodb.version>3.2.2</mongodb.version> </properties> 复制代码
4.maven的仓库
那么当我们将相应的依赖导入到了工程里面之后,又会发生什么事情了呢?
maven的内部会有一个从网上边下载依赖的功能,我们通常称这个拥有依赖jar的平台为仓库。
在maven里面仓库有分为多种:本地仓库,第三方仓库,中央仓库
通常被下载下来的jar会存在开发者电脑上的本地仓库,这个默认的地址是在 $user.home/.m2/repository目录底下:
这里面存储了许多自己曾经下载过的jar,这样就可以避免日后再次使用到相同jar时二次请求中央仓库了。
中央仓库是指maven官方自己维护的一个远程公用仓库:repo1.maven.org/maven2 在这里面提供了丰富的jar包供开发人员进行下载使用。有时候我们在开发中会遇见下载jar包网速过慢的情况,这个时候可以尝试将mirrors配置修改为访问阿里云镜像的配置:
<mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror> 复制代码
第三方仓库通常是指公司自己内部搭建的公共类库站点,只提供给公司内部共享服务所使用,通常都是搭建在局域网内部使用,而且对于内部私服的连接,通常公司都会有相关的账号密码进行控制。
Nexus就是一款较为强大的Maven仓库管理工具,它极大地简化了自己内部仓库的维护和外部仓库的访问。利用Nexus你可以只在一个地方就能够完全控制访问 和部署在你所维护仓库中的每个Artifact。Nexus是一套“开箱即用”的系统不需要数据库,它使用文件系统加Lucene来组织数据。Nexus 使用ExtJS来开发界面,利用Restlet来提供完整的REST APIs,通过m2eclipse与Eclipse集成使用。Nexus支持WebDAV与LDAP安全身份认证。
![在这里插入描述]失https://
除了Nexus以外,还有挺多知名的仓库管理工具,例如说JFrog Artifactory
5.maven工程的项目结构是如何的呢?
在idea编译器里面,对于maven工程的创建时候,默认的结构通常都是如下所示:
在开发的时候,通常代码编写都是在main文件夹底下进行,而如果需要编写相应的测试代码则在test目录底下进行,java目录下一般是放置我们的代码内容,resources目录底下更多的是存放一些我们的配置文件,例如说xml,yml,properties这类型的文件内容。
当然如果是创建maven-web结构的工程的话,可以在建立maven工程的时候选择相应的构建模板:
项目结构如下所示:(可能idea版本不同,最终的成效截图会有所出入)
当然,现在的项目大多都是基于父子工程的偏多,maven里面也支持这种工程的搭建,通常我们可以事先构建好一个父工程结构,然后再在父工程的基础上边构建相应的module工程。例如下边的工程截图:
6.maven的常用命令和生命周期
其实maven它本身是具有三套独立的生命周期的,这三套的生命周期分别是clean,default,site,分别有着不同的职责:清理,构建,建立站点
maven的三套生命周期之间实质上是需要互相依赖的,通常都是后者依赖于前者的关系,以clean生命周期为例,它包含的阶段有pre-clean、clean和post-clean。当用户调用pre-clean的时候,只有pre-clean阶段得以执行;当用户调用clean的时候,pre-clean和clean阶段会得以顺序执行;当用户调用post-clean的时候,pre-clean、clean和post-clean会得以顺序执行。
maven之所以将整个项目的阶段划分得如此细致,我个人的观点是这种细粒度的划分更加地利于工程构建过程中的排查错误,不同的环节由不同的插件来负责这一模块,当抛出了异常报错,我们就只需要对该环节进行分析,例如编译出错,打包出错等。
maven自身提供了非常多的命令供我们使用,下边列举了我们常用的命令基本如下:
mvn archetype:create :创建 Maven 项目
mvn compile :编译源代码
mvn test-compile :编译测试代码
mvn test : 运行应用程序中的单元测试
mvn site : 生成项目相关信息的网站
mvn clean :清除目标目录中的生成结果
mvn package : 依据项目生成 jar 文件
mvn install :在本地 Repository 中安装 jar
7.通过profile文件来指定特定的编译环境
在实际的项目开发过程中,我们通常会需要结合实际的应用场合切换不同的运行环境(dev,test,pre,pro),在不同的环境中我们通常需要读取不同的配置文件,例如不同的数据源配置,端口号配置等。如果每次切换环境的时候都要开发人员进行相关的手动修改配置的方式来进行的话,那么实际的工作效率会显得较低,不妨可以试试使用pom里面提供的profile配置:
<profiles> <profile> <!-- 本地开发环境 --> <id>dev</id> <properties> <profiles.active>dev</profiles.active> </properties> <activation> <activeByDefault>true</activeByDefault> </activation> </profile> <profile> <!-- 测试环境 --> <id>test</id> <properties> <profiles.active>test</profiles.active> </properties> </profile> <profile> <!-- 生产环境 --> <id>pro</id> <properties> <profiles.active>pro</profiles.active> </properties> </profile> </profiles> 复制代码
在pom文件里面配置以上相应的profile内容之后,在进行工程打包的时候默认通过mvn clean package -Pdev(对应profile文件的id)的方式来判断不同环境下的读取方式。
这样我们就可以更加专心的进行代码开发工作,基于这种思路,我们可以通过编写相应的脚本来实现不同环境下自动化打包的功能。