Maven是Apache软件基金会唯一维护的一款自动化构建工具,专注于服务Java平台的项目构建和依赖管理。
Maven是基于项目对象模型(POM),可以通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。
可以通过mvn命令使用原型 archetype 插件创建项目。
//默认使用maven-archetype-quickstart 插件 mvn archetype:generate -DgroupId=com.companyname.bank -DartifactId=consumerBanking -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false //也可以通过Darchetype指定archetype插件 mvn -B archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DgroupId=com.mycompany.app -DartifactId=my-app //也可以自定义archetype插件并使用 注:如果自定义可以快速搭建需要的公司项目框架 mvn archetype:generate -DarchetypeGroupId=com.zhongan -DarchetypeArtifactId=open-hellowms-archetype -DarchetypeVersion=1.0.0-SNAPSHOT -DarchetypeCatalog=internal注:maven 核心原理 https://www.cnblogs.com/yulonglyw/p/8550603.html
Maven 能够实现自动化构建是和它的内部原理分不开的,这里我们从 Maven 的九个核心概念入手, 看看 Maven 是如何实现自动化构建的
POM约定的目录结构坐标依赖管理仓库管理生命周期插件和目标继承聚合**Maven 的核心程序中仅仅定义了抽象的生命周期,而具体的操作则是由 Maven 的插件来完成的(这也是maven的核心原理,所有操作都是通过插件来完成)。**可是 Maven 的插件并不包含在 Maven 的核心程序中,在首次使用时需要联网下载。 下载得到的插件会被保存到本地仓库中。本地仓库默认的位置是:~.m2repository。
Java开发领域普遍认同的一个观点:约定>配置>编码(能用配置解决的问题就不编码,能基于约定的就不配置)
Project Object Model:项目对象模型。将 Java 工程的相关信息封装为对象作为便于操作和管理的模型。
Maven 工程的核心配置。
Maven 的坐标 使用如下三个向量在 Maven 的仓库中唯一的确定一个 Maven 工程。 groupid:公司或组织的域名倒序+当前项目名称 artifactId:当前项目的模块名称 version:当前模块的版本 net.lazyegg.maven Hello 0.0.1-SNAPSHOT 如何通过坐标到仓库中查找 jar 包?
将 gav 三个向量连起来 net.lazyegg.maven+Hello+0.0.1-SNAPSHOT 以连起来的字符串作为目录结构到仓库中查找 net/lazyegg/maven/Hello/0.0.1-SNAPSHOT/Hello-0.0.1-SNAPSHOT.jar
※ 注意:我们自己的 Maven 工程必须执行安装操作才会进入仓库。安装的命令是:mvn install
Maven 中最关键的部分,我们使用 Maven 最主要的就是使用它的依赖管理功能。要理解和掌握 Maven 的依赖管理,我们只需要解决以下几个问题:
① 依赖的目的是什么
当 A jar 包用到了 B jar 包中的某些类时,A 就对 B 产生了依赖,这是概念上的描述。那么如何在项目中以依赖的方式引入一个我们需要的 jar 包呢? 答案非常简单,就是使用 dependency 标签指定被依赖 jar 包的坐标就可以了。
<dependency> <groupId>net.lazyegg.maven</groupId> <artifactId>Hello</artifactId> <version>0.0.1-SNAPSHOT</version> <scope>compile</scope> </dependency>② 依赖的范围
有时依赖信息中除了目标 jar 包的坐标还有一个 scope 设置,这就是依赖的范围。依赖的范围有几个可选值,常用的有:compile、test、provided 三个,当然还有不常用的 runtime、system…
compile:默认范围,编译测试运行都有效provided:在编译和测试时有效runtime:在测试和运行时有效test:只在测试时有效system:在编译和测试时有效,与本机系统关联,可移植性差常用依赖范围有效性总结 compiletestprovided主程序√×√测试程序√√√参与部署√×× **注:provided范围的jar包不参与部署,只参与编译和测试,即部署打包不会把provided范围的jar包打进去,test是只在测试阶段使用,compile三个阶段都会使用。**③ 依赖的传递性
A 依赖 B,B 依赖 C,A 能否使用 C 呢?那要看 B 依赖 C 的范围是不是 compile,如果是则可用,否则不可用。
④ 依赖的排除 如果我们在当前工程中引入了一个依赖是 A,而 A 又依赖了 B,那么 Maven 会自动将 A 依赖的 B 引入当 前工程,但是个别情况下 B 有可能是一个不稳定版,或对当前工程有不良影响。这时我们可以在引入 A 的时候将 B 排除。
<dependency> <groupId>net.lazyegg.maven</groupId> <artifactId>Hello</artifactId> <version>0.0.1-SNAPSHOT</version> <scope>compile</scope> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency>⑤ 统一管理所依赖 jar 包的版本,对同一个框架的一组 jar 包最好使用相同的版本。为了方便升级框架,可以将 jar 包的版本信息统一提取出来
统一声明版本号 <properties> <starfish.spring.version>4.1.1.RELEASE</starfish.spring.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> 引用前面声明的版本号 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${starfish.spring.version}</version> <scope>compile</scope> </dependency>⑥ 依赖的原则:解决 jar 包冲突
路径最短者优先路径相同时先声明者优先 项目版本冲突时候的那种蛋疼的感觉,只有疼过的才知道,所以,我们来看看疼过的人是怎么解决的,推荐一个IDEA插件,Maven Helper,比自带的好用,一目了然maven仓库配置的优先级
maven在settings.xml配置文件中有mirrors和profile中repositories可以配置仓库路径,还有maven项目pom文件中的repositories可以配置仓库路径。settings.xml中配置仓库地址相当于全局配置,pom中是每个项目中具体配置,优先级是pom中的高于settings.xml中全局配置。
5.6.1. 什么是 Maven 的生命周期? Maven 生命周期定义了各个构建环节的执行顺序,有了这个清单,Maven 就可以自动化的执行构建命令了。
Maven 有三套相互独立的生命周期,分别是:
- Clean Lifecycle 在进行真正的构建之前进行一些清理工作 - Default Lifecycle 构建的核心部分,编译,测试,打包,安装,部署等等 - Site Lifecycle 生成项目报告,站点,发布站点它们是相互独立的,你可以仅仅调用 clean 来清理工作目录,仅仅调用 site 来生成站点。当然你也可以直接运行 mvn clean install site 运行所有这三套生命周期。 每套生命周期都由一组阶段(Phase)组成,我们平时在命令行输入的命令总会对应于一个特定的阶段。比 如,运行 mvn clean,这个 clean 是 Clean 生命周期的一个阶段。有 Clean 生命周期,也有 clean 阶段。
Maven 拥有三套相互独立的生命周期: clean、default 和 site, 而每个生命周期包含一些phase阶段, 阶段是有顺序的, 并且后面的阶段依赖于前面的阶段。 而三套生命周期相互之间却并没有前后依赖关系, 即调用site周期内的某个phase阶段并不会对clean产生任何影响。
5.6.2. Clean 生命周期 Clean 生命周期一共包含了三个阶段:
- pre-clean 执行一些需要在 clean 之前完成的工作 - clean 移除所有上一次构建生成的文件 - post-clean 执行一些需要在 clean 之后立刻完成的工作5.6.3. Site 生命周期
- pre-site 执行一些需要在生成站点文档之前完成的工作 - site 生成项目的站点文档 - post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备 - site-deploy 将生成的站点文档部署到特定的服务器上 这里经常用到的是 site 阶段和 site-deploy 阶段,用以生成和发布 Maven 站点,这可是 Maven 相当强大 的功能,Manager 比较喜欢,文档及统计数据自动生成,很好看。5.6.4. Default 生命周期 Default 生命周期是 Maven 生命周期中最重要的一个,绝大部分工作都发生在这个生命周期中(列出一些重要阶段)
- validate:验证工程是否正确,所有需要的资源是否可用。 - compile:编译项目的源代码。 - test:使用合适的单元测试框架来测试已编译的源代码。这些测试不需要已打包和布署。 - package:把已编译的代码打包成可发布的格式,比如 jar、war 等。 - integration-test:如有需要,将包处理和发布到一个能够进行集成测试的环境。 - verify:运行所有检查,验证包是否有效且达到质量标准。 - install:把包安装到maven本地仓库,可以被其他工程作为依赖来使用。 - deploy:在集成或者发布环境下执行,将最终版本的包拷贝到远程的 repository,使得其他的开发者或者工程可以共享5.6.5. 生命周期与自动化构建 运行任何一个阶段的时候,它前面的所有阶段都会被运行,例如我们运行 mvn install 的时候,代码会被编译,测试,打包。这就是 Maven 为什么能够自动执行构建过程的各个环节的原因。此外,Maven 的插件机制是完全依赖 Maven 的生命周期的,因此理解生命周期至关重要。
Maven 的核心仅仅定义了抽象的生命周期,具体的任务都是交由插件完成的 每个插件都能实现多个功能,每个功能就是一个插件目标 Maven 的生命周期与插件目标相互绑定,以完成某个具体的构建任务 例如:compile 就是插件 maven-compiler-plugin 的一个目标;pre-clean 是插件 maven-clean-plugin 的一个目标
生命周期的每个阶段与插件的目标goal相互绑定, 用以完成实际的构建任务。而对于插件本身,为了能够复用插件,一个插件往往能够完成多个目标goal,这些功能聚集在一个插件里,每个功能就是一个目标。所以maven生命周期的多个阶段phase可以通过一个插件的多个目标goal来完成。
如:$ mvn compiler:compile: 冒号前是插件前缀, 后面是该插件目标(即: maven-compiler-plugin的compile目标). 而该目标绑定了default生命周期的compile阶段: 因此, 他们的绑定能够实现项目编译的目的.为什么需要继承机制?
由于非 compile 范围的依赖信息是不能在“依赖链”中传递的,所以有需要的工程只能单独配置
创建父工程 创建父工程和创建一般的 Java 工程操作一致,唯一需要注意的是:打包方式处要设置为 pom 在子工程中引用父工程 ,从当前目录到父项目的 pom.xml 文件的相对路径
<parent> <groupId>com.starfish.maven</groupId> <artifactId>Parent</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- 以当前文件为基准的父工程pom.xml文件的相对路径 --> <relativePath>../Parent/pom.xml</relativePath> </parent>此时如果子工程的 groupId 和 version 如果和父工程重复则可以删除。
在父工程中管理依赖 将 Parent 项目中的 dependencies 标签,用 dependencyManagement 标签括起来
<dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> <scope>test</scope> </dependency> </dependencies> </dependencyManagement>在子项目中重新指定需要的依赖,删除范围和版本号
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency>如果在parent需要管理的依赖过多,可以在该pom中的dependencyManagement中加入其他pom类型的依赖,并且设置scope为import如:
<dependencyManagement> <dependencies> dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>因此采用在dependencyManagement中使用scope为import的方式可以分类引入更多的管理配置,也解决了单继承限制的问题。
注:在没有指定parent的pom中也会默认继承maven的默认pom 如:在…/projects 文件夹中新增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/xsd/maven-4.0.0.xsd"> <!-- 模型版本 --> <modelVersion>4.0.0</modelVersion> <!-- 公司或者组织的唯一标志,并且配置时生成的路径也是由此生成, 如com.companyname.project-group,maven会将该项目打成的jar包放本地路径:/com/companyname/project-group --> <groupId>com.companyname.project-group</groupId> <!-- 项目的唯一ID,一个groupId下面可能多个项目,就是靠artifactId来区分的 --> <artifactId>project</artifactId> <!-- 版本号 --> <version>1.0</version> </project>然后在该目录下执行命令:mvn help:effective-pom 会输出实际生效的pom文件(即整合maven默认pom后的实际生效pom文件):
<?xml version="1.0" encoding="GBK"?> <!-- ====================================================================== --> <!-- --> <!-- Generated by Maven Help Plugin on 2020-07-13T14:58:46+08:00 --> <!-- See: http://maven.apache.org/plugins/maven-help-plugin/ --> <!-- --> <!-- ====================================================================== --> <!-- ====================================================================== --> <!-- --> <!-- Effective POM for project --> <!-- 'com.companyname.project-group:project:jar:1.0' --> <!-- --> <!-- ====================================================================== --> <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.companyname.project-group</groupId> <artifactId>project</artifactId> <version>1.0</version> <!-- 这个是maven实际生效的pom配置,结合了maven默认的父pom,每个maven都会最终继承这个默认的pom,因为pom的继承关系是向下传递的 --> <!-- 下面的repositories配置是读取的setting --> <properties> <JAVA_1_8_HOME>/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home</JAVA_1_8_HOME> </properties> <repositories> <repository> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> <id>central</id> <url>http://central</url> </repository> <repository> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> <id>thirdparty</id> <url>http://thirdparty</url> </repository> <repository> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> <id>thirdparty-snapshots</id> <url>http://thirdparty-snapshots</url> </repository> <repository> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> <id>spring</id> <url>http://spring</url> </repository> <repository> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> <id>jboss</id> <url>http://jboss</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> <id>central</id> <url>http://central</url> </pluginRepository> <pluginRepository> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> <id>thirdparty</id> <url>http://thirdparty</url> </pluginRepository> <pluginRepository> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> <id>thirdparty-snapshots</id> <url>http://thirdparty-snapshots</url> </pluginRepository> <pluginRepository> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> <id>spring</id> <url>http://spring</url> </pluginRepository> <pluginRepository> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> <id>jboss</id> <url>http://jboss</url> </pluginRepository> </pluginRepositories> <build> <sourceDirectory>D:\code\projects\src\main\java</sourceDirectory> <scriptSourceDirectory>D:\code\projects\src\main\scripts</scriptSourceDirectory> <testSourceDirectory>D:\code\projects\src\test\java</testSourceDirectory> <outputDirectory>D:\code\projects\target\classes</outputDirectory> <testOutputDirectory>D:\code\projects\target\test-classes</testOutputDirectory> <resources> <resource> <directory>D:\code\projects\src\main\resources</directory> </resource> </resources> <testResources> <testResource> <directory>D:\code\projects\src\test\resources</directory> </testResource> </testResources> <directory>D:\code\projects\target</directory> <finalName>project-1.0</finalName> <pluginManagement> <plugins> <plugin> <artifactId>maven-antrun-plugin</artifactId> <version>1.3</version> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.2-beta-5</version> </plugin> <plugin> <artifactId>maven-dependency-plugin</artifactId> <version>2.8</version> </plugin> <plugin> <artifactId>maven-release-plugin</artifactId> <version>2.5.3</version> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>2.5</version> <executions> <execution> <id>default-clean</id> <phase>clean</phase> <goals> <goal>clean</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>2.6</version> <executions> <execution> <id>default-testResources</id> <phase>process-test-resources</phase> <goals> <goal>testResources</goal> </goals> </execution> <execution> <id>default-resources</id> <phase>process-resources</phase> <goals> <goal>resources</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-jar-plugin</artifactId> <version>2.4</version> <executions> <execution> <id>default-jar</id> <phase>package</phase> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <executions> <execution> <id>default-compile</id> <phase>compile</phase> <goals> <goal>compile</goal> </goals> </execution> <execution> <id>default-testCompile</id> <phase>test-compile</phase> <goals> <goal>testCompile</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.12.4</version> <executions> <execution> <id>default-test</id> <phase>test</phase> <goals> <goal>test</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.4</version> <executions> <execution> <id>default-install</id> <phase>install</phase> <goals> <goal>install</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.7</version> <executions> <execution> <id>default-deploy</id> <phase>deploy</phase> <goals> <goal>deploy</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-site-plugin</artifactId> <version>3.3</version> <executions> <execution> <id>default-site</id> <phase>site</phase> <goals> <goal>site</goal> </goals> <configuration> <outputDirectory>D:\code\projects\target\site</outputDirectory> <reportPlugins> <reportPlugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-project-info-reports-plugin</artifactId> </reportPlugin> </reportPlugins> </configuration> </execution> <execution> <id>default-deploy</id> <phase>site-deploy</phase> <goals> <goal>deploy</goal> </goals> <configuration> <outputDirectory>D:\code\projects\target\site</outputDirectory> <reportPlugins> <reportPlugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-project-info-reports-plugin</artifactId> </reportPlugin> </reportPlugins> </configuration> </execution> </executions> <configuration> <outputDirectory>D:\code\projects\target\site</outputDirectory> <reportPlugins> <reportPlugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-project-info-reports-plugin</artifactId> </reportPlugin> </reportPlugins> </configuration> </plugin> </plugins> </build> <reporting> <outputDirectory>D:\code\projects\target\site</outputDirectory> </reporting> </project>为什么要使用聚合?
将多个工程拆分为模块后,需要手动逐个安装到仓库后依赖才能够生效。修改源码后也需要逐个手动进 行 clean 操作。而使用了聚合之后就可以批量进行 Maven 工程的安装、清理工作。
如何配置聚合?
在总的聚合工程中使用 modules/module 标签组合,指定模块工程的相对路径即可 <!-- 配置聚合 --> <modules> <!-- 指定各个子工程的相对路径 --> <module>starfish-learn-grpc</module> <module>starfish-learn-kafka</module> <module>starfish-web-demo</module> </modules>maven 是模块聚合 和 模块继承 模块聚合:pom文件中的dependencyManager中增加pom类型的依赖。 模块继承:pom文件中通过parent 标签进行pom的继承。
注:模块继承只能继承一个pom文件,模块聚合可以聚合多个pom文件,也可以模块聚合和模块继承同时使用。
maven 生命周期和插件
生命周期是分阶段的,插件是maven最重要的部分,用于项目构建、打包和运行。
网上有很多关于maven项目中mirror、profile、repository的搜索顺序的文章,说法不一。官方文档并没有找到相关的说明,鉴于此,我抽时间做了一个验证。
依赖仓库的配置方式 maven项目使用的仓库一共有如下几种方式:
中央仓库,这是默认的仓库 镜像仓库,通过 sttings.xml 中的 settings.mirrors.mirror 配置 全局profile仓库,通过 settings.xml 中的 settings.repositories.repository 配置 项目仓库,通过 pom.xml 中的 project.repositories.repository 配置 项目profile仓库,通过 pom.xml 中的 project.profiles.profile.repositories.repository 配置 本地仓库 如果所有配置都存在,依赖的搜索顺序就会变得异常复杂。
分析依赖搜索顺序 先从最简单开始,慢慢增加配置,查看有什么变化。
准备测试环境 安装jdk、maven。
使用如下命令创建测试项目:
复制代码代码如下:
yes | mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=true -DgroupId=com.pollyduan -DartifactId=myweb -Dversion=1.0 -Dpackage=com.pollyduan创建完成后,为了避免后续测试干扰,先执行一次compile。
cd myweb mvn compile最后,修改 pom.xml 文件,将 junit版本号改为 4.12 。我们要使用这个jar来测试依赖的搜索顺序。
默认情况 首先确保junit4.12不存在:
rm -rf ~/.m2/repository/junit/junit/4.12默认情况下没有配置任何仓库,也就是说,既没改 $M2_HOME/conf/settings.xml 也没有添加 ~/.m2/settings.xml
执行编译,查看日志中拉取junit的仓库。
mvn compile ... Downloaded from central: https://repo.maven.apache.org/maven2/junit/junit/4.12/junit-4.12.pom (24 kB at 11 kB/s)可以看出,默认是从 central 中央仓库拉取的jar. 配置镜像仓库 settings_mirror 创建 ~/.m2/setttings.xml ,内容如下:
<settings> <mirrors> <mirror> <id>settings_mirror</id> <url>https://maven.aliyun.com/repository/public</url> <mirrorOf>central</mirrorOf> </mirror> </mirrors> </settings>重新测试:
rm -rf ~/.m2/repository/junit/junit/4.12 mvn compile在日志中查看下载依赖的仓库:
复制代码代码如下:
Downloaded from settings_mirror: https://maven.aliyun.com/repository/public/junit/junit/4.12/junit-4.12.pom (24 kB at 35 kB/s)可以看出,是从 settings_mirror 中下载的jar 结论:settings_mirror 的优先级高于 central 配置pom中的仓库 pom_repositories 在 project 中增加如下配置:
<repositories> <repository> <id>pom_repositories</id> <name>local</name> <url>http://10.18.29.128/nexus/content/groups/public/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories>由于我们改变了id的名字,所以仓库地址无所谓,使用相同的地址也不影响测试。 执行测试:
rm -rf ~/.m2/repository/junit/junit/4.12 mvn compile在日志中查看下载依赖的仓库:
复制代码代码如下:
Downloaded from pom_repositories: http://10.18.29.128/nexus/content/groups/public/junit/junit/4.12/junit-4.12.pom (24 kB at 95 kB/s)从显示的仓库id可以看出:
jar 是从 pom_repositories 中下载的。 pom_repositories 优先级高于 settings_mirror 配置全局profile仓库 settings_profile_repo 在 ~/.m2/settings.xml 中 settings 的节点内增加:
<profiles> <profile> <id>s_profile</id> <repositories> <repository> <id>settings_profile_repo</id> <name>netease</name> <url>http://mirrors.163.com/maven/repository/maven-public/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> </profile> </profiles>执行测试:
rm -rf ~/.m2/repository/junit/junit/4.12 mvn compile -Ps_profile在日志中查看下载依赖的仓库:
复制代码代码如下:
Downloaded from settings_profile_repo: http://mirrors.163.com/maven/repository/maven-public/junit/junit/4.12/junit-4.12.pom (24 kB at 63 kB/s)从显示的仓库id可以看出:
jar 是从 settings_profile_repo 中下载的。 settings_profile_repo 优先级高于 settings_mirror。 settings_profile_repo 优先级高于 pom_repositories 。 配置项目profile仓库 pom_profile_repo
<profiles> <profile> <id>p_profile</id> <repositories> <repository> <id>pom_profile_repo</id> <name>local</name> <url>http://10.18.29.128/nexus/content/groups/public/</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> </profile> </profiles>执行测试:
rm -rf ~/.m2/repository/junit/junit/4.12 mvn compile -Ps_profile,p_profile mvn compile -Pp_profile,s_profile在日志中查看下载依赖的仓库:
复制代码代码如下:
Downloaded from settings_profile_repo: http://mirrors.163.com/maven/repository/maven-public/junit/junit/4.12/junit-4.12.pom (24 kB at 68 kB/s)从显示的仓库id可以看出:
jar 是从 settings_profile_repo 中下载的 settings_profile_repo 优先级高于 pom_profile_repo 进一步测试:
rm -rf ~/.m2/repository/junit/junit/4.12 mvn compile -Pp_profile在日志中查看下载依赖的仓库:
复制代码代码如下:
Downloaded from pom_profile_repo: http://10.18.29.128/nexus/content/groups/public/junit/junit/4.12/junit-4.12.pom (24 kB at 106 kB/s)从显示的仓库id可以看出:
jar 是从 settings_profile_repo 中下载的 pom_profile_repo 优先级高于 pom_repositories 最后确认 local_repo 本地仓库 ~/.m2/repository 这不算测试了,只是一个结论,可以任意测试。
只要 ~/.m2/repository 中包含依赖,无论怎么配置,都会优先使用local本地仓库中的jar. 最终结论
settings_mirror 的优先级高于 central settings_profile_repo 优先级高于 settings_mirror settings_profile_repo 优先级高于 pom_repositories settings_profile_repo 优先级高于 pom_profile_repo pom_profile_repo 优先级高于 pom_repositories pom_repositories 优先级高于 settings_mirror 通过上面的比较得出完整的搜索链:
local_repo > settings_profile_repo > pom_profile_repo > pom_repositories > settings_mirror > central
maven仓库配置
仓库优先级为:本地仓库(localRepositories) > profile中的repositories仓库 > POM > mirrors全局仓库
注:如果activeProfiles中配置profiles profile中的配置才会生效
<activeProfiles> <activeProfile>profileTest1</activeProfile> </activeProfiles>通过mirror配置
如果仓库X可以提供仓库Y所有的内容,那么我们就可以认为X是Y的一个镜像,通俗点说,可以从Y获取的构件都可以从他的镜像中进行获取。可以采用镜像的方式配置远程仓库,镜像在settings.xml中进行配置,在setting.xml中的标签下加入如下子标签配置便配置了一个maven镜像。
<mirror> <id>alimaven</id> <name>aliyun maven</name> <!--mirrorOf的配置很重要后面会详细说明--> <mirrorOf>central</mirrorOf> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> </mirror>添加如上配置后,maven会读取setting.xml中配置的mirror作为jar包的下载地址,我们以在项目中下载fastjson为例来看一下效果。
可以看到,配置了上面的mirror后,maven是从aliyun仓库下载的jar包,不配置的时候,默认从apache的maven中央仓库下载的jar包。
上面提到,的设置很重要,比如上面我设置的mirrorOf为central,如果我随便设置一个参数,如abc,这时候我们配置的仓库就不起作用了,这是因为maven默认内置了如下一个仓库,这个默认仓库的id为central,当我们把mirrorOf设置为central时,maven就会查找有没有id为central的仓库,然后把id为central的仓库地址换成我们标签配置的那个url,这样我们配置的mirror才会起作用。当然我们也可以把mirrorOf设置为*,表示所有仓库都使用我们配置的这个mirror作为jar包下载地址。
<repositories> <repository> <id>central</id> <name>Central Repository</name> <url>https://repo.maven.apache.org/maven2</url> <layout>default</layout> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>通过repositories配置
通过setting.xml方式配置会对所有maven项目生效,如果只想在本项目中配置一个maven仓库,可以通过在pom.xml中配置标签来实现。在自己的maven项目的pom.xml中添加如下配置,就配置好了一个仓库。这时候,maven会优先采用这个配置,而不会去读setting.xml中的配置了。这样配置好后,maven就会自动从aliyun下载jar包了。
<repositories> <repository> <id>aliyun-releases</id> <name>阿里云仓库(name可以随便起)</name> <url>https://maven.aliyun.com/repository/public</url> </repository> </repositories>我们知道,repositories标签下可以配置多个repository,如果我们配置了多个repository,maven会用哪个呢,答案是按出现顺序使用,如果第1个可用,就用第一个,如果不可用,就依次往下找,下面的2张图片可以说明这个问题。
上面配置时似乎也没什么用,确实是,如果你只是在pom.xml中配置个仓库,这个id是没什么用的,可以随便写,其实这个id是配合上面讲的mirror一块使用的,还记得mirrorOf吗,我们配置mirrorOf为central是,mirror中的url就是central仓库的url给覆盖了,所以这里的标签下的id是给mirrorOf用的。
可以看下面一个例子,本来我们的abc-releases这个仓库是不可用的,因为根本就没有https://abc.def.com/repository/public/这个仓库,但是我们通过mirror配置,改变了id为abc-releases这个仓库的url,从而使用maven也可以从id为abc-releases这个仓库下载jar包了。当然这样配置也没只啥意义,只是为了方便理解repository和mirror之间的关系。
maven仓库配置的其他选项
<!--releases和snapshots中有个enabled属性,是个boolean值,默认为true, 表示是否需要从这个远程仓库中下载稳定版本或者快照版本的构建, 一般使用第三方的仓库,都是下载稳定版本的构建。--> <repository> <id>aliyun-releases</id> <url>https://maven.aliyun.com/repository/public</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>false</enabled> </snapshots> </repository>maven默认的内置仓库的配置位置
<!-- 可以从以下文件中找到maven仓库的默认配置如下 apache-maven-3.6.1\lib\maven-model-builder-3.6.1.jar\org\apache\maven\model\pom-4.0.0.xml --> <repositories> <repository> <id>central</id> <name>Central Repository</name> <url>https://repo.maven.apache.org/maven2</url> <layout>default</layout> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>在配置之前请将JDK安装好。
1. 环境变量配置 添加M2_HOME:对应Maven的解压目录即可。
编辑Path环境变量:
测试,在cmd窗口输入mvn -v查看 显示如下即配置成功:
2. 修改配置文件
通常我们需要修改解压目录下conf/settings.xml文件,这样可以更好的适合我们的使用。
此处注意:所有的修改一定要在注释标签外面,不然修改无效。Maven很多标签都是给的例子,都是注释掉的。
3. 本地仓库位置修改 在标签内添加自己的本地位置路径
<!-- localRepository | The path to the local repository maven will use to store artifacts. | | Default: ${user.home}/.m2/repository <localRepository>/path/to/local/repo</localRepository> --> <localRepository>D:\tools\repository</localRepository>4. Profiler修改maven默认的JDK版本 在标签下添加一个标签,修改maven默认的JDK版本。 profiles中的id对应pom中指定profiles的id,如果pom中指定profiles相当于会使用profiles中的repositories配置。
<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>激活方式
profile的激活方式有很多种
通过maven命令参数 即在使用maven打包时通过-P参数,-P后跟上profile的唯一id,如 mvn clean package -Ptest打包时test的profile被激活,打包后的包结构为:
通过pom文件里的activation属性 <profile> <id>prod</id> <properties> <profiles.active>prod</profiles.active> </properties> <!--activation用来指定激活方式,可以根据jdk环境,环境变量,文件的存在或缺失--> <activation> <!--配置默认激活--> <activeByDefault>true</activeByDefault> <!--通过jdk版本--> <!--当jdk环境版本为1.5时,此profile被激活--> <jdk>1.5</jdk> <!--当jdk环境版本1.5或以上时,此profile被激活--> <jdk>[1.5,)</jdk> <!--根据当前操作系统--> <os> <name>Windows XP</name> <family>Windows</family> <arch>x86</arch> <version>5.1.2600</version> </os> <!--通过系统环境变量,name-value自定义--> <property> <name>env</name> <value>test</value> </property> <!--通过文件的存在或缺失--> <file> <missing>target/generated-sources/axistools/wsdl2java/ com/companyname/group</missing> <exists/> </file> </activation> </profile>这里我写了多种方式,可以通过activeByDefault、jdk版本、操作系统、系统环境变量(在win10我试了不成功,win7可以,不知道为啥)、文件的存在或缺失,实际项目可以根据需要选取一种即可。这种的优先级低于maven命令参数指定的方式。
settings.xml中使用activeProfiles指定(了解即可) 即mave目录下的settings.xml也可以添加下面的代码来指定激活哪个profile。 <activeProfiles> <activeProfile>profileTest1</activeProfile> </activeProfiles>值得注意的是1. setting.xml在当前系统用户的.m2文件夹有(如没有可手动拷贝过去也会生效),针对的当前用户的profile配置,在maven的安装目录下“conf/settings.xml”,针对的是全局的profile配置。2.profile也可以定义在setting.xml文件中,但是这种方式个人感觉并不实用的,不推荐。
5. mirro添加国内镜像源 添加标签下,添加国内镜像源,这样下载jar包速度很快。默认的中央仓库有时候甚至连接不通。一般使用阿里云镜像库即可。这里我就都加上了,Maven会默认从这几个按顺序开始下载,没有的话就会去中央仓库了。
**mirrorOf 设置对应repository中的id过滤,如果是默认是全部仓库的url都会替换成该mirror中的url镜像地址。如果不配置repository maven默认会有一个central为id的仓库,所以当没有配置repository时mirror至少要有个mirrorOf为central的配置或则是才能走镜像仓库,否则会走maven中心库。如果repository的id没有符合配置的mirrorOf,那就走自身配置的url路径下载jar包。另外如果不配置repository会有maven内置的一个repository,id为central,url为maven中央库地址。 **
maven内置默认repository配置
<repositories> <repository> <id>central</id> <name>Central Repository</name> <url>https://repo.maven.apache.org/maven2</url> <layout>default</layout> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <!-- 阿里云仓库 --> <mirror> <id>alimaven</id> <mirrorOf>central</mirrorOf> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/repositories/central/</url> </mirror> <!-- 中央仓库1 --> <mirror> <id>repo1</id> <mirrorOf>central</mirrorOf> <name>Human Readable Name for this Mirror.</name> <url>http://repo1.maven.org/maven2/</url> </mirror> <!-- 中央仓库2 --> <mirror> <id>repo2</id> <mirrorOf>central</mirrorOf> <name>Human Readable Name for this Mirror.</name> <url>http://repo2.maven.org/maven2/</url> </mirror>常用IDE下配置Maven
IDEA下配置Maven
1:此处修改为自己解压的Maven目录
2:勾选Override,修改为自己目录下的settings.xml目录
3:修改为自己的本地仓库地址,一般会自动识别。
此处勾选,当修改pom文件时,Maven就能帮我们自动导包了。
附:完整的Settings.xml文件
<?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <!-- | This is the configuration file for Maven. It can be specified at two levels: | | 1. User Level. This settings.xml file provides configuration for a single user, | and is normally provided in ${user.home}/.m2/settings.xml. | | NOTE: This location can be overridden with the CLI option: | | -s /path/to/user/settings.xml | | 2. Global Level. This settings.xml file provides configuration for all Maven | users on a machine (assuming they're all using the same Maven | installation). It's normally provided in | ${maven.conf}/settings.xml. | | NOTE: This location can be overridden with the CLI option: | | -gs /path/to/global/settings.xml | | The sections in this sample file are intended to give you a running start at | getting the most out of your Maven installation. Where appropriate, the default | values (values used when the setting is not specified) are provided. | |--> <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> <!-- localRepository | The path to the local repository maven will use to store artifacts. | | Default: ${user.home}/.m2/repository <localRepository>/path/to/local/repo</localRepository> --> <localRepository>D:\tools\repository</localRepository> <!-- interactiveMode | This will determine whether maven prompts you when it needs input. If set to false, | maven will use a sensible default value, perhaps based on some other setting, for | the parameter in question. | | Default: true <interactiveMode>true</interactiveMode> --> <!-- offline | Determines whether maven should attempt to connect to the network when executing a build. | This will have an effect on artifact downloads, artifact deployment, and others. | | Default: false <offline>false</offline> --> <!-- pluginGroups | This is a list of additional group identifiers that will be searched when resolving plugins by their prefix, i.e. | when invoking a command line like "mvn prefix:goal". Maven will automatically add the group identifiers | "org.apache.maven.plugins" and "org.codehaus.mojo" if these are not already contained in the list. |--> <pluginGroups> <!-- pluginGroup | Specifies a further group identifier to use for plugin lookup. <pluginGroup>com.your.plugins</pluginGroup> --> </pluginGroups> <!-- proxies | This is a list of proxies which can be used on this machine to connect to the network. | Unless otherwise specified (by system property or command-line switch), the first proxy | specification in this list marked as active will be used. |--> <proxies> <!-- proxy | Specification for one proxy, to be used in connecting to the network. | <proxy> <id>optional</id> <active>true</active> <protocol>http</protocol> <username>proxyuser</username> <password>proxypass</password> <host>proxy.host.net</host> <port>80</port> <nonProxyHosts>local.net|some.host.com</nonProxyHosts> </proxy> --> </proxies> <!-- servers | This is a list of authentication profiles, keyed by the server-id used within the system. | Authentication profiles can be used whenever maven must make a connection to a remote server. |--> <servers> <!-- server | Specifies the authentication information to use when connecting to a particular server, identified by | a unique name within the system (referred to by the 'id' attribute below). | | NOTE: You should either specify username/password OR privateKey/passphrase, since these pairings are | used together. | <server> <id>deploymentRepo</id> <username>repouser</username> <password>repopwd</password> </server> --> <!-- Another sample, using keys to authenticate. <server> <id>siteServer</id> <privateKey>/path/to/private/key</privateKey> <passphrase>optional; leave empty if not used.</passphrase> </server> --> </servers> <!-- mirrors | This is a list of mirrors to be used in downloading artifacts from remote repositories. | | It works like this: a POM may declare a repository to use in resolving certain artifacts. | However, this repository may have problems with heavy traffic at times, so people have mirrored | it to several places. | | That repository definition will have a unique id, so we can create a mirror reference for that | repository, to be used as an alternate download site. The mirror site will be the preferred | server for that repository. |--> <mirrors> <!-- mirror | Specifies a repository mirror site to use instead of a given repository. The repository that | this mirror serves has an ID that matches the mirrorOf element of this mirror. IDs are used | for inheritance and direct lookup purposes, and must be unique across the set of mirrors. | <mirror> <id>mirrorId</id> <mirrorOf>repositoryId</mirrorOf> <name>Human Readable Name for this Mirror.</name> <url>http://my.repository.com/repo/path</url> </mirror> --> <!-- 阿里云仓库 --> <mirror> <id>alimaven</id> <mirrorOf>central</mirrorOf> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/repositories/central/</url> </mirror> <!-- 中央仓库1 --> <mirror> <id>repo1</id> <mirrorOf>central</mirrorOf> <name>Human Readable Name for this Mirror.</name> <url>http://repo1.maven.org/maven2/</url> </mirror> <!-- 中央仓库2 --> <mirror> <id>repo2</id> <mirrorOf>central</mirrorOf> <name>Human Readable Name for this Mirror.</name> <url>http://repo2.maven.org/maven2/</url> </mirror> </mirrors> <!-- profiles | This is a list of profiles which can be activated in a variety of ways, and which can modify | the build process. Profiles provided in the settings.xml are intended to provide local machine- | specific paths and repository locations which allow the build to work in the local environment. | | For example, if you have an integration testing plugin - like cactus - that needs to know where | your Tomcat instance is installed, you can provide a variable here such that the variable is | dereferenced during the build process to configure the cactus plugin. | | As noted above, profiles can be activated in a variety of ways. One way - the activeProfiles | section of this document (settings.xml) - will be discussed later. Another way essentially | relies on the detection of a system property, either matching a particular value for the property, | or merely testing its existence. Profiles can also be activated by JDK version prefix, where a | value of '1.4' might activate a profile when the build is executed on a JDK version of '1.4.2_07'. | Finally, the list of active profiles can be specified directly from the command line. | | NOTE: For profiles defined in the settings.xml, you are restricted to specifying only artifact | repositories, plugin repositories, and free-form properties to be used as configuration | variables for plugins in the POM. | |--> <profiles> <!-- profile | Specifies a set of introductions to the build process, to be activated using one or more of the | mechanisms described above. For inheritance purposes, and to activate profiles via <activatedProfiles/> | or the command line, profiles have to have an ID that is unique. | | An encouraged best practice for profile identification is to use a consistent naming convention | for profiles, such as 'env-dev', 'env-test', 'env-production', 'user-jdcasey', 'user-brett', etc. | This will make it more intuitive to understand what the set of introduced profiles is attempting | to accomplish, particularly when you only have a list of profile id's for debug. | | This profile example uses the JDK version to trigger activation, and provides a JDK-specific repo. <profile> <id>jdk-1.4</id> <activation> <jdk>1.4</jdk> </activation> <repositories> <repository> <id>jdk14</id> <name>Repository for JDK 1.4 builds</name> <url>http://www.myhost.com/maven/jdk14</url> <layout>default</layout> <snapshotPolicy>always</snapshotPolicy> </repository> </repositories> </profile> --> <!-- | Here is another profile, activated by the system property 'target-env' with a value of 'dev', | which provides a specific path to the Tomcat instance. To use this, your plugin configuration | might hypothetically look like: | | ... | <plugin> | <groupId>org.myco.myplugins</groupId> | <artifactId>myplugin</artifactId> | | <configuration> | <tomcatLocation>${tomcatPath}</tomcatLocation> | </configuration> | </plugin> | ... | | NOTE: If you just wanted to inject this configuration whenever someone set 'target-env' to | anything, you could just leave off the <value/> inside the activation-property. | <profile> <id>env-dev</id> <activation> <property> <name>target-env</name> <value>dev</value> </property> </activation> <properties> <tomcatPath>/path/to/tomcat/instance</tomcatPath> </properties> </profile> --> <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> </profiles> <!-- activeProfiles | List of profiles that are active for all builds. | <activeProfiles> <activeProfile>alwaysActiveProfile</activeProfile> <activeProfile>anotherAlwaysActiveProfile</activeProfile> </activeProfiles> --> </settings>注:maven wrapper使用
maven wrapper 背景
Maven是一款非常流行的Java项目构建软件,它集项目的依赖管理、测试用例运行、打包、构件管理于一身,是我们工作的好帮手,maven飞速发展,它的发行版本也越来越多,如果我们的项目是基于Maven构件的,那么如何保证拿到我们项目源码的同事的Maven版本和我们开发时的版本一致呢,可能你认为很简单,一个公司嘛,规定所有的同事都用一个Maven版本不就万事大吉了吗?一个组织内部这是可行的,要是你开源了一个项目呢?如何保证你使用的Maven的版本和下载你源码的人的Maven的版本一致呢,这时候mvnw就大显身手了。
mvnw全名是Maven Wrapper,它的原理是在maven-wrapper.properties文件中记录你要使用的Maven版本,当用户执行mvnw clean 命令时,发现当前用户的Maven版本和期望的版本不一致,那么就下载期望的版本,然后用期望的版本来执行mvn命令,比如刚才的mvn clean。
如果大家使用IntelliJ IDEA来开发Spring boot项目, 如果选择从Spring Initializr来创建项目,则会在项目中自动应用Maven Wrapper。简单点说就是在项目目录下面会多出两个文件: mvnw 和 mvnw.cmd。
为项目添加mvnw支持很简单,有两种方式:
方法一:在Pom.Xml中添加Plugin声明:
<plugin> <groupId>com.rimerosolutions.maven.plugins</groupId> <artifactId>wrapper-maven-plugin</artifactId> <version>0.0.4</version> </plugin>这样当我们执行mvn wrapper:wrapper 时,会帮我们生成mvnw.cmd、mvnw、maven-wrapper.jar、maven-wrapper.properties这些文件。
├── .mvn │ └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── mvnw └── mvnw.cmdmvnw是Linux系统的启动文件。
mvnw.cmd是windows系统的启动文件。
本文不会详细讲解启动文件的内部信息,有兴趣的小伙伴可以自行去研究。除了这两个启动文件,在项目中还会生成一个.mvn的隐藏文件夹。
然后我们就可以使用mvnw代替mvn命令执行所有的maven命令,比如mvnw clean package
方法二:直接执行Goal(推荐使用这种)
mvn -N io.takari:maven:wrapper mvn -N io.takari:maven:wrapper -Dmaven=3.3.3 -Dmaven表示我们期望使用的Maven的版本为3.3.3产生的内容和第一种方式是一样的,只是目录结构不一样,maven-wrapper.jar和maven-wrapper.properties在".mvn/wrapper"目录下
使用的注意事项
1、由于我们使用了新的Maven ,如果你的settings.xml没有放在当前用户下的.m2目录下,那么执行mvnw时不会去读取你原来的settings.xml文件
2、在mvnw.cmd中有如下的一段脚本:if exist “%M2_HOME%\bin\mvn.cmd” goto init,意思是如果找到mvn.cmd就执行初始化操作,但是Maven早期版本不叫mvn.cmd,而是叫mvn.bat,所以会报"Error: M2_HOME is set to an invalid directory"错误,改成你本地的maven的匹配后缀就好了。
测试工程:https://github.com/easonjim/5_java_example/tree/master/mvnw/testproject
参考:
https://github.com/takari/maven-wrapper(官网)
http://www.javacoder.cn/?p=759(以上内容转自此篇文章)
注:Maven 自定义archeType
创建maven项目可以根据已有的archetype项目原型(模型),进行项目创建,里面会有特定项目中需要的一些固定的文件夹、文件、类等资源,方便我们直接进行项目开发。一般公司都会有自己的archetype,方便公司员工构建项目。
创建archetype,假如自己已经有了一个maven项目,想给该项目创建一个archeType模板。
cd 到项目根目录下执行(pom.xml同级目录)下面命令。
mvn archetype:create-from-project执行完此时会在项目target下生成这些文件:
生成archetype模板
进入生成的archetype文件夹下面,然后执行install命令。
先 cd target/generated-sources/archetype/ 然后执行 mvn install执行成功后,执行crawl命令,在本地仓库的根目录生成archetype-catalog.xml骨架配置文件:
mvn archetype:crawl来看一看它里面的内容:
[fantj@lalala repository]$ cat archetype-catalog.xml <?xml version="1.0" encoding="UTF-8"?> <archetype-catalog xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0 http://maven.apache.org/xsd/archetype-catalog-1.0.0.xsd" xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <archetypes> <archetype> <groupId>com.fantj</groupId> <artifactId>my-self-defind-archtype-archetype</artifactId> <version>0.0.1-SNAPSHOT</version> <description>my-self-defind-archtype</description> </archetype> </archetypes> </archetype-catalog>使用archetype模板
archetype模板生成后,执行mvn archetype:generate -DarchetypeCatalog=local从本地archeType模板中创建项目。
mvn archetype:generate -DarchetypeCatalog=local然后会让你选择模板序号和groupIdartifactIdversion和package信息:
Choose archetype: 1: local -> com.fantj:my-self-defind-archtype-archetype (my-self-defind-archtype) Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): : 1 Define value for property 'groupId': com.fantj Define value for property 'artifactId': my-self-defind-archetype-test Define value for property 'version' 1.0-SNAPSHOT: : Define value for property 'package' com.fantj: : Confirm properties configuration: groupId: com.fantj artifactId: my-self-defind-archetype-test version: 1.0-SNAPSHOT package: com.fantj Y: : y [INFO] ---------------------------------------------------------------------------- [INFO] Using following parameters for creating project from Archetype: my-self-defind-archtype-archetype:0.0.1-SNAPSHOT [INFO] ---------------------------------------------------------------------------- [INFO] Parameter: groupId, Value: com.fantj [INFO] Parameter: artifactId, Value: my-self-defind-archetype-test [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] Parameter: package, Value: com.fantj [INFO] Parameter: packageInPathFormat, Value: com/fantj [INFO] Parameter: package, Value: com.fantj [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] Parameter: groupId, Value: com.fantj [INFO] Parameter: artifactId, Value: my-self-defind-archetype-test [INFO] Project created from Archetype in dir: /home/fantj/IdeaProjects/maven-tutorial/my-self-defind-archetype-test [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS项目创建成功!
当然,也可以使用IDEA来帮我们用图形界面使用archeType模板创建项目:

maven的依赖和依赖管理是通过dependencies 和 dependencyManager来完成的。
maven依赖作用
假设我们有10个项目,都需要引入spring core模块,那么需要十份重复的Spring Core.jar和commons-logging.jar
使用Maven:maven使用本地仓库存储的jar,所有项目都会公用仓库中的同一分jar
Spring Core.jar必须同时引入版本兼容的commons-log.jar,否则会报错
使用Maven:maven不需要关心这些问题,会自动引入Spring core.jar所需的兼容版本jar
如果一个项目里面有个100个jar,不知道那些jar是彼此关联的,那些是互相排斥的,当需要升级版本时,增加或删除一些jar,很容易出各种问题
使用Maven:maven升级jar,只需要把版本3.x改成4.x,他会自动解决那些问题
概括的说:Maven是一个项目依赖管理和项目构建的综合工具。Maven简化和标准化项目建设过程。处理编译,分配,文档,团队协作和其他任务的无缝连接。Maven增加可重复性并负责建立相关的业务。
pom的依赖关系说明
maven 依赖范围scope详解 依赖范围一共包括如下几种,分别代表的是jar包在什么环节要被引入。
compile 这个是默认的依赖范围,代表从编译阶段就需要被引入。如大部分都是用默认方式表明依赖是编译期和运行期都需要的。
provided 这个代表该依赖在运行时runtime是由jdk或者容器来提供,无需引入。因此provided的包只有在本地编译和测试环节才会被引入,运行时不会被引入。比如我们常见的servlet-api的包,就会申明为provided阶段。如servlet jar包加载。
runtime 运行时依赖,代表这个包在编译的时候是不需要的,只有在运行时以及测试时才需要被依赖。如JDBC驱动加载。
test 代表这个包在生产环境是不需要的,只有在执行test时才需要。如test模块代码一般是开发阶段单元测试用到,生产环境中是不会把单元测试代码打包进来的,所以生产环境不需要把他们引用的jar包加进来。
system 很少用
import 在<dependencyManagement>使用时,可以将其他的POM类型的<dependencyManagement>通过 import的方式引入,从而构建出整体所需的一个依赖管理集合。如需要通过依赖管理引用其他pom依赖项目
子pom内声明依赖的优先于父pom中的依赖,父pom中声明的依赖优先于传递依赖。
Maven 父pom中dependencyManagement版本优先级高于传递依赖版本例如: 父pom
<dependencyManagement> <dependencies> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> </dependencyManagement>该工程beanutils将会传递依赖logging 1.1.1
<dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.2</version> </dependency>结果:此时该工程中logging的版本将是1.2,即父pom dependencyManagement中的版本。
maven冲突通常是由传递依赖造成的,传递依赖是指A->B->C,所以C就是由A包的传递依赖过来的。
maven依赖冲突一般有四种解决方式,按照优先级(从高到低)介绍:
1. 依赖管理(通过dependencyManager所有版本锁定) 在配置文件pom.xml中先声明要使用哪个版本的相应jar包,声明后其他版本的jar包一律不依赖
<properties> <spring.version>4.2.4.RELEASE</spring.version> <hibernate.version>5.0.7.Final</hibernate.version> <struts.version>2.3.24</struts.version> </properties> </properties> <!-- 锁定版本,struts2-2.3.24、spring4.2.4、hibernate5.0.7 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> </dependencies> </dependencyManagement>如果是应用在同一个工程内有多个模块时,提取出一个父亲模块来管理子模块共同依赖的 jar 包版本,则子模块相同jar包不需要指定version信息
2. 移除依赖 如果我们不想通过 A->B->C>D1 引入 D1 的话,那么我们在声明引入 A 的时候将 D1 排除掉 举个例子:将 zookeeper 的 jline 依赖排除
<dependency> <groupId>org.apache.hadoop</groupId> <artifactId>zookeeper</artifactId> <version>3.3.1</version> <exclusions> <exclusion> <groupId>jline</groupId> <artifactId>jline</artifactId> </exclusion> </exclusions> </dependency>3. 第一声明优先原则 在pom.xml配置文件中,如果有两个名称相同版本不同的依赖声明,那么先写的会生效。 所以,先声明自己要用的版本的jar包即可。
4. 最短路径优先 直接依赖优先于传递依赖,如果传递依赖的jar包版本冲突了,那么可以自己声明一个指定版本的依赖jar,即可解决冲突。如果路径相同就按照先声明的优先原则。
注:3和4方法时对应同一优先级的基础上修改的,一般我们会在优先级高的进行同层次修改。
包冲突检查工具:
使用maven helper 插件进行查看分析使用mvn dependency 命令处理: mvn dependency:tree mvn dependency:analyze还可以通过idea Maven Projects 菜单右键项目选择show dependencies