打怪升级之小白的大数据之旅(三十七)<Maven的核心知识>

Posted GaryLea

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了打怪升级之小白的大数据之旅(三十七)<Maven的核心知识>相关的知识,希望对你有一定的参考价值。

打怪升级之小白的大数据之旅(三十七)

Maven的核心知识

上次回顾

上一章对Maven进行了简单的介绍与使用,本章来对Maven的核心知识进行讲解,了解清楚这些,可以更清晰地认识Maven,因为后面我们大数据会使用到它,所以我们重在理解哈。。

Maven核心概念

接下来我就详细介绍一下Maven的POM,目录结构以及坐标等内容

POM

  • POM全称:project Object Model:项目对象模型
  • 它主要是将Java工程的相关信息封装为对象作为便于操作和管理的模型。Maven工程的核心配置。可以说学习Maven就是学习pom.xml文件中的配置

约定的目录结构

  • 现在JavaEE开发领域普遍认同一个观点:约定>配置>编码
  • 意思就是能用配置解决的问题就不编码,能基于约定的就不进行配置
  • 而Maven正是因为指定了特定文件保存的目录才能够对我们的Java工程进行自动化构建
    下面再次回顾一下开篇提到过的目录结构
    main目录用于存放主程序。
    test目录用于存放测试程序。
    java目录用于存放源代码文件。
    resources目录用于存放配置文件和资源文件
    
  • 整个Maven就两大主模块,一个是main一个是test,我们最终在服务器部署运行的程序都是在main这个文件夹里,而test专门用于代码的测试,用于调试我们的项目

坐标

  • 坐标就跟我们现实生活中的概念一样:例如在几何中,一个平面中使用x、y两个向量可以唯一的确定平面中的一个点,在一个三维空间中使用x、y、z三个向量可以唯一的确定空间中的一个点
  • 在Maven中的坐标是使用三个向量来确定的,它们分别是
    • groupId:公司或组织的域名倒序+当前项目名称
    • artifactId:当前项目的模块名称
    • version:当前模块的版本
    <groupId>com.company.helloworld</groupId>
    <artifactId>Hello</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    
  • 这下再看这三个参数就懂了吧,它们就是坐标,当我们自己的Maven工程使用mvn install命令安装工程后,就可以将这三个向量连起来在我们的本地仓库中找到我们的项目:com.company.helloworld+Hello+0.0.1-SNAPSHOT

了解清楚这三个主要知识点,我们再来进行第三个Maven工程

第三个Maven工程

第一步:创建HelloFriend Module,直接右键建立model即可,我们只是在MavenProject这个项目中建立了另一个功能模块,然后在pom.xml配置文件中配置当前工程依赖Hello

<?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>

    <groupId>com.company.helloworld</groupId>
    <artifactId>HelloFriend</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.company.helloworld</groupId>
            <artifactId>Hello</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

第二步:编写主程序代码,在main/java目录下编写HelloFriend.java
在这里插入图片描述

package com.company.helloworld;

public class HelloFriend {
    public String sayHelloToFriend(String name){
        Hello hello = new Hello();
        String str = hello.sayHello(name)+" I am "+this.getMyName();
        return str;
    }
    public String getMyName(){
        return "Idea";
    }
}

第三步:编写测试程序,在/src/test/java目录下新建测试文件HelloFriendTest.java

package com.company.helloworld;

import org.junit.Test;

public class HelloFriendTest {
    @Test
    public void testHelloFriend(){
        HelloFriend helloFriend = new HelloFriend();
        String results = helloFriend.sayHelloToFriend("Maven");
        System.out.println(results);
    }

}

在这里插入图片描述
这个工程最主要的一点就是我们开第一步中的pom.xml中的依赖继承,我们继承了我们第二个工程中的Hello依赖,所以才可以在main方法中创建Hello的对象,正是因为Hello被下载到了本地仓库,并且可以根据坐标找到了它

依赖管理

下面就针对上面的知识点,对依赖进行详细的说明

基本概念

  • 当A jar包需要用到B jar包中的类时,我们就说A对B有依赖。例如:commons-fileupload-1.3.jar依赖于commons-io-2.0.1.jar
  • 就像第三个Maven工程中,当前工程会到本地仓库中根据坐标查找它所依赖的jar包
  • 直接依赖和间接依赖
    • 如果A依赖B,B依赖C,`那么A→B和B→C都是直接依赖,而A→C是间接依赖

依赖的范围

就像在java的作用域一样,依赖也可以指定范围,在Maven中有三种范围指定方式

  • compile

    [1]main目录下的Java代码可以访问这个范围的依赖
    [2]test目录下的Java代码可以访问这个范围的依赖
    [3]部署到Tomcat服务器上运行时要放在WEB-INF的lib目录下
    例如:对Hello的依赖。主程序、测试程序和服务器运行时都需要用到
    
  • test

    [1]main目录下的Java代码不能访问这个范围的依赖
    [2]test目录下的Java代码可以访问这个范围的依赖
    [3]部署到Tomcat服务器上运行时不会放在WEB-INF的lib目录下
    例如:对junit的依赖。仅仅是测试程序部分需要
    
  • provided

    [1]main目录下的Java代码可以访问这个范围的依赖
    [2]test目录下的Java代码可以访问这个范围的依赖
    [3]部署到Tomcat服务器上运行时不会放在WEB-INF的lib目录下
    

依赖的传递性与原则

依赖的传递性

  • 当存在间接依赖的情况时,主工程对间接依赖的jar可以访问吗?这要看间接依赖的jar包引入时的依赖范围——只有依赖范围为compile时可以访问在这里插入图片描述

依赖的原则:为了解决jar包的冲突

  • 路径最短者优先
    • 依赖按照继承顺序,首先找到最近的那个依赖,就像下图,三个工程模块都继承了log的jar包,如果我们的MakeFriend在打包时,就会先找自己的依赖,如果自己没有,就会找HelloFriend的在这里插入图片描述
  • 路径相同时先声明者优先
    • 就像下图中,MakeFriend同时继承了HelloFriend和OurFriends两个jar包,而它们又各自有不同版本的log,此时就根据我们声明依赖时的顺序来判断,这里“声明”的先后顺序指的是dependency标签配置的先后顺序在这里插入图片描述

依赖的排除与统一管理jar包版本

依赖的排除

  • 有的时候为了确保程序正确可以将有可能重复的间接依赖排除,请看如下的例子:
    • 假设当前工程为MakeFriend,直接依赖OurFriends。
    • OurFriends依赖commons-logging的1.1.1对于MakeFriend来说是间接依赖。
    • 当前工程MakeFriend直接依赖commons-logging的1.1.2
    • 加入exclusions配置后可以在依赖OurFriends的时候排除版本为1.1.1的commons-logging的间 接依赖
      <dependency>
          <groupId>com.atguigu.maven</groupId>
          <artifactId>OurFriends</artifactId>
          <version>1.0-SNAPSHOT</version>
          <!--依赖排除-->
          <exclusions>
              <exclusion>
                  <groupId>commons-logging</groupId>
                  <artifactId>commons-logging</artifactId>
              </exclusion>
          </exclusions>
      </dependency>
      
      <dependency>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
          <version>1.1.2</version>
      </dependency>
      

统一管理jar包版本
当我们有很多的jar包,我们可以使用变量来统一管理相同版本的包,这样方便后期维护,示例代码:

// 我们工程用到的以下依赖时,版本都是4.0.0
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.0.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.0.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.0.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>4.0.0.RELEASE</version>
</dependency>
// 使用变量来统一管理
<properties>
    <spring.version>4.0.0.RELEASE</spring.version>
</properties>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>${spring.version}</version>
</dependency>

仓库

我在上一章开篇说了,Maven就是一个仓库管理员,管理着本地和远程两个仓库,下面来说明一下仓库的具体情况在这里插入图片描述
本地仓库

  • 就是为我们当前的电脑中所有的Maven工程服务
    远程仓库
  • 私服
    • 私服就是架设在当前局域网环境下,为当前局域网范围内的所有Maven工程服务
    • 在公司中多用的就是私服来共同维护一个项目,例如一个项目有很多的功能,每个功能就是一个Maven工程,每个人负责一个功能的搭建
  • 中央仓库
    • 架设在Internet上,为全世界所有Maven工程服务
  • 中央仓库镜像
    • 架设在各个大洲,为中央仓库分担流量。减轻中央仓库的压力,同时更快的响应用户请求
    • 在上一章maven的conf中的setting中配置的那个阿里的仓库镜像就是中央仓库的镜像

仓库中的文件

  • Maven的插件,还记得我们第一次使用构建时,使用的那几个命令mvn install。。这些都是需要下载插件才能使用的
  • 我们自己开发的项目模块
  • 第三方框架或工具的jar包
  • 不管是什么样的jar包,在仓库中都是按照坐标生成目录结构,所以可以通过统一的方式查询或依赖

生命周期

  • Maven生命周期定义了各个构建环节的执行顺序,有了这个清单,Maven就可以自动化的执行构 建命令了
  • Maven有三套相互独立的生命周期,分别是:
    • Clean Lifecycle在进行真正的构建之前进行一些清理工作。
    • Default Lifecycle构建的核心部分,编译,测试,打包,安装,部署等等。
    • Site Lifecycle生成项目报告,站点,发布站点

clean生命周期

  • Clean生命周期一共包含了三个阶段:
    pre-clean 执行一些需要在clean之前完成的工作 
    clean 移除所有上一次构建生成的文件 
    post-clean 执行一些需要在clean之后立刻完成的工作
    

Site生命周期

  • pre-site 执行一些需要在生成站点文档之前完成的工作
    site 生成项目的站点文档
    post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
    site-deploy 将生成的站点文档部署到特定的服务器上
    

Default生命周期

  • Default生命周期是Maven生命周期中最重要的一个,绝大部分工作都发生在这个生命周期中。这里,只解释一些比较重要和常用的阶段
    compile 编译项目的源代码
    test-compile 编译测试源代码
    test 使用合适的单元测试框架运行测试。这些测试代码不会被打包或部署
    package 接受编译好的代码,打包成可发布的格式,如JAR
    install将包安装至本地仓库,以让其它项目依赖
    deploy将最终的包复制到远程的仓库,以让其它开发人员与项目共享或部署到服务器上运行
    

注意:运行任何一个阶段的时候,它前面的所有阶段都会被运行,例如我们运行mvn install 的时候,代码会被编译,测试,打包。这就是Maven为什么能够自动执行构建过程的各个环节的原因。此外,Maven的插件机制是完全依赖Maven的生命周期的,因此理解生命周期至关重要

插件和目标

  • Maven的核心仅仅定义了抽象的生命周期,具体的任务都是交由插件完成的。
  • 每个插件都能实现多个功能,每个功能就是一个插件目标。
  • Maven的生命周期与插件目标相互绑定,以完成某个具体的构建任务。
    例如:compile就是插件maven-compiler-plugin的一个功能;pre-clean是插件maven-clean-plugin的一个目标

继承

  • 就如同java的继承一样,我们在继承的时候不需要重复的加载相同的依赖,举一个实际的例子:在一个电商项目中,我们时时刻刻需要用户登录,不论是购物车模块还是订单模块,我们只需要继承账户这个模块的的jar包,就可以同时继承账户这个程序所需要的相关依赖包

父工程

  • 有了继承自然需要一个父工程
  • 父工程的打包方式为pom
  • 父工程只需要保留pom.xml文件即可
    <groupId>com.company.helloworld</groupId>
    <artifactId>Parent</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    

在子工程中引用父工程

  • 此时如果子工程的groupId和version如果和父工程重复则可以删除
    <parent>
    	<!-- 父工程坐标 -->
    <groupId>...</groupId>
    	<artifactId>...</artifactId>
    	<version>...</version>
    <!--指定从当前pom.xml文件出发寻找父工程的pom.xml文件的相对路径-->
    <relativePath>..</relativePath>
    </parent>
    
    // 继承
    <!--继承-->
    <parent>
        <groupId>com.company.helloworld</groupId>
        <artifactId>Parent</artifactId>
        <version>1.0-SNAPSHOT</version>
    <!--指定从当前pom.xml文件出发寻找父工程的pom.xml文件的相对路径-->
    <relativePath>../Parent/pom.xml</relativePath>
    </parent>
    

在父工程中管理依赖

  • 将Parent项目中的dependencies标签,用dependencyManagement标签括起来
    <!--依赖管理-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.0</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    

聚合

  • 将多个工程拆分为模块后,需要手动逐个安装到仓库后依赖才能够生效。修改源码后也需要逐个手动进行clean操作。而使用了聚合之后就可以批量进行Maven工程的安装、清理工作
  • 在总的聚合工程中使用modules/module标签组合,指定模块工程的相对路径即可
  • Maven可以根据各个模块的继承和依赖关系自动选择安装的顺序
    <!--聚合-->
    <modules>
        <module>../MakeFriend</module>
        <module>../OurFriends</module>
        <module>../HelloFriend</module>
        <module>../Hello</module>
    </modules>
    

酷站

我们可以到http://mvnrepository.com/搜索需要的jar包的依赖信息。
http://search.maven.org/

总结

Maven的相关知识点就介绍到这里,核心内容只是为了让我们更加清晰地了解Maven机制,重在理解,我们后面大数据会用到它,不要怕,到时候忘记了再回看我这两篇博客就好啦。下一章我会为大家带来Linux相关的知识点,大数据嘛,肯定要跟Linux打交道的。。

以上是关于打怪升级之小白的大数据之旅(三十七)<Maven的核心知识>的主要内容,如果未能解决你的问题,请参考以下文章

打怪升级之小白的大数据之旅(三十八)<Linux基础知识>

打怪升级之小白的大数据之旅(五十七)<Hadoop压缩>

打怪升级之小白的大数据之旅(四十七)<HDFS扩展知识点>

打怪升级之小白的大数据之旅(三十九)<Linux常用命令>

打怪升级之小白的大数据之旅(三十五)<JDBC的扩展知识点>

打怪升级之小白的大数据之旅(六十七)<Hive旅程第八站:Hive的函数>