<a name="8FDqF"></a>
maven--一种项目自动化构建工具
- 所谓自动构建,那eclipse举例,eclipse是半自动构建。
- 全自动构建:包括编译(.java --> .class )、部署(Java project --> Web Project )、jar管理,项目管理等等
- 半自动构建:eclipse只能做到编译和部署
- 自动化构建工具有:Make -> Ant -> Maven -> Gradle(从旧到新,Make和Ant已淘汰),Maven主流,用xml配置,Gragle使用自己的语言Groovy配置。
<a name="feMPN"></a>
基本概念
- 仓库
<br />总仓库有着几乎全世界的jar包,备份到n个镜像上,分布在世界各地,你可以指定一个离你最近的镜像(如阿里云镜像),写项目时所有用到的jar包(除了jdk)都由maven管理。不用每次都复制粘贴到项目的lib文件夹中,maven首先在本地仓库找,找不到就去私服(局域网,使用nexus搭建)找,再找不到才去镜像(中央仓库)下载。项目也可以放在本地仓库中
- 目录结构
maven目录结构为:(以下均为文件夹)<br />
src
main
java
包
resources
配置文件
** test**
java
包
resources
配置文件
** pom.xml**
<br />src存放源代码,main是项目代码,java下面就是各个包了,resource是配置文件。<br />test是测试代码,内容结构和main一样。<br />与src同级的是maven配置文件pom.xml。
<a name="CA5Lo"></a>
测试:
package com.ezeta.maven
import org.junit.Test
public class HelloWorld{
Hello hel = new Hellp();
//随便调用Hello类一个方法,取得String类型返回值
String returns = hel.returnmathod();
//测试返回值是否是“success”
assertEquals("success",returns);//此步称之为【断言】
}
在maven进行test时,会汇报有多少断言通过,有多少失败。
<a name="D21yO"></a>
配置文件(pom.xml)
这个很重要,maven就靠这个来运行<br />pom.xml是项目对象模型,和dom对比区别在于dom是如html当中一个标签为一个对象。
<a name="omtyt"></a>
pom结构
<?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>
<!-- 上面是模型版本,头和尾标签都是固定的,copy就好 -->
<!-- 继承关系 -->
<parent>
<!-- 1.加入父工程的GAV -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<!-- 2.当前工程的pom.xml和父工程pom.xml的绝对路径 -->
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 以下三个标签简称(GAV)是项目在本地仓库中的定位(坐标) -->
<!-- groupId:组名称,[反转地址.大项目名称] -->
<groupId>com.ezeta</groupId>
<!-- artifactId:小项目名称(模块名称) -->
<artifactId>signSystem</artifactId>
<!-- version:项目版本 -->
<version>0.0.1-SNAPSHOT</version>
<!-- 名字通常和项目(模块)名称一样 -->
<name>signSystem</name>
<!-- 项目打包的方式(是jar包还是war包等) -->
<packaging>jar</packaging>
<!-- 版本配置 -->
<properties>
<java.version>11.0</java.version>
</properties>
<!-- 依赖(配置jar包) -->
<dependencies>
<!-- jdbc -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.13</version>
</dependency>
</dependencies>
<!--插件、部署等一系列配置-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.4.2</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</project>
(未完待补)
<a name="JNUxs"></a>
常用命令(cmd需在项目pom.xml所在目录执行)
- mvn compile --编译main目录中的java文件
- mvn test --测试(编译test目录的java文件)
- mvn package --打包,java文件打包成jar/war/pom(测试通过才能打包)
- mvn install --将开发的模块放入本地仓库,供其他模块使用(放入的位置由GAV决定)
- mvn clean --删除target(编译文件)目录
- update project --在pom.xml配置完新的依赖后,需要右键项目->Maven->update project来更新依赖
ps:在eclipse中,右键pom.xml点击Run as->Maven build...在Goals里面写上命令,Eclipse就会自动执行命令行(此处不需要写mvn,直接写命令即可),再次点击Run as->****Maven build就可以执行上一次命令。
<a name="cPwwm"></a>
Maven生命周期
举个例子:在Maven命令中,有个package命令,执行后会发现Console里面实际执行了四个个命令:<br />(resource->compile->test->package),这就是生命周期。
- 当Maven中存在一个命令生命周期顺序:A命令 B命令 C命令 D命令 E命令
执行D命令,实际执行:A B C D
- 生命周期包含三个阶段(了解):
clean lifecycle:清理<br />pre-clean clean post-clean<br />default lifecycle<br />有非常多命令,省略。。<br />site lifecycle:站点(发布)<br />pre-site site post-site site -dedeploy
<a name="1q1E9"></a>
依赖
- 依赖
形如pom.xml中
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
这种就是依赖,即对jar包的依赖。这里省略了<version></version>,三个标签即GAV来定位jar包。
2. **依赖有效性**
先看这段依赖:
```xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<scope></scope>定义了依赖的范围(有效性),值有三个:<br />compile(不声明则默认这个),test,provided。区别是:<br /><br />原因:Maven在编译、测试、运行时,各自使用一套不同的classpath。<br />举个例子,如果我写了个Servlet,此时需要用到Servlet-api.jar,那么我编译时(主程序)会用到这个jar,测试时也会,但是部署时(运行)就不需要了(因为tomcat自带Servlet-api.jar),所以我可以将有效性设置为provide。
- 依赖排除
当B.jar依赖于A.jar时,引入B.jar会自动引入A.jar,如果此时依赖是部分依赖,而我只需要没有依赖的部分,那么我引入B.jar时,就不需要A.jar,此时就需要将A.jar排除。
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.18.RELEASE</version>
<!-- 这个jar会引入beans.jar,aop.jar等等,我们下面将其排除 -->
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</exclusion>
</exclusions>
</dependency>
如上,在dependency标签GAV下面写exclusions标签,标签内写n个exclusion标签,里面是需要排除的jar包的GA(通常不写V,因为排除的肯定是依赖同版本的)。
- 依赖传递性
如果A.jar->B.jar->C.jar;<br />那么A.jar->C.jar的充要条件是:但且仅当B.jar->C.jar的范围(有效性)是compile。
- 依赖原则
- 路径最短优先原则
<a name="da5Am"></a>
项目整合
Maven可以将多个项目整合成一个项目,当项目A->项目B时,两者需要通信,只需:1.将A执行install命令(将项目A打包到仓库中);2.然后让B依赖(配置)A就行了。<br />这里需要注意一下:由于Maven的“约定由于配置”,假如B在cn.hello包下的类,依赖调用了A当中cn.hello包下类,此时不需要import,因为Maven已将同样包名的类打包到了一起(哪怕不是同一个文件、甚至不是同一个项目)。<br />
<a name="YdQ5t"></a>
同一版本&编码
- 统一JDK版本
用<profiles><profile></profile></profiles>标签配置,一般不用这个方法,JDK版本管理方法略
- 统一依赖版本&编码
一般用变量的方式,动态管理版本。在<properties>配置(JDK也能配置)
<?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.ezeta</groupId>
<artifactId>signSystem</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>signSystem</name>
<properties>
<!-- JDK版本 -->
<java.version>11.0</java.version>
<!-- 编码 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- 统一版本 -->
<cn.ezeta.jdbc.version>1.2.3</cn.ezeta.jdbc.version>
<cn.ezeta.druid.version>1.1.13</cn.ezeta.druid.version>
</properties>
<!-- 依赖(配置jar包) -->
<dependencies>
<!-- jdbc -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!--版本使用前面声明的变量动态控制 -->
<version>${cn.ezeta.jdbc.version}</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<!--版本使用前面声明的变量动态控制 -->
<version>${cn.ezeta.druid.version}</version>
</dependency>
</dependencies>
</project>
将properties标签写在pom上面,随意命名一个标签(名字最好显而易见,方便他人知道是什么依赖的版本),标签内容即版本号,然后在依赖标签的<version>标签中内容即是类似EL表达式的properties内的自定义标签(变量)。
<a name="RCV7I"></a>
继承
在依赖传递时,需要compile约束,如果使用继承,则子工程可以使用父工程所有依赖。<br />如A->(继承)B,则A能使用B的所有依赖(jar),不用管什么compile。<br />但通常用于更好的版本管理<br />这里需注意:父工程打包方式需要是“pom”(不是jar,不是war)。<br />
- 在父工程中
<dependencyManagement>
<dependencies>
<dependency>
...
</dependency>
</dependencies>
</dependencyManagement>
需要再<dependencies>外面套一层<dependencyManagement>。
- 子工程的配置见例子
- 子工程需要声明要用到父工程哪些依赖。
<dependency>
<!-- 声明:需要用父类的某jar(只需要写ga即可) -->
<g></g>
<a></a>
</dependency>
<a name="luzBT"></a>
聚合
前面说到,如果A->B则需要将Binstall到仓库中,A才能依赖B,但是如果A依赖很多很多项目,一个个install太麻烦<br />所以有了聚合<br />聚合有个前 置条件:聚合需要配置在一个总工程里面,这个总工程也需要pom方式打包<br />配置方式:
<?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.ezeta</groupId>
<artifactId>project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>project</name>
<!--聚合配置-->
<modules>
<!--需要被聚合的项目根目录的绝对路径-->
<module>../A</module>
<module>../B</module>
<module>../C</module>
</modules>
</project>
在<modules>中每个<module>就是一个要聚合的项目,即当启动这个总项目时,会自动按合适的顺序将<modules>内的项目依次全部启动(这里合理的顺序maven会自动按依赖关系判断,不需要特地写module的顺序),于是当启动A之前会先启动B,那么A就可以依赖B了,这样就不用一个个install了。<br />聚合的本质就是,对总工程进行什么操作,就相当于对所有聚合工程按合适的顺序依次或同时进行一样的操作(如install,package等等)
<a name="GqCa4"></a>
部署Web项目
- <build>标签配置cargo插件
- mvn命令deploy(部署)
实际开发中,还是不太会用cargo,一般还是开发工程师打包成war包后交给实施工程师部署。