maven完结版,入门到精通。

START

在这里插入图片描述

Maven

当没有学Maven的时候,项目需要我们去手动自行构建,而且idea,eclipse,甚至一些其他开发工具的构建方式是不一样的。那么有没有一种工具,可以帮助我们构建项目,无需手动构建,只需要通过配置即可。

Maven 功能

Maven 能够帮助我们完成以下工作:

  • 构建
  • 文档生成
  • 统一管理jar包,自动导入jar及其依赖。
  • 项目移植之后不需要安装开发工具,只需要maven加命令就可以跑起来。
  • 使我们的项目流水线成为可能,只需要加简单的命令我们就可以完成项目的编译,打包,发布等工作。

Maven的优势

  1. 优势一: 相同的项目结构

使用Maven管理的Java 项目都有着相同的项目结构

  • 有一个pom.xml 用于维护当前项目都用了那些jar包

  • 所有的java代码都放在 src/main/java

  • 所有的测试代码都放在src/test/java

  1. 优势二:统一维护jar包

比如说有3个Java 项目,这些项目都不是maven风格。那么这3个项目,就会各自维护一套jar包。 而其中有些jar包是相同的。

而maven风格的项目,首先把所有的jar包都放在"maven仓库“ 里,然后哪个项目需要用到这个jar包,只需要给出jar包的名称和版本号就行了。如下所示:

<dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
  1. 优势三:模块划分

平时我们开发项目时,一般都是一个项目就是一个工程。我们划分模块时,都是使用package来进行划分。但是,当项目很大时,有很多子模块时,即使是package来进行划分,也是让人眼花缭乱。此时可借助Maven将一个项目拆分成多个工程,最好是一个模块对应一个工程,利于分工协作。而且模块之间还是可以发送消息的。

Maven的特点

  • 项目遵循统一的规则

  • 一个庞大且不断增长的库

  • 可扩展,能够轻松编写 Java 或脚本语言的插件

  • 项目信息的一致性站点 − 使用与构建过程相同的元数据,Maven 能够生成一个网站或PDF,包括您要添加的任何文档,并添加到关于项目开发状态的标准报告中。
  • 发布管理和发布单独的输出 − Maven 将不需要额外的配置,就可以与源代码管理系统(如 Subversion 或 Git)集成,并可以基于某个标签管理项目的发布。它也可以将其发布到分发位置供其他项目使用。Maven 能够发布单独的输出,如 JAR,包含其他依赖和文档的归档,或者作为源代码发布。
  • 向后兼容性 − 您可以很轻松的从旧版本 Maven 的多个模块移植到 Maven 3 中。
  • 子项目使用父项目依赖时,正常情况子项目应该继承父项目依赖,无需使用版本号,
  • 并行构建 − 编译的速度能普遍提高20 - 50 %。
  • 更好的错误报告 − Maven 改进了错误报告,它为您提供了 Maven wiki 页面的链接,您可以点击链接查看错误的完整描述。

Maven下载及其安装

下载地址:http://maven.apache.org/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EYTbk0Yv-1591469800210)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20200606112252539.png)]

Apache软件基金会(也就是Apache Software Foundation,简称为ASF),是专门为支持开源软件项目而办的一个非盈利性组织。在它所支持的Apache项目与子项目中,所发行的软件产品都遵循Apache许可证(Apache License)。

安装及配置环境(学过Java的都会)

  1. 解压
  2. 配置MAVEN_HOME
  3. 配置 path,%MAVEN_HOME%\bin
  4. cmd 执行mvn-v ,出现 maven 的版本号及配置成功。

Maven核心全局配置文件

去 Maven 安装路径下的 conf 文件夹下 用记事本(其他软件)打开 settings.xml 文件

配置路径(路径是你自己的路径,当你不配置这个jar包默认会往你的C:/…/.m2文件夹下下载)

<localRepository>D:/repository</localRepository>

配置阿里云镜像(当你需要下载 jar 时,系统默认会去 maven 中央仓库去下载,国内访问 下载会很慢,所以配置一个阿里云镜像,让它去阿里云仓库去下载)

<mirrors>
  <mirror>
    <id>alimaven</id>
    <name>aliyun maven</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
    <mirrorOf>central</mirrorOf>
  </mirror>
<mirrors>

配置全局编译 jdk 版本

<profile>  
  <id>jdk-1.8</id>  
  <activation>  
  <activeByDefault>true</activeByDefault>  
  <jdk>1.8</jdk>  
   </activation>  
  <properties>  
    <maven.compiler.source>1.8</maven.compiler.source>  
    <maven.compiler.target>1.8</maven.compiler.target>  
    <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>  
  </properties>  
</profile>

Maven 的目录

src                
    |--main
    	|--java     源代码目录
    	|--resources   资源目录   
    |--test
    	|--java     测试代码目录
    	|--resources   测试资源目录
|--target
    |--classes    编译后的class文件目录
    |--test-classes 编译后的测试class文件目录
pom.xml       Maven工程配置文件

pom.xml 的基本要求:

<?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">
 
    <!-- 模型版本 -->
    <modelVersion>4.0.0</modelVersion>
    <!-- 公司或者组织的唯一标志,并且配置时生成的路径也是由此生成, 如com.xinzhi,maven会将该项目打成的jar包放本地路径:/com/xinzhi -->
    <groupId>com.xinzhi</groupId>
 
    <!-- 项目的唯一ID,一个groupId下面可能多个项目,就是靠artifactId来区分的 -->
    <artifactId>project</artifactId>
 
    <!-- 版本号 -->
    <version>1.0</version>
</project>

Maven 生命周期

Maven生命周期就是描述了一个项目从源代码到部署的整个周期(由以下几个阶段的序列组成)

img

Maven 有以下三个标准的生命周期:

  • clean:项目清理的处理,就是我们经常做的,删除out文件夹
  • default(或 build):项目部署的处理,进行项目编译打包等工作
  • site:项目站点文档创建的处理,生成项目报告,站点,发布站点

默认(default)的声明周期包括以下阶段

阶段 处理 描述
验证 validate 验证项目 验证项目是否正确且所有必须信息是可用的
编译 compile 执行编译 源代码编译在此阶段完成
测试 Test 测试 使用适当的单元测试框架(例如JUnit)运行测试。
包装 package 打包 创建Jar/war包如在 pom.xml 中定义提及的包
检查 verify 检查 对集成测试的结果进行检查,以保证质量达标
安装 install 安装 安装打包的项目到本地仓库,以供其他项目使用
部署 deploy 部署 拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程
mvn install

此命令在执行安装之前按顺序(验证(validate),编译(compile),打包(package)等)执行每个默认生命周期阶段。在这种情况下,您只需要调用最后一个构建阶段来执行,安装(install)。

mvn clean deploy

相同的命令可以在多模块场景(即具有一个或多个子项目的项目)中使用。Maven遍历每个子项目并执行清洁(clean),然后执行部署(deploy)(包括所有之前的构建阶段步骤)。
注意:在我们开发阶段,有一些生命周期的阶段,比如验证(validate)这些,基本很少用到。只要使用关键的几
个基本能满足需求。

Clean 生命周期

当我们执行 mvn post-clean 命令时,Maven 调用 clean 生命周期,它包含以下阶段:

  • pre-clean:执行一些需要在clean之前完成的工作
  • clean:移除所有上一次构建生成的文件
  • post-clean:执行一些需要在clean之后立刻完成的工作

Maven的常用命令

命令 说明
mvn –version 显示版本信息
mvn clean 清理项目生产的临时文件,一般是模块下的target目录
mvn compile 编译源代码,一般编译模块下的src/main/java目录
mvn package 项目打包工具,会在模块下的target目录生成jar或war等文件
mvn test 测试命令,或执行src/test/java/下junit的测试用例
mvn install 将打包的jar/war文件复制到你的本地仓库中,供其他模块使用
mvn deploy 将打包的文件发布到远程参考,提供其他人员进行下载依赖
mvn site 生成项目相关信息的网站
mvn dependency:tree 打印出项目的整个依赖树
mvn archetype:generate 创建Maven的普通java项目
mvn tomcat:run 在tomcat容器中运行web应用

在idea中配置Maven

把画红线的东西全部配置成自己的。最后一个是仓库,在你的其他盘找一个地方新建repository文件夹,自己要知道,选中,如果勾选不了就选择都选override。

如果不选择仓库会把jar包下载至C:/Users/…/.m2/repository 文件下,不好维护,还占用c盘空间。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xPPDB1eI-1591469800213)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20200606151914396.png)]

两处都要配置,一个是当前项目的maven配置,一个是新建项目的maven配置。(我的idea是19版本的,和20版本的位置有差别,但设置都一致)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fNfAEiEh-1591469800215)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20200606152011412.png)]

Maven依赖

管理包依赖是 Maven 核心功能之一,下面通过如何引入 jar 包;如何解析 jar 包依赖;包冲突是如何产生;如何解决包冲突;依赖管理解决什么问题;什么是依赖范围;使用包依赖的最佳实践等 6 个问题来介绍。

Maven 远程仓库:https://mvnrepository.com/

Maven 阿里云远程仓库:https://maven.aliyun.com/mvn/search

如何引入 jar 包

在代码开发时,如果需要使用第三方 jar 包提供的类库,那么需要在 pom.xml 加入该 jar 包依赖。

例如:使用 zookeeper client

<dependencies>
  <!-- https://mvnrepository.com/artifact/org.apache.hadoop/zookeeper -->
  <dependency>
      <groupId>org.apache.hadoop</groupId>
      <artifactId>zookeeper</artifactId>
      <version>3.3.1</version>
  </dependency>
</dependencies>

Maven 如何解析 jar 包依赖——传递依赖

如上所述,在 pom.xml 中引入 zookeeper jar 包依赖,当 Maven 解析该依赖时,需要引入的 jar 包不仅仅只有 zookeeper,还会有 zookeeper 内部依赖的 jar 包,还会有 zookeeper 内部依赖的 jar 包依赖的 jar 包…,依赖关系不断传递,直至没有依赖。

例如:上述 pom.xml 引入 zookeeper 依赖,实际引入的 jar 包有:img

包冲突如何产生?

举个🌰:假设 A->B->C->D1, E->F->D2,D1,D2 分别为 D 的不同版本。
如果 pom.xml 文件中引入了 A 和 E 之后,按照 Maven 传递依赖原则,工程内需要引入的实际 Jar 包将会有:A B C D1 和 E F D2,因此 D1,D2 将会产生包冲突。

如何解决包冲突

Maven 解析 pom.xml 文件时,同一个 jar 包只会保留一个,这样有效的避免因引入两个 jar 包导致的工程运行不稳定性。

Maven 默认处理策略

  • 最短路径优先

Maven 面对 D1 和 D2 时,会默认选择最短路径的那个 jar 包,即 D2。E->F->D2 比 A->B->C->D1 路径短 1。

  • 最先声明优先

如果路径一样的话,举个🌰: A->B->C1, E->F->C2 ,两个依赖路径长度都是 2,那么就选择最先声明

移除依赖

如果我们不想通过 A->B->->D1 引入 D1 的话,那么我们在声明引入 A 的时候将 D1 排除掉,这样也避免了包冲突。

举个🌰:将 zookeeper 的 jline 依赖排除

<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.3.1</version>
    <exclusions>
        <exclusion>
            <groupId>jline</groupId>
            <artifactId>jline</artifactId>
        </exclusion>
    </exclusions>
</dependency>

检测包冲突工具

mvn dependency:help
mvn dependency:analyze
mvn dependency:tree
mvn dependency:tree -Dverbose

Maven依赖范围

classpath (类路径) 就是编译好的 class 文件所在的路径事实上,就是我们的类加载器(classloader) 就是去对应的 classpath 中加载 class 二进制文件。

maven项目:

maven工程会将 src/main/java 和 src/main/resources 文件夹下的文件全部打包在classpath中。运行时他们两个的文件夹下的文件会被放在一个文件夹下。

maven 项目不同的阶段引入到classpath中的依赖是不同的,例如:

  • 编译时 ,maven 会将与编译相关的依赖引入classpath中
  • 测试时 ,maven会将测试相关的的依赖引入到classpath中
  • 运行时 ,maven会将与运行相关的依赖引入classpath中

而依赖范围就是用来控制依赖于这三种classpath的关系。

scope标签就是依赖范围的配置

有些jar包(如selvlet-api)运行时其实是不需要的,因为tomcat里有,但编译时是需要的,因为编译的时候没有tomcat环境。

有些jar只在测试的时候才能用到。比如junit,真是运行不需要的。

有些jar运行,测试时必须要有,编译时不需要,如jdbc驱动,编译时用的都是jdk中的接口,运行时我们才使用反射注册了驱动。

类似以上的这些jar包不是说使用默认的compile一定不行,但是设置成合适的范围更好,当然有事会有问题,比如你引入的servlet-api和tomcat自带的不一样,就会出问题。

编译依赖范围(compile)

如果没有指定,就会默认使用该依赖范围。使用此依赖范围的maven依赖,对于编译 测试 运行三种的classpath都有效。

举个简单的例子,假如项目中有 fastjson 的依赖,那么 fastjson 不管是在编译,测试,还是运行都会被用到,因此 fastjson 必须是编译范围(构件默认的是编译范围,所以依赖范围是编译范围的无须显示指定)

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.68</version>
</dependency>

测试依赖范围(test)

使用此依赖范围的Maven依赖,只对于测试的classpath有效,在编译主代码或者运行主代码的时候都无法依赖此类依赖。典型的例子是jUnit,它只有在编译测试代码及运行测试代码的时候才有效。所以它的依赖范围是测试,因此它的依赖范围需要显示指定为
test,当然不显示指定依赖范围也不会报错,但是该依赖会被加入到编译和运行的classpath中,造
成不必要的浪费 。

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.7</version>
  <scope>test</scope>
</dependency>

已提供依赖范围(provided)

使用此依赖范围的maven依赖,对于编译和测试classpath有效,但在运行时无效。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行的时候,由于容器已经提供,就不需要maven重复地引入一遍。打包的时候可以不用包进去,别的设施会提供。事实上该依赖理论上可以参与编译,测试,运行等周期。相当于compile,但是打包阶段做了exclude操作

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.1</version>
  <scope>provided</scope>
</dependency>

运行时依赖范围(runtime)

使用此依赖范围的maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只需要jdk提供的jdbc的接口,只有在执行测试或者运行测试的时候才需要实现上述接口的jdbc的驱动。

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.25</version>
  <scope>runtime</scope>
</dependency>

系统依赖范围(system)

从参与度来说,和provided相同,不过被依赖项不会从maven仓库下载,而是从本地文件系统拿。需要添加systemPath的属性来定义路径,该依赖与三种范围的classpath

和provided依赖范围完全一致。可能造成不可移植,谨慎使用。

导入依赖范围(import)

该依赖范围不会对三种classpath产生实际的影响。只有在dependencyManagement下才有效果。

Maven聚合和继承(分布式开发必须使用)

Maven的聚合特性可以帮助我们把项目的多个模块聚合在一起,使

用一条命令进行构建,即一条命令实现构建多个项目;

Maven的继承特性可以将各个模块相同的依赖和插件配置提取出

来,在简化POM的同时还可以促进各个模块配置的一致性。

聚合模块(父模块)的打包方式必须为pom,否则无法完成构建。

在聚合多个项目时,如果这些被聚合的项目中需要引入相同的Jar,那么可以将这些Jar写入父pom中,各个子项目继承该pom即可。,父模块的打包方式必须为pom,否则无法构建项目。

<packaging>pom</packaging>

通过在各个子模块中配置来表明其继承与哪一个父模块:

<parent>
  <artifactId>parent</artifactId>
  <groupId>org.example</groupId>
  <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>childern-two</artifactId>

可以被继承的POM元素如下:

  • groupId:项目组ID,项目座标的核心元素
  • version:项目版本,项目座标的核心因素
  • properties:自定义的Maven属性 一般用于同一制定各个依赖的版本号
  • dependencies:项目的依赖配置 公共的依赖
  • dependencyManagement:项目的依赖管理配置
  • repositories:项目的仓库配置
  • build:包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等

一些对项目的描述

  • description:项目的描述信息
  • organization:项目的组织信息
  • inceptionYear:项目的创始年份
  • url:项目的URL地址
  • developers:项目的开发者信息
  • contributors:项目的贡献者信息
  • distributionManagement:项目的部署配置
  • issueManagement:项目的缺陷跟踪系统信息
  • ciManagement:项目的持续集成系统信息
  • scm:项目的版本控制系统
  • malilingLists:项目的邮件列表信息
  • reporting:包括项目的报告输出目录配置、报告插件配置等

聚合和继承的关系

虽然聚合模块和父模块经常合二为一,但是聚合和继承是两个不同的概念,其实是没有什么关系的。

聚合模块知道它聚合了哪些模块,但是被聚合的模块不知道聚合模块的存在;

父模块不知道子模块的存在,但是子模块都必须知道自己的父模块是谁。

可以用下图来表示这两个不同的概念:

img

Maven插件

Maven插件介绍

Maven 实际上是一个依赖插件执行的框架,每个任务实际上是由插件完成。Maven 插件通常被用来:

  • 打包jar 文件
  • 创建 war 文件
  • 编译代码文件
  • 代码单元测试
  • 创建工程文档
  • 创建工程报告

插件通常提供了一个目标的集合,并且可以使用下面的语法执行:

mvn [plugin-name]:[goal-name]

例如,一个 Java 工程可以使用 maven-compiler-plugin 的 compile-goal 编译,使用以下命令:

mvn compiler:compile

maven-compiler-plugin

设置maven编译的jdk版本,maven3默认用jdk1.5,maven2默认用jdk1.3

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
        <source>1.8</source> <!-- 源代码使用的JDK版本 -->
        <target>1.8</target> <!-- 需要生成的目标class文件的编译版本 -->
        <encoding>UTF-8</encoding><!-- 字符集编码 -->
    </configuration>
</plugin>

tomcat插件

<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <configuration>
        <port>8080</port>
        <uriEncoding>UTF-8</uriEncoding>
        <path>/xinzhi</path>
        <finalName>xinzhi</finalName>
    </configuration>
</plugin>

点击idea右侧的maven我们可以方便的看到我们使用了什么插件,并可以点击执行相应的命令。

通过插件和命令我们都可以启动项目了,都不用部署到tomcat里了。

war包打插件

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-war-plugin</artifactId>
  <configuration>
    <warName>test</warName>
    <webResources>
      <resource>
        <directory>src/main/webapp/WEB-INF</directory>
        <filtering>true</filtering>
        <targetPath>WEB-INF</targetPath>
        <includes>
          <include>web.xml</include>
        </includes>
      </resource>
    </webResources>
  </configuration>
</plugin>

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.0http://maven.apache.org/xsd/maven
-4.0.0.xsd">
  <!-- 模型版本。maven2.0必须是这样写,现在是maven2唯一支持的版本 -->
  <modelVersion>4.0.0</modelVersion>
  <!-- 公司或者组织的唯一标志,并且配置时生成的路径也是由此生成, 如com.xinzhi,maven会将该项目打
成的jar包放本地路径:/com/xinzhi/ -->
  <groupId>com.xinzhi</groupId>
  <!-- 本项目的唯一ID,一个groupId下面可能多个项目,就是靠artifactId来区分的 -->
  <artifactId>test</artifactId>
  <!-- 本项目目前所处的版本号 -->
  <version>1.0.0-SNAPSHOT</version>
 
  <!-- 打包的机制,如pom,jar, war,默认为jar -->
  <packaging>jar</packaging>
  <!-- 为pom定义一些常量,在pom中的其它地方可以直接引用 使用方式 如下 :${file.encoding} -->
  <!-- 常常用来整体控制一些依赖的版本号 -->
  <properties>
    <file.encoding>UTF-8</file.encoding>
    <java.source.version>1.8</java.source.version>
    <java.target.version>1.8</java.target.version>
  </properties>
 
  <!-- 定义本项目的依赖关系,就是依赖的jar包 -->
  <dependencies>
    <!-- 每个dependency都对应这一个jar包 -->
    <dependency>
      <!--一般情况下,maven是通过groupId、artifactId、version这三个元素值(俗称座标)来检
索该构件, 然后引入你的工程。如果别人想引用你现在开发的这个项目(前提是已开发完毕并发布到了远程仓库),-
->
      <!--就需要在他的pom文件中新建一个dependency节点,将本项目的groupId、artifactId、
version写入, maven就会把你上传的jar包下载到他的本地 -->
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <!-- 依赖范围 -->
      <scope>complie</scope>
      <!-- 设置 依赖是否可选,默认为false,即子项目默认都继承。如果为true,
        则子项目必需显示的引入 -->
      <optional>false</optional>
     
      <!-- 依赖排除-->
      <exclusions>
        <exclusion>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  </dependencies>
 ...
</project>

资源处理配置

<!-- 处理资源被过滤问题 -->
<build>
  <resources>
    <resource>
      <directory>src/main/java</directory>
      <includes>
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <filtering>false</filtering>
    </resource>
    <resource>
      <directory>src/main/resources</directory>
      <includes>
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <filtering>false</filtering>
    </resource>
  </resources>
</build>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章