Maven初入

maven 是一个项目管理工具, 它包含了一个 项目对象模型(Project Object Model POM), 一组标准集合, 一个项目生命周期(Project Lifecycle), 一个依赖管理系统(Dependency Management System), 和用来运行 定义在 生命周期阶段中插件目标的逻辑.

Maven的核心只做一些基础的事情, 解析XML文档, 管理生命周期, 插件, 仅此而已; Maven的主要职责是委派给各种各样的插件, 如编译源码, 打包二进制代码, 发布站点 和 其他构建任务, 而插件从 maven仓库获得.

文档参考自: Maven权威指南

Maven初步

安装自不必赘述, Maven的相关配置在 ~/.m2/settings.xml,

~/.m2/repository 是本地仓库目录.

maven核心概念

  1. 插件和目标

    就像在前面所提到过的, Maven的核心所做的工作很少, 大部分工作都会叫给插件来做, 一个插件 是一个或多个目标的集合, 插件的直观表现就是一个或多个jar包, 目标指的就是 某一个具体的方法, 可以配置相应的参数, 同时需要给定一部分必须参数;

    简写: pluginId:goalId

  2. 生命周期(Lifecycle)

    生命周期是包含在一个项目中一系列有序的阶段, 在maven中配有默认的生命周期, 以验证项目的基本完整性开始, 以把项目发布成产品结束.

    其中, 插件目标是可以附着在生命周期上的, 会随着生命周期的阶段 一步步执行, 当 maven执行一个阶段的时候, 他首先会有序执行前面的所有阶段, 并执行绑定在阶段上的默认目标, 到命令指定的那个阶段为止;

    recourses: recourses; Recourses插件的 recourses目标绑定在了 recourses阶段, 这个目标复制 src/main/recourses 下的所有资源 和 其他任何配置的资源目录, 到输出目录;

    compiler: compile 绑定到了 compile阶段,编译 src/main/java 下的所有源代码 和 其他任何配置的资源目录, 到输出目录.

    recourses: testRecourses Resources插件的 testRecourses目标绑定到了 test-recourses阶段, 对应 src/test/resources

    compiler: testCompile 对应 src/test/java

    surefire: test surefire插件的目标test 绑定到 test阶段, 这个目标运行所有的测试, 并创建那些 捕捉 详细测试结果的文件, 默认情况下, 如果有测试失败, 这个目标会终止

    jar:jar 绑定到 package阶段, 把输出目录打包成 jar文件.

  3. Maven 坐标

    POM为项目命名, 提供了项目的一组唯一标识符(坐标), 并通过 依赖(dependencies), 父(parents) 和 先决条件(prerequisite) 来定义和其他项目的关系.

    Maven定义了一组坐标, 他们可以用来标识一个项目, 一个依赖, 或者MavenPom里一个插件.

    GroupId: 团体, 公司, 组织等其他, 就是java中的 com.company.project

    artifactId: 项目标识

    version: 版本号, 一般会通过加上 "SNAPSHOT"标记, 标识正在开发中.

    packing(非必须): 默认为 jar, 项目打包后输出, war 表示web 项目.

    同时需要注意的是: 在 artifactId中最好不要使用 "."

  4. Maven仓库

    路径为, 相对于仓库根目录:

    /<groupId>/<artifactId>/<version>/<artifactId>-<version>.<packing>

  5. Maven依赖

    对于依赖, 目前只需要知道依赖具有传递性,即可.

Maven注意事项

  1. 优化, 降低依赖重复

    1. 上移共同的依赖至 dependencyManagement

      如果多于一个项目依赖于一个特定的依赖, 就可以在 dependencyManagement中列出这个依赖, 父POM包含一个版本和一组排除配置, 在子POM中需要使用 groupId和artifactId引用这个依赖, 如果依赖已经在 dependencyManagement中列出, 子项目可以额忽略版本和排除配置;

       <properties>
      <hibernate.annotation.version>3.3.0</hibernate.annotation.version>
      </properties>

      通过这种方式将版本信息定义为 常量, 通过 ${ }引用变量

       <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-annotation</artifactId>
      <version>${hibernate.hibernate.annotation.version}</version>
      </dependency>
    2. 为兄弟项目使用内置的 version 和 groupId

    3. 使用相同的 groupId 和 ${project.version}.

    4. 上移共同的 plugin 至 pluginManagement

    5. 显示的声明依赖, 不要通过依赖传递性来引用 jar包

    6. 使用 Maven Denpendency插件优化:

      通过 mvn dependency:analyze 对项目进行分析, 但增删依赖判断的先决条件是单元测试;

      在 analyze中, 生命周期依次为:

      recourses, compile, testRecourses, testCompile, analyze;

      会将执行中的错误, 未声明的 jar, 声明未使用的jar 种种体现出来.

      而使用 mvn dependency:tree , 会列出项目中所有的直接和传递性依赖.

    7. 几个帮助插件

      mvn help:active-profiles 列出当前构建中活动的 Profile

      mvn help:effective-pom 显示当前构建的实际 pom

      mvn help:effective-settings 打印实际的setting, 包含全局和用户级别的

      mvn help:describe 描述插件的属性, 无需在项目目录下运行, 但必须提供插件的 groupId 和 artifactId

      如: mvn help:describe -Dplugin=complier [Dmojo=compile] [-Dfull]

      第二个参数表示插件中的某一个目标, 第三个参数为目标的所有信息, 同时在:

      "-D<name>=<value>" 这种方式设定 调用 mvn 插件目标 ,传入目标中的参数中的 值. 需要注意的是, 这并非是 Maven的语法, 其实是 java 用来设置系统属性的方式.

Maven Pom

所有的 Maven POM 都继承自超级POM, 超级POM所处目录为: {Maven HOME}/lib/maven-model-builder-{Maven Version}.jar 内 org.apache.maven.model 下的 POM-4.0.0.xml.

文件主要定义了:

  1. 单独的远程仓库, https://repo.maven.apache.org/maven2

     <repositories>
    <repository>
    <id>central</id>
    <name>Central Repository</name>
    <url>https://repo.maven.apache.org/maven2</url>
    <layout>default</layout>
    <snapshots>
    <enabled>false</enabled>
    </snapshots>
    </repository>
    </repositories>
  2. 为核心插件提供了默认的版本

我们自己建立的 POM最顶层继承自 超级 POM, 其次是所有的 父级POM, 自上向下 会一层层 覆盖之前的默认配置, 通过 mvn help:effective 可以查看当前项目的有效pom.

下面就开始一步步看POM.xml文件中的配置:

  1. version

     <major version>.<minor version>.<incremental version>-<qualifier>
    
     1.3.5-beta-01

    其中1为主版本号, 3为次版本号, 5为增量版本号, beta-01为限定版本号(alpha 和 beta). 如果版本号符合规则要求, 则按照版本号来比较, 否则按照字符串规则来进行比较. 比如 a10 是 排在 a2前面的, 因此 a10属于旧版本, 但在我们的定义中, 却应该是相反的.

    版本界限配置方式:

    (loVersion, hiVersion) 不包含

    [loVersion, hiVersion] 包含

     <version>[3.8, 4.1.2]</version>

    当不指定上界/下界时, 则为以上/以下

    SNAPSHOT

    如果你在版本中使用了 字符串 SNAPSHOT, 表示项目正处于 活动的 开发状态, Maven会在安装 或部署的时候将 符号展开为 一个时间和日期,转换为 UTC.(也就是快照版本)

    如在创建的时候, 默认为 0.1-SNAPSHOT, 而后将项目部署到了 Maven仓库, Maven会将版本展开为 0.1-YYYYMMDD-HH24MISS-1, 这里的时间 为UTC时间.

    如果项目依赖的一个组件正处于开发过程中, 依赖它的 SNAPSHOT版本, 则在运行构建的时候, 会自动从仓库下载最新的 SNAPSHOT, 同时, 要依赖 SNAPSHOT版本, 用户必须在 POM中使用 repository 和 pluginRepository 开启下载 SNAPSHOT功能.

     <!--选择对应的 坐标, 将 enabled 属性设置为 true 即可-->
    <repositories>
    <repository>
    <id>central</id>
    <name>Central Repository</name>
    <url>https://repo.maven.apache.org/maven2</url>
    <snapshots>
    <enabled>true</enabled>
    </snapshots>
    </repository>
    </repositories> <pluginRepositories>
    <pluginRepository>
    <id>central</id>
    <name>Central Repository</name>
    <url>https://repo.maven.apache.org/maven2</url>
    <snapshots>
    <enabled>true</enabled>
    </snapshots>
    </pluginRepository>
    </pluginRepositories>

    而发布到 非 snapshot的 Maven仓库的构建不能依赖于 SNAPSHOT版本, 仅用于开发过程.

    LATEST 和 RELEASE

    当依赖于一个插件 或 依赖, 可以使用特殊值:

    LATEST: 最新发布的版本 或 快照版.

    RELEASE: 仓库中 最后一个非快照版本.

    在项目发布的时候, 尽量不要使用 这三个关键字, 仅在开发时使用

  2. 变量引用

    在Maven中有三个内置隐士变量:

    env: 表示 environment, 系统的环境变量, 如 ${env.PATH}, 需要注意的是需要大写, 如 ${env.JAVA_HOME}

    settings: 这个指的是 settings.xml中的属性, 但一直引用不成功.

    project: 引用当前 project中的属性 如 ${project.artifactId}.

    ${basedir}, 可以访问当前项目根目录

    Java系统属性

    凡是可以被 java.lang.System 中的 getProperties()方法访问的属性

    可以在Java中通过 System.getProperties().list(System.out); 在Maven中通过 ${} 直接访问, 如 ${java.runtime.name}

    自定义属性:

     <properties>
    <attribute>value</attribute>
    </properties>

    访问方式即: ${attribute.value}

  3. 依赖范围

     <version>1.0</version>
    <scope>test</scope>

    compile: 编译范围, 默认范围, 在所有的classpath都可以使用, 也会被打包

    provided: 已提供范围, 只有当 JDK/容器已经提供该依赖之后才使用, 如在 开发中 需要 Servlet API编译一个 Servlet, 但在打包发布之后这部分应该由 容器/服务器本身来提供. 仅在编译时可用. 不可传递, 不会打包.

    runtime: 运行时范围, 在编译时不需要, 在运行时需要.

    test: 测试范围, 仅在测试时需要, 测试运行, 测试编译.

    system: 系统范围, 必须提供 systemPath, 即本地jar文件的路径.

    可选依赖:

     <version>1.0</version>
    <optional>true</optional>

    通过这种方式生命的依赖, 不会被传递. 需要在子项目中再度生命

  4. 依赖的传递

    test范围不会被传递, provided范围 仅在 provided中被传递, runtime 和 compile 在 四种范围都会被传递.

    e.g. : A 包含对 B的测试范围依赖, B 包含对 C的编译时依赖, 则 C为A的测试范围依赖

     A:
    <dependency>
    <groupId>B</groupId>
    <artifactId>B</artifactId>
    <version>1.0</version>
    <scope>test</scope>
    </dependency>
    B:
    <dependency>
    <groupId>C</groupId>
    <artifactId>C</artifactId>
    <version>1.0</version>
    </dependency>

    e.g. : A包含对 B的测试范围依赖, B包含对C的测试范围依赖, 则 A与C无关.

     A:
    <dependency>
    <groupId>B</groupId>
    <artifactId>B</artifactId>
    <version>1.0</version>
    <scope>test</scope>
    </dependency>
    B:
    <dependency>
    <groupId>C</groupId>
    <artifactId>C</artifactId>
    <version>1.0</version>
    <scope>test</scope>
    </dependency>

    依赖追踪:

    在 Maven中, 如果多个项目依赖于同一个 project, 则Maven会找到 所有依赖中版本最新的 依赖, 作为最终的选择, 所以可以排除对应的依赖, 且同时 可以 更换自己想要的版本.

    e.g.:

     <dependency>
    <groupId>B</groupId>
    <artifactId>B</artifactId>
    <version>1.0</version>
    <exclusions>
    <exclusion>
    <groupId>C</groupId>
    <artifactId>C</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
  5. 依赖管理

    这在之前 优化 已经提到, 采取在父级项目中定义 dependencyManagement, pluginManagement, 在子级中沿用父级的版本, 仅需要列出所选取的 依赖坐标, 而无需再度定义版本(如果定义子级版本, 父级就会被忽略);

    多模块项目:

     <modules>
    <module>project-a</module>
    <module>project-b</module>
    </modules>

    多模块项目的打包总是一个 POM 而非构建, 其中各个模块可以为 POM 或者 jar

    项目继承:

     <parent>
    <groupId>C</groupId>
    <artifactId>C</artifactId>
    <version>1.0-SNAPSHOT</version>
    </parent>

    可以被继承的项目:

    • 定义符: groupId 和 artifactId 必须有一个被重写, 不能有完全相同的坐标.
    • 依赖
    • 开发者和贡献者
    • 插件列表
    • 报告列表
    • 插件执行
    • 插件配置

    继承中, 当 父级 POM 在 父目录../pom.xml 或者 在 本地仓库目录时 可用, 否则的话需要指明 父级POM的相对位置.

      <parent>
    <groupId>C</groupId>
    <artifactId>C</artifactId>
    <version>1.0-SNAPSHOT</version>
    <relativePath>../a-parent/pom.xml</relativePath>
    </parent>

暂时告一段落.

Maven初步的更多相关文章

  1. Maven初步接触

    最近随着搜资料,网上这样的字眼越来越多,我了解到这是构建项目的一种方式,于是准备简单看一下 首先粘几篇文章,作为学习的初步资料 Maven入门 http://blog.csdn.net/prstaxy ...

  2. (一)Maven初步了解与认识

    Apache Maven是一个软件项目管理的综合工具.基于项目对象模型(POM)的概念,提供了帮助管理构建.文档.报告.依赖.发布等方法,Maven简化和标准化项目建设过程.处理编译,分配,文档,团队 ...

  3. Maven初步搭建 (一)

    什么是maven? 也许很多人开始的时候跟我一样,在看了很多工程之后都不知道这个鸟东西到底是用来干嘛用的!:-D 一个东西之所以会出现是有其原因的,譬如Linus大神写git. Maven项目对象模型 ...

  4. maven初步入门demo

    Maven是跨平台的项目管理工具.作为Apache组织中的一个颇为成功的开源项目,主要服务于基于java平台的项目构建.依赖管理和项目信息管理. maven本身使用java开发而成,所以使用前确保电脑 ...

  5. SSH深度历险(四) Maven初步学习

    这几天接触这个词,很多遍了,只是浅显的体会到它在GXPT中的好处,功能之强大,又通过网络查询了资料进一步的认识学习了,和大家分享. Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理 ...

  6. Maven初步踩坑

    2015-02-08 今天创建maven项目,要从中央仓库下载一堆包到本地仓库,等了好久.结果下好了之后,maven项目上有个感叹号,也没有发现代码里哪配置有错误. 和实验室好多小伙伴一起交流 也没找 ...

  7. SSH深度历险(四) Maven初步学�

    这几天接触这个词,非常多遍了,仅仅是浅显的体会到它在GXPT中的优点,功能之强大,又通过网络查询了资料进一步的认识学习了,和大家分享. Maven是基于项目对象模型(POM),能够通过一小段描写叙述信 ...

  8. maven初步了解

    目标:创建一个父maven项目,有两个子项目分别为serverCenter,dbConnector. 建议:全程不要导入Jar包,全部使用maven依赖的方式导入包. 1.创建maven项目 这个创建 ...

  9. 关于Maven的安装及初步使用

    关于Maven的初步使用 1.  下载: 进入http://maven.apache.org/download.cgi下载  Maven 3.3.1 2.  将压缩包解压到自己的硬盘中,最好放在某个盘 ...

随机推荐

  1. Oracle之 11gR2 RAC 修改监听器端口号的步骤

    Oracle 11gR2 RAC 修改监听器端口号的步骤 说明:192.168.188.181 为public ip1192.168.188.182 为public ip2192.168.188.18 ...

  2. iframe标签里面的页面元素只读

    iframe标签里面的页面元素只读,可以通过设置一个只读的透明div进行遮罩实现. html代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1 ...

  3. ThinkPHP3.2中英文切换!

    小伙伴们好久不见!!!   最近公司项目版本升级,小梦已经忙成了狗,无暇顾及文章,今天抽时间写一篇助助兴!   用Thinkphp这个国产框架已经2年多了,现在有一个小功能:网站中英文切换功能,当然这 ...

  4. JavaScript call()和apply()

    ECMAScript规范给所有函数都定义了call()与apply()两个方法,call()与apply()的第一个参数都是需要调用的函数对象,在函数体内这个参数就是this的值,剩余的参数是需要传递 ...

  5. Python 操作 GA API 指南

    因为需要写一个 Blog Feature 的缘故,所以接触了下 GA 的 Python API,发现 G 家的 API 不是那么直观,比较绕,但是,在使用过程中发现其实 G 家的 API 设计挺有意思 ...

  6. HDU 1728 逃离迷宫(DFS经典题,比赛手残写废题)

    逃离迷宫 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  7. Vijos P1448 校门外的树【多解,线段树,树状数组,括号序列法+暴力优化】

    校门外的树 描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的…… 如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作: K=1,K= ...

  8. UVA 572 dfs求连通块

    The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSu ...

  9. c语言基础学习07_关于指针的复习

    ============================================================================= 指针变量之间赋值是需要兼容的. 例如:int ...

  10. Django 用散列隐藏数据库中主键ID

    最近看到了一篇讲Django性能测试和优化的文章, 文中除了提到了很多有用的优化方法, 演示程序的数据库模型写法我觉得也很值得参考, 在这单独记录下. 原文的演示代码有些问题, 我改进了下, 这里可以 ...