Maven学习笔记

为什么要使用 Maven?

  1. 添加第三方 jar 包
    在今天的 JavaEE 开发领域,有大量的第三方框架和工具可以供我们使用。要使用这些 jar 包最简单的方法就是复制粘贴到 WEB-INF/lib 目录下。但是这会导致每次创建一个新的工程就需要将 jar 包重复复制到 lib 目录下,从而造成工作区中存在大量重复的文件,让我们的工程显得很臃肿。而使用 Maven 后每个 jar 包本身只在本地仓库中保存一份,需要 jar 包的工程只需要以坐标的方式简单的引用一下就可以了。不仅极大的节约了存储空间,让项目更轻巧,更避免了重复文件太多而造成的混乱。
  2. jar 包之间的依赖关系
    jar 包往往不是孤立存在的,很多 jar 包都需要在其他 jar 包的支持下才能够正常工作,我们称之为jar 包之间的依赖关系。最典型的例子是:commons-fileupload-1.3.jar 依赖于 commons-io-2.0.1.jar,如果没有 IO 包,FileUpload 包就不能正常工作。
    那么问题来了,你知道你所使用的所有 jar 包的依赖关系吗?当你拿到一个新的从未使用过的 jar
    包,你如何得知他需要哪些 jar 包的支持呢?如果不了解这个情况,导入的 jar 包不够,那么现有的程序将不能正常工作。再进一步,当你的项目中需要用到上百个 jar 包时,你还会人为的,手动的逐一确认它们依赖的其他 jar 包吗?这简直是不可想象的。
    而引入 Maven 后,Maven 就可以替我们自动的将当前 jar 包所依赖的其他所有 jar 包全部导入进来,无需人工参与,节约了我们大量的时间和精力。用实际例子来说明就是:通过 Maven 导入
    commons-fileupload-1.3.jar 后,commons-io-2.0.1.jar 会被自动导入,程序员不必了解这个依赖关系。
  3. 获取第三方 jar 包
    JavaEE 开发中需要使用到的 jar 包种类繁多,几乎每个 jar 包在其本身的官网上的获取方式都不尽相同。为了查找一个 jar 包找遍互联网。不仅如此,找的 jar 包里有的时候并没有需要的那个类,又或者获取的 jar 包是不规范的。
    使用 Maven 我们可以使用一个完全统一规范的 jar 包管理体系。只需要在你的项目中以坐标的
    方式依赖一个 jar 包,Maven 就会自动从中央仓库进行下载,并同时下载这个 jar 包所依赖的其他 jar 包。
  4. 将项目拆分成多个工程模块
    随着 JavaEE 项目的规模越来越庞大,开发团队的规模也与日俱增。一个项目上千人的团队持续开发很多年对于 JavaEE 项目来说再正常不过。那么我们想象一下:几百上千的人开发的项目是同一个 Web工程。那么架构师、项目经理该如何划分项目的模块、如何分工呢?这么大的项目已经不可能通过 package 结构来划分模块,必须将项目拆分成多个模块协同开发。多个模块工程中有的是 Java 工程,有的是 Web 工程。

什么是 Maven?

简介

Maven 是 Apache 软件基金会组织维护的一款自动化构建工具,专注服务于 Java 平台的项目构建依赖管理
在这里插入图片描述

构建

构建并不是创建,创建一个工程并不等于构建一个项目。构建是指以我们编写的 Java 源代码、框架配置文件等其他资源文件、JSP 页面和图片等静态资源作为“原材料”,去“生产”出一个可以运行的项目的过程。构建包括以下几个过程:

  1. 清理:删除以前的编译结果,为重新编译做好准备。
  2. 编译:将 Java 源程序编译为字节码文件。
  3. 测试:针对项目中的关键点进行测试,确保项目在迭代开发过程中关键点的正确性。
  4. 报告:在每一次测试后以标准的格式记录和展示测试结果。
  5. 打包:将一个包含诸多文件的工程封装为一个压缩文件用于安装或部署。Java 工程对应 jar 包,Web工程对应 war 包。
  6. 安装:在 Maven 环境下特指将打包的结果——jar 包或 war 包安装到本地仓库中。
  7. 部署:将打包的结果部署到远程仓库或将 war 包部署到服务器上运行。

编译后的目录结构

在这里插入图片描述

约定的目录结构

要使 Maven 能够自动构建项目,必须让项目的目录结构和下面的结构相同:
在这里插入图片描述

安装

  1. Maven官网 上下载最新版本的 Maven 压缩包,将其解压在适当的目录下,注意,全路径名不能有中文和空格
  2. 配置环境变量:
    新建变量名:MAVEN_HOME或M2_HOME,变量值为 Maven 的解压路径。
    在 Path 中追加路径:%MAVEN_HOME%\bin
  3. 测试是否安装成功:
    在命令行中输入:mvn -v,若显示 Maven 版本信息,则安转成功。
  4. 修改本地仓库位置:
    Maven 本地仓库的默认位置为:C:\Users\MCC(用户名)\.m2 下,在 Maven的安装目录下,打开 conf\settings.xml 文件,在<localRepository>标签中设置本地仓库地址。
    在这里插入图片描述

常用命令

注意:执行下列命令,必须先进入 pom.xml 文件所在的目录(工程目录)。

命令功能
mvc clean清理
mvc compile编译主程序
mvc test-compile编译测试程序
mvc test执行测试
mvc package打包
mvc install注册进入本地仓库
mvn site生成站点

注意:多个命令可以同时执行,如

POM、坐标、仓库

  1. POM:Project Object Model,项目对象模型。将 Java 工程的相关信息封装为对象作为操作和管理的模型。pom.xml 是 Maven 工程的核心配置文件,可以说学习 Maven 就是学习 pom.xml 文件中的配置。

  2. 坐标:Maven 使用如下三个坐标在 Maven 仓库中唯一确定一个 Maven 工程。
    groupId:公司或组织的域名倒序+项目名称
    artifactId:模块名称
    version:版本号

  3. 坐标与仓库中路径的对应关系:

    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.2.6.RELEASE</version>
    

    对应的仓库路径为:org/springframework/spring-core/5.2.6.RELEASE/spring-core-5.2.6.RELEASE.jar

  4. 仓库的分类:
    (1)本地仓库。
    (2)远程仓库:私服、中央仓库、中央仓库镜像。
    仓库中保存的内容:
    (1)Maven 自身所需要的插件。
    (2)第三方框架或工具所需要的 jar 包。
    (3)自己开发的 Maven 工程。

依赖

自己的工程

Maven 在解析依赖信息时,先在本地仓库中查找所依赖的 jar 包,若查找失败,则连接外网下载 jar 包。当某个模块需要依赖的信息是我们之前自己创建的类时,需要先将被依赖的类注册到 Maven 的本地仓库中,之后才可以被依赖。

在需要注册装入仓库的工程(或模块)目录下,使用命令:mvc install,即可将该工程(或模块)装入仓库。

注意:将某个工程装入仓库,不仅仅是将该工程打包成 jar 包,还会生成一些其他文件,所以不能简单理解为注册装入仓库,就是将该工程打成 jar 包(mvc package 才仅仅是将工程打成 jar 包)。

依赖的范围

Maven 提供四种依赖:compile、test、provided、runtime。

  • compile编译、测试、运行时均有效。
    • 对主程序:有效
    • 对测试程序:有效
    • 打包、部署:是
  • test测试时有效。
    • 对主程序:无效
    • 对测试程序:有效
    • 打包、部署:否
    • 典型例子:junit
  • provided编译、测试时有效。
    • 对主程序:有效
    • 对测试程序:有效
    • 打包、部署:否
    • 典型例子:servlet、jsp 等 tomcat 可以提供的 jar 包
  • runtime测试、运行时有效。
    • 对主程序:有效
    • 对测试程序:有效
    • 打包、部署:是
    • 典型例子:JDBC

注意:依赖的范围一定要写对,否则可能会报错,例如将 servlet-api.jar 声明为 compile,因为部署时,tomcat 也会提供一份 servlet-api.jar,就有可能导致 jar 包冲突,发生异常。

依赖的传递性

A 依赖 B,B 依赖 C,A 能否使用 C 呢?此时需要看 B 依赖 C 的范围是否为 compile,若是,则可以使用,否则不可以使用。

好处:依赖的传递性可以使各个模块不必引入相同的依赖,减少工程 jar 包的冗余。
注意:由于只有 compile 范围的依赖才可以被传递,因此如果需要使用非 compile 范围的依赖就必须重复声明。

依赖的排除

如果我们在当前工程中引入了一个依赖 A,而 A 又依赖了 B,由于依赖的传递性,Maven 会自动将 A 依赖的 B 引入当前工程,但是在个别情况下,B 有可能是一个不稳定的版本,或对当前工程有不良影响,这时我们就需要在引入 A 时将 B 排除。

<!-- 假设模块需要引入依赖MavenWeb,但是MavenWeb所依赖的logging是我们不想引入的,
此时可以通过<exclusion>标签进行依赖的排除
 -->
<dependency>
 	<groupId>com.mcc</groupId>
	<artifactId>MavenWeb</artifactId>
	<version>0.0.1-SNAPSHOT</version>
 	<scope>compile</scope>
 	<exclusions> 
 		<exclusion> 
 		<groupId>commons-logging</groupId> 
 		<artifactId>commons-logging</artifactId> 
 		</exclusion> 
 	</exclusions> 
</dependency>

依赖的原则

当模块中有多个相同的 jar 包时,Maven 通过下面的原则,解决 jar 包冲突问题。
在这里插入图片描述
在这里插入图片描述
当然,每个模块都以自己的 pom.xml 中配置的版本为准。上面的例子中,工程A的 pom.xml 中没有配置 log4j 依赖,如果配置了,则要以自己配置的版本为准。

统一管理所依赖 jar 包的版本

项目中同一个框架所需要的核心 jar 包最好使用相同版本,避免不必要的错误,如 spring、springMVC 使用的版本号最好相同。此时如果需要统一升级框架的版本,在 pom.xml 文件中逐个修改比较浪费时间,可以使用<properties>标签实现 jar 包版本号的统一修改。

情境:现在需要将项目中的 spring 框架升级到 5.3.4。

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>5.2.6.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.2.6.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-beans</artifactId>
  <version>5.2.6.RELEASE</version>
</dependency>

实现方式:

(1)在<properties>标签内自定义一个标签,标签名任意,标签内容为版本号。

<properties>
  <spring.version>5.3.4</spring.version>
</properties>

(2)在声明依赖版本号的<version>标签内,使用${自定义的标签名},引入声明的版本号。

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

此外,properties 标签内还可以声明项目的编码格式等内容,如:

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>1.7</maven.compiler.source>
  <maven.compiler.target>1.7</maven.compiler.target>
  <spring.version>5.3.4</spring.version>
</properties>

继承

由于 test 范围的依赖不能传递,如 junit,此时每个模块中都有自己的 junit,如果想同一管理 junit 的版本,会很麻烦。“继承”可以解决这个问题。

实现方式:

(1)创建一个 Maven 工程作为父工程,注意:父工程的打包方式要为 pom。<packaging>pom</packaging>

<groupId>com.mcc.maven</groupId>
<artifactId>MavenParent</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>

(2)在子工程中使用<parent>标签,声明父工程。其中,relativePath 标签是以当前模块为起点的父工程的 pom.xml 文件的相对路径。

<parent>
   <artifactId>MavenParent</artifactId>
    <groupId>com.mcc.maven</groupId>
    <version>1.0-SNAPSHOT</version>
    <!--以当前模块为起点的父工程的pom.xml文件的相对路径-->
    <relativePath>../pom.xml</relativePath>
</parent>

(3)删除子工程的<groupId>、<version>标签,由于子工程属于父工程的一部分,因此子工程与父工程在同一个 groupId 下,版本号可以不同,但一般情况下也应该相同,所以子工程中的这两个标签需要删除。

<artifactId>SubWeb</artifactId>

(4)在父工程中使用<dependencyManagement>标签统一管理 test 范围的依赖,如 junit。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

(5)删除子工程中 junit 依赖中的<version>标签。

当然,如果子工程使用的 junit 版本,确实需要和父工程不同,可以保留 dependency 标签中的 version 标签,相当于对父工程 junit 依赖版本的重写。

在这里插入图片描述
注意:上述过程的 (1) (2) (3) 步,在使用 idea 创建 Maven 工程时,可以自动实现。选择要继承的父工程之后,就已经自动配置好了,我们只需要进行第 (4) 步即可。
在这里插入图片描述
注意:

为什么在父类中写了 Junit 依赖,子类中还要写呢?

首先要明白 dependencies 与 dependencyManagement 的区别:

  • dependencies 即使在子项目中不写该依赖项,那么子项目仍然会从父项目中继承该依赖项,如果父类有很多依赖,这样没用的也继承来,会造成臃肿。

  • dependencyManagement 里只是声明依赖,并不实现引入,因此子项目需要显式的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且 version 和 scope 都读取自父类 pom;另外,如果子项目中指定了版本号,那么会使用子项目中指定的 jar 包版本。

聚合

  1. 为什么要使用聚合?
    将多个工程拆分为模块后,需要手动逐个安装到仓库后依赖才能够生效。修改源码后也需要逐个手动进行 clean 操作。而使用了聚合之后就可以批量进行 Maven 工程的安装、清理工作。
  2. 实现方式:
    在总的聚合工程中使用<modules><module>标签组合,指定子工程的相对路径即可。总的聚合工程可以是继承时使用的父工程,相对路径以父工程的 pom.xml 文件为起点。
<modules>
    <module>SubJava</module>
    <module>SubWeb</module>
</modules>

在这里插入图片描述

查询依赖信息

我们可以到 MavenRepository 搜索需要的 jar 包的依赖信息。

生命周期

Maven 有三套相互独立的生命周期,分别是:

  • Clean Lifecycle 在进行真正的构建之前进行一些清理工作。
  • Default Lifecycle 构建的核心部分,编译,测试,打包,安装,部署等等。
  • Site Lifecycle 生成项目报告,站点,发布站点。

它们是相互独立的,可以只调用 clean 来清理工作目录,只调用 site 来生成站点。当然你也可以直接运行mvn clean install site运行所有这三套生命周期。

运行任何一个阶段的时候,它前面的所有阶段都会被运行,例如我们运行 mvn install 的时候,代码会被编译,测试,打包。

idea 中配置 Maven

在这里插入图片描述

在 idea 中创建 Maven 版的 Java 工程

在这里插入图片描述
创建成功后的项目结构为:
在这里插入图片描述

在 idea 中执行 Maven 命令

在这里插入图片描述

在 idea 中创建 Maven 版的 Web 工程

自动创建所有目录结构

在 idea 中创建的 Maven 版 Web 工程,目录结构中只有 src/main/webapp,可以选择每次都手动新建目录,也可以采用修改配置文件的方式,让 idea 为我们创建。具体配置方式点击链接查看

配置文件修改完成后,按照如下步骤新建 Web 项目:
在这里插入图片描述

修改 web.xml 头文件版本

Maven 构建的 web 项目,使用的 webapp 版本比较低,只有2.3,不支持 jsp 自动解析 EL 表达式、servlet 的注解使用等,因此要修改 web.xml 的头文件为:

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  version="4.0"
  metadata-complete="false">
  
</web-app>

每次都要修改比较麻烦,可以在配置文件中修改,使得每次生成的 web.xml 版本都提高到4.0,操作方式点击链接查看

解决在 idea 中使用 Maven 骨架生成 web 项目很慢的问题

在这里插入图片描述

在使用 webapp 创建 Maven 版的 web 项目时,有时等待很久,Maven 都没有将工程的目录结构创建出来,此时可以在创建 web 项目时,按照上图,为项目添加一条属性name=archetypeCatalog, value=internal,即可解决问题。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值