文章目录
摘要
MAVEN是一个能够帮助你1、管理依赖库,2、构建代码包的命令行工具
。它由管理命令,执行周期(生命周期),依赖仓库三大核心
点组成。
基础概念
版本:如果你学习过GITHUB基础概念与使用,当你在实际开发中运用版本
,你是希望保存历史和现今版本的,如果你迭代了一个新的版本但是这个版本的迭代出现了问题,你可以选择回滚
以达到上一个完美运行的版本。
编译:依赖有千万种,但是有些依赖你在正式跑项目时是不需要的。因为它们根本就不可能执行。比如测试用例你只会在开发环境(你自己验证时)使用得到,但是你又不可能每次编译时将他们删除。通过日常的配置
加上简单的命令
来完成N个依赖的编译和打包处理。排除那些不需要的,打包所有需要的。
生命周期
所谓的生命周期就是在使用的过程中,在什么时间或阶段干了什么事情。当我们使用eclipse或idea打包一个项目时它们的生命周期(执行过程)是单一的。
Maven的生命周期(执行过程)包含了:清理(删除本地之前编译的)- 构建(验证,编译,执行测试,打包,发送到仓库)- 部署(基本不用)。并且
在同一个周期内
可以有多个组件
依次为了该操作执行。Maven将所有的生命周期都封装为了扩展点
,也就是说你完全可以自己实现某个过程中的某个处理。
在MAVEN中如果你执行了打包命令,那么在MAVEN中实际执行了这些命令的集合。(以下每一个周期你都可以引用多个处理该周期的组件,甚至开发自己的扩展去处理):
- clean : 清理,就是删除文件
- validate :校验,检查是不是合规的maven项目
- compile:编译项目中的代码
- test :执行项目中的测试案例(你自己编写用于验证正确性的代码)
- package :打成jar或者war包
- verify :校验jar或war。
- install :安装到本地专门存放包的仓库。
- site:生成站点文档
- deploy:安装到远程专门存放包的仓库。
以clean为例:MAVEN底层的封装并不是直接执行clean,而是检查你是否有执行clean的组件,没有的话就执行自己开发的组件。请注意MAVEN自带的组件也在它本身的声明周期之外。
安装
Maven下载链接->MAVEN官网地址
安装前的准备
必须要有JAVA环境。如果还没有安装过可以参考:JAVA环境搭建
windows
下载.zip
解压后放置任意一个目录,并记录位置。和配置JAVA一样,找到环境变量配置的地方。
- 编辑系统变量,变量名称你随意,记住了后面还要用别弄错就行(这里是在网络上的截图,和我示例版本无关,因为使用的是mac所以无法为大家完整演示windows,真实的版本需要按你自己下载的来)
- 然后在系统变量中继续寻找
PATH
变量,找到后;%Maven_Home%\bin;
将该内容追加到PATH
后,注意;
是为了区分多个不同的变量(只可多不可能少也就是说你可以;;;;;;;;;;;;;%Maven_Home%\bin;
这样都行)。- 确认后在命令行输入
mvn -version
或mvn -v
校验。
mac
下载.tar.gz
初学者还是建议不使用Homebrew
等工具来安装它。你需要足够了解它的内容,因为该工具(或该类)会一直伴随着你。解压后放置到资源库。
- 如果你还记得安装java环境时的
~/.zshrc
或者不记得,在~/目录下
新建或修改zshrc
就可以。可以参考zshrc文件类型的描述,以及如何在命令行新建文件- 我的命令执行过程
apple@apples-MacBook-Pro ~ % vim ~/.zshrc apple@apples-MacBook-Pro ~ % source ~/.zshrc apple@apples-MacBook-Pro ~ % mvn -version Apache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3cd08dcc295161ae) Maven home: /Library/apache-maven-3.9.6 Java version: 1.8.0_361, vendor: Oracle Corporation, runtime: >/Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre Default locale: zh_CN, platform encoding: UTF-8 OS name: "mac os x", version: "12.6.3", arch: "x86_64", family: "mac" apple@apples-MacBook-Pro ~ %
~/.zshrc
文件中的内容:export MAVEN_HOME=/Library/apache-maven-3.9.6 export PATH=$MAVEN_HOME/bin:$PATH
source ~/.zshrc
后在命令行输入mvn -version
或mvn -v
校验。
开始使用
认识代码仓库
目前我们必须要了解到的两个配置
(路径:你的目录/apache-maven-3.9.6/conf/settings.xml
):
localRepository
(本地仓库):这是本地仓库目录路径,maven会自动的通过镜像地址下载依赖到本地仓库。该配置在文件中默认是注释掉的,因为它默认在${当前用户目录}/.m2/repository
目录。
该目录和.zshrc一样,都是隐藏存在的,如果是mac则可以通过如图所示的快捷键中显示所有隐藏的文件夹和文件。
如果是通过命令行ls -a
可以显示隐藏的文件夹和文件:apple@apples-MacBook-Pro ~ % cd ~/ apple@apples-MacBook-Pro ~ % cd .m2/repository/ apple@apples-MacBook-Pro repository % ls antlr commons-io org com commons-lang xmlpull commons-collections io apple@apples-MacBook-Pro repository % pwd Users/apple/.m2/repository
mirrors-mirror
,是执行命令时maven下载依赖的网址。默认该配置里的内容是http://0.0.0.0
代表了当前你的机器的IP地址。但实际你执行命令它默认是去到自己官网去下载内容。- 通常我们会改变1.(你希望存放的路径)2.(你需要更快的下载速度)的配置。第一点不用说,改变路径即可。第二点通常我们要配置国内的网站。比如:
aliyun
。<mirror> <id>alimaven</id> <name>aliyun-maven</name> <mirrorOf>central</mirrorOf> <url>http://maven.aliyun.com/nexus/content/groups/public</url> </mirror>
- 如果不修改此位置很可能使用mvn命令时是卡顿的,因为毕竟官网是国外站点。
- 修改后执行时下载依赖的站点
使用命令行来创建项目
mvn archetype:generate
:
archetype?
:使用不同的项目原型(目录结构和必须的文件,比如jar和war的结构是不一样的)来建立项目。
- 按照默认的样本输入
1
创建
groupId?
:要理解这一点我们必须观察该命令的执行结果mvn dependency:get -DremoteRepositories=http://maven.aliyun.com/nexus/content/groups/public -DgroupId=mysql -DartifactId=mysql-connector-java -Dversion=8.0.33
。
- 通过
mvn dependency:get
复制远程镜像的依赖到本地,DremoteRepositories
是远程地址。
前面
setting配置文件中localRepository
的目录,找到mysql
groupId
是包前缀:包前缀通常是公司名称,.
间隔后到本地会是以.
间隔为目录,比如:。
com
通常作为一家企业的默认的前缀,所以我们在上面的命令行中提示的groupId
中输入com.edu.samuel
artifactId
:就是在mysql目录中的mysql-connector-java
,在java中项目名称也都通过词与词之间小写化
+-
来作为项目名称。也就是说groupId
通常作用于是哪个公司,哪个项目组来完成的。
version
:在软件的世界中通常使用x.x.x来标识一个版本,第一个x表达大进化,其次依次是更小的变动,其中这个界限在哪里,没有硬性的规定,某个团队中或许会有明确的要求。
package
:打包时的jar或war文件名称。输入后继续输入y
来完成提示内容。
pom.xml
apple@apples-MacBook-Pro lesson1 % pwd
/Users/apple/lesson1
apple@apples-MacBook-Pro lesson1 % ls
pom.xml src
apple@apples-MacBook-Pro main % cat pom.xml
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.edu.samuel</groupId>
<artifactId>lesson1</artifactId>
<version>0.0.1</version>
<name>Archetype - lesson1</name>
<url>http://maven.apache.org</url>
</project>
pom.xml
主要是配置依赖
与生命周期中使用的组件
的配置文件,它将指导着你希望如何构建这个项目。- 刚才我们有一个谜题还没得到验证,就是package的执行结果
- 我们最开始选择了根据默认创建的模型创建项目,所以这里在
该目录下
执行mvn package
package
周期执行完成(在不修改任何pom.xml内容)时的执行结果会有一个target目录,查看该目录结果,classes目录是所有你可以直接查看的class文件,- 而
lesson1-0.0.1.jar
则是需要通过jd-gui打开JD-GUI。 - 我们执行
mvn install
,前面说过,它是打包到本地的包仓库。而mvn package
只是在当前目录下生成了编译后的class与jar。 - 所以到这里
install
命令的意义是,将这个目录公布到仓库中,让其它协作的人员或团队
能够同样通过maven配置
的方式引用到你的最新内容。 - 而打包的jar名字是通过
pom.xml
中的<name>Archetype - lesson1</name>
来确定的。
依赖
我们将刚才新建的项目中的pom.xml
内容修改为(添加了mysql的依赖):
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.edu.samuel</groupId>
<artifactId>lesson1</artifactId>
<version>0.0.1</version>
<name>Archetype - lesson1</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
</dependencies>
</project>
此时你会发现执行
package
命令结果,并不如你所愿,因为刚才我们说过,maven只是规定了生命周期
但是具体怎么做
,仍然需要你添加更多的配置(指定
):
build -> plugins -> plugin
我们来实现一个自己的工作过程添加到maven中,通过这个过程理解plugin。
-
通过idea打开该工程:
-
在pom.xml中添加依赖(我们需要实现maven提供的生命周期接口,注意
dependencies
是dependency
的复数,所以dependency在dependencies之下)。
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.5</version>
</dependency>
- 如果报错(红色)通过
mvn dependency:resolve
在pom.xml文件命令行下,下载依赖到本地仓库(此时可以观察org.apache.maven.plugin-tools
在目录中的构成,这是理解groupId
处理很好的例子)。 - 完整执行后我们的依赖会是如下:
- 编写我们自定义的插件类(注意是package周期时的,这意味着clean周期不会执行)
package test.maven.plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
@Mojo(name = "myLifeCycle", defaultPhase = LifecyclePhase.PACKAGE)//LifecyclePhase.PACKAGE="package"
public class MyLifeCycle extends AbstractMojo {
public void execute() throws MojoExecutionException, MojoFailureException {
System.out.println("Custom plugin exec");
}
}
配置自定义插件到周期中我们需要干两件事情
将我们的插件install
到本地仓库中
- 定义java
package test.maven.plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
@Mojo(name = "myLifeCycle", defaultPhase = LifecyclePhase.PACKAGE)//LifecyclePhase.PACKAGE="package"
public class MyLifeCycle extends AbstractMojo {
public void execute() throws MojoExecutionException, MojoFailureException {
System.out.println("Custom plugin exec");
}
}
- 修改pom.xml(请注意
packaging
和plugin
中的内容,因为本该使用两个工程一个是插件plugin
工程install
后,然后从另外一个工程中引入该插件在maven的世界中一切皆是dependency“依赖”
)
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.edu.samuel</groupId>
<artifactId>lesson1</artifactId>
<version>0.0.1</version>
<packaging>maven-plugin</packaging>
<name>Archetype - lesson1</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 配置插件用的插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.5.2</version>
<configuration>
<!-- 插件执行命令前缀 -> mvn prefix:mojoName,例: mvn customPlugin:customMojo -->
<goalPrefix>myLifeCycle</goalPrefix>
<skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 通过
install
来打包当前的plugin
版本,目的是为了后面引入。
引入插件
上一个小目录中我们强调了本该应该使用两个工程。而我们现在使用一个工程示例,所以必须先通过install把plugin
工程的内容打包到maven的本地仓库
中。然后在我们测试该插件时引入它。
此时我们将lesson1
工程复制重命名为lesson2
并且修改pom.xml
为(请注意artifactId
,以及plugins
的区别”刚在是定义自己的插件,现在是引入“),并且MyLifeCycle.java
在当前lesson2工程中是可以删除的:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.edu.samuel</groupId>
<artifactId>lesson2</artifactId>
<version>0.0.1</version>
<name>Archetype - lesson2</name>
<packaging>jar</packaging>
<url>http://maven.apache.org</url>
<build>
<plugins>
<plugin>
<groupId>com.edu.samuel</groupId>
<artifactId>lesson1</artifactId>
<version>0.0.1</version>
<executions>
<execution>
<!-- 执行id -->
<id>myLifeCycle</id>
<!-- 生效阶段,不指定则取插件类的@Mojo注解中的defaultPhase。此处专门设定了一个与defaultPhase不同的阶段值 -->
<phase>package</phase>
<!-- 需要运作的Goal -->
<goals>
<goal>myLifeCycle</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
此时我们在lesson2工程目录中的命令行执行
mvn package
时就会出现Custom plugin exec
了:
如果输入clean命令不会出现该内容:
输入install命令是会出现,因为install生命周期包含了package:
引入三方库并且打包到内容中
除非必要的情况之下,大多数场景都已经实现了你需要的。比如我们刚才没有解决的问题:打包时将mysql一起打包。你可以理解为assembly
插件为你做了这个事情,所以我们修改pom.xml(意思就是引入它,和我们刚才自己实现一样
)
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.edu.samuel</groupId>
<artifactId>lesson2</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<name>Archetype - lesson2</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.3</version>
<executions>
<execution>
<id>make-assembly</id><!--名字任意 -->
<phase>package</phase><!-- 绑定到package生命周期阶段上 -->
<goals>
<goal>single</goal><!-- 该打包任务只运行一次 -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
此时我们如果是执行mvn package
可以在工程内的target
目录中发现lesson2-0.0.1.jar
和lesson2-0.0.1-jar-with-dependencies.jar
两个文件,我们可以使用JD-GUI工具打开它们看看,如果是with-dependencies
是包含了mysql依赖的:
IDEA打开MAVEN工程
src/main
该目录是所有存放正式代码
与配置
,和它相对的还有src/test。
- 但是我们可以通过jd-gui发现src main并没有作为最终的编译结果目录(它把src/main丢失掉了)。
- src是源码目录
- resource包含着所有除.java以外的一切文件(通过打包时的结构,在java中的使用不同,建议研究一下java流与jar文件目录结构,在此不做追溯)。
- target目录是所有的编译结果目录可以直接查看,不像jar需要通过jd-gui。比如classes:是所有变异后的源码(.class)。
- target目录下每次通过
mvn package
命令时会更新,当然了mvn install
生命周期包含了package
,所以也会更新:
IDEA新建MAVEN工程
在IDEA中FILE->PROJECT->NEW PROJECT中:
- 新建输入Name,Name默认会被作为MAVEN中的ArtifactId
- 选择build system是maven
- GroupId在我们初步学习中其实也并不需要特别的在意,但在实际工作时定义它的名字取决于你对该项目的认识认知与个人水平。
Maven Archetype
- mac默认目录一样,都是在/Users/apple
- Catalog标识了有哪些源,从哪里拉取继续下面的配置。
- Archetype 和上面命令行新建项目时一样,是什么样的项目类型
- 简单项目
- j2ee项目
IDEA 配置MAVEN
如果你刚才尝试了新建maven项目,那么你一定发现idea执行的maven不是我们前面配置的仓库地址,这是因为它自己也自带一个maven。在Perferences
中可以通过搜索找到MAVEN:
- 覆盖 Maven home path
- 覆盖setting.xml
- repository
Overrride
看情况,比如我默认的目录就是在此。(MAC中没有系统磁盘C盘的概念)
IDEA中操作MAVEN生命周期
- 添加了mysql与alibaba druid的依赖,mysql本次仓库已经拥有了该依赖所以没有报错。
- 打开在界面右侧的maven,执行verify周期即可。
- 其它生命周期都同理,它都以~/EDU-Samuel为基准目标
MAVEN依赖配置的总库
https://mvnrepository.com/
是MAVEN仓库的全球基础,所有的国内镜像在找不到依赖时最终访问的还是它,所以我们在需要依赖时完全可以在这里搜索:
- 但是国内比如阿里的镜像到达你的网络是快速的
- 而它到达国外站点拥有专有通道而已
- 所以它们之间并没有本质区别
mvn idea:idea
mvn idea:idea
是重新生成在idea中的结构命令,当你添加新的依赖后(或者修改什么其它maven配置后)执行了verity,依然在idea中的 External Libraries 没有找到你的依赖的话。说明idea没有识别到你的修改。我们可以通过如下两种方式:
- 通过idea操作maven reload
- 在项目目录下执行 mvn idea:idea