Maven实战计划

2018年3月20日14点29分

前言

  • 接着上一篇JSON的文章,我又算是系统的学习了一遍Maven吧
  • 之前对Maven的使用中,只把它当作一个Jar包自动导入工具,对于它提供的很多其他功能几乎都不怎么用
  • 趁着恶补JSON知识的时候,顺手又来了一发《Maven实战》,算是提升码农搬砖效率的核心工程吧
  • 我记笔记只记录感觉是点睛之笔的语句,纯手敲,不粘贴,为的是在往完扫一本书的过程中记住这些散发着光亮的句子
  • 分享给大家当作看这本书的入口

优秀的构建工具

  • maven的用途之一就是服务于构建,能够自动化构建过程,从清理,编译,测试到生成报告,再到打包和部署
  • 我们一直在不停地寻找避免重复的方法。设计的重复,编码的重复,文档的重复,当然还有构建的重复。Maven最大化地消除了构建的重复,抽象了构建生命周期,并且为大部分的构建提供了已经实现的插件

不仅仅是构建工具

  • Maven还是一个依赖管理工具和项目信息管理工具
  • Maven也是一个约定大于配置的开源项目管理构建工具

编写主代码

  • 项目主代码与测试代码不同,项目的主代码会被打包到最终的构件中,比如Jar包,War包(web归档包),而测试代码只在运行测试时用到
  • src/main/java中的Java类的包名应该与groupId和artifactId相吻合
  • mvn clean compile:Maven编译命令
  • scope为依赖范围,若依赖范围为test表示该依赖只对测试有效,在主代码中import Junit会导致编译报错

典型单元测试

  1. 准备测试类及数据
  2. 执行要测试的行为
  3. 检查结果

历史原因Maven核心插件compiler

  • Maven的核心插件之一——compiler只支持编译Java1.3,因此需要配置该插件使其支持Java高版本
  • mvn clean test:编译并运行测试

打包

  • 项目最终的产出物-Jar|War
  • Maven默认打包类型为Jar
  • mvn clean package:编译并且打包

如何让其他的Maven项目引用这个Jar

  • mvn clean install:编译并将项目安装到Maven本地仓库中

maven-shade-plugin

  • maven默认打包生成的Jar包是不能够直接运行的,因为带有main方法的类信息不回添加到manifest中(打开jar文件中的META-INF/MANIFEST.MF文件,将无法看到Main-Class一行)
  • 为了生成可执行的Jar文件,需要借助maven-shade-plugin
  • 配置并重新运行mvn clean install,会生成两个Jar包,其中带有original-前缀的Jar包是原始Jar,依然为不可以运行的Jar包

通过简单案例学习Maven

需求用例

注册账户
主要场景:
    1,用户注册页面
    2,系统生成验证码图片
    3,用户输入想要的ID,Emial地址
    4,用于输入验证码
    ......
扩展场景:
    4a,用户无法看清验证码,请求重新生成
        1.跳转到步骤2
  • 注册账户=>主要场景=>扩展场景
  • 设计简要的界面原型

简要设计

接口

  • 详细了解了这个简单账户注册服务的需求之后,就能勾勒出该系统对外的接口
  • 定义了系统核心的接口之后,基于功能分割和方便复用的原则,再对系统进一步进行划分。这里基于包名划分模块,这也是在Java中比较常见的做法
  • ...service...系统的核心,它封装了所有下层细节,对外暴露简单的接口。这实际是一个Facade模式

坐标和依赖

  • Maven坐标为各种构件引入了秩序,任何一个构件必须明确定义自己的坐标,而一组Maven坐标是通过一些元素定义的,它们是groupId,artfactId,version,packaging,classifier

依赖范围

  • compile:编译依赖范围。如果没有指定,就会默认使用该依赖范围,此范围的Maven依赖,对于编译,测试,运行三种classpath都有效。典型的例子是spring-core,在编译,测试,运行的时候都需要使用该依赖
  • test:测试依赖范围。只对于测试classpath有效,典型为Junit,它只有在编译测试代码及运行测试的时候才需要
  • provided:已提供依赖范围,对于编译和测试classpath有效,但在运行的时候无效。典型是Servlet-api,编译和测试项目时需要该依赖,运行时由于容器提供,不需要Maven重复地引入一遍
  • runtime:运行时依赖范围,对于测试和运行classpath有效,但在编译主代码时无效。典型是JDBC驱动实现,项目主代码的编译只需要通过JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动

传递性依赖

  • ...Maven会解析各个直接依赖的POM,将那些必要的间接依赖以传递性依赖的形式引入到当前的项目中
  • 当依赖传递性造成问题的时候,我们需要清楚地知道该依赖性传递是从哪条依赖路径引入的。Maven依赖调解(Dependency Mediation)的第一原则是:路径最近者优先。当两个路径相同时,第一声明者优先的第二原则就生效

可选依赖

  • 使用<option></option>元素声明的依赖表示这个依赖不会被传递给依赖于此项目的项目
  • 在理想的情况下,是不应该使用可选依赖的,大部分情况下使用可选依赖的原因是某一个项目实现了多个特性,有悖于面向对象设计中的单一职责性原则

排除依赖

  • 使用<exclusion></exclusion>排除依赖,声明的时候只需要groupId和artifactId,而不需要version元素就可以唯一定位依赖图中的某个依赖

归类依赖

  • 通过在根元素下的<properties>下自定义属性值标签来实现对依赖版本号的统一管理

优化依赖

  • mvn dependency:list:查看当前项目的已解析依赖
  • mvn dependency:tree:产看该项目的依赖树
  • mvn dependency:analyze分析当前项目的依赖

仓库

何为Maven仓库

  • 对于Maven来说,每个用户只有一个本地仓库,但可以配置很多远程仓库
  • 最原始的本地仓库是空的,Maven必须知道至少一个可用的远程仓库,才能在执行Maven命令的时候下载到需要的构件
  • 私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用
  • 在repositories元素下,可以使用repository子元素声明一个或者多个远程仓库
  • 在Maven世界中,任何一个项目或者构建都必须有自己的版本,版本的值可能是1.0.0,1.3-alpha,2.1-SNAPSHOT

快照版本和发布版本

  • 快照版本只应该在组织内部的项目或者模块间依赖使用,因为这时,组织对于这些快照版本的依赖具有完全的理解及控制权
  • 项目不应该依赖于任何组织外部的快照版本依赖,这样的依赖会造成潜在的危险

生命周期和构建

  • Maven的生命周期就是为了所有的构建过程进行抽象和统一
  • Maven生命周期包含了项目的清理,初始化,编译,测试,打包,集成测试,验证,部署和站点等几乎所有的构建步骤。也就是说,几乎所有的项目的构建,杜能映射到这样一个生命周期上
  • Maven的生命周期是抽象的,这意味着生命周期本身不做任何实际的工作,在Maven的设计中,实际的任务(如编译源代码,执行测试用例集)都交由插件来完成。这种思想与设计模式中的模板方法(Template Method)非常相似
  • 模板方法模式在父类中定义算法的整体结构,子类可以通过实现或者重写父类的方法来控制实际的行为。这就既保证了算法有足够的可扩展性,又能够严格控制算法的整体结构

三套生命周期

  • Maven拥有三条相互独立的生命周期,分别是clean,default,site
  • clean目的是清理项目
  • default目的是构建项目
  • site目的是建立项目站点
  • 每个生命周期包含一些阶段(phase),这些阶段是有顺序的,并且后面的阶段依赖于前面的阶段。用户与Maven最直接的交互方式就是调用这些生命周期阶段

clean生命周期

  • pre-clean:执行一些清理前需要完成的工作
  • clean:清理上一次构建生成的文件
  • post-clean:执行一些清理后需要完成的工作

default生命周期

  • default生命周期定义了真正构建时所需要执行的所有步骤,它是所有生命周期中最核心的部分
  • validate
  • initialize
  • generate-sources
  • process-sources:处理项目主资源文件,一般来说是对src/main/resources目录的内容进行变量替换等工作后,复制到项目输出的主classpath目录中
  • generate-resources
  • process-resources
  • compile编译项目的主源码。一般来说是对src/main/java目录下的Java文件至项目输出的主classpath目录中
  • process-classes
  • generate-test-sources
  • process-test-sources:处理项目测试资源文件
  • test-compile:编译项目测试代码
  • process-test-classes
  • test:使用单元测试框架运行测试,测试代码不会被打包或部署
  • prepare-package
  • package:接受编译好的代码,打包成可发布的格式,如JAR
  • pre-integration-test
  • integration-test
  • post-integration-test
  • verify
  • install:将包安装到Maven本地仓库,供本地其他Maven项目使用
  • deploy:将最终的包复制到远程仓库,供其他开发人员和Maven项目使用

site生命周期

  • site生命周期的目的是建立和发布项目站点,Maven能够基于POM所包含的信息,自动生成一个友好的站点,方便团队交流和发布项目信息。该生命周期包含如下阶段:
  • pre-site:执行一些在生成项目站点之前需要完成的工作
  • site:生成项目站点文档
  • post-site:执行一些在生成项目站点之后需要完成的工作
  • site-deploy:将生成的项目站点发布到服务器上

命令行与生命周期

  • 从命令行执行Maven任务的最主要方式就是调用Maven的生命周期阶段
  • 各个生命周期是相互独立的,而一个生命周期的阶段是有前后依赖关系的
  • mvn clean:该命令调用clean生命周期的clean阶段
  • mvn test
  • mvn clean install:该命令调用clean生命周期的阶段和default生命周期的install阶段,在执行真正的项目构建之前,清理项目是一个很好的实践

聚合和继承

  • 为了解决软件的复杂性问题,通过各种方式对软件划分模块,以得到更清晰的设计以及更高的重用性。当把Maven应用到实际项目中时候,也需要将项目划分成不同的模块
  • Maven的聚合特性能够把项目的各个模块聚合在一起构建
  • Maven的继承特性则能帮助抽取各模块相同的依赖和插件等配置,在简化POM的同时,还能促进各个模块配置的一致性

使用Web自动测试工具测试

  • 可以用单元测试覆盖的代码就不应该依赖于Web页面测试
  • Web页面测试应该仅限于页面的层次,如JSP,CSS,JavaScript修改,其他代码测试修改(如数据访问),请编写单元测试

版本管理

  • 一个健康的项目通常有一个长期的,合理的版本演变过程
  • 理想的发布版本应当对应了项目某个时刻比较稳定的状态,包括源代码的状态以及构建的状态,应当满足如下条件

发布版本应当满足的条件

  1. 所有自动化测试应当全部通过
  2. 项目没有配置任何快照版本的依赖
  3. 项目没有配置任何快照版本的插件
  4. 项目所包含的代码已经全部提交到版本控制系统中

Maven版本号约定

<主版本>.<次版本>.<增量版本>-<里程碑版本>
  • 主版本表示项目的重大架构变更
  • 次版本表示较大范围内的功能增加和变化
  • 增量版本一般为重大Bug的修复
  • 里程碑版本,顾名思义,这往往指某一个版本的里程碑

灵活的构建

  • 一个优秀的构建系统必须足够灵活,它应该能让项目在不同的环境下都能成功地构建
  • Maven三个构建特性:属性,Profile,资源过滤

常用双子星属性

  • ${basedir}表示项目根目录
  • ${version}表示项目版本

POM属性

  • 用户可以使用该类属性引用POM文件中对应元素的值
  • ${project.artifactId}
  • ${project.build.sourceDirectory}:项目的主源码目录src/main/java
  • ${project.build.directory}:项目构建输出目录,默认为target
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容