关于maven的使用总结
- maven介绍
项目构建过程
eclipse只是开发工具,虽然提供了创建、编码、编译、测试、运行等功能,但并不是项目构建工具。
项目构建主要过程如下:
实际的项目构建过程要复杂繁琐的多。如果是一个独立的项目,使用人工去构建勉强可以接受。但如果一个项目由很多子模块组成,这时的构建过程就很繁琐痛苦,而且容易出问题。所以我们希望能有一个工具帮我们很方便的、自动化的完成构建工作。
项目依赖jar包的管理
项目中会用到各种框架、工具包,也就是项目中会添加依赖的jar包。由于可能会依赖很多jar包,而且每个jar包可能会有多个版本,而且某些jar包可能又会依赖其他jar包...这就造成了jar包管理的混乱,特别容易出错。
我们希望有一个工具可以帮助我们管理项目所依赖的jar包,特别是管理jar包的版本,避免出现混乱和错误
使用maven来解决
- maven是apache组织下的一个开源项目
- maven是项目管理工具,主要管理java语言编写的项目
- maven可以有效的构建项目、管理项目的jar包依赖
- maven遵从插件思想的设计,所有需要的各个功能由各个插件提供
- maven具有跨平台、自动化、标准化等特点
- maven可以独立完成整个项目的构建,也就是说可以单独使用maven。但项目开发和构建有很多步骤是重复的,所以一般在eclipse中使用maven插件,把项目开发和构建结合起来,用起来更加方便。
- maven项目基本目录结构
- maven项目坐标
<groupId>com.xxx</groupId> <artifactId>hello</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging>
说明:
groupId:组织、公司或整个项目的唯一标识
artifactId:项目名称
version:项目版本
packaging:打包方式,也就是项目类型。jar表示普通Java项目,war表示web项目等
- 中央仓库
全世界所有的maven项目都可以发布到中央仓库,中央仓库中的项目是公开的,可以任意引用,并且几乎所有的项目都提供了源码 。
发布到中央仓库的项目一般是一些组织或者公司的开源项目,发布的目的就是为了方便别的项目引用。而公司自己的商业项目等是不应该发布到中央仓库的。
当然并不能随意的就可以把项目发布到中央仓库,需要先申请,还有其他操作,具体用到的时候可以去网上搜教程。
- 镜像
中央仓库的copy,可缓解中央仓库的下载压力,速度一般比中央仓库快
配置镜像:在.m2目录下 settinngs.xml中 <mirrors>下:
<mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror>
- 项目构建
一个maven项目从源代码状态到完成部署,要经历很多阶段(可以称为项目构建的生命周期),每个阶段由若干maven插件来完成,插件所完成的事情称为插件目标,插件目标的执行顺序是事先规定好的,当执行某个插件目标时,会自动的先执行前面的插件目标。
另外还有一个常用的插件目标clean,用来清除项目target下编译好的文件
- 依赖管理
如果项目A使用了项目B中的类、接口等,则项目A依赖项目B(简写为A -> B)
- 配置依赖
maven以配置的方式在pom.xml文件中管理项目的依赖
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies>
- <dependencies>:用来管理项目的所有依赖
- <dependency>:用来配置一个依赖
- <groupId>:被依赖项目的坐标的groupId
- <artifactId>:被依赖项目的坐标的artifactId
- <version>:被依赖项目的坐标的版本
- <scope>:此依赖的生命周期
依赖的生命周期(<scope>取值)
- compile 编译、测试、运行时都会依赖,是默认值
- test 编译、测试时依赖,运行时不依赖,如junit
- provided 编译、测试时依赖,运行时不依赖,由运行环境提供,如servlet-api由tomcat提供
- runtime 编译时不依赖,测试、运行时依赖,如mysql-connector-java-5.1.37
- 依赖传递
maven项目之间的依赖可以传递
A -> B,B -> C,那么A -> C
依赖传递并不是绝对的,跟依赖的scope有关。
如果B -> C的scope是compile、runtime时,A -> C,否则不依赖。
并且A -> C的scope和B -> C的scope 一致。
- 依赖传递的冲突和解决
通过直接配置或者依赖传递而获得的依赖中如果有同一个项目的多个不同的版本,此时就会产生版本冲突。解决方法是指定优先级规则,优先级规则如下:
深度最小优先
直接配置的依赖深度为1,传递依赖时每间隔一个项目深度加1
A -> C 1.0 的深度为2
A -> C 2.0 的深度为3
根据深度最小优先原则,A -> C 1.0
最先配置优先
根据深度最小优先原则无法解决时,最先配置的版本优先,即A -> C 1.0
- 主动排除传递的依赖
可以通过配置主动让项目排除某个传递的依赖
<dependency> <groupId>org.glassfish.web</groupId> <artifactId>jstl-impl</artifactId> <version>1.2</version> <exclusions> <exclusion> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </exclusion> <exclusion> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> </exclusion> </exclusions> </dependency>
- 继承
一个较大的maven项目可以拆分为若干个maven子项目(可以称为模块)。一般都会创建一个parent模块让各个子模块继承,在parent模块中统一管理各个依赖的版本。
- 创建parent模块
创建maven项目时指定<packaging>为pom即可创建一个pom类型的项目,可作为parent模块。
- 管理依赖的版本
管理依赖的版本并不意味着parent项目本身依赖这些jar包。
<dependencyManagement> <dependencies> <!-- mysql驱动包依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.37</version> </dependency> <!-- c3p0依赖 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5</version> </dependency> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency> </dependencies> </dependencyManagement>
- 创建子项目
只需要在创建maven项目时填写parent相关信息
子项目在配置依赖时不用配置依赖的版本,依赖的具体版本由父项目管理。同时子项目也不用配置插件信息,都由父项目来管理
- 管理其他插件版本
如可以指定JDK版本
<build> <plugins> <!-- 指定JDK编译版本 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build>
- 聚合
如果项目较大,通常的做法就是把项目切分成若干个模块,并由一个父模块来管理依赖、插件等的版本。各个模块会分别打包并安装到仓库,而且通常由某个子模块作为主模块并调用其他子模块,项目部署运行时运行这个主模块。
- 聚合方式1
子模块使用Maven Module的方式创建,父子模块之间有很强的包含关系,并且子模块创建在父模块目录下
工作空间中目录结构如下:
- 聚合方式2
直接以Maven Project(普通方式)的方式创建各个模块,只要正确指定父子关系以及模块间的依赖关系,这些模块在逻辑上就是聚合的。
这时的子模块目录和父模块目录同级,并且父模块pom.xml中没有<modules>,除此之外和“聚合方式1”几乎都一样,这两种聚合方式都经常使用。