目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

Maven

安装 Maven

Maven下载
配置环境变量

重启
检测是否安装成功

C:\Users\soulboy>mvn --version
Apache Maven 3.5.4 (1edded0938998edf8bf061f1ceb3cfdeccf443fe; 2018-06-18T02:33:14+08:00)
Maven home: F:\Development\Maven\bin\..
Java version: 1.8.0_111, vendor: Oracle Corporation, runtime: F:\Development\JDK1.8\jre
Default locale: zh_CN, platform encoding: GBK
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

Maven 仓库的分类

本地仓库
 maven 本地仓库的默认位置:无论是 Windows 还是 Linux,在用户的目录下都有一个。m2/repository/的仓库目录,这就是 Maven 仓库的默认位置。也可以修改 setting.xml 配置文件,手动指定 Maven 本地仓库的位置。

<settings>
	<localRepository>D:\Development\repository</localRepository>
</settings>

远程仓库

  • 中央仓库
     最核心的中央仓库开始,中央仓库是默认的远程仓库,maven 在安装的时候,自带的就是中央仓库的配置,可以通过修改 setting.xml 文件来修改默认的中央仓库地址。中央仓库包含了绝大多数流行的开源 Java 构件,以及源码、作者信息、SCM、信息、许可证信息等。一般来说,简单的 Java 项目依赖的构件都可以在这里下载到,以下配置是安装 Maven 之后的默认配置,无需显式配置。
<repositories>
    <repository>
      <id>central</id>
      <name>Central Repository</name>
      <url>http://repo.maven.apache.org/maven2</url>
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>
  • 私服
  • 其他公共仓库

Maven 项目的目录结构

src 
	main
		java	#源代码文件		
		resources	#资源库
		webapp
			WEB-INF
			CSS
			JS
		Bin	#脚本库
		config	#配置文件
		Filters	#资源过滤库
	test
		java	#测试源代码文件
		resources	#测试资源库
		filters	#测试资源过滤库
target #存放项目构建后的文件和目录:编译后的classes文件,jar包,war包等…

POM 文件结构

  • project:工程的根标签。
  • modelVersion:pom 模型版本,maven2 和 3 只能为 4.0.0。
  • groupId:这是工程组的标识。它在一个组织或者项目中通常是唯一的。例如,一个银行组织 com.companyname.project-group 拥有所有的和银行相关的项目。
  • artifactId:这是工程的标识。它通常是工程的名称。例如,消费者银行。groupId 和 artifactId 一起定义了 artifact 在仓库中的位置
  • version:这是工程的版本号。在 artifact 的仓库中,它用来区分不同的版本。
  • packaging:定义 Maven 项目的打包方式,有 JAR 、WAR 和 EAR 三种格式。
  • super pom:父(Super)POM 是 Maven 默认的 POM。所有的 POM 都继承自一个父 POM(无论是否显式定义了这个父 POM)。父 POM 包含了一些可以被继承的默认设置。因此,当 Maven 发现需要下载 POM 中的 依赖时,它会到 Super POM 中配置的默认仓库 。使用以下命令来查看 Super POM 默认配置:
mvn help:effective-pom
  • 依赖配置信息
<!-- dependencies -->
<dependencies>
    <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
    </dependency>
</dependencies>

<!-- parent -->
<parent>
    <groupId>com.soulboy<groupId>
    <artifactId>demo-parent</artifactId>
    <!-- relativePath:Maven首先在当前项目中找父项目的pom,然后在文件系统的这个位置(relativePath),然后在本地仓库,再在远程仓库找。 -->
    <relativePath>/</relativePath>
    <version>1.0</version>
</parent>

<!-- modules:有些maven项目会做成多模块的,这个标签用于指定当前项目所包含的所有模块。之后对这个项目进行的maven操作,会让所有子模块也进行相同操作。 -->
<modules>
   <module>com-a</module>
   <module>com-b</module>
   <module>com-c</module>
</modules>

<!-- properties:用于定义pom常量,pom文件的任意地方通过${java.version}来引用 -->
<properties>
    <java.version>1.7</java.version>
</properties>

<!-- dependencyManagement:当我们的项目模块很多的时候,我们依赖包的管理就会出现很多问题,为了项目的正确运行,必须让所有的子项目使用依赖项的同一版本,确保应用的各个项目的依赖项和版本一致,才能保证测试的和发布的是相同的结果。使用的好处:在父模块中定义后,子模块不会直接使用对应依赖,但是在使用相同依赖的时候可以不加版本号,这样的好处是,可以避免在每个使用的子项目中都声明一个版本号,这样想升级或者切换到另一个版本时,只需要在父类容器里更新,不需要任何一个子项目的修改 -->
父项目:
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.2.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
子项目1:
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
</dependency>
子项目2:
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
</dependency>
子项目3:
如果子项目需要明确与父项目的版本你不同,需要明确显式声明。
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>5.0</version>
</dependency>

<!-- dependencyManagement和dependencies的区别 -->
* dependencies:“会引入具体的实现类”,即使在子项目中不写该依赖项,那么子项目仍然会从父项目中继承该依赖项(全部继承)。
* dependencyManagement:里只是声明依赖,“并不会引入具体的实现类”,因此子项目需要显示的声明需要用的依赖。如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目中写了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom;另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。

Maven 生命周期

 Maven 的生命周期就是对所有的构建过程进行抽象和统一。包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有的构建步骤。
maven 的三个构建生命周期

  • clean
* pre-clean 执行一些清理前需要完成的工作
* clean 清理上一次构建生成的文件
* post-clean 执行一些清理后需要完成的工作
  • default
* validate:验证工程是否正确
* compile:编译项目的源代码
* test:使用合适的单元测试框架来测试已编译的源代码。
* package:把已编译的代码打包成可以发布的格式,比如jar或者war
* verify:运行所有检查,验证包是否有效
* install:安装到maven本地仓库
* deploy:部署到远程的仓库,使得其他开发者或者工程可以共享
  • Site

常用的 maven 基本命令

常用命令

  • mvn validate 验证项目是否正确
  • mvn package maven 打包
  • mvn generate-sources 生成源代码
  • mvn compile 编译
  • mvn test-compile 编译测试代码
  • mvn test 运行测试
  • mvn verify 运行检查
  • mvn clean 清理项目
  • mvn install 安装项目到本地仓库
  • mvn deploy 发布项目到远程仓库
  • mvn dependency:tree 显示 Maven 依赖树
  • mvn dependency:list 显示 Maven 依赖列表

常用参数

  • -D 指定参数,如 -Dmaven.test.skip=true 跳过单元测试;
  • -P 指定 Profile 配置,可以用于区分环境;

Web 相关命令(集成相关容器)

  • mvn tomcat:run 启动 Tomcat
  • mvn jetty:run 启动 Jetty
  • mvn tomcat:deploy 运行打包部署

导入第三方 jar 包到本地仓库

 以 fastjson-1.2.47.jar 为例。

* 进入cmd命令界面
    
* 输入指令如下:mvn install:install-file -Dfile=D:\fastjson-1.2.47.jar -DgroupId=com.alibaba -DartifactId=fastjson -Dversion=1.0 -Dpackaging=jar -DgeneratePom=true -DcreateChecksum=true
# Dfile为jar包文件路径
# DgroupId一般为jar开发组织的名称,也是坐标groupId
# DartifactId一般为jar名称,也是坐标 artifactId
# Dversion是版本号
# Dpackaging是打包类型

[INFO] Installing D:\fastjson-1.2.47.jar to D:\Development\repository\com\alibaba\fastjson\1.0\fastjson-1.0.jar
[INFO] Installing C:\Users\soulboy\AppData\Local\Temp\mvninstall7809068423679066613.pom to D:\Development\repository\com\alibaba\fastjson\1.0\fastjson-1.0.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.857 s
[INFO] Finished at: 2019-09-01T10:28:43+08:00
[INFO] ------------------------------------------------------------------------

常用 Maven 插件

maven 官方插件列表

两种调用 maven 插件的方式

  • 将插件目标与生命周期阶段绑定,例如 maven 默认将 maven-compiler-plugin 的 compile 与 maven 生命周期的 compile 阶段绑定。
  • 直接在命令行显示指定要执行的插件目标,例如 mvn archetype:generate 就表示调用 maven-archetype-plugin 的 generate 目标。

常用的 maven 插件

  • maven-antrun-plugin:maven-antrun-plugin 能让用户在 Maven 项目中运行 Ant 任务。用户可以直接在该插件的配置以 Ant 的方式编写 Target,然后交给该插件的 run 目标去执行。
  • maven-archetype-plugin:rchtype 指项目的骨架,Maven 初学者最开始执行的 Maven 命令可能就是 mvn archetype:generate,这实际上就是让 maven-archetype-plugin 生成一个很简单的项目骨架,帮助开发者快速上手。
  • maven-assembly-plugin:maven-assembly-plugin 的用途是制作项目分发包,该分发包可能包含了项目的可执行文件、源代码、readme、平台脚本等等。
  • maven-dependency-plugin:
*   maven-dependency-plugin最大的用途是帮助分析项目依赖
*   dependency:list能够列出项目最终解析到的依赖列表
*   dependency:tree能进一步的描绘项目依赖树
  • maven-enforcer-plugin:maven-enforcer-plugin 能够允许你创建一系列规则强制大家遵守,包括设定 Java 版本、设定 Maven 版本、禁止某些依赖、禁止 SNAPSHOT 依赖。
  • maven-help-plugin:
*   maven-help-plugin是一个小巧的辅助工具。
*   最简单的help:system可以打印所有可用的环境变量和Java系统属性。
  • maven-release-plugin:maven-release-plugin 的用途是帮助自动化项目版本发布,它依赖于 POM 中的 SCM 信息。

Maven 私人服务器

 私服是在局域网的一种特殊的远程仓库,目的是代理远程仓库及部署第三方构件。有了私服之后,当 Maven 需要下载 jar 包时,先请求私服,私服上如果存在则下载到本地仓库。否则,私服直接请求外部的远程仓库,将 jar 包下载到私服,再提供给本地仓库下载。

安装
 使用专门的 Maven 仓库管理软件来搭建私服,这里使用 Nexus。下载地址Nexus 专业版是需要付费的,这里下载开源版 Nexus OSS,最新的是 OSS3.x,这里选择稳定的版本 2.x。

# 下载

# 以管理员身份打开cmd,进入到bin目录,先执行nexus install命令,再执行nexus start。
C:\Windows\system32>F:
F:\>cd F:\Development\Nexus\nexus-2.14.13-01\bin
F:\Development\Nexus\nexus-2.14.13-01\bin>nexus install
wrapper  | nexus installed.
F:\Development\Nexus\nexus-2.14.13-01\bin>nexus start
wrapper  | Starting the nexus service...
wrapper  | Waiting to start...
wrapper  | Waiting to start...
wrapper  | Waiting to start...
wrapper  | nexus started.

# 打开浏览器,访问http://localhost:8081/nexus

# 点击右上角Log in,使用用户名:admin,密码:admin123登录

Nexus 服务器预置的仓库

Nexus服务器预置的仓库

类型介绍

  • hosted:是本地仓库,用户可以把自己的一些 jar 包,发布到 hosted 中,比如公司的第二方库
  • proxy,代理仓库,它们被用来代理远程的公共仓库,如 maven 中央仓库。不允许用户自己上传 jar 包,只能从中央仓库下载
  • group,仓库组,用来合并多个 hosted/proxy 仓库,当你的项目希望在多个 repository 使用资源时就不需要多次引用了,只需要引用一个 group 即可
  • virtual,虚拟仓库基本废弃了。

预置仓库

  • Central:该仓库代理 Maven 中央仓库,其策略为 Release,因此只会下载和缓存中央仓库中的发布版本构件。
  • Releases:这是一个策略为 Release 的宿主类型仓库,用来部署正式发布版本构件
  • Snapshots:这是一个策略为 Snapshot 的宿主类型仓库,用来部署开发版本构件。
  • 3rd party:这是一个策略为 Release 的宿主类型仓库,用来部署无法从 maven 中央仓库获得的第三方发布版本构件,比如 IBM 或者 oracle 的一些 jar 包(比如 classe12.jar),由于受到商业版权的限制,不允许在中央仓库出现,如果想让这些包在私服上进行管理,就需要第三方的仓库。
  • Public Repositories:一个组合仓库

在 Nexus 中建立一个仓库

  • 建库,Add-- >Hosted Repository
  • 填写仓库信息
*   Respository ID 仓库编号
    *   Repository NAME 仓库名称
    *   Repository Type 仓库类型
    *   Repository Policy 仓库策略
    *   Default Local Storage Location 仓库路径
    *   Deployment Policy 发布策略
  • 然后选择 Public Repositories,打开 configuration 选项卡,将自己创建的仓库添加到

将项目发布到 Maven 私服

修改 Maven 配置文件 settings.xml

<!-- 添加server -->
  <servers>
    <server>
      <id>xdclass</id>
      <username>admin</username>
      <password>admin123</password>
    </server>
  </servers>

<!-- 添加镜像 -->
  <mirrors>
  	<mirror>
      <id>nexusMirror</id>
      <mirrorOf>nexus,central</mirrorOf>
      <name>local nexus</name>
      <url>http://localhost:8081/nexus/content/groups/public</url>
    </mirror> 
  </mirrors>

<!-- 添加profile -->
  <profiles>
    <profile>
      <id>xd</id>
      <repositories>
        <repository>
          <id>local-nexus</id>
          <url>http://localhost:8081/nexus/content/groups/public/</url>
          <releases>
          	<enabled>true</enabled>
          </releases>
          <snapshots>
          	<enabled>false</enabled>
          </snapshots>
        </repository>
      </repositories>
    </profile>
  </profiles>

<!-- 添加activeProfiles-->
  <activeProfiles>
    <activeProfile>xd</activeProfile>
  </activeProfiles>

修改要发布项目的 pom 文件

<distributionManagement>
    <repository>
      <id>soulboy</id>
<url>http://localhost:8081/nexus/content/repositories/xdclass</url>
    </repository>
  </distributionManagement>

部署项目到 nexus 的个人仓库中
部署项目到nexus的个人仓库中

F:\Project\Maven_XX\deploy-practice>mvn clean
F:\Project\Maven_XX\deploy-practice>mvn package
F:\Project\Maven_XX\deploy-practice>mvn deploy

Maven snapshot

快照 vs 版本

  • 对于版本,Maven 一旦下载了指定的版本(例如 data-service:1.0),它将不会尝试从仓库里再次下载一个新的 1.0 版本。想要下载新的代码,数据服务版本需要被升级到 1.1。需要频繁更新版本号。使用者还需要频繁的知道最新的版本才可以使用。
  • 对于快照,每次用户接口团队构建他们的项目时,Maven 将自动获取最新的快照(data-service:1.0-SNAPSHOT)。快照是一个特殊的版本,它表示当前开发的一个副本。与常规版本不同,Maven 为每一次构建从远程仓库中检出一份新的快照版本。

新建 snapshot 类型仓库
snapshot类型仓库

修改要发布项目的 pom.xml 文件

<?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.xdclass</groupId>
  <artifactId>deploy-practice</artifactId>
  <version>1.0-SNAPSHOT</version>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <distributionManagement>
    <snapshotRepository>
      <id>xdclass</id>
      <url>http://localhost:8081/nexus/content/repositories/xdclass_snapshot</url>
    </snapshotRepository>
  </distributionManagement>
</project>

部署 snapshot 版本类型的项目

F:\Project\Maven_XX\deploy-practice>mvn clean
F:\Project\Maven_XX\deploy-practice>mvn package
F:\Project\Maven_XX\deploy-practice>mvn deploy

查看 nexus
坐标

快照策略(updatePolicy)

  • always 每次都去远程仓库查看是否有更新
  • daily 每天第一次的时候查看是否有更新
  • interval 允许设置一个分钟为单位的间隔时间,在这个间隔时间内只会去远程仓库中查找一次
  • never 从不会

setting.xml

<profile>
      <id>xd</id>
      <repositories>
        <repository>
          <id>local-nexus</id>
          <url>http://localhost:8081/nexus/content/groups/public/</url>
          <releases>
          	<enabled>true</enabled>
          </releases>
          <snapshots>
          	<enabled>true</enabled>
		<!-- 快照策略 -->
          	<updatePolicy>always</updatePolicy>
          </snapshots>
        </repository>
      </repositories>
    </profile>

Maven 的依赖管理

依赖的传递性
 传递性依赖是在 maven2 中添加的新特征,这个特征的作用就是你不需要考虑你依赖的库文件所需要依赖的库文件,能够将依赖模块的依赖自动的引入。

A依赖 spring
B依赖 A
B自动会导入spring,B传递了spring的依赖

依赖的作用范围

  • compile:这是默认范围,编译依赖对项目所有的 classpath 都可用。此外,编译依赖会传递到依赖的项目。
  • provided:表示该依赖项将由 JDK 或者运行容器在运行时提供,也就是说由 Maven 提供的该依赖项我们只有在编译和测试时才会用到,而在运行时将由 JDK 或者运行容器提供。
  • runtime:表明编译时不需要依赖,而只在运行时依赖。
  • test:只在编译测试代码和运行测试的时候需要,应用的正常运行不需要此类依赖。
  • system:系统范围与 provided 类似,不过你必须显式指定一个本地系统路径的 JAR,此类依赖应该一直有效,Maven 也不会去仓库中寻找它。
<project>  
  ...  
  <dependencies>  
    <dependency>  
      <groupId>sun.jdk</groupId>  
      <artifactId>tools</artifactId>  
      <version>1.5.0</version>  
      <scope>system</scope>  
      <systemPath>${java.home}/../lib/tools.jar</systemPath>  
    </dependency>  
  </dependencies>  
  ...  
</project>
  • import:范围只适用于部分。表明指定的 POM 必须使用部分的依赖。因为依赖已经被替换,所以使用 import 范围的依赖并不影响依赖传递。

依赖的两大原则

  • 路径近者优先
A > B > C-1.0
A > C-2.0
  • 第一声明优先
A > B > D-1.0
A > C > D-2.0

依赖的管理

  • 依赖排除: 任何可传递的依赖都可以通过 "exclusion" 元素被排除在外。举例说明,A 依赖 B, B 依赖 C,因此 A 可以标记 C 为 "被排除的" 。
<dependency>
		<exclusions>
			<exclusion>
				<groupId>org.springframework</groupId>
				<artifactId>spring-core<artifactId>
			</exclusion>
		</exclusions>
	</dependency>
  • 依赖可选:任何可传递的依赖可以被标记为可选的,通过使用 "optional" 元素。例如:A 依赖 B, B 依赖 C。因此,B 可以标记 C 为可选的, 这样 A 就可以不再使用 C。
<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-core<artifactId>
		<version>5.1.5.RELEASE</version>
		<optional>true</optional>
	</dependency>

如何解决 jar 包冲突

 当出现 jar 包冲突时,我们应该如何快速定位和处理 jar 包冲突问题。

mvn dependency:tree -Dverbose

作者:Soulboy