一、Maven简介
传统项目管理现状:
基于以上问题,Maven出现了。
Maven介绍
- Maven的本质是一款工具,做项目管理的工具
- 将项目开发和管理过程抽象成一个项目对象模型POM,及Project Object Model
Maven的作用:
- 项目构建:提供标准的、跨平台的自动化项目构建方式
- 依赖管理:方便快捷管理项目依赖的资源(jar包),避免资源间的版本冲突问题
- 统一开发结构:提供标准的、统一的项目结构
二、下载与安装
下载
Maven下载地址:https://maven.apache.org/download.cgi
安装
解压zip文件(Maven属于绿色版软件,解压即安装)
打开文件夹后,各目录的解释:
环境变量的配置
- 依赖Java,配置JAVA_HOME
- 设置Maven自身的运行环境,配置MAVEN_HOME
做完以上,打开cmd窗口,输入mvn,以下即是配置成功
三、Maven基础概念
仓库
仓库,用于存储各种资源。简单狭义的讲,存jar包的
如上图:
-
本地仓库,即我本地计算机中保存的jar包。
-
工作中,需要某jar包,我们可以去远端的某台服务器上去下载,即中央服务器,对应存储jar包的位置,就叫中央仓库,这个仓库是Maven开发团队服务维护的。
-
但如果每个人都去中央仓库下载,再加上境外、带宽等因素,下载效率必然很低。由此,私服诞生,这是公司自己的仓库,一般为局域网级别。
- 本地仓库:即自己电脑上存储资源的仓库,连接远程仓库获取资源。
- 远程仓库:即非本机电脑上的仓库。分为中央仓库和私服。中央仓库由Maven团队维护,存储所有资源。私服是公司范围内存储资源的仓库,从中央仓库获取资源。
☀☀☀
私服的作用:
- 保存具有版权的资源,如自主研发或购买的jar。而中央仓库的jar是开源的,不能存储有版权的资源
- 一定范围内共享资源,仅对内部开放,不对外共享
坐标
坐标,用来描述仓库中资源的位置,https://repo1.maven.org/maven2/
Maven坐标的主要组成:
- 组织ID
- 项目ID
- 版本号
鉴于Maven坐标的组成方式,这样搜索是不对的,再者,Maven坐标是给Maven工具用的,它会按照我们提供的坐标去查找、下载、使用这个资源。
坐标的获取:
进入https://mvnrepository.com/,搜索关键字,锁定后选择版本号
复制Maven下的地址即坐标:
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
仓库配置
- 本地仓库配置
在cmd窗口执行mvn后,可以看到在C盘下新增了这个目录,即本地仓库的位置
更改本地仓库的位置,需要修改配置文件,即安装Maven的conf目录下的settings.xml文件
- 远程仓库的配置
和本地仓库一样,在setting.xml文件中加入以下配置,用阿里云提供的开源仓库代替maven的中央仓库:
<!--配置具体的仓库的下载镜像-->
<mirror>
<!--此境像的唯一标识符,来区分不同的mirror元素-->
<id>nexus-aliyun</id>
<!--对哪种仓库进行镜像,简单的来说就是要代替哪个仓库-->
<mirrorOf>central<mirrorOf>
<!--镜像名称-->
<name>Nexus aliyun</name>
<!--镜像url-->
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
(到此对镜像的理解又加深了,即和镜子对面的本体一样,但又有其自身的灵活性和优势)
添加在这里:
到此,关于仓库的配置,从哪儿下载,下载好以后存本地的哪儿,就都写明白了。
全局setting和用户setting
以上的配置即全局setting,定义了当前计算机中Maven的公共配置,而用户setting即针对每个登录用户,可以做自己的个性化配置。
在上面用户的maven目录下,和repository同级的地方复制一份setting文件过来,公共配置和全局setting中的不一样时,用户setting覆盖全局setting
四、第一个Maven项目(手工制作)
- Maven工程目录结构
Maven的工程结构如图:
- 代码准备
照着以上的目录结构,在本地某盘中新建出一个同样结构的目录,在main目录的java文件夹下新建Demo.java:
package com.llg;
public class Demo{
public String say(String name){
System.out.println("hello!" + name);
return "hello!" + name;
}
}
同样在test目录下的java文件夹下,写一个DemoTest.java的测试程序:
package com.llg;
import org.junit.Test;
import org.junit.Assert;
public class DemoTest{
@Test
public void testSay(){
Demo d = new Demo();
String ret = d.say("maven");
Assert.assertEquals("hello!maven",ret);
}
}
在src目录下新建pom.xml文件,文件内容如下:
- 手动构建指令
Maven的构建命令使用mvn开头,后面添加功能参数,可以一次执行多个指令,使用空格分隔
- mvn compile 编译
- mvn clean 清理编译出来的结果
- mvn test 测试
- mvn package 打包
- mvn install 安装到本地仓库
打开DOS窗口,
在cmd窗口输入指令mvn compile:
运行结果报这个错误的时候,是maven的setting文件中写的jdk版本的问题,解决参考这篇https://blog.csdn.net/qq_45737419/article/details/106790054
编译成功如下图:
cmd窗口执行指令mvn clean,则刚才编译产生的文件夹target就被删除了
mvn clean
执行mvn test,结果中可以看到:执行成功1个,失败0个,跳过0个
接下来执行mvn package来进行打包:
在target目录下,可以看到打包成功的jar包:
接下来执行mvn install,将上一步打好的jar包安装到我们本地的仓库。
☀30个常用的Maven指令:
https://zhuanlan.zhihu.com/p/29208926
使用mvn插件创建Maven工程
手动创建Maven项目的时候,按照以上一步步去创建目录,再各种新建文件,流程繁琐。可以使用mvn插件直接创建Maven工程。
对于 Maven 插件而言,为了提高代码的复用性,通常一个 Maven 插件能够实现多个功能,每一个功能都是一个插件目标,即 Maven 插件是插件目标的集合。我们可以把插件理解为一个类,而插件目标是类中的方法,调用插件目标就能实现对应的功能。
在cmd窗口执行以上指令创建项目,对比Java工程和web工程在结构上的区别:
五、第一个Maven项目(IDEA生成)
在IDEA中创建一个空的工程,取名maven-project:
接下来配置maven,先选择project的SDK:
接下来file–setting,搜索maven:
修改home path和setting文件的路径,点击apply。这里的maven版本选择低一些,比如3.6.1,低版本下载地址https://archive.apache.org/dist/maven/maven-3/
点击新建模块java001,效果如图:
修改pom文件的内容,添加依赖junit:
写java源程序Demo和测试程序DemoTest:
点击右侧生命周期管理,进行测试、编译等:
除了右侧,也可在这里配置相关的操作:
可以看到编译测试等操作均成功运行:
接下来使用IDEA的模板来快速创建Maven工程:
同样新建一个模块,搜索quick,选择quickstart,点击Next:
接下来一路next后点击Finish,等待下载完成:
点击新建目录,创建resources,Make Directory as:
接下来创建Web项目:
继续点击IDEA右上角快捷创建模块,选择maven,搜索web:
接下来一路next–finish–OK,然后等待加载:
这里加载可能会卡住或者超级慢,可以考虑这三个解决帖子:
https://blog.csdn.net/xwhokay/article/details/122930149
https://blog.csdn.net/qq_38723677/article/details/124795928
https://blog.csdn.net/Zlucien/article/details/114671636
成功后项目结构如下:
根据自己的需要再修改一下即可:
下面是Tomcat插件安装和web工程的启动:
进入maven坐标库,搜索tomcat maven,进入这个:
进入后选择第一项就是需要的插件:
选择2.1版本后,复制坐标:
<!-- https://mvnrepository.com/artifact/org.apache.tomcat.maven/tomcat7-maven-plugin -->
<dependency>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
</dependency>
然后进入pom.xml文件,使用build标签来添加插件:
这时查看右侧Maven可以看到插件(标红是因为正在下载,稍等刷新)
双击tomcat7:run,开始运行:
启动成功:
到此,整体说明一下pom文件各个参数的含义。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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!-- 模型版本。maven2.0必须是这样写,现在是maven2唯一支持的版本 -->
<modelVersion>4.0.0</modelVersion>
<!-- 公司或者组织的唯一标志,并且配置时生成的路径也是由此生成, 如com.winner.trade,maven会将该项目打成的jar包放本地路径:/com/winner/trade -->
<groupId>com.winner.trade</groupId>
<!-- 本项目的唯一ID,一个groupId下面可能多个项目,就是靠artifactId来区分的 -->
<artifactId>trade-core</artifactId>
<!-- 本项目目前所处的版本号 -->
<version>1.0.0-SNAPSHOT</version>
<!-- 打包的机制,如pom,jar, maven-plugin, ejb, war, ear, rar, par,默认为jar -->
<packaging>jar</packaging>
<!-- 帮助定义构件输出的一些附属构件,附属构件与主构件对应,有时候需要加上classifier才能唯一的确定该构件 不能直接定义项目的classifer,因为附属构件不是项目直接默认生成的,而是由附加的插件帮助生成的 -->
<classifier>...</classifier>
<!-- 定义本项目的依赖关系 -->
<dependencies>
<!-- 每个dependency都对应这一个jar包 -->
<dependency>
<!--一般情况下,maven是通过groupId、artifactId、version这三个元素值(俗称坐标)来检索该构件, 然后引入你的工程。如果别人想引用你现在开发的这个项目(前提是已开发完毕并发布到了远程仓库),-->
<!--就需要在他的pom文件中新建一个dependency节点,将本项目的groupId、artifactId、version写入, maven就会把你上传的jar包下载到他的本地 -->
<groupId>com.winner.trade</groupId>
<artifactId>trade-test</artifactId>
<version>1.0.0-SNAPSHOT</version>
<!-- maven认为,程序对外部的依赖会随着程序的所处阶段和应用场景而变化,所以maven中的依赖关系有作用域(scope)的限制。 -->
<!--scope包含如下的取值:compile(编译范围)、provided(已提供范围)、runtime(运行时范围)、test(测试范围)、system(系统范围) -->
<scope>test</scope>
<!-- 设置指依赖是否可选,默认为false,即子项目默认都继承:为true,则子项目必需显示的引入,与dependencyManagement里定义的依赖类似 -->
<optional>false</optional>
<!-- 屏蔽依赖关系。 比如项目中使用的libA依赖某个库的1.0版,libB依赖某个库的2.0版,现在想统一使用2.0版,就应该屏蔽掉对1.0版的依赖 -->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<!-- 为pom定义一些常量,在pom中的其它地方可以直接引用 使用方式 如下 :${file.encoding} -->
<properties>
<file.encoding>UTF-8</file.encoding>
<java.source.version>1.5</java.source.version>
<java.target.version>1.5</java.target.version>
</properties>
...
</project>
<build>
<!-- 产生的构件的文件名,默认值是${artifactId}-${version}。 -->
<finalName>myPorjectName</finalName>
<!-- 构建产生的所有文件存放的目录,默认为${basedir}/target,即项目根目录下的target -->
<directory>${basedir}/target</directory>
<!--当项目没有规定目标(Maven2叫做阶段(phase))时的默认值, -->
<!--必须跟命令行上的参数相同例如jar:jar,或者与某个阶段(phase)相同例如install、compile等 -->
<defaultGoal>install</defaultGoal>
<!--当filtering开关打开时,使用到的过滤器属性文件列表。 -->
<!--项目配置信息中诸如${spring.version}之类的占位符会被属性文件中的实际值替换掉 -->
<filters>
<filter>../filter.properties</filter>
</filters>
<!--项目相关的所有资源路径列表,例如和项目相关的配置文件、属性文件,这些资源被包含在最终的打包文件里。 -->
<resources>
<resource>
<!--描述了资源的目标路径。该路径相对target/classes目录(例如${project.build.outputDirectory})。 -->
<!--举个例子,如果你想资源在特定的包里(org.apache.maven.messages),你就必须该元素设置为org/apache/maven/messages。 -->
<!--然而,如果你只是想把资源放到源码目录结构里,就不需要该配置。 -->
<targetPath>resources</targetPath>
<!--是否使用参数值代替参数名。参数值取自properties元素或者文件里配置的属性,文件在filters元素里列出。 -->
<filtering>true</filtering>
<!--描述存放资源的目录,该路径相对POM路径 -->
<directory>src/main/resources</directory>
<!--包含的模式列表 -->
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<!--排除的模式列表 如果<include>与<exclude>划定的范围存在冲突,以<exclude>为准 -->
<excludes>
<exclude>jdbc.properties</exclude>
</excludes>
</resource>
</resources>
<!--单元测试相关的所有资源路径,配制方法与resources类似 -->
<testResources>
<testResource>
<targetPath />
<filtering />
<directory />
<includes />
<excludes />
</testResource>
</testResources>
<!--项目源码目录,当构建项目的时候,构建系统会编译目录里的源码。该路径是相对于pom.xml的相对路径。 -->
<sourceDirectory>${basedir}\src\main\java</sourceDirectory>
<!--项目脚本源码目录,该目录和源码目录不同, <!-- 绝大多数情况下,该目录下的内容会被拷贝到输出目录(因为脚本是被解释的,而不是被编译的)。 -->
<scriptSourceDirectory>${basedir}\src\main\scripts
</scriptSourceDirectory>
<!--项目单元测试使用的源码目录,当测试项目的时候,构建系统会编译目录里的源码。该路径是相对于pom.xml的相对路径。 -->
<testSourceDirectory>${basedir}\src\test\java</testSourceDirectory>
<!--被编译过的应用程序class文件存放的目录。 -->
<outputDirectory>${basedir}\target\classes</outputDirectory>
<!--被编译过的测试class文件存放的目录。 -->
<testOutputDirectory>${basedir}\target\test-classes
</testOutputDirectory>
<!--项目的一系列构建扩展,它们是一系列build过程中要使用的产品,会包含在running bulid‘s classpath里面。 -->
<!--他们可以开启extensions,也可以通过提供条件来激活plugins。 -->
<!--简单来讲,extensions是在build过程被激活的产品 -->
<extensions>
<!--例如,通常情况下,程序开发完成后部署到线上Linux服务器,可能需要经历打包、 -->
<!--将包文件传到服务器、SSH连上服务器、敲命令启动程序等一系列繁琐的步骤。 -->
<!--实际上这些步骤都可以通过Maven的一个插件 wagon-maven-plugin 来自动完成 -->
<!--下面的扩展插件wagon-ssh用于通过SSH的方式连接远程服务器, -->
<!--类似的还有支持ftp方式的wagon-ftp插件 -->
<extension>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>2.8</version>
</extension>
</extensions>
<!--使用的插件列表 。 -->
<plugins>
<plugin>
<groupId></groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<!--在构建生命周期中执行一组目标的配置。每个目标可能有不同的配置。 -->
<executions>
<execution>
<!--执行目标的标识符,用于标识构建过程中的目标,或者匹配继承过程中需要合并的执行目标 -->
<id>assembly</id>
<!--绑定了目标的构建生命周期阶段,如果省略,目标会被绑定到源数据里配置的默认阶段 -->
<phase>package</phase>
<!--配置的执行目标 -->
<goals>
<goal>single</goal>
</goals>
<!--配置是否被传播到子POM -->
<inherited>false</inherited>
</execution>
</executions>
<!--作为DOM对象的配置,配置项因插件而异 -->
<configuration>
<finalName>${finalName}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptor>assembly.xml</descriptor>
</configuration>
<!--是否从该插件下载Maven扩展(例如打包和类型处理器), -->
<!--由于性能原因,只有在真需要下载时,该元素才被设置成true。 -->
<extensions>false</extensions>
<!--项目引入插件所需要的额外依赖 -->
<dependencies>
<dependency>...</dependency>
</dependencies>
<!--任何配置是否被传播到子项目 -->
<inherited>true</inherited>
</plugin>
</plugins>
<!--主要定义插件的共同元素、扩展元素集合,类似于dependencyManagement, -->
<!--所有继承于此项目的子项目都能使用。该插件配置项直到被引用时才会被解析或绑定到生命周期。 -->
<!--给定插件的任何本地配置都会覆盖这里的配置 -->
<pluginManagement>
<plugins>...</plugins>
</pluginManagement>
</build>
六、依赖管理
依赖配置
依赖配置即当前项目运行所需的jar包,一个项目可以设置多个依赖
<!-- 设置当前项目依赖的所有jar包 -->
<dependencies>
<!-- 具体的每个依赖,每个dependency都对应这一个jar包 -->
<dependency>
<!--一般情况下,maven是通过groupId、artifactId、version这三个元素值(俗称坐标)来检索该构件, 然后引入你的工程。如果别人想引用你现在开发的这个项目(前提是已开发完毕并发布到了远程仓库),-->
<!--就需要在他的pom文件中新建一个dependency节点,将本项目的groupId、artifactId、version写入, maven就会把你上传的jar包下载到他的本地 -->
<!--依赖所属的群组id-->
<groupId>com.winner.trade</groupId>
<!--依赖所属的项目id-->
<artifactId>trade-test</artifactId>
<!--依赖的版本号-->
<version>1.0.0-SNAPSHOT</version>
<!-- maven认为,程序对外部的依赖会随着程序的所处阶段和应用场景而变化,所以maven中的依赖关系有作用域(scope)的限制。 -->
<!--scope包含如下的取值:compile(编译范围)、provided(已提供范围)、runtime(运行时范围)、test(测试范围)、system(系统范围) -->
<scope>test</scope>
<!-- 设置指依赖是否可选,默认为false,即子项目默认都继承:为true,则子项目必需显示的引入,与dependencyManagement里定义的依赖类似 -->
<optional>false</optional>
<!-- 屏蔽依赖关系。 比如项目中使用的libA依赖某个库的1.0版,libB依赖某个库的2.0版,现在想统一使用2.0版,就应该屏蔽掉对1.0版的依赖 -->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
依赖传递
项目1需要用到项目2,则在pom文件中复制项目2自身的坐标,写到项目1的<dependency>中,则2中依赖的jar包,1也可以用了
图示:
依赖传递途中,出现了两个不同版本的同一个jar包,优先级理论如下:
理解就行,工作时刷新右侧Maven,出来哪个自然就是哪个生效了。
可选依赖(不透明)
即,引用我的人看不到我是否用了这个依赖。不想让别人知道我用过这个资源。
<!-- 设置指依赖是否可选,默认为false,即子项目默认都继承:为true,则子项目必需显示的引入,与dependencyManagement里定义的依赖类似 -->
<optional>false</optional>
java001引用java002,本来可以看到2中引用了log4j:
被引用的2不想让别人知道引用了log4j,则加optional:
总结即:被引用方隐藏自己依赖的部分jar
排除依赖(不需要)
即:主动断开依赖的资源,这时不用写版本,三坐标中的version不用
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
引用方001,默认可以看到被引用的002的依赖关系,如log4j:
接下来引用方001来主动排除002中的依赖:
可选依赖是控制这个资源会不会被引用方看到,排除依赖是引用方去主动断开这个依赖
依赖范围
依赖的jar默认在任何地方都可以使用,可以通过scope标签来更该其作用范围
标签内容取值如下表:
依赖范围具有传递性:
七、生命周期与插件
生命周期,即人几岁的时候,插件即在几岁的时候干的某件事
构建生命周期
项目构建的整体生命周期如下:
phase标签中填入以下哪个值,则该值及之前的过程全部执行:
插件
使用build标签来添加插件:
execution标签即执行,phase标签即说明插件在哪个阶段执行,goal标签的取值说明:
jar 用于将项目的主要源代码捆绑到 jar 存档中。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/146087.html