Maven入门

  有用过Maven,但是一直都不知道是什么~被人一问,发现好像有点东西。随口一说是管理Jar包的,一般都是复制粘贴的。却被人说是啊是啊,但是复制粘贴是别人的又不是你的。说的好像jar包就是自己的一样(白眼.jpg)。——fzj

 

一.Maven的作用:

  是一个项目管理工具。跨平台对外提供了一直的操作接口。统一开发规范与工具,统一管理jar包,还能自动下载构件。

 

二.安装:

  链接放这里:https://www.cnblogs.com/zhaoyang/archive/2012/01/07/2315443.html(Maven的安装与配置)

 

三.Maven 目录:

  bin目录:该目录包含了mvn运行的脚本,这些脚本用来配置Java命令,准备好classpath和相关的Java系统属性,然后执行Java命令。

  boot目录:该目录质保函一个文件,名字为plexus-classworlds-2.6.0.jar,是一个类加载器框架,相对于默认的Java类加载器,它提供了更加丰富的语法以及方便配置,Maven使用该框架加载自己的类库。

  conf目录:该目录包含了一个非常重要的配置文件叫settings.xml。直接修改该文件,就能在电脑上全局地定制Maven的行为。一般都是复制一份在桌面上,用记事本打开,然后修改,然后替换以前那一份。

  lib目录:该目录包含了所有Maven运行时需要的Java类库,需要用到的第三方依赖等。

 

四.pom.xml

  这才是Maven最核心的东西,很有必要去解析一下。

 

打开pom.xml,你可以看到原始的

 1 <project xmlns="http://maven.apache.org/POM/4.0.0" 
 2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 4   <modelVersion>4.0.0</modelVersion>
 5   <groupId>com.baidu</groupId>
 6   <artifactId>MavenProject</artifactId>
 7   <version>0.0.1-SNAPSHOT</version>
 8   <packaging>war</packaging>
 9  <dependencies>
10   <dependency>
11       <groupId>ch.inftec.ju</groupId>
12       <artifactId>ju-dbutil-test-mysql</artifactId>
13       <version>4.1</version>
14   </dependency>
15  </dependencies>
16 </project>

 

  第1~3行就是一些简单的声明,xml文件都有的

  第4行,modelVersion 是指定了当前的Maven模型的版本号,对于Maven2和Maven3来说,它只能是4.0.0

  第5行,groupId 这个应该是公司名或是组织名。一般来说groupId是由三个部分组成,每个部分之间以"."分隔,第一部分是项目用途,比如用于商业的就是"com",用于非营利性组织的就是"org";第二部分是公司名,比如"tengxun"、"baidu"、"alibaba";第三部分是你的项目名

  第6行,artifactId 可以认为是Maven构建的项目名,比如你的项目中有子项目,就可以使用"项目名-子项目名"的命名方式

  第7行,version 这个是版本号,SNAPSHOT意为快照,说明该项目还在开发中,是不稳定的版本。

注意,在Maven中,groupId、artifactId、version三个元素生成了一个Maven项目的基本坐标。

  第8行,packing 项目打包的类型,可以使用jar、war、rar、ear、pom,默认是jar。

 

dependencies和dependency:

  前者包含后者。前面说了,Maven的一个重要作用就是统一管理jar包,为了一个项目可以build或运行,项目中不可避免的,会依赖很多其他的jar包,在Maven中,这些依赖就被称为dependency。

  这里引入一个概念,就是本地仓库远程仓库

  官方下载的本地仓库的配置存放在"%MAVEN_HOME%\conf\settings.xml"里面,找一下"localRepository"就可以了;

  MyEclipse默认的本地仓库的地址在"{user.home}/.m2/repository"路径下,同样找一下"localRepository"就可以找到MyEclipse默认的本地仓库了。

  本地仓库和远程仓库是这样的,Maven工程首先会从本地仓库中获取jar包,当无法获取指定jar包时,本地仓库会从远程仓库(中央仓库)中下载jar包,并放入本地仓库以备将来使用

 

properties

  properties是用来定义一些配置属性的,例如project.build.sourceEncoding(项目构建源码编码方式),可以设置为UTF-8,防止中文乱码,也可定义相关构建版本号,便于日后统一升级。

build

  build表示与构建相关的配置,比如build下有finalName,表示的就是最终构建之后的名称。

 

接着解释一下Maven的目录结构

  • main目录下是项目的主要代码,test目录下存放测试相关的代码
  • 编译输出后的代码会放在target目录下
  • src/main/java下存放Java代码,src/main/resources下存放配置文件
  • 这里没有webapp,Web项目会有webapp目录,webapp下存放Web应用相关代码
  • pom.xml是Maven项目的配置文件

 

 

关于依赖的配置:这里引 嘟嘟独立 的一张图:

  我觉得这个图片可真直观~厉害厉害

 

下面讲讲依赖范围(即<scope>)

  是什么?

   maven 项目在不同的阶段引入到classpath中的依赖是不同的,例如,编译时,maven 会将与编译相关的依赖引入classpath中,测试时,maven会将测试相关的的依赖引入到classpath中,运行时,maven会将与运行相关的依赖引入classpath中,而依赖范围就是用来控制依赖于这三种classpath的关系。总结起来就是三种:编译classpath,测试classpath、运行classpath。

  有什么?有好几种呢。

    compile(编译依赖范围)、test(测试依赖范围)、provided(已提供依赖范围)、

    runtime(运行时依赖范围)、system(系统依赖范围)、import(引入依赖范围)

  怎么用?

  1)编译依赖范围(compile),该范围就是默认依赖范围,此依赖范围对 于编译、测试、运行三种classpath都有效,举个简单的例子,假如项目中有spring-core的依赖,那么spring-core不管是在编译,测试,还是运行都会被用到,因此spring-core必须是编译范围(构件默认的是编译范围,所以依赖范围是编译范围的无须显示指定)

     <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-core</artifactId>
     <version>2.5</version>
     <scope>compile</scope> <!--默认为该依赖范围,无须显示指定--〉
    </dependency>

  2)测试依赖范围(test),顾名思义就是针对于测试的,使用此依赖范围的依赖,只对测试classpath有效,在编译主代码和项目运行时,都将无法使用该依赖,最典型的例子就是 Junit, 构件在测试时才需要,所以它的依赖范围是测试,因此它的依赖范围需要显示指定为<scope>test</scope> ,当然不显示指定依赖范围也不会报错,但是该依赖会被加入到编译和运行的classpath中,造成不必要的浪费 。

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

  3)已提供依赖范围(provided),使用该依赖范围的maven依赖,只对编译和测试的classpath有效,对运行的classpath无效,典型的例子就是servlet-api, 编译和测试该项目的时候需要该依赖,但是在运行时,web容器已经提供的该依赖,所以运行时就不再需要此依赖,如果不显示指定该依赖范围,并且容器依赖的版本和maven依赖的版本不一致的话,可能会引起版本冲突,造成不良影响。

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

  4)运行时依赖范围(runtime),使用该依赖范围的maven依赖,只对测试和运行的classpath有效,对编译的classpath无效,典型例子就是JDBC的驱动实现,项目主代码编译的时候只需要JDK提供的JDBC接口,只有在测试和运行的时候才需要实现上述接口的具体JDBC驱动。

  5)系统依赖范围(system),该依赖与classpath的关系与 provided依赖范围完全一致,但是系统依赖范围必须通过配置systemPath元素来显示指定依赖文件的路径,此类依赖不是由maven仓库解析的,而且往往与本机系统绑定,可能造成构件的不可移植,因此谨慎使用,systemPath元素可以引用环境变量:

    <dependency>
    <groupId>javax.sql</groupId>
    <artifactId>jdbc-stext</artifactId>
    <version>2.0</version>
    <scope>system</scope>
    <systemPath>${java.home}/lib/rt.jar</systemPath> 
    </dependency>

  6)导入依赖范围(import),该依赖范围不会对三种classpath产生影响,该依赖范围只能与dependencyManagement元素配合使用,其功能为将目标pom文件中dependencyManagement的配置导入合并到当前pom的dependencyManagement中。

 

这里又引 嘟嘟独立 的一张图:(除import以外的各种依赖范围与三种classpath的关系如下:)

 

 

 Maven传递性依赖(Optional Dependencies):

  是什么?

    当一个项目A依赖另一个项目B时,项目A可能很少一部分功能用到了项目B,此时就可以在A中配置对B的可选依赖。举例来说,一个类似hibernate的项目,它支持对mysql、oracle等各种数据库的支持,但是在引用这个项目时,我们可能只用到其对mysql的支持,此时就可以在这个项目中配置可选依赖。

    简单来说就是:A-->B,B-->C   ==   A-->C。配置可选依赖的原因:1、节约磁盘、内存等空间;2、避免license许可问题;3、避免类路径问题,等等。

    有了传递性依赖机制,在使用Spring Framework的时候就不用去考虑它依赖了什么,也不用担心引入多余的依赖。Maven会解析各个直接依赖的POM,将那些必要的间接依赖,以传递性依赖的形式引入到当前的项目中。

    

依赖范

  假设A依赖于B,B依赖于C,我们说A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖。第一直接依赖和第二直接依赖的范围决定了传递性依赖的范围,如下图所示,最左边一行表示第一直接依赖范围,最上面一行表示第二直接依赖范围,中间的交叉单元格则表示传递依赖范围。

从上图中,我们可以发现这样的规律:

  • 当第二直接依赖的范围是compile的时候,传递性依赖的范围与第一直接依赖的范围一致;
  • 当第二直接依赖的范围是test的时候,依赖不会得以传递;
  • 当第二直接依赖的范围是provided的时候,只传递第一直接依赖范围也为provided的依赖,切传递依赖的范围同样为provided;
  • 当第二直接依赖的范围是runtime的时候,传递性依赖的范围与第一直接依赖的范围一致,但compile列外,此时传递性依赖范围为runtime

依赖调解:

  是什么?

    当传递性依赖造成为问题的时候,就需要清楚地知道该传递性依赖是从哪条依赖路径引入的。这就是依赖调解的作用

  有什么?

   依赖调解有两大原则:

  1. 路径最近者优先
    比如项目有A有这样的依赖关系:A->B->C->X(1.0)、A->D->X(2.0),X是A的传递性依赖,但是两条依赖路径上有两个版本的X,所以根据第一原则,A->D->X(2.0)路径短,所以X(2.0)会被解析使用
  2. 第一声明者优先
    如果路径都一样长的话,第一原则就不行了,比如 A->B->Y(1.0)、A->C->Y(2.0),Y(1.0)和Y(2.0)的路径一样,所以这时候根据第二原则,先声明的被解析。

  

可选依赖:

 

  如图,项目中A依赖B,B依赖于X和Y,如果所有这三个的范围都是compile的话,那么X和Y就是A的compile范围的传递性依赖,但是如果我想X,Y不作为A的传递性依赖,不给他用的话。就需要下面提到的配置可选依赖。

 

 1 <project>  
 2     <modelVersion>4.0.0</modelVersion>  
 3     <groupId>com.juvenxu.mvnbook</groupId>  
 4     <artifactId>project-b</artifactId>  
 5     <version>1.0.0</version>  
 6     <dependencies>  
 7         <dependency>  
 8             <groupId>mysql</groupId>  
 9             <artifactId>mysql-connector-java</artifactId>  
10             <version>5.1.10</version>  
11             <optional>true</optional>  
12         </dependency>  
13         <dependency>  
14             <groupId>postgresql</groupId>  
15             <artifactId>postgresql</groupId>  
16             <version>8.4-701.jdbc3</version>  
17             <optional>true</optional>  
18         </dependency>  
19     </dependencies>  
20 </project>
View Code

配置也简单,在依赖里面添加

    <optional>true</optional> 

就表示可选依赖了,这样A如果想用X,Y就要直接显示的添加依赖了。

 

排除依赖:

  有时候你引入的依赖中包含你不想要的依赖包,你想引入自己想要的,这时候就要用到排除依赖了,比如下图中spring-boot-starter-web自带了logback这个日志包,我想引入log4j2的,所以我先排除掉logback的依赖包,再引入想要的包就行了

 

排除依赖代码结构:

1 <exclusions>
2     <exclusion>
3         <groupId>org.springframework.boot</groupId>
4         <artifactId>spring-boot-starter-logging</artifactId>
5     </exclusion>
6 </exclusions>

 

 这里注意:声明exclustion的时候只需要groupId和artifactId,而不需要version元素,这是因为只需要groupId和artifactId就能唯一定位依赖图中的某个依赖。

 

归类依赖:

  有时候我们引入的很多依赖包,他们都来自同一个项目的不同模块,所以他们的版本号都一样,这时候我们可以用属性来统一管理版本号

 1 <project>  
 2     <modelVersion>4.0.0</modelVersion>  
 3     <groupId>com.juven.mvnbook.account</groupId>  
 4     <artifactId>accout-email</artifactId>  
 5     <version>1.0.0-SNAPSHOT</version>  
 6     <properties>  
 7         <springframework.version>1.5.6</springframework.version>  
 8     </properties>  
 9     <dependencies>  
10         <dependency>  
11             <groupId>org.springframework</groupId>  
12             <artifactId>spring-core</artifactId>  
13             <version>${springframework.version}</version>  
14         </dependency>   
15         <dependency>  
16             <groupId>org.springframework</groupId>  
17             <artifactId>spring-beans</artifactId>  
18             <version>${springframework.version}</version>  
19         </dependency>         
20     </dependencies>  
21 </project>
View Code

如图所示,先通过

</properties>
    这里定义你先要的版本
</properties>

  来定义,然后在下面依赖使用${}来引入你的属性。

 

 

 

本文有参考以下文章:http://tengj.top/2018/01/01/maven/ (嘟嘟MD)

          https://blog.csdn.net/chenlushun12/article/details/89261586

posted @ 2019-08-21 01:10  F正经  阅读(479)  评论(0编辑  收藏  举报