Maven的基础了解与使用

首发日期:2018-11-04


Maven的介绍:

什么是Maven:

  • Maven是apache旗下的一个java开源项目。
  • Maven是一个项目管理工具,它可以帮助我们管理项目
  • 可以使用Maven对java项目进行项目构建(构建包括清理、编译、测试、报告、打包、部署六个过程,你可以认为是一个项目的从代码到完整可运行项目的过程)、依赖管理。

为什么要学习maven?

以一个例子说一下maven的好处,说了它的好处,

1.maven可以帮我们管理依赖。在以往的时候,我们都是手动的导入jar包,然后build path;在导入jar包之前,我们需要去查找有哪些包,需要哪些包,这是一个非常繁杂的问题,如果你不是“老司机”的话,你可能会遗漏某些jar包;而在maven中,我们可以使用pom.xml来声明需要哪些依赖包,然后maven就会根据pom.xml中的信息去获取仓库中的依赖包的引用,这就相当于导入了jar包。而且,maven存储了大量的jar包和大量的依赖规则,所以你可以直接去百度搜索一下某个关键字+maven,就可以查找到某个框架或工具的依赖信息,直接把这个依赖信息拷贝到pom.xml中,maven就会帮你管理这个依赖。

2.maven可以帮我们进行工程管理。在以往的时候,我们开发一个项目都是在一个工程中开发,但事实上这对多人开发并不友好,多个开发者之间的开发产生了耦合关系,这对整合造成了一些小困扰(但并不是说不好,只是说有更好的手段)。而使用maven之后,可以建立多个工程来组成一个项目,在不同的工程中开发不同的模块,而多个工程之间的关系由maven管理,maven可以帮我们把多个工程组合成一个项目。



安装与配置:


下载:

点击链接,下载Maven:

下载完了之后,直接解压即可,它是免安装的。


配置环境变量

  • 配置JAVA_HOME环境变量,值是jdk程序根目录【如果已经配置过的,可以省略】

  • %JAVA_HOME%\bin添加到path环境变量中【如果已经配置过的,可以省略】【注意不要弄乱了path的值】

  • 配置MAVEN_HOME环境变量,值是maven程序根目录

  • %MAVEN_HOME%\bin添加到path环境变量中【注意不要弄乱了path的值】

测试安装结果:

配置了环境变量后,可以在CMD中键入mvn -v来测试是否可以运行,下面是我的输出结果:

Apache Maven 3.5.4 (1edded0938998edf8bf061f1ceb3cfdeccf443fe; 2018-06-18T02:33:14+08:00)
Maven home: J:\software\apache-maven-3.5.4\bin\..
Java version: 1.8.0_91, vendor: Oracle Corporation, runtime: E:\SOFTWARD\Java\jdk1.8.0_91\jre
Default locale: zh_CN, platform encoding: GBK
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

Maven概念:

在学会maven之前,先了解几个概念。下面的概念了解即可,后面会在实际的配置中涉及。

坐标

在以往的build path过程中,其实只是把jar包的路径引用添加到eclipse中,eclipse知道需要的包的路径之后,在编译的时候会去引用。

而maven可以根据坐标来指定使用哪个依赖包,坐标经过一定的组合规则就可以得出依赖包所在的路径,maven会根据坐标对应的路径在仓库中来查找jar包。

  • maven用三个向量来组成一个坐标,这个坐标确定唯一的依赖包:

    • groupid:公司或组织域名倒序+项目名
    • artifactid:模块名\工程名
    • version:jar包版本
  • maven会根据坐标在仓库中来查找jar包,把三个向量拼接起来就是依赖包的路径。

    • <dependency>
        		<groupId>org.springframework</groupId>
        		<artifactId>spring-core</artifactId>
        		<version>4.3.0.RELEASE</version>
        	</dependency>
      <!--对应的路径转换格式:groupid/artifactid/artifactid+version+.jar -->
      <!--org/springframework/spring-core/spring-core4.3.0.RELEASE  .jar-->
      

仓库

在上面提到了坐标,你应该认识到了坐标标识了依赖包的路径,而这个路径是相对于仓库的路径的。为什么需要一个仓库呢?上面说了eclipse实质上也是通过路径来导入依赖包的,如果你没有一个统一的文件夹来管理依赖包的话,零散的依赖包足以让你头疼了。而maven的仓库是一个包含了众多依赖包的仓库,而且maven的依赖管理可以很方便地添加依赖包信息。

  • 仓库的分类
    • 本地仓库:本机上的仓库,通常都会有一个本机仓库,不然你老是需要从远程仓库获取的话就很费时间了;而事实上maven会指定一个默认的本地仓库路径,第一次使用maven的时候,会把maven需要的插件和远程库中存储的jar包下载下来并存储到本地仓库中。
    • 远程仓库:事实上你可以给本地仓库存储你自己的jar包,而某个jar包本地没有的时候,就需要从远程仓库下载下来。
      • 私服仓库:是一个远程仓库,但距离比较近,通常是企业中自己内部的maven仓库,通常私服maven仓库都会使用nexus来搭建。
      • 中央仓库:是maven维护的远程仓库,它里面存储的东西比较全。
  • 依赖包的查找顺序:先从本地仓库查找,本地仓库没有就去远程仓库查找(企业中一般是本地仓库->私服仓库->中央仓库)。当查找到了之后,都会下载到本地仓库。【记住初始情况下,maven的仓库是比较干净的,仅仅包含一些基本插件。】
  • 仓库中存储的内容:
    • 插件【maven的功能依赖于插件,没有插件就没有功能,好比电脑需要驱动,maven的构建是通过插件来实现的】
    • jar包
    • 自己开发的maven工程【其实你应该知道自己是可以把自己的工程打成jar包,然后可以在别的工程中导入这个jar包来使用这个jar包中的类,所以你是可以把自己的类库放到仓库中的


入门示例

下面以创建一个maven项目,并使用maven的依赖管理来给项目添加依赖为例:

创建maven工程:

关于如何创建一个maven项目,下面以eclipse中的为例,如果你需要idea的,可以点击下面的链接学习。
图解在IntelliJ IDEA中创建第一个Maven项目

新建工程->选择maven project

添加依赖

在pom.xml中添加下列代码:

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

可以看得出来,依赖已经导入了我们项目的类库。

所以我们利用依赖包中的类来编写代码的时候就不会报错了。


Maven标准目录结构

maven要依据一定的目录规范来管理项目,所以要想用maven管理项目,要遵循规范。下面会讲一下目录定义规范,这样是面向全手动创建maven项目的时候,在很多时候,都会使用工具来创建,比如eclipse中就可以直接创建一个maven工程,这个工程遵循maven工程的目录规范。

约定的目录结构

maven构建一个工程要遵循这个目录规范。

  • 工程目录【下面的缩进程度代表目录级数】
    • src目录:存放工程源码的地方
      • main目录:存放主程序的源代码,这里放的是主体程序代码。
        • java目录:存放java源文件
        • resource目录:存放框架或其他工具的配置文件
        • 【为web项目时会多出一个webapp目录】webapp目录:存放页面素材
      • test目录:存放测试程序的源代码的地方,这里放的都是一些测试用的代码。
        • java目录:存放java源文件
        • resource目录:存放框架或其他工具的配置文件
    • pom.xml文件:这个文件定义了这个maven工程的相关配置。

补充:

  • maven使用一个pom.xml文件来管理依赖。pom中配置依赖信息和maven的一些配置信息,这会在下面讲解。

pom配置:

  • pom是Project Object Model项目对象模型的意思。
  • pom.xml是maven工程的核心文件,与构建工程相关的一切配置(依赖信息、插件信息等等)都在这个文件中配置
  • pom.xml中的可配置标签很多,我们这里仅仅介绍经常使用的。这些经常使用的也足够你日常使用了。

常见标签

  • modelVersion:是pom的版本,一般都是默认生成的,不需要关心
  • groupId:标识当前工程的所属组织,写法类似包名。【为什么工程也有这个呢?因为我们的工程也是能打包到本地仓库的。】
  • artifactId:当前工程的工程名
  • version标签:当前工程的版本号
  • dependencies标签:用于管理这个工程的依赖
    • dependency标签:指定某个依赖的信息
      • groupId:标识依赖包的所属组织,写法类似包名。
      • artifactId:依赖包的包名。
      • version:依赖包的版本。
      • scope标签:依赖包的依赖范围。

依赖级别\依赖范围

依赖信息中的scope标签是用来定义依赖范围的。依赖范围影响依赖的生存周期(就好比游戏中的特殊状态,可能一些状态可用于pk,一些状态可用于打副本,一些状态可用于任务,不同的地方影响效果是否生效。),依赖范围的值有以下几个:

  • compile:编译级别的依赖会用在编译、测试、运行的过程中。默认依赖范围:compile
  • test:test仅仅针对test目录下的源文件,由于test目录下存放的是test文件,测试文件一般都不会编译到主程序中,所以test级别的依赖是不会在编译和运行中生效的。只在测试编译和测试运行阶段可用。这个级别的依赖包例如有junit包,junit仅仅用来测试,在主程序编译和运行中是不需要它的。
  • provided:provided代表已提供的意思,provided范围会用来编译和测试,不会出现在运行中,provided主要用来处理容器也提供了我们所需要的包的情况。例如servlet-api这种依赖包tomcat容器也会提供给部署的程序,如果提供多个同名的依赖包可能会导致主程序运行出错。
  • runtime:在编译的时候不需要(没有用到具体类),但是在运行和测试的时候需要用到,就可以使用这个。例如数据库驱动包,它仅仅在运行和测试的时候会使用到这个依赖包。
  • system:类似provided,对于编译和测试有效,运行时不需要,不建议使用,所以不讲

依赖传递的导入

要注意,在一个工程中,如果导入的依赖需要一系列依赖(A包需要B包才能正常,那么也会导入B包),那么也会导入这一些依赖,例如struts2-core依赖一系列的包。

演示:基于eclipse

仅仅导入struts2-core的时候,maven会自动导入struts2-core所依赖的包:

发现maven自动导入了struts2-core依赖的包(这些依赖包是由struts2-core项目中的pom.xml指定的)

依赖传递问题

  • 依赖传递的过程中:
    • 路径最短者优先
      • A依赖B,B依赖C,C依赖D(版本1.1)
      • A依赖E,E依赖D(版本1.2)
      • 导入时选择版本D(版本1.2)
    • 路径相同,先声明者优先【意思是如果A同时依赖于B和C,而B和C都含有同一个依赖包P,如果在A的继承声明中先声明B,那么A会继承B的依赖包P,所以P版本取决于B】

依赖排除

可能会遇到一种情况,在同一个工程中,A包依赖B包的1.0版本,C包依赖B包的1.5版本。那么B的1.0和1.5都被引入了。这可能会导致紊乱,因为构建的时候会不清楚使用哪个版本的B依赖包。这时候我们需要使用依赖排除来解决这个问题。【一般都是排除低版本】

例如struts2-core依赖javassist包,hibernate-core也依赖javassist包,根据依赖的依赖的导入规则,这时候会有两个javassist

为了避免紊乱,我们要使用exclusions排除。在eclipse中,我们可以在Dependency Hierarchy中右键选中包进行排除,也可以使用以下xml式排除:

  	<dependency>
  		<groupId>org.apache.struts</groupId>
  		<artifactId>struts2-core</artifactId>
  		<version>2.3.34</version>
  		<exclusions>
            <!-- 排除struts2-core的依赖中的javassist依赖 -->
  			<exclusion>
  				<groupId>javassist</groupId>
  				<artifactId>javassist</artifactId>
  			</exclusion>
  		</exclusions>
  	</dependency>

依赖的继承

在建立多个有继承关系的工程时,父工程的依赖信息会传递给子工程。
在父工程中声明了依赖后,就算子工程没有声明,也会传递到子工程中

版本锁定

在分模块开发时,多个子模块可能会使用上同一个依赖包,那么如何限定多个子模块都使用同一版本的依赖包呢?可以使用版本锁定。

  • 在父工程使用dependencyManagement来管理依赖(dependencyManagement不会导入依赖),那么依赖的版本会被父工程锁定。
  • 通常情况下,父工程的依赖会传递给子工程(如果你另外也使用了dependencies标签来声明依赖),那么子工程不声明的时候是没问题的;如果子工程显式导入被锁定版本的依赖时,会报错,会提示版本被父工程锁定。
<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>junit</groupId>
				<artifactId>junit</artifactId>
				<version>4.9</version>
				<scope>test</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

统一管理依赖版本:

你应该经常见到某个框架的依赖包都是同一版本的,如果我们将这些依赖信息都添加到pom.xml中,可能会出现多个重复的version标签,如果你要修改的话是很麻烦的,要逐个逐个去修改版本。

事实上,是可以统一管理依赖版本的,同一管理依赖版本之后,如果我们要修改这个框架下的包的版本,那么只需要修改一处就行了。

  • 使用properties内使用自定义标签统一版本号,自定义标签相当于一个变量,后面的version那里可以引用这个变量。
 <properties>
     <!-- 使用自定义标签统一版本号,标签名是自定义的 -->
  	<struts2-version>2.3.34</struts2-version>
  </properties>
  
  <dependencies>
  	<dependency>
  		<groupId>org.apache.struts</groupId>
  		<artifactId>struts2-core</artifactId>
        <!--在version标签中引用 -->
  		<version>${struts2-version}</version>
  	</dependency>
  </dependencies>

注意:properties标签并不是只能用于统一声明依赖版本,但凡是需要统一声明的地方都可以考虑使用properties标签。



Maven命令

全局命令

  • maven -v :查看版本

工程级命令

以下命令针对于maven工程,必须到pom.xml目录才能执行命令

  • mvn clean:清理之前编译出的class文件,相当于清理target目录及其目录下的所有文件。
  • mvn compile:编译主程序,效果是把src/main/java下的java源文件编译为class文件并输出到target下的classes目录下。
  • mvn test-compile:编译测试程序
  • mvn test:执行src/test/java下的单元测试类,会打印出测试结果(如果被junit标识成测试类的话),并把src/main/java下的java源文件编译为class文件并输出到target下的test-classes目录下。
  • mvn package:打包,java项目打包成jar包,web项目打包成war包。打包的文件存储到target目录下。
  • mvn install:安装,把maven工程打包成jar包或war包并保存到本地仓库中。【在本地仓库目录下根据坐标来生成包路径来保存】。对于我们自己的maven工程,可以使用mvn install把它安装到仓库中。

命令生命周期

  • 属于同一个生命周期的指令,当后面的命令执行时,前面的命令也会自动执行。
  • 常见命令周期:
    • clean :在进行真正构建之前的一些清理工作。
      • 包含命令:pre-clean,clean,post-clean
    • default:构建的核心部分:编译、测试、打包、部署等等。【要注意,大部分命令都处于default生命周期,所以执行某个命令时,生命周期前面的命令也会自动执行。】
      • 包含命令:validate,compile,test,package,verify,install,deploy....
    • site:生成项目报告、站点、发布站点。。
      • 包含命令:pre-site,site,post-site,site-deploy

每一个阶段都有一个对应的命令,且有相应的插件来支持命令的运行。


setting.xml配置文件

仓库配置

本地仓库配置

maven安装路径下\conf\settings.xml文件,在settings.xml中配置localResposity标签。,它是被注释了的,有配置方法的提示。

默认目录:用户目录下.m2/repository

添加远程仓库

<mirrors>
	<!-- 中央仓库1 -->
        <mirror>
            <id>repo1</id>
            <mirrorOf>central</mirrorOf>
            <name>Human Readable Name for this Mirror.</name>
            <url>http://repo1.maven.org/maven2/</url>
        </mirror>

        <!-- 中央仓库2 -->
        <mirror>
            <id>repo2</id>
            <mirrorOf>central</mirrorOf>
            <name>Human Readable Name for this Mirror.</name>
            <url>http://repo2.maven.org/maven2/</url>
        </mirror>
</mirrors>
        

Eclipse中使用maven

配置maven

eclipse有自带的maven插件,但不建议使用。

把独立的maven添加成一个新的maven:

配置user settings:

创建maven工程:

【maven model用于分模块开发时创建子工程,多个子工程与核心工程组成一个完整的项目。】

新建工程->选择maven project

下面给的是打包方式为war的时候的目录结构:

修改JRE版本:

默认情况下,maven工程引用的jre库是1.5的,这可能会导致一些语法问题(例如泛型的语法问题),所以通常需要更改这个引用的jre库版本。

  • 修改方法:在setting.xml中修改profiles标签
<profile>
			<id>jdk18</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>
				<maven.compiler.encoding>utf-8</maven.compiler.encoding>
			</properties>
</profile>

导入依赖

  • 方式一:手动添加,通过手动拷贝等方式统一增加。可以百度包名+maven来查找依赖信息的写法,拷贝下来粘贴到pom.xml中即可。

    • <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
          <scope>provided</scope>
      </dependency>
      
  • 方式二:在eclipse,双击打开pom.xml,默认情况下不是xml界面,点击下面的dependencies选项,再点击add,在中间的搜索框输入信息搜索依赖,选择依赖包,最后点击确认。这要求你比较熟悉需要哪些包。

1539015718240

1539015941160

添加插件

有时候我们希望给maven工程添加额外的插件,例如tomcat7:run插件,这个插件能使得我们的工程虚拟地部署到tomcat中。

  • mvn tomcat:run 命令是一个插件,需要添加才能执行这条命令,添加方式:项目右键选择maven,再add plugin,然后搜索tomcat

    • <!--build与dependencies是同一级的 -->
      <build>
        	<plugins>
        		<plugin>
        			<groupId>org.apache.tomcat.maven</groupId>
        			<artifactId>tomcat7-maven-plugin</artifactId>
        			<version>2.2</version>
        		</plugin>
              <configuration>
      		<!-- 端口 -->
      		<port>8080</port>
      		<!-- 访问路径 -->
      		<path>/helloworld</path>
      		<!-- 编码 -->
      		<uriEncoding>utf-8</uriEncoding>
      	</configuration>
        	</plugins>
      </build>
      

这里仅仅给一个添加插件的示例,其他的插件有兴趣可以自查。

Eclipse中执行maven命令

工程右键->run as ->第一个maven build可以让你选择之前执行过的命令来执行,第二个maven build可以让你输入指定命令来执行(在goals中输入命令,mvn test只需要输入test即可);至于后面的clean,install和test的意思已经显而易见了。

创建web工程

如果想创建一个web工程,需要在创建工程的时候打包方式改成war。但默认情况下src/main下是没有webapp目录(存放WEB-INF目录和web.xml的目录)的。

  • 生成webapp目录:
    • 方式一: WEB-INF目录和web.xml,javaEE tools->Generate Deploy...
    • 方式二:手动创建目录和文件

依赖范围冲突问题:

什么是依赖范围冲突呢?这涉及到依赖范围问题,主要是provided问题。以servlet-api依赖为例,这个依赖tomcat会提供给我们部署的项目,但如果我们添加这个依赖的时候选择了compile,那么这个依赖也会带到部署的项目中,使得存在了两个servlet-api依赖。

解决方法:这时候要修改servlet-api依赖的范围,改成provided。

依赖排除问题:

这个在pom配置的依赖排除中讲过了。这里只提一下,不再演示。

如何运行项目

java项目:

  • 运行方式一:项目右键->run as->java application
  • 由于方式二跟直接到目标目录执行java没什么区别,所以这里不讲,有兴趣可以自查mvn exec

web项目:

  • 部署方式一:在添加了插件之后,使用tomcat插件部署:mvn tomcat7:run
    • 选择5 Maven build之后,输入命令tomcat7:run
    • 区别:插件的是虚拟环境,会比较快。
  • 部署方式二:打成war包之后,把war包拷贝到tomcat目录中。
  • 部署方式三:建立服务器之后,把项目添加到tomcat中;或者在pom.xml文件点击右键,直接把项目添加到tomcat中。

工程拆分和聚合

  • 在一个比较大的项目开发协作中,如果按照以前的开发的话,是一个工程。这样会有一些问题。拆分、分模块便于测试和开发。不同开发者仅仅面向自己的工程。
  • 然后在整合的时候,把工程聚合起来,就能聚合成一个完整的项目了。

工程的拆分

工程的拆分是创建一个核心父工程,然后创建多个子模块的情况。核心父工程一般不会编写什么内容,一般只作为依赖的汇总(让父工程引入共有依赖,子工程单独依赖的单独引入)。

创建父工程:

创建子工程

为了让父工程能管理到子工程,所以在父工程下右键"new-->maven module"

创建完父工程和子模块后,可以在父工程的pom.xml中看到父工程管理到了子模块:

而子模块也指向了父工程:

然后子模块怎么开发呢?它相当于与一个独立的模块,所以你可以像往常一样开发。不过提一下的是,可能会发生service层调用dao层,那么这怎么实现呢?这就需要我们在service层中添加dao层的依赖了,这样service层就可以调用dao层的方法了。

这里提一下工程拆分与框架整合的问题,在以前一个工程中,dao和service都是交给spring去管理的,那么现在
该怎么处理呢?首先,要注意的是,只要我们配置了spring(这里注意,依赖已经导入了),无论是xml还是注解
式,那么spring就能够管理好我们的bean。所以,我们现在其实只需要关心我们的bean是否交给了spring来管理
即可。而这个单个模块的测试可以在test目录下再编写代码来测试。

工程的聚合

拆分工程之后,开发完成了,怎么聚合使用呢?
首先,要注意父工程管理着子模块,

如果打包父工程,那么子工程也会进行打包。

而通常我们在进行web开发的时候,由于子模块web是核心项目,而子模块web又依赖着子模块service,而在打包的时候依赖的包也会打成jar包,所以打包子模块web的时候,web工程的lib里面是有依赖的兄弟工程的,所以我们可以直接运行web工程即可。【这是运行war包的情况】

我们也可以选择在IDE中直接运行子模块web(在eclipse直接run as),也是能够调用到其他兄弟模块的功能的。


写在最后

这篇关于maven的博文看完了,你应该能对maven的使用有一个基本的了解。

这里给一个常用的查maven的依赖信息的网站:mvnrepository.com


posted @ 2018-11-04 15:17  随风行云  阅读(1785)  评论(0编辑  收藏  举报