maven基本知识的7个提问
在如今的互联网项目开发当中,特别是Java领域,Maven的仓库管理、依赖管理、继承和聚合等特性为项目的构建提供了一整套完善的解决方案。
这里我们通过7个关于Maven的提问来了解Maven的一些基本知识。
Maven的一般使用方式
在进行提问之前,先了解下Maven的一般使用方式。
一般在搭建开发环境的时候(使用Maven做项目管理),你安装完JDK后就会安装配置Maven(MAVEN_HOME、path),很大可能性你需要修改settings.xml文件,比如你会修改本地仓库地址路径,比如你很可能会copy一段配置到你的settings.xml中(很可能就是私服的一些配置)。
接下来,你会到IDEA或者Eclipse中进行Maven插件配置,然后你就可以在工程中的pom.xml里面开始添加<dependency>标签来管理jar包,在Maven规范的目录结构下进行编写代码,最后你就可以通过插件的方式来进行测试、打包(jar or war)、部署、运行。
提问1:什么是Maven的本地仓库?Maven到底有哪些仓库?这些仓库之间有什么关系?
Maven查找jar包是先到本地仓库查找,如果在本地仓库找不到,就上私服去找,在私服上也找不到,就到中央仓库去查找。如果最后在中央仓库找到了,就会在私服和本地仓库都放一份,以便下次不用去中央仓库去找,因为中央仓库是需要消耗网络资源的。
在上面的描述中就可以得到Maven中的仓库有三个,一个是本地仓库,一个是私服,一个是中央仓库。
本地仓库顾名思义就是在你的本地建立的仓库,本地仓库就是相当于加了一层jar包缓存。
私服,就是公司内部局域网的一台服务器而已,你想一下,当你的工程Project-A依赖别人的Project-B的接口,怎么做呢?没有Maven的时候,当然是copy Project-B jar到你的本地lib中引入,那么Maven的方式,很显然需要其他人把Project-B deploy到私服仓库中供你使用。因此私服中存储了本公司的内部专用的jar!不仅如此,私服还充当了中央仓库的镜像。
中央仓库,存储了互联网上的jar,由Maven团队来维护,地址是:http://repo1.maven.org/maven2/。
提问2:对于<dependency>标签的使用你了解多少?
这里以commons-dbcp作为例子。
上图是pom.xml文件中使用作为<dependency>标签引入依赖的实例,下面我们来看看下载下来在本地仓库是什么样子的。
可以看出,<dependency>标签揭示了jar的查找坐标的三个元素:groupId、artifactId和version。一般而言,我们可以到私服上输入artifactId进行搜索,或者到【http://search.maven.org/】、【http://mvnrepository.com/】上进行查找并确定坐标。
其中,version分为开发版本(Snapshot)和发布版本(Release),那么为什么要分呢?在实际开发中,我们经常遇到这样的场景,比如A服务依赖于B服务,A和B同时开发,B在开发中发现了BUG,修改后,将版本由1.0升级为2.0,那么A必须也跟着在POM.XML中进行版本升级。过了几天后,B又发现了问题,进行修改后升级版本发布,然后通知A进行升级。。。可以说这是开发过程中的版本不稳定导致了这样的问题。因此Maven替我们想好的解决方案就是使用Snapshot版本:在开发过程中B发布的版本标志为Snapshot版本,A进行依赖的时候选择Snapshot版本,那么每次B发布的话,会在私服仓库中,形成带有时间戳的Snapshot版本,而A构建的时候会自动下载B最新时间戳的Snapshot版本。
提问3:既然Maven进行了依赖管理,为什么还会出现依赖冲突?处理依赖冲突的手段是什么?
我们来看一个引用了两个不同版本的相同依赖的例子:
首先,对于Maven来说,在同一个groupId的同一个artifactId下,只能使用一个version,因为xml是从上至下依次解析的,因此写在后面的依赖会覆盖掉前面相同的依赖,于是根据依赖顺序就可以得出最终使用的版本是1.2版本的jar。
那么,我们可以思考关于依赖冲突的问题了。比如工程中需要引入A、B,而A依赖1.0版本的C,B依赖2.0版本的C,那么问题来了,因为C使用的版本将由引入A、B的顺序而定,如果A的依赖写在B的依赖后面,将意味着最后引入的是1.0版本的C,很可能在运行阶段出现类(ClassNotFoundException)、方法(NoSuchMethodError)找不到的错误(因为B使用的是高版本的C)。
事实上,这里涉及到了两个重要的概念,一个是传递依赖(Transitive),一个是Maven的最近依赖策略。传递依赖是指,如果A依赖B,B依赖于C,那么一旦引入了A就意味着B和C都会被引入。Maven的最近依赖策略是指,如果一个项目依赖相同的groupId、artifactId的多个版本,那么在依赖树(mvn dependency:tree)中离项目最近的那个版本将会被使用。
处理依赖冲突主要有以下三种做法:
1.如果我们清楚要使用哪个版本的话,就可以强制忽略传递依赖,进行版本锁定。具体的做法是使用<dependencyManagement>标签,这种做法主要用于子模块的版本一致性中。
2.在传递依赖中去掉不需要的或冲突的依赖。具体的做法是使用<exclusions>标签。
3.因为Maven有最近依赖策略,那么我们只要显式依赖指定的版本,就可以做到依赖覆盖的效果。具体的做法就是使用<dependency>标签将冲突的依赖选择一个合适的版本显式引入进来。
提问4:怎样提前发现依赖冲突的问题呢?
在工程中,我们避免不了需要加一些依赖,一般我们的做法都是在加了依赖后,实际运行时才会发现存在依赖冲突,然后再去解决依赖冲突的问题。那么能不能在运行前提前发现问题呢?答案是可以的,具体的做法是在新加入依赖之后使用mvn dependency:tree命令形成依赖树,就可以看出新加入的依赖是否存在传递依赖,传递依赖中是否和依赖树中的版本存在冲突。
提问5:Maven规范化的目录结构是怎样的?
我们都知道,Maven是遵循的【约定优于配置】理念的,因此其目录结构是规范化的。
上图是一个简单的Java工程的目录结构,有两点注意事项:
1.src/main下内容最终会打包到jar/war中,而src/test下是测试内容,并不会打包进去。
2.src/main/resources中的资源文件会copy至目标目录,这是Maven的默认生命周期中的一个规定动作。(可是这样的话,hibernate/mybatis的映射xml岂不是必须要放入resources下,而不能在放在其他地方了?实际上Maven提供了配置标签来包含其他目录下的资源文件)
提问6:Maven的生命周期是怎样的?
关于Maven的生命周期我们可以通过Idea开发工具中的Maven插件来了解。
当执行后面的命令时,前面的命令会自动得到执行,而实际上,我们最常用的就是这么几个:
clean:清理,将之前本地打包的东西清理掉。
compile:编译,编译代码。
package:打成jar包或ar包,会自动进行clean+compile。
install:将本地工程Jar上传到本地仓库。
deploy:上传到私服。
提问7:Maven中scope的依赖范围是怎样的?
既然,Maven的生命周期存在编译、测试、运行这些过程,那么显然有些依赖只用于测试,比如junit;有些依赖编译用不到,只有运行的时候才能用到,比如mysql的驱动包在编译期就用不到(编译期用的是JDBC接口),而是在运行时用到的;还有些依赖,编译期要用到,而运行期不需要提供,因为有些容器已经提供了,比如servlet-api在tomcat中已经提供了,我们只需要的是编译期提供而已。
compile:默认的scope,运行期有效,需要打入包中。
provided:编译期有效,运行期不需要提供,不会打入包中。
runtime:编译不需要,在运行期有效,需要导入包中(接口与实现分离)。
test:测试需要,不会打入包中。
system:非本地仓库引入、存在系统的某个路径下的jar(一般不使用)。
"衣带渐宽终不悔,为伊消得人憔悴。"
maven基本知识的7个提问的更多相关文章
- maven基础知识
1.maven基础知识 1.1maven坐标 maven坐标通常用冒号作为分割符来书写,像这样的格式:groupId:artifactId:packaging:version.项目包含了junit3. ...
- Maven基础知识详解
1. 简介 Maven在Java领域的应用已经非常广泛了,有了Maven的存在是的开发人员在搭建.依赖.扩展和打包项目上变得非常简单. 2. Windows安装Maven 下载安装包 http ...
- 0.1 Maven相关知识(项目开发基础)
一.Maven 1.1Maven是什么 Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件. Maven这个单词来自于意第绪语(犹太语),意为知识的 ...
- maven package 知识(转载)
“打包“这个词听起来比较土,比较正式的说法应该是”构建项目软件包“,具体说就是将项目中的各种文件,比如源代码.编译生成的字节码.配置文件.文档,按照规范的格式生成归档,最常见的当然就是JAR包和WAR ...
- Maven基础知识(转)
文章摘自http://www.cnblogs.com/xing901022/p/4170248.html 谢谢楼主的总结,界面设计的很好看! 一.什么是Maven Maven是一个用于项目构建的工具, ...
- Maven基础知识和环境搭建
基本概念和生命周期 Maven是现在流行的构建自动化工具,提供了软件构建过程中全生命周期的管理. 基础目录结构 基础目录结构如下: 根目录:存放pom.xml 和所有的子目录 ${basedir}/s ...
- Maven入门知识介绍
1.1 Maven简介 Apache Maven 是一个软件项目管理工具.基于项目对象模型的概念,Maven可用来管理项目的依赖.编译.文档 等信息. 使用maven管理项目时,项目的依赖的jar包将 ...
- maven基础知识汇总
maven的dependency中scope=compile和provided的区别 对于scope=compile的情况(默认scope),也就是说这个项目在编译,测试,运行阶段都需要这个artif ...
- Maven 基础知识
Maven MavenMaven 简介 Maven MavenMaven 是 Apache Apache Apache 软件基金会组织维护的 软件基金会组织维护的 软件基金会组织维护的 软件基金会组织 ...
随机推荐
- Java基础—内部类
在Java语言中,可以把一个类定义到另一个类的内部,在类里面的这个类就叫作内部类,外面的类叫作外部类.在这种情况下,这个内部类可以被看成外部类的是一个成员(与类的属性和方法类似).还有一种类被称为顶层 ...
- Windows Socket知识总结
目录 0 理解Socket 1 WinSock API 2 阻塞socket 3 非阻塞Socket 4 套接字IO模型 4.1 套接字IO模型:select(选择) 4.2 套接字IO模型:W ...
- 苹果审核之遇到IPV6问题被拒的解决方法
情景: 等待苹果审核上线时,发现因为IPV6被拒了.这是悲剧,以下是苹果审核给我的理由: We discovered one or more bugs on Wi-Fi connected to an ...
- Arcgis CreateFishnet工具,生成到FileGDB中要素类的格网大小不一致
我的第一篇博客!哈哈 最近在做一些关于创建渔网的工作,发现一些问题,做个总结. 1.问题描述:如图1,设置好渔网的必要参数,输出目录为gdb里的矢量图层,(行列数比较大,渔网的地理范围较小),输出的格 ...
- Unity整合TortoiseSVN
解决各种漏传 资源 / 代码 的疑难杂症. 因为Unity比较特殊的meta文件系统, 忘传漏传文件在后期可能导致重大引用丢失, 将SVN整合进项目势在必行. TortoiseSVN自带了命令行工具, ...
- 3-剑指Offer: 连续子数组的最大和
题目描述 HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决.但是,如果向量 ...
- 【洛谷P5331】 [SNOI2019]通信
洛谷 题意: \(n\)个哨站排成一列,第\(i\)个哨站的频段为\(a_i\). 现在每个哨站可以选择: 直接连接到中心,代价为\(w\): 连接到前面某个哨站\(j(j<i)\),代价为\( ...
- 前端之CSS(下)
文本属性 ## 文字对齐 #text-align属性规定元素中文本的水平对齐方式 left: 左边对齐 默认值 right: 右对齐 center: 居中对齐 justify: 两端对齐 ## 文字装 ...
- Python 包:
分享一波油藏描述方面的Python开源包 前一阵去捷克参加了数学地质年会(IAMG2018),听完汇报,发现在数学地质领域用python的越来越多了,他们的很多成果都是用python做出来的.不管喜不 ...
- Autofac注册组件详解
注册概念:我们通过创建 ContainerBuilder 来注册 组件 并且告诉容器哪些 组件 暴露了哪些 服务.组件 可以通过 反射 创建; 通过提供现成的 实例创建; 或者通过 lambda 表达 ...