日常开发需要掌握的Maven知识
文章来自:https://www.jianshu.com/p/e224a6dc8f20和https://www.jianshu.com/p/20b39ab6a88c
Maven出现之前
jar包默认都是放到/lib目录下,而如果要新增一个jar包,就需要到处找相应的jar包,如果这个jar包又依赖其他jar包,就比较坑爹了,
网上很多都需要积分或者VIP。或者是如果新建一个项目,我们需要把之前的jar拷贝过去,总之,jar包管理很麻烦
直到Maven出现
上述的关于jar包的各种闹心的问题都能迎刃而解,而我们只需要关心功能和业务
Maven的功能有哪些
1、工程的创建、测试
2、依赖管理
3、仓库管理
4、自动化部署
。。。。
仓库
仓库就是一个位置,可以存储jar包、library jar、插件任何其他的工程指定的文件。
1、本地仓库
第一次运行maven命令在本地创建的一个文件夹,会把依赖的jar包放到本地仓库,避免每次构建都引用远程仓库的依赖文件
默认地址:${user.home}/.m2/repository目录下。要修改默认位置,只要在 settings.xml文件中定义另一个路径即可,例如:
<localRepository>/anotherDirectory/.m2/respository</localRepository>
2、远程仓库
Maven的远程仓库可以是任何其他类型的存储库,可通过各种协议,例如 file://和 http:// 来访问。这些存储库可以是由第三方
提供的可供下载的远程仓库,
例如Maven 的中央仓库(central repository):
repo.maven.apache.org/maven2
uk.maven.org/maven2
也可以是在公司内的FTP服务器或HTTP服务器上设置的内部存储库,用于在开发团队和发布之间共享私有的 artifacts。
中央仓库
Maven 的中央仓库是 Maven 社区维护的,里面包含了大量常用的库,我们可以直接引用,但是前提是我们的项目能够访问外网。
maven仓库地址:https://mvnrepository.com/
私有仓库
除了 Maven 的中央仓库外,还有一种就是私有仓库,本人公司使用的就是私有仓库,因为在内网使用。
Maven依赖查找jar包顺序:
本地仓库--->私有仓库--->配置的中央仓库--->报错。这中间只要在某一个仓库中找到了就会返回了,除非仓库中有更新的版本,或者是snapshot版本。
Maven远程仓库配置:
<profiles>
<profile>
<id>central</id>
<repositories>
<repository>
<id>Central</id>
<name>Central</name>
<url>http://repo.maven.apache.org/maven2/</url>
</repository>
</repositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>central</activeProfile>
</activeProfiles>
镜像
Mirror相当于代理,我们配置镜像一般为了网速考虑
可以在Maven中配置该镜像来替代中央仓库。在settings.xml中配置如下代码:
<mirrors>
<mirror>
<id>maven.net.cn</id>
<mirrorOf>maven.net.cn</mirrorOf>
<name>one of the central mirrors in china</name>
<url>http://maven.net.cn/content/groups/public/</url>
</mirror>
</mirrors>
生命周期
Maven有三个内置的构建生命周期: default, clean 和 site。每个生命周期都由一系列的阶段所构成
阶段的执行是按顺序的,一个阶段执行完成之后才会执行下一个阶段。

比如我们执行了一个如下的指令:
mvn install
实际会执行 install 阶段之前的所有阶段,然后才会执行 install 阶段本身。
常用:
1、clean:有问题就清理
2、package:打成jar或war包,自动进行clean和compile
3、install:将本地jar上传到本地仓库
4、deploy:将jar包上传到私服
PS:当我们的项目是多模块的,我们在最顶层执行该指令时,Maven 会遍历每一个子模块,依次执行所有的阶段。
坐标
groupId:表示一个团体,可以是公司、组织等
artifactId:表示团体下的某个项目
version:表示某个项目的版本号
他们之间的关系是一对多的,即每个团体下可以有多个项目,每个项目可以有多个版本号,可以用下面这张图来表示:

Scope依赖范围
Maven生命周期存在编译、测试、运行的过程,例如Junit只用于测试,MySQL驱动在编译期用不到,只是在运行期才使用,编译期用到的是JDBC接口,Tomcat
的servlet-api只在编译器用到,而运行期间不需要提供,因为有些容器已经提供
scope:
1、compile:默认的scope,运行期间有效,需要打到jar包
2、provided:编译期有效,运行期不提供,不打到jar包
3、runtime:编译期不需要,运行期有效,需要打到jar包(接口和实现分离)
4、test:测试需要,不打到jar包
5、system:非本地仓库引用、存在系统的某个路径下的jar包(一般不使用)
依赖
Maven 核心特点之一是依赖管理。一旦我们开始处理多模块工程(包含数百个子模块或者子工程)的时候,模块间的依赖关系就变得非常复杂,
管理也变得很困难。针对此种情形,Maven 提供了一种高度控制的方法。
1、依赖传递
如果引入一个jar包,这个jar包又依赖另一个jar包,项目编译时,maven会把直接引用和间接引用的jar包都下载到本地仓库。但是依赖传递有时又很麻烦,
因为很可能会造成依赖的冲突。
2、依赖冲突
当同一个项目中由于不同的jar包依赖了相同的jar包,此时就会发生依赖冲突的情况,如下图所示:

当项目中依赖了a和c,而a和c都依赖了b,这时就造成了冲突。为了避免冲突的产生,Maven 使用了两种策略来解决冲突,分别是短路优先
和声明优先。
依赖冲突不是指引入多个不同version的相同jar包,这种冲突,只能手动解决
在IDEA中,可以在pom.xml中,右键Maven--->Show Dependency,直接通过Ctrl+O查找具体某个jar,在pom文件中是否存在多个依赖

原文对依赖冲突有很详细的解释,原文地址在文章最上面
2.1、短路优先
短路优先的意识是,从项目一直到最终依赖的jar的距离,哪个距离短就依赖哪个,距离长的将被忽略掉。例如下图所示:
声明优先
声明优先的意思是,通过jar包声明的顺序来决定使用哪个,最先声明的jar包总是被选中,后声明的jar包则会被忽略,如下图所示:

依赖排除
如果我们只想引用我们直接依赖的jar包,而不想把间接依赖的jar包也引入的话,那可以使用依赖排除的方式,将间接引用的jar包排除掉,
如下面的配置所示:
<exclusions>
<exclusion>
<groupId>excluded.groupId</groupId>
<artifactId>excluded-artifactId</artifactId>
</exclusion>
</exclusions>
引入依赖的最佳实践
我们再添加依赖的时候,可能在运行的时候才发现依赖冲突,而实际上可以提前就发现问题
加入一个新的依赖的时候,先通过mvn dependency:tree形成依赖树,查看是否存在传递依赖,传递依赖中是否和依赖树中版本行程冲突,这时候可以提前解决
解决方案:
1、要使用哪个版本,我们是清楚的,那么能不能不管如何依赖传递,都可以进行版本锁定呢?
使用<dependencyManagement> [这种主要用于子模块的版本一致性中]
2、在依赖传递中,能不能去掉我们不想依赖的?
使用<exclusions> [在实际中我们可以在IDEA中直接利用插件帮助我们生成]
3、既然是最近依赖策略,那么我们就直接使用显式依赖指定版本,那不就是最靠近项目的么?
使用<dependency>
依赖管理
聚合
将多个项目同时运行就称为聚合,如下就是一个多模块的项目:
<packaging>pom</packaging>
<modules>
<module>module-</module>
<module>module-</module>
<module>module-</module>
</modules>
聚合的优势在于可以在一个地方编译多个pom文件。
PS:聚合时packaging必须要是pom
继承
跟java类的继承类似,Maven 的继承特性也会继承父pom中的依赖,假设我们定义了一个父pom:
<groupId>com.houyi</groupId>
<artifactId>maven-parent</artifactId>
<version>0.0.-SNAPSHOT</version> <dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.</version>
</dependency>
</dependencies>
</dependencyManagement>
然后在子pom中引入这个父pom:
<!-- 指定parent,说明是从哪个pom继承 -->
<parent>
<groupId>com.houyi</groupId>
<artifactId>maven-parent</artifactId>
<version>0.0.-SNAPSHOT</version>
<!-- 指定相对路径 -->
<relativePath>../maven-parent</relativePath>
</parent> <!-- 只需要指明groupId + artifactId,就可以到父pom找到了,无需指明版本 -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
使用dependencyManagement,可对依赖进行管理。子类只要不引用这个里面写的groupId + artifactId,则不会添加依赖,这样防止造成重复加了包:
如果不使用dependencyManagement,那么只要写了dependency,子pom中会全部添加到依赖中,而其中很多包可能都用不上。
插件
插件是 Maven 的核心,所有执行的操作都是基于插件来完成的。
为了让一个插件中可以实现众多的相类似的功能,Maven 为插件设定了目标,一个插件中有可能有多个目标。其实生命周期中的每个阶段都是
由插件的一个具体目标来执行的
例如可以用下面的方式配置一个插件:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.</version>
<!-- 配置执行 -->
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
配置目标 goal 的目的是:这样在执行 mvn package 的时候,就会自动执行 mvn source:jar-no-fork了,jar-no-fork这个目标是用来进行源码打包的。
除了可以在build元素中配置插件,当然也可以在parent项目中,用pluginManagement来配置,然后在子项目继承即可使用。
PS:
通过插件我们可以做很多事,比如通过mybatis-generator 我们可以生成很多DAO层的代码,再配合通用Mapper+lombok使用的话就可以使你的代码
非常简洁,绝对的生产力工具!
指令
下面列举一些常用的 maven 指令:

指令参数
上面列举的只是比较通用的命令,其实很多命令都可以携带参数以执行更精准的任务。
Maven命令可携带的参数类型如下:
-D 传入属性参数
比如命令:mvn package -Dmaven.test.skip=true
以-D开头,将 maven.test.skip 的值设为 true ,就是告诉maven打包的时候跳过单元测试。
-P 使用指定的Profile配置
比如项目开发需要有多个环境,一般为开发,测试,预发,正式4个环境,在pom.xml中的配置如下:
<profiles>
<profile>
<id>dev</id>
<properties>
<env>dev</env>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>qa</id>
<properties>
<env>qa</env>
</properties>
</profile>
<profile>
<id>pre</id>
<properties>
<env>pre</env>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<env>prod</env>
</properties>
</profile>
</profiles> ... <build>
<filters>
<filter>config/${env}.properties</filter>
</filters>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
profiles定义了各个环境的变量id,filters中定义了变量配置文件的地址,其中地址中的环境变量就是上面profile中定义的值,resources中是定义
哪些目录下的文件会被配置文件中定义的变量替换。
通过maven可以实现按不同环境进行打包部署,命令为:
mvn package -P dev
其中 dev 为环境的变量id,代表使用Id为 dev 的 profile。
-e 显示maven运行出错的信息
-o 离线执行命令,即不去远程仓库更新包
-X 显示maven允许的debug信息
-U 强制去远程更新snapshot的插件或依赖,默认每天只更新一次
举个例子
将自己的jar包部署到远程仓库去,可以使用 deploy 指令:
mvn deploy:deploy-file -DgroupId=<group-id> \
-DartifactId=<artifact-id> \
-Dversion=<version> \
-Dpackaging=<type-of-packaging> \
-Dfile=<path-to-file> \
-DrepositoryId=<id-to-map-on-server-section-of-settings.xml> \
-Durl=<url-of-the-repository-to-deploy>
最后说下我们为什么要学习maven,大概可以收获这些好处吧:
- 提高自己的生产力
- 更好的管理项目中的jar包
- 自己开发的jar包可以共享给别人
- 遇到jar包冲突问题可以不求人
。。。
日常开发需要掌握的Maven知识的更多相关文章
- IDEA的几个常用配置,日常开发必备。
用了IDEA有很长时间了,身边的同事朋友也都慢慢的开始都从Eclipse切换到IDEA了,其实无论是Eclipse还是IntelliJ IDEA都是开发工具而已,各自都有优点.但是刚从Eclipse切 ...
- IDEAL葵花宝典:java代码开发规范插件 (maven helper)解决maven 包冲突的问题
小编说到: 在我们日常开发当中常常我们会遇到JAR包冲突.找来找去还找不到很是烦人.那么所谓的JAR包冲突是指的什么那?JAR包冲突就是-引入的同一个JAR包却有好几个版本. 例如: 项目中引用了两个 ...
- Android开发需要了解的 IM 知识
引言 即便在通讯如此发达的今天,IM 也依然是诸多场景下非常重要的基础能力.因此做为 一名 Android 开发,不可避免的会遇到一些IM 相关的需求或问题.本文以一个Android开发的角度来讲述I ...
- Idea开发环境中搭建Maven并且使用Maven打包部署程序
1.配置Maven的环境变量 a.首先我们去maven官网下载Maven程序,解压到安装目录,如图所示: b.配置M2_HOME的环境变量,然后将该变量添加到Path中 备注:必须要有JAVA_HOM ...
- Centos 基础开发环境搭建之Maven私服nexus
hmaster 安装nexus及启动方式 /usr/local/nexus-2.6.3-01/bin ./nexus status Centos 基础开发环境搭建之Maven私服nexus . 软件 ...
- 日常开发使用SVN命令
现在把我日常开发中用到的svn命令总结出来,做个备忘,其实真正用到也就那几个. 如果遇到参数不知道使用或其它困难请使用:svn --help 得到帮助 1)检出: svn co svn地址 本地路径 ...
- 从日常开发说起,浅谈HTTP协议是做什么的。
引言 HTTP协议作为Web开发的基础一直被大多数人所熟知,不过相信有很多人只知其一不知其二.比如咱们经常用到的session会话机制是如何实现的,可能很多人都说不出来吧.其实session会话就是H ...
- Android开发学习必备的java知识
Android开发学习必备的java知识本讲内容:对象.标识符.关键字.变量.常量.字面值.基本数据类型.整数.浮点数.布尔型.字符型.赋值.注释 Java作为一门语言,必然有他的语法规则.学习编程语 ...
- 为什么选择 Intellij IDEA 作为日常开发工具
作为一个从事 Java 开发的程序员,每天离不开编辑器的帮助.还记得刚开始学习 Java 编程的时候,使用 Eclipse 作为日常开发工具.后来工作以后,需要使用 Intellij IDEA,刚开始 ...
随机推荐
- 实战c++中的vector系列--vector的一些异常
今天就写一写vector的一些异常.能够捕捉的异常. out_of_range 相当于数组的越界了.vector会自己主动增大容量,可是假设索引超出了当前的size.就会引发异常. #include& ...
- HttpURL连接远程serverGet和Post方式请求并返回数据
查看原文:http://www.ibloger.net/article/1813.html package cn.gis; import java.io.BufferedReader; import ...
- 十分简便的APK反编译(Mac 版本号 具体解释)
之前參考了网上大神们介绍的apk for mac 的反编译的文章,里面写的十分具体而有用,可是因为apk for mac中反编译细节十分繁琐,过程也相对照较复杂,针对这个缺陷本人对其反编译的过程进行 ...
- STM32学习之路-感觉自己走到了一个天大的坑里了!
先前兴致勃勃的来弄16位并口驱动LCD.本以为就须要改下LCD IC的初始化即可了,没想到弄了这么多天最终发现自己走进了一个深坑了 T T 原因是我的开发板是奋斗V5的, 它确实有MCU外扩IO口, ...
- MySQl 子查询,左右连接,多表连接学习笔记
1.子查询是指在还有一个查询语句中的SELECT子句. 例句: SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2); 当中, ...
- JavaScriptSerializer 序列号datatime时少了8小时
有人说主要的因素是在于JSON格式不直接支持日期和时间. 简单一点处理办法是ToLocalTime()一下:dt = dt.ToLocalTime(); 参考http://blog.csdn.net/ ...
- [办公自动化]如何在windows7中编辑hosts文件 (提示权限不够)
请按如下步骤尝试: 1.在开始菜单里,单击“所有程序”,找到“附件”,单击找到里面的“记事本”,右键,然后选择“以管理员身份运行”,如果有对话框,选择“是”.2.然后单击记事本窗口的“文件”菜单,选择 ...
- 网络学习笔记:TCP/IP连网和Internet
1.网关 由硬件和软件组成,实现不同网段间的数据传送. 常用路由器充当网关. 网关通常维护一份路由表,但只有少量的编址信息.它用这些信息把数据转发到知道更多信息的网关. 组成互联网骨干的网关称为核心网 ...
- 协方差矩阵与主成分分析PCA
今天看论文,作者是用主成分分析(PCA)的方法做的.仔细学习了一下,有一篇博客写的很好,介绍的深入浅出! 协方差:http://pinkyjie.com/2010/08/31/covariance/ ...
- ramfs、rootfs和initramfs【转】
ramfs, rootfs and initramfs October 17, 2005 Rob Landley <rob@landley.net> =================== ...