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