目录
maven介绍
Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件。
Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性,所以常常用两三行 Maven 构建脚本就可以构建简单的项目。由于 Maven 的面向项目的方法,许多 Apache Jakarta 项目发文时使用 Maven,而且公司项目采用 Maven 的比例在持续增长。
maven仓库:
需要的jar包不可能每次使用都去互联网上下载所以本地仓库相当于加了一层jar包缓存,通常会先在本地仓库查找如果没有找到就会去私服上找如果还没有找到就会去中央仓库找,找到后会把jar的信息同步到私服和本地仓库。
私服:公司内部局域网的一台服务器。因此私服中存储了本公司的内部专用的jar!不仅如此,私服还充当了中央仓库的镜像,说白了就是一个代理!
中央仓库:该仓库存储了互联网上的jar,由Maven团队来维护,比如地址是类似这样的:https://repo1.maven.org/XXXX。
Maven工程可以共享jar包.通过仓库的形式共享jar包
Maven还有继承、版本控制、聚合等功能。
maven的安装和配置
1. 下载maven
http://maven.apache.org/download.cgi
2. 对maven进行解压
3. maven的目录结构
4. 环境变量的配置
MAVEN_HOME F:\java803\apache-maven-3.5.4
PATH F:\java803\apache-maven-3.5.4\bin
5. 测试
6. 配置本地仓库位置 settings.xml
默认仓库的位置: ${user.home}/.m2/repository
自定义仓库位置: F:\java803\repository(自己仓库的位置)
7. 修改中央仓库加速器
阿里加速
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
华为加速
<mirror>
<id>huaweicloud</id>
<mirrorOf>*</mirrorOf>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
</mirror>
选取其中一个加速即可。
8. 指定jdk版本
<profile>
<id>jdk-1.8</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>
</properties>
</profile>
maven与eclipse集成
- 打开eclipse中的window-->prefenerces
eclipse创建maven项目
- File-->new-->maven project
maven项目目录结构
maven常用指令
Compile 编译
Test 测试
Install 按装
clean 清理
执行test ,先执行compile
Install compile---> test ---> install
clean compile
clean test
clean install
maven依赖
我们maven工程想引用一些jar包时,在pom.xml中直接引入依赖即可。
依赖采用三角坐标进行定位引入。(公司名+项目名+版本)
可以从网上maven仓库中查询三角坐标
示例:
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
maven直接依赖间接依赖
在C工程中使用B工程中的类,可以在C工程的pom.xml直接引入B工程。这种叫做直接依赖。
如果B工程依赖了A 工程,这时C工程中也会依赖A工程,A工程就收C的间接依赖。
maven依赖scope属性
Scope的值如果是compile范围,则具有依赖的传递性。
Scope的值如果是test、provided范围,则不具有依赖的传递性。
既然,Maven的生命周期存在编译、测试、运行这些过程,那么显然有些依赖只用于测试,比如junit;有些依赖编译用不到,只有运行的时候才能用到,比如mysql的驱动包在编译期就用不到(编译期用的是JDBC接口),而是在运行时用到的;还有些依赖,编译期要用到,而运行期不需要提供,因为有些容器已经提供了,比如servlet-api在tomcat中已经提供了,我们只需要的是编译期提供而已。
总结来说:
compile:默认的scope,运行期有效,需要打入包中。
provided:编译期有效,运行期不需要提供,不会打入包中。
runtime:编译不需要,在运行期有效,需要导入包中。(接口与实现分离)
test:测试需要,不会打入包中。
system:非本地仓库引入、存在系统的某个路径下的jar。(一般不使用)
maven可选依赖
在compile范围默认都具有传递性,如果你希望一个依赖不具有传递性,可以加一个标签
<optional>true</optional>设置为true表示不具有传递性。 false是一个默认值,具有传递性。
maven的依赖排除
当我们引入一个jar时,这个jar包可能还依赖其它的jar包,这些jar包和我工程中的其它的版本不一致时,可以使用依赖排除。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.3</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>org.jboss.netty</groupId>
<artifactId>netty</artifactId>
</exclusion>
</exclusions>
</dependency>
maven依赖冲突
首先来说,对于Maven而言,同一个groupId同一个artifactId下,只能使用一个version!
根据上图的依赖顺序,将使用1.2版本的jar。
现在,我们可以思考下了,比如工程中需要引入A、B,而A依赖1.0版本的C,B依赖2.0版本的C,那么问题来了,C使用的版本将由引入A、B的顺序而定?这显然不靠谱!如果A的依赖写在B的依赖后面,将意味着最后引入的是1.0版本的C,很可能在运行阶段出现类(ClassNotFoundException)、方法(NoSuchMethodError)找不到的错误(因为B使用的是高版本的C)!
这里其实涉及到了2个概念:依赖传递(transitive)、Maven的最近依赖策略。
依赖传递:如果A依赖B,B依赖C,那么引入A,意味着B和C都会被引入。
Maven的最近依赖策略:如果一个项目依赖相同的groupId、artifactId的多个版本,那么在依赖树(mvn dependency:tree)中离项目最近的那个版本将会被使用。(从这里可以看出Maven是不是有点小问题呢?能不能选择高版本的进行依赖么?据了解,Gradle就是version+策略)
现在,我们可以想想如何处理依赖冲突呢?
想法1:要使用哪个版本,我们是清楚的,那么能不能不管如何依赖传递,都可以进行版本锁定呢?
使用<dependencyManagement> [这种主要用于子模块的版本一致性中]
想法2:在依赖传递中,能不能去掉我们不想依赖的?
使用<exclusions> [在实际中我们可以在IDEA中直接利用插件帮助我们生成]
想法3:既然是最近依赖策略,那么我们就直接使用显式依赖指定版本,那不就是最靠近项目的么?
使用<dependency>
maven继承与统一版本管理
packaging值有三个 pom jar war
父工程的packaging只能是pom
Java工程 packaging只能就 jar
Web工程 packaging只能是 war
父工程:parent
<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.offcn</groupId>
<artifactId>parent</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<dependencies>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- dbutils -->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
</project>
子工程:sub_demo
<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>
<parent>
<groupId>com.offcn</groupId>
<artifactId>parent</artifactId>
<version>1.0</version>
</parent>
<artifactId>sub_demo</artifactId>
<packaging>jar</packaging>
</project>
子工程继承了父工程,就继承了父工程中所有依赖。不在区分scope范围。
统一版本管理
父工程中声明依赖的版本
<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.offcn</groupId>
<artifactId>parent</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<properties>
<junit-version>4.12</junit-version>
<dbutils-version>1.6</dbutils-version>
<c3p0-version>0.9.5.2</c3p0-version>
<mysql-version>5.1.47</mysql-version>
<logging-version>1.2</logging-version>
</properties>
<!-- 声明依赖的版本 -->
<dependencyManagement>
<dependencies>
<!-- 单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit-version}</version>
<scope>test</scope>
</dependency>
<!-- dbutils -->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>${dbutils-version}</version>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0-version}</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-version}</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>${logging-version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
子工程
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
</dependency>
</dependencies>