博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Maven
阅读量:6818 次
发布时间:2019-06-26

本文共 4266 字,大约阅读时间需要 14 分钟。

转载自

 前言:

  Maven的仓库管理、依赖管理、继承和聚合等特性为项目的构建提供了一整套完善的解决方案。

如果新到一家公司,那么安装完JDK之后就会安装配置Maven(MAVEN_HOME、path),很大可能性需要修改setting.xml文件,比如会修改本地仓库地址

路径,copy一段配置到你的setting.xml中(很可能就是私服的一些配置)。然后,到IDEA中进行Maven插件的配置;最后就可以在工程中的pom.xml里面开始添加<dependency>标签来管理jar包,在Maven规范的目录结构下进行编写代码,最后会通过插件的方式来进行测试、打包(jar or war)、部署、运行。

思考?

1、本地仓库?Maven到底有哪些仓库?它们什么关系?

maven仓库:

 

本地仓路径配置

D:/repo/

这样,项目中需要的jar包不需要每次都去联网下载。所以,本地仓库就是相当于加了一层jar包缓存,先到本地仓库去查,如果查不到,再去私服上

找,如果私服也找不到,那么就会去中央仓库中找,找到jar包后,会把jar包的信息同步到私服和本地仓库中。

私服:公司内部局域网的一台服务器,其内部存储了公司内部专用的jar包;不仅如此,私服还充当了中央仓库的镜像,说白了就是一个代理。

中央仓库:该仓库存储了互联网上的jar,由Maven团队来维护,地址是:http://repo1.maven.org/maven2/。

 2、关于<dependency>的使用

依赖管理:

仓库jar的路径揭示了jar包的查找坐标:groupId、artifactId、version。

一般而言,我们可以到私服上输入artifactId进行搜索,或者到、上进行查找确定坐标。

在实际开发中,我们经常遇到这样的场景,比如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!
上面的依赖顺序,将使用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)!

这里其实涉及到了2个概念:依赖传递(transitive)、Maven的最近依赖策略。
依赖传递:如果A依赖B,B依赖C,那么引入A,意味着B和C都会被引入。
Maven的最近依赖策略:如果一个项目依赖相同的groupId、artifactId的多个版本,那么在依赖树(mvn dependency:tree)中离项目最近的那个版本将会被使用。(从这里可以看出Maven是不是有点小问题呢?能不能选择高版本的进行依赖么?据了解,Gradle就是version+策略)

  如何解决依赖冲突呢?

  1、不管如何依赖传递,都进行版本锁定?

  使用<dependencyManagement>  [这种主要用于子模块的版本一致性]

  2、在依赖传递中,去掉不想依赖的
  使用<exclusions> [在实际中我们可以在IDEA中直接利用插件帮助我们生成]
 
4、如何提前发现依赖冲突
如果我们新加入一个依赖的话,那么先通过mvn dependency:tree命令形成依赖树,看看我们新加入的依赖,是否存在传递依赖,传递依赖中是否和依赖树中的版本存在冲突,如果存在多个版本冲突,利用上文的方式进行解决!
5、Maven规范化目录结构
这里有两点需要注意:
1、src/main下内容最终会打包到jar/war包中,而src/test下是测试内容,并不会打包进去
2、src/mian/resource中的资源文件会copy进目标目录,这是maven默认生命周期中的一个规定动作
 
6、Maven的生命周期
需要注意的是:执行后面的命令时,前面的命令会自动得到执行
clean:清理上一次构建生成的文件,有问题,多清理
test:使用合适的单元测试框架来测试已经编译的源代码,这些测试不需要已打包和部署
package:打成jar或war包,会自动进行clean+compile
install:将本地工程jar上传到本地仓库
deploy:上传到私服
 
7、关于scope依赖范围
既然,Maven的生命周期存在编译、测试、运行这些过程,那么显然有些依赖只用于测试,比如Junit;有些依赖编译用不到,只在运行的时候才能用到,比如MySQL的驱动包在编译器就用不到(编译器用的是JDBC接口),而是在运行时用到的;还有些依赖,编译期要用到,而运行期不需要,因为有些容器已经提供了,比如servlet-api在tomcat中已经提供了,我们只需要的是编译期提供而已。
compile:编译范围,默认的scope,运行期有效,需要打入包中
provided:已提供范围,编译期有效,运行期不需要提供,不会打入包中
runtime:运行时范围,编译不需要,但运行期有效,需要导入包中
test:测试范围,在编译和运行时都不需要,只在测试需要,不会打入包中
system:系统范围,非本地仓库引入,存在系统的某个路径下的jar
 
不同环境使用不同配置 Profile+Filter
在实际的开发场景下,我们必然会存在多套环境:开发环境、测试环境、生产环境等,在不同的环境下,一般都会有多个配置文件,比如数据源配置。
我们期望的是,不论部署到什么环境,不必修改代码,不必修改配置。
Maven提供了一个方便的解决方案:Profile功能。
  对于多套环境而言,我们可以抽取出相同的部分,放入公共的文件当中,把那些跟着环境变化而变化的配置信息,分环境存放,最后根据选择的环境而将那部分配置信息动态注入到公共的文件当中。比如(db.properties和filter/db-xxx.properties)。当然也可以建立多个目录,每一个目录表示一个环境,那么选择一套环境,就让这个目录下的资源文件生效(比如xxx/config.xml)。
demo Profile定义:
IDEA Maven插件:
如pom.xml文件所示,通过profile定义了dev、release、test这3套环境。注意在<profile>中通过<properties>进行了自定义属性。
Maven属性的概念?
Maven有一套自己内置的属性,比如${basedir},${project.xxx},Java相关,操作系统相关等。这些可以直接在pom.xml中进行引用;用户也可以通过<properties>来自定义属性,如上面可以在pom.xml中通过${profiles.active}来指明用户选择的profile。
注意,可以指定默认的profile。
选择Profile如何进行打包?其实就是在打包时执行 mvn package -Pxxx而已。
配置文件信息:
注意在db.properties中,我们通过${jdbc.username}进行了引用,而jdbc.username是在db-xxx.properties中定义的。
filter配置:
第一:通过filter来指定变量配置文件的地址,要通过profile变量进行动态选择;
第二:要知道默认Maven资源文件的打包,就是copy一份资源文件到默认的输出目录,一般就是classes下,现在必须让资源文件可以进行变量替换,因此开启过滤功能;
第三:如图中配置,通过exclude排除了filter资源目录下的文件,也就是最后打包里面没有filter目录下的文件;
第四:要么使用绝对路径,那就要使用到Maven的内置变量;要么使用相对路径,相对于pom.xml文件的路径;
 
资源插件配置:
上面的意思就是说把不同环境目录下的配置文件拷贝到classes下,而不是classes下的XXX目录下。
比如我们选择profile为test打包,结果如下:
 
多模块开发:继承与聚合
对Maven而言,我们可以将一个大的复杂的项目,进行模块划分,这样,各个模块各司其职,独立开发。这就涉及到继承与聚合了。
工程结构:
依赖关系:
父工程关键片段:
注意打包方式以及子模块包含
子工程关键片段:
 
上面的工程可以划分为:
parent:root工程,没有代码,只有配置(比如进行版本锁定),用于聚合子模块,在此工程上进行 mvn clean/package等,那么Maven会自动根据依赖关系对每一个模块进行处理。
web模块依赖service模块,service模块依赖dao模块:
  dao模块负责对DB的持久化操作,比如需要依赖mybatis,肯定也需要Spring来进行bean管理以及Mapper代理,也即是依赖mybatis+spring,注意mybatis的mapper文件以及spring的配置文件都放入到resources下。
  service模块负责业务逻辑,需要依赖dao模块。由于依赖dao自然就引入了spring依赖,因此只需要加入事务的相关配置。
  web模块负责前端交互,需要依赖service模块,以及springmvc
 

转载于:https://www.cnblogs.com/yangyongjie/p/10893327.html

你可能感兴趣的文章
python疑问6:生成器,可迭代对象,迭代器区别和联系
查看>>
【299天】跃迁之路——程序员高效学习方法论探索系列(实验阶段57-2017.12.01)...
查看>>
对象的点查询和中括号查询
查看>>
一行代码搞定人脸识别
查看>>
python3进程和线程
查看>>
【quickhybrid】Android端的项目实现
查看>>
Webpack3简单入门1
查看>>
好的代码可以自己说话!
查看>>
css揭秘笔记——用户体验
查看>>
【287天】每日项目总结系列025(2017.11.19)
查看>>
对于“不用setInterval,用setTimeout”的理解
查看>>
JavaScript设计模式--工厂模式
查看>>
前端开发者搭建自己的博客
查看>>
storm集群安装与部署
查看>>
tomcat
查看>>
微信原图泄露的只能是 Exif ,你的隐私不在这!!!
查看>>
在 V8 中从 JavaScript 到 C++ 的类型转换
查看>>
升级Python导致的yum,pip报错解决方案
查看>>
leetcode 342. Power of Four
查看>>
【Node断言assert】
查看>>