我认为Maven陡峭的学习曲线和匮乏的文档是当时最主要的问题。为了能改善这个问题,,我开始在博客中撰写各类关于Maven的中文博客,翻译了O’Reilly出版的《Maven权威指南》一书,并建立了国内的Maven中文社区,不定期的回答各类Maven相关问题,这在一定程度上推动了Maven这一优秀的技术在国内的传播
最佳实践老板Yin亲手烘焙咖啡豆、并能做出据说是苏州最好的咖啡—苏州十全街边的Solo咖啡馆
使用Maven最高效的方式永远是命令行
约定优于配置(Convention Over Configuration)
大多数Maven用户需要复制M2_HOME/conf/settings.xml文件到~/.m2/settings.xml
Maven用户可以选择配置$M2_HOME/conf/settings.xml或者~/.m2/settings.xml。
前者是全局范围的,整台机器上的所有用户都会直接受到该配置的影响,
而后者是用户范围的,只有当前用户才会受到该配置的影响
应该尽可能地不去修改任何Maven安装目录下的文件
在面向对象设计中,有个单一职责性原则,意指一个类应该只有一项职责,而不是糅合太多的功能
显式声明任何项目中直接用到的依赖。
环境变量的所以然
值得注意的是Path环境变量
当我们在cmd中输入命令时,Windows首先会在当前目录中寻找可执行文件或脚本,
如果没有找到,Windows会接着遍历环境变量Path中定义的路径。
由于将%M2_HOME%bin添加到了Path中,而这里%M2_HOME%实际上是引用了前面定义的另一个变量,其值是Maven的安装目录。
因此,Windows会在执行命令时搜索目录D:binapache-maven-3.0bin,而mvn执行脚本的位置就是这里
10年的这个版本,想让打包出来的jar包能用,还得引入一个插件
默认打包生成的jar是不能够直接运行的,
因为带有main方法的类信息不会添加到manifest中(打开jar文件中的meta-INF/MANIFEST.MF文件,将无法看到Main-Class一行)。
为了生成可执行的jar文件,需要借助maven-shade-plugin
裁剪构建Maven提供很多的命令行选项支持裁剪反应堆,输入mvn-h可以看到这些选项 构建管理
编译、运行单元测试、生成文档、打包和部署等烦琐且不起眼的工作上,这就是构建
这个生命周期包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有构建步骤
默认情况下,Maven构建的所有输出都在target/目录中;
接着执行resources:resources任务(未定义项目资源,暂且略过);
最后执行compiler:compile任务,将项目主代码编译至target/classes目录(编译好的类为com/juvenxu/mvnbook/helloworld/HelloWorld.Class)
该文件也位于target/输出目录中,它是根据artifact-version.jar规则进行命名的,如有需要,还可以使用finalName来自定义该文件的名称
Maven构建高度依赖于远程仓库,因此,当Internet不稳定的时候,Maven构建也会变得不稳定,甚至无法构建。
使用私服后,即使暂时没有Internet连接,由于私服中已经缓存了大量构件,Maven也仍然可以正常运行
mvn和mvnDebug有什么区别和关系呢
打开文件我们就可以看到,两者基本是一样的,
只是mvnDebug多了一条MAVEN_DEBUG_OPTS配置,
其作用就是在运行Maven时开启debug,以便调试Maven本身
网络检查
直接运行命令ping repo1.maven.org可以检查网络
我们可以运行telnet 218.14.227.1973128来检测该地址的该端口是否畅通。
如果得到出错信息,需要先获取正确的代理服务信息;
如果telnet连接正确,则输入ctrl+],然后q,回车,退出即可
通常需要设置MAVEN_OPTS的值为-Xms128m-Xmx512m Pom配置
groupId:定义当前Maven项目隶属的实际项目
artifactId:该元素定义实际项目中的一个Maven项目(模块),推荐的做法是使用实际项目名称作为artifactId的前缀
plugin元素在POM中的相对位置应该在下面
最后一个name元素声明了一个对于用户更为友好的项目名称,
虽然这不是必须的,但还是推荐为每个POM声明name,以方便信息交流
该Java类的包名是com.juvenxu.mvnbook.helloworld,这与之前在POM中定义的groupId和artifactId相吻合
单元测试
一个典型的单元测试包含三个步骤:
①准备测试类及数据;②执行要测试的行为;③检查结果
scope为依赖范围,若依赖范围为test则表示该依赖只对测试有效
在JUnit 3中,约定所有需要执行测试的方法都以test开头
针对接口测试是一个单元测试的最佳实践
在Maven执行测试(test)之前,它会先自动执行项目主资源处理、主代码编译、测试资源处理、测试代码编译等工作,这是Maven生命周期的一个特性
surefire是Maven中负责执行测试的插件,这里它运行测试用例HelloWorldTest,并且输出测试报告,显示一共运行了多少测试,失败了多少,出错了多少,跳过了多少
prepare()方法使用了@Before标注,表示在执行测试用例之前执行该方法
生命周期
Maven拥有三套相互独立的生命周期,它们分别为clean、default和site
Maven的生命周期与插件相互绑定,用以完成实际的构建任务。
具体而言,是生命周期的阶段与插件的目标相互绑定,以完成某个具体的构建任务
default生命周期的阶段与插件目标的绑定关系由项目打包类型所决定
执行test之前是会先执行compile的,执行package之前是会先执行test的,
而类似地,install之前会执行package
archetype我们实际上是在运行插件maven-archetype-plugin,注意冒号的分隔,其格式为groupId:artifactId:version:goal 依赖管理
当第二直接依赖的范围是compile的时候,传递性依赖的范围与第一直接依赖的范围一致;
当第二直接依赖的范围是test的时候,依赖不会得以传递;
当第二直接依赖的范围是provided的时候,只传递第一直接依赖范围也为provided的依赖,且传递性依赖的范围同样为provided;
当第二直接依赖的范围是runtime的时候,传递性依赖的范围与第一直接依赖的范围一致,但compile例外,此时传递性依赖的范围为runtime
代码中使用exclusions元素声明排除依赖,exclusions可以包含一个或者多个exclusion子元素,因此可以排除一个或者多个传递性依赖
Maven依赖调解(Dependency Mediation)的第一原则是:路径最近者优先
Maven定义了依赖调解的第二原则:第一声明者优先
XML代码片段中,使用元素表示mysql-connector-java和postgresql这两个依赖为可选依赖,它们只会对当前项目B产生影响,当其他项目依赖于B的时候,这两个依赖不会被传递
由于dependency:analyze只会分析编译主代码和测试代码需要用到的依赖,一些执行测试和运行时需要的依赖它就发现不了
Maven属性可以使用美元符号和大括弧环绕的方式引用Maven属性 Maven仓库
Maven自带的中央仓库使用的id为central,
如果其他的仓库声明也使用该id,就会覆盖中央仓库的配置
仓库信息可以直接配置在POM文件中,但是认证信息必须配置在settings.xml文件中
settings.xml中server元素的id必须与POM中需要认证的repository元素的id完全一致
id为该远程仓库的唯一标识,name是为了方便人阅读,关键的url表示该仓库的地址
可是当Maven需要的插件在本地仓库不存在时,它就不会去这些远程仓库查找。
Plugin管理Maven的生命周期是抽象的,其实际行为都由插件来完成如果不设置插件版本,其效果就和RELEASE一样,Maven只会解析最新的发布版本构件这是一种通用的写法,冒号前面是插件前缀,冒号后面是该插件的目标有很多插件的目标在编写时已经定义了默认绑定阶段参数-D是Java自带的,其功能是通过命令行设置一个Java系统属性,Maven简单地重用了该参数,在准备插件的时候检查系统属性,便实现了插件参数的配置插件前缀与groupId:artifactId是一一对应的 聚合继承
聚合POM与继承关系中的父POM的packaging都必须是pom,同时,聚合模块与继承关系中的父模块除了POM之外都没有实际的内容
前者主要是为了方便快速构建项目,后者主要是为了消除重复配置
在dependencyManagement元素下的依赖声明不会引入实际的依赖,不过它能够约束dependencies下的依赖使用
超级POM在文件$MAVEN_HOME/lib/maven-model-builder-x.x.x.jar中的org/apache/maven/model/pom-4.0.0.xml路径下
Nexus是典型的Java Web应用