更新时间: 2019-12-17 17:54:49       分类: 学习笔记


Maven不只是一个依赖管理工具

1. 坐标与依赖

为了能够自动化地解析任何一个Java构件, Maven必须将它们唯一标识, 这就是依赖管理的底层基础-坐标.

坐标

e.g

<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
<packaging>jar</packaging>

由 groupId, artifactId, version, packaging 和 classfier 唯一标记的一个组件。

undefined

依赖

e.g.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>4.2.7.RELEASE</version>

    <type>jar</type>
    <scope>compile</scope>
    <optional>false</optional>
    <exclusions>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </exclusion>
    </exclusions>
</dependency>
  1. 依赖传递

    引入一个依赖的时候不用考虑这个依赖的依赖。比如引入spring core的时候,不用考虑spring core本身依赖的其他包,maven会自动解析并引入相关的依赖。

    不过也正因如此,会出现同一个依赖的不同版本被重复引入,即常见的依赖冲突,这里要了解maven的处理原则,即路径最近优先第一声明者优先,借助依赖树可以更方便地解决此类问题。

  2. 依赖构成

    undefined

  3. 依赖管理

    参见maven dependency插件

仓库

仓库(Repository)是集中储存管理 依赖、插件、及项目构建输出的地方

分为两类,本地仓库(~/.m2)和远程仓库(私有、公共)

生命周期与插件

Maven 将所有项目的构建过程统一抽象成一套生命周期: 项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成 … 几乎所有项目的构建,都能映射到这一组生命周期上. 但生命周期是抽象的(Maven的生命周期本身是不做任何实际工作), 任务执行(如编译源代码)均交由插件完成. 其中每个构建步骤都可以绑定一个或多个插件的目标,而且Maven为大多数构建步骤都编写并绑定了默认插件.当用户有特殊需要的时候, 也可以配置插件定制构建行为, 甚至自己编写插件.

生命周期

maven具有三套互相独立的生命周期:clean、default和site。每套生命周期内部由不同的phase阶段组成(phase有顺序依赖)

插件

生命周期中不同的阶段phase与插件的目标goal相互绑定,用以完成实际的构建任务。

对于插件而言,为了能够复用代码,一般可以有很多不同的功能,也就是有很多的目标,如mvn compiler: complie,就是执行了maven-compiler-plugin插件的compile功能(goal),该目标绑定了default生命周期的complie阶段。

默认内置绑定

在不特别指定phase的情况下,maven的默认plugin绑定如下:

undefined

undefined

undefined

自定义绑定

如果想使用某个第三方的插件的目标来指定生命阶段中的某个phase,可以通过build.plugins.plugin标签进行绑定,举例如下:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-source-plugin</artifactId>
            <version>3.0.0</version>
            <executions>
                <execution>
                    <id>attach-sources</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>jar-no-fork</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

上面这个例子使用了maven-source-plugin插件的jar-no-fork目标(功能),并把它绑定在default生命周期的verify阶段。可以使用多个execution标签来绑定多个不同的phase。

模块化:聚合与继承

聚合

项目结构越来越复杂,开发人员就不得不将整个项目拆分成几个不同的小模块来并行开发。但最终整个项目要一同打包部署,如果逐个模块进行构建再手动合并,未免显得太过累赘。因此maven便推出了模块聚合的功能,将整个项目聚合成一个完成的大模块,再进行构建。

举例:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.vdian.feedcenter</groupId>
    <artifactId>feedcenter-push</artifactId>
    <packaging>pom</packaging>
    <version>1.0.0.SNAPSHOT</version>

    <modules>
        <module>feedcenter-push-client</module>
        <module>feedcenter-push-core</module>
        <module>feedcenter-push-web</module>
    </modules>

</project>

使用modules标签来声明和聚合子模块。注意这里的packing标签,必须要声明为pom类型才可以实现聚合构建。

这也是我们在一个项目的根pom文件中最常看见的一种结构。

继承

在maven中,子模块可以继承父pom中的一些内容,以简化项目整体的管理成本。

父pom

举例:

	<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.vdian.feedcenter</groupId>
    <artifactId>feedcenter-push</artifactId>
    <packaging>pom</packaging>
    <version>1.0.0.SNAPSHOT</version>

    <modules>
        <module>feedcenter-push-client</module>
        <module>feedcenter-push-core</module>
        <module>feedcenter-push-web</module>
    </modules>

    <properties>
        <finalName>feedcenter-push</finalName>
        <warName>${finalName}.war</warName>
        <spring.version>4.0.6.RELEASE</spring.version>
        <junit.version>4.12</junit.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <warExplodedDirectory>exploded/${warName}</warExplodedDirectory>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>

           <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-source-plugin</artifactId>
                    <version>3.0.0</version>
                    <executions>
                        <execution>
                            <id>attach-sources</id>
                            <phase>verify</phase>
                            <goals>
                                <goal>jar-no-fork</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

子POM

举例:

	<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <groupId>com.vdian.feedcenter</groupId>
        <artifactId>feedcenter-push</artifactId>
        <version>1.0.0.SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>feedcenter-push-client</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

可以看到子pom不必声明自己的groupId和version等,而是会根据parent继承父pom,具体可以继承的元素包括:

这样做的优势就是可以在父POM中对依赖插件等进行统一的管理,不必逐个模块地解决冲突等问题。

打包

这里对一直以来都没怎么搞明白的maven打包机制进行一个深层次的梳理

首先,打包是什么?很简单,就是将项目中的各种文件,比如源代码、编译生成的字节码、配置文件、文档,按照规范的格式生成归档,然后压缩进一个包文件(jar,war,tar.gz等)里,方便传输和分发。

packaging

每一个maven项目都需要定义POM元素packaging来指定项目的打包形式,默认为jar。

简单测试:执行mvn package操作,会发现jar和war使用了不同的插件,打包流程也不一样。因此可以说,打包的具体行为,是由绑定到packaing上的插件来操控的。


评论

还没有评论