文章目录

  • 概述
  • Maven 的工作机制
  • Maven中的坐标
  • 说明
  • 坐标的向量的取值方式
  • 坐标和仓库中jar包的存储路径之间的对应关系
  • 命令
  • 深入POM
  • 含义
  • 模型化思想
  • 思想落地
  • POM文件详解
  • POM的四个层次
  • 超级POM
  • 父POM
  • 有效POM
  • POM中属性的声明和引用
  • help插件的各个目标
  • help:evaluate 访问系统属性
  • help:evaluate 访问环境变量
  • help:evaluate 访问project属性
  • help:evaluate 访问setting全局配置
  • build标签详解
  • build标签的组成
  • 典型应用:制定JDK版本
  • 典型应用:SpringBoot定制化打包
  • Profile详解
  • 外部视角
  • 内部视角
  • 激活profile
  • 资源属性过滤
  • 简介
  • 依赖
  • 依赖范围
  • 依赖传递
  • 依赖仲裁
  • 依赖排除
  • 依赖继承
  • 依赖聚合
  • 聚合
  • Maven约定的目录结构
  • 目录
  • 约定目录结构的意义
  • 生命周期
  • 作用
  • 三个生命周期
  • 插件和目标
  • 插件
  • 目标
  • Nexus
  • 仓库概念
  • 将jar包部署到Nexus
  • 引用上传的jar包
  • 生产实践
  • 多模块项目仅打包某子模块
  • 切换到子模块目录再打包
  • 在父级目录通过打包选项实现
  • jar包冲突解决
  • 概述
  • IDEA的Maven Helper插件
  • Maven的enforcer插件
  • 体系外jar包导入
  • 概述
  • 方案
  • 总结


概述

Maven是一款构建管理、依赖管理、项目管理的工具。Maven提供了开发人员构建一个完整的生命周期框架。开发团队可以自动完成项目的基础工具建设,Maven使用标准的目录结构和默认构建生命周期。

在多个开发团队环境时,Maven可以设置按标准在非常短的时间里完成配置工作。由于大部分项目的设置都很简单,并且可重复使用,Maven让开发人员的工作更轻松,同时创建报表,检查,构建和测试自动化设置。

Maven 的工作机制

maven资源打包 maven打包原理_maven

  • Maven核心程序:负责调度
  • Maven插件的jar:打包过程中的具体执行者

Maven中的坐标

说明

使用三个“向量”在Maven仓库中定位一个jar包。

  • groupId:公司或组织的id
  • artifiactId:一个项目或者项目中一个模块的id
  • version:版本号

坐标的向量的取值方式

  • groupId:公司或组织域名的倒序,通常也会加上项目名称。(如:com.lfc.mall)
  • artifiactId:模块的名称,将来作为Maven工程的工程名。
  • version:模块的版本号,根据需要决定。(如:1.1-SNAPSHOT 或者 2.0-RELEASE)

坐标和仓库中jar包的存储路径之间的对应关系

<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>

对应于本地仓库目录(可看setting.xml中的localRepository标签):

# 文件目录
maven仓库地址/mysql/mysql-connector-java/8.0.20

# 文件结构
.
├── _remote.repositories
├── mysql-connector-java-8.0.20.jar
├── mysql-connector-java-8.0.20.jar.sha1
├── mysql-connector-java-8.0.20.pom
└── mysql-connector-java-8.0.20.pom.sha1

命令

汇总:

命令

作用

说明

mvn archetype:generate

命令行创建工程

会生成pom文件

mvn clean

清理操作

删除target目录

mvn compile

主程序编译

编译结果存放的目录:target/classes

mvn test-compile

测试程序编译

编译结果存放的目录:target/test-classes

mvn test

测试操作

测试报告存放的目录:target/surefire-reports

mvn package

打包

存放于target目录, artifactId-version 组成的jar包

mvn install

安装

将生成的jar包存入Maven仓库;还会将pom.xml文件转换成xxx.pom一起存入本地仓库。(可以直接使用mvn clean install)

mvn dependency:tree

查看依赖树

可以看出传递性

mvn dependency:list

查看依赖列表

运行命令要在对应的pom.xml所在目录,操作哪个工程就进入对应工程目录。如果执行的命令的目录没有pom文件会报错如下:

The goal you specified requires a project to execute 
but there is no POM in this directory

-D可以带参数执行命令,对插件的目标参数进行配置:
mvn -DpropA=valueA -DpropB=valueB -DpropC=valueC clean package-DpropertyName=propertyValuemvn clean install -Dmaven.test.skip=true

  • 如果propertyName不存在pom.xml,它将被设置。
  • 如果propertyName已经存在pom.xml,其值将被作为参数传递的值覆盖-D。

-P:指定所用的profile
mvn test -Penv=test

深入POM

含义

POM:Project Object Model,项目对象模型。和POM类似:DOM,文档对象模型。都是模型化思想的具体体现。

模型化思想

POM表示将工程抽象为一个模型,再用程序中的对象来描述这个模型,便于使用程序管理项目。在开发的过程中,最基本的做法是:将现实生活中的事物抽象成模型,然后封装模型相关的数据作为一个对象,进而可以在程序中计算与现实事物相关的数据(契合 Java中一切皆对象的思想)。

思想落地

POM理念集中体现在Maven工程根目录下pom.xml这个配置文件中。所以这个pom.xml配置文件就是Maven的核心配置文件。

POM文件详解

<?xml version="1.0" encoding="UTF-8"?>
<!-- project 标签:根标签,表示对当前工程进行配置和管理 -->
<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 标签:从Maven2开始就是4.0.0 -->
<!-- 代表当前pom.xml采用的标签结构 -->
	<modelVersion>4.0.0</modelVersion>
<!-- 坐标信息 -->
    <groupId>com.lfc</groupId>
	<artifactId>mall</artifactId>
	<version>2.1.2-SNAPSHOT</version>
	
<!-- 工程名称 -->
	<name>rmall</name>
	<description>林凡尘的大型门户商城</description>

<!-- packaging标签:打包方式 -->
<!-- jar:java工程(默认);war:war工程;pom:管理子工程和模块 -->
	<packaging>pom</packaging>

<!-- properties标签:定义属性值,通常为版本维护 -->
	<properties>
		<commons-httpclient.version>3.1</commons-httpclient.version>
		<java.version>1.8</java.version>
	</properties>

<!-- parent标签:定义当前工程的父工程 -->
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.2.RELEASE</version>
		<relativePath/>
	</parent>



	<organization>
		<name>Roncoo</name>
		<url>http://www.roncoo.com</url>
	</organization>

	<!--项目模块-->
	<modules>
		<module>order</module>
		<module>product</module>
	</modules>

	<!-- 配置maven地址 -->
	<distributionManagement>
		<repository>
			<id>nexus-releases</id>
			<name>Nexus Release Repository</name>
			<url>http://192.168.1.221:8081/nexus/content/repositories/releases/</url>
		</repository>
		<snapshotRepository>
			<id>nexus-snapshots</id>
			<name>Nexus Snapshot Repository</name>
			<url>http://192.168.1.221:8081/nexus/content/repositories/snapshots/</url>
		</snapshotRepository>
	</distributionManagement>

	
	<!--  dependencyManagement标签:子工程所用依赖的版本管理,子工程还是需要引入依赖,不需写版本号 -->
	<dependencyManagement>
		<dependencies>
			<!-- spring boot -->
			<dependency>
				<groupId>org.mybatis.spring.boot</groupId>
				<artifactId>mybatis-spring-boot-starter</artifactId>
				<version>${mybatis-spring-boot-starter.version}</version>
				<!-- 依赖范围 -->
				<scope>compile</scope>
			</dependency>

			<dependency>
				<groupId>com.baomidou</groupId>
				<artifactId>mybatis-plus</artifactId>
				<version>2.1.0</version>
			</dependency>


		</dependencies>
	</dependencyManagement>

	<!-- 开发者配置 -->
	<developers>
		<developer>
			<name>Along</name>
			<id>shen.jialong</id>
			<email>shenjl@roncoo.com</email>
			<roles>
				<role>Developer</role>
			</roles>
			<timezone>+8</timezone>
		</developer>
	</developers>

	<!-- 对构建过程进行定制 -->
    <build>
    	<!-- 当前工程在构建过程中使用的最终名称 -->
		<finalName>order-service</finalName>
		<!-- 要将微服务打包成可以运行的jar包,包含:微服务本身代码、依赖的jar包、内置Tomcat。
		要加入额外的资源和相关配置等等,仅靠Maven自身的构建能力是不够的,所以要通过build标签引入下面的插件。加上以下插件会生成原始jar包和完整jar包。 -->
		<plugins>
        	<plugin>
            	<groupId>org.springframework.boot</groupId>
            	<artifactId>spring-boot-maven-plugin</artifactId>
        	</plugin>
    	</plugins>
		
    </build>
</project>

其中父工程的插件管理:

<build>
    <pluginManagement>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.6.2</version>
        </plugin>
    </pluginManagement>
</build>

POM的四个层次

超级POM

Maven构建过程中的很多默认设定,比如:源文件存放的目录、测试源文件存放的目录、构建输出的目录等,都是经过Maven定义的,定义的位置就是:超级POM。自己创建的POM即使没有指定一个父工程(父POM),本质也默认继承了超级POM,可以类比 自己写的Java类继承了Object类。

内容如下:

<?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.
-->
<!-- START SNIPPET: superpom -->
<project> 
  <modelVersion>4.0.0</modelVersion>  
  <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>  
  <pluginRepositories> 
    <pluginRepository> 
      <id>central</id>  
      <name>Central Repository</name>  
      <url>http://repo.maven.apache.org/maven2</url>  
      <layout>default</layout>  
      <snapshots> 
        <enabled>false</enabled> 
      </snapshots>  
      <releases> 
        <updatePolicy>never</updatePolicy> 
      </releases> 
    </pluginRepository> 
  </pluginRepositories>  
  <build> 
    <directory>${project.basedir}/target</directory>  
    <outputDirectory>${project.build.directory}/classes</outputDirectory>  
    <finalName>${project.artifactId}-${project.version}</finalName>  
    <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>  
    <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>  
    <scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>  
    <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>  
    <resources> 
      <resource> 
        <directory>${project.basedir}/src/main/resources</directory> 
      </resource> 
    </resources>  
    <testResources> 
      <testResource> 
        <directory>${project.basedir}/src/test/resources</directory> 
      </testResource> 
    </testResources>  
    <pluginManagement> 
      <!-- NOTE: These plugins will be removed from future versions of the super POM -->  
      <!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) -->  
      <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.1</version> 
        </plugin>  
        <plugin> 
          <artifactId>maven-release-plugin</artifactId>  
          <version>2.0</version> 
        </plugin> 
      </plugins> 
    </pluginManagement> 
  </build>  
  <reporting> 
    <outputDirectory>${project.build.directory}/site</outputDirectory> 
  </reporting>  
  <profiles> 
    <!-- NOTE: The release profile will be removed from future versions of the super POM -->  
    <profile> 
      <id>release-profile</id>  
      <activation> 
        <property> 
          <name>performRelease</name>  
          <value>true</value> 
        </property> 
      </activation>  
      <build> 
        <plugins> 
          <plugin> 
            <inherited>true</inherited>  
            <artifactId>maven-source-plugin</artifactId>  
            <executions> 
              <execution> 
                <id>attach-sources</id>  
                <goals> 
                  <goal>jar</goal> 
                </goals> 
              </execution> 
            </executions> 
          </plugin>  
          <plugin> 
            <inherited>true</inherited>  
            <artifactId>maven-javadoc-plugin</artifactId>  
            <executions> 
              <execution> 
                <id>attach-javadocs</id>  
                <goals> 
                  <goal>jar</goal> 
                </goals> 
              </execution> 
            </executions> 
          </plugin>  
          <plugin> 
            <inherited>true</inherited>  
            <artifactId>maven-deploy-plugin</artifactId>  
            <configuration> 
              <updateReleaseInfo>true</updateReleaseInfo> 
            </configuration> 
          </plugin> 
        </plugins> 
      </build> 
    </profile> 
  </profiles> 
</project>
<!-- END SNIPPET: superpom -->

父POM

和Java类一样,POM之间是单继承的,当我们给一个POM指定了父POM,那么继承关系如下图所示:

maven资源打包 maven打包原理_jar包_02

有效POM

在POM的继承关系中,子POM可以覆盖父POM中的配置;如果子POM没有覆盖,那么父POM中的配置将会被继承。按照这个规则,继承关系中的所有POM叠加到一起,就得到了最终生效的POM。显然Maven实际运行过程中,执行构建操作就是按照这个最终生效的POM来运行的。使用mvn help:effective-pom 来查看。

POM中属性的声明和引用

help插件的各个目标

目标

说明

help:active-profiles

列出当前已激活的profile

help:all-profiles

列出当前工程所有可用的profile

help:describe

描述一个插件的Mojo属性

help:effective-pom

以XML格式展示有效的POM

help:effective-settings

为当前工程以XML格式计算得到的settings配置

help:evaluate

计算用户在交互模式下给出的Maven表达式,查看pom中property的属性,如有变量则会显示计算后的值。执行命令之后输入:${property_xxx}

help:system

显示平台详细信息列表,如系统属性和环境变量

help:evaluate 访问系统属性

具体有哪些系统属性可以在程序中通过 System.getProperties()获取。在命令可以通过以下方式获取:

  • ${java.runtime.name}
  • ${os.version}

help:evaluate 访问环境变量

  • ${env.JAVA_HOME}

help:evaluate 访问project属性

在POM中配置的元素值,可以通过${project.xxx}访问。

  • ${project.artifactId}
  • ${project.groupId}
  • ${project.parent.groupId}
  • ${project.modules[0]}

help:evaluate 访问setting全局配置

访问maven的配置文件setting.xml中配置的元素值
${setting.标签名}

  • ${settings.localRepository}

build标签详解

我们配置的build标签都是对超级POM配置的叠加,并且在默认配置无法满足需求的时候会定制构建过程。

build标签的组成

定义约定的目录结构

目录名

作用

sourceDirectory

主体源程序存放目录

scriptSourceDirectory

脚本源程序存放目录

testSourceDirectory

测试源程序存放目录

outputDirectory

主体源程序编译结果输出目录

testOutputDirectory

测试源程序编译结果输出目录

resources

主体资源文件存放目录

testResources

测试源文件存放目录

directory

构建结果输出目录

备用插件管理
通过pluginManagement 标签管理起来的插件就像dependencyManagement一样,子工程使用时可以省略版本号,起到腐工程中统一管理版本的效果。

dependencyManagement 标签存放着几个极少用到的插件:

  • maven-antrun-plugin
  • maven-assembly-plugin
  • maven-dependency-plugin
  • maven-release-plugin

生命周期插件
plugins标签存放的是默认生命周期中实际会用到的插件。

<plugin>                                                                                                                                      
    <!-- 指定maven编译的jdk版本,如果不指定,maven3默认用jdk 1.5 maven2默认用jdk1.3 -->                                                                           
    <groupId>org.apache.maven.plugins</groupId>                                                                                               
    <artifactId>maven-compiler-plugin</artifactId>                                                                                            
    <version>3.1</version>                                                                                                                    
    <configuration>                                                                                                                           
        <!-- 一般而言,target与source是保持一致的,但是,有时候为了让程序能在其他版本的jdk中运行(对于低版本目标jdk,源代码中不能使用低版本jdk中不支持的语法),会存在target不同于source的情况 -->                    
        <source>1.8</source> <!-- 源代码使用的JDK版本 -->                                                                                             
        <target>1.8</target> <!-- 需要生成的目标class文件的编译版本 -->                                                                                     
        <encoding>UTF-8</encoding><!-- 字符集编码 -->
        <skipTests>true</skipTests><!-- 跳过测试 -->                                                                             
        <verbose>true</verbose>
        <showWarnings>true</showWarnings>                                                                                                               
        <fork>true</fork><!-- 要使compilerVersion标签生效,还需要将fork设为true,用于明确表示编译版本配置的可用 -->                                                        
        <executable><!-- path-to-javac --></executable><!-- 使用指定的javac命令,例如:<executable>${JAVA_1_4_HOME}/bin/javac</executable> -->           
        <compilerVersion>1.3</compilerVersion><!-- 指定插件将使用的编译器的版本 -->                                                                         
        <meminitial>128m</meminitial><!-- 编译器使用的初始内存 -->                                                                                      
        <maxmem>512m</maxmem><!-- 编译器使用的最大内存 -->                                                                                              
        <compilerArgument>-verbose -bootclasspath ${java.home}\lib\rt.jar</compilerArgument><!-- 这个选项用来传递编译器自身不包含但是却支持的参数选项 -->               
    </configuration>    

	<executions>
		<execution>
			<id>default-testCompile</id>
			<phase>test-compile</phase>
			<goals>
				<goal>testCompile</goal>
			</goals>
		</execution>
	</executions>                                                                                                                      
</plugin>

坐标部分:
groupId和artifactId标签定义了插件的坐标,作为Maven的自带插件这里省略了groupId。

执行部分:
executions标签内可以配置多个execution,execution标签内:

  • id:指定唯一标识
  • phase:关联的生命周期阶段
  • goals/goal:关联指定生命周期的目标
    goals标签中可以配置多个goal标签,标识一个生命周期环节可以对应当前插件的多个目标。

configuration标签内进行配置使用时的标签是插件本身定义的。

每个插件能够做哪些设置都是各个插件自己规定的,无法一概而论。

典型应用:制定JDK版本

提出问题
在本地环境通过setting.xml实现的配置的JDK版本,将Maven配置上服务器,会脱离setting.xml,该如何保证程序的运行?可以将JDK的版本信息,配置到负责编译的maven-compiler-plugin插件,让它在构建的过程中,按照我们指定的信息工作。如上文所示。

两种配置的区别:

  • setting.xml中配置:仅在本地生效,如果脱离当前setting.xml环境,则无法运行。
  • xml中配置:各个环境都可以运行。

典型应用:SpringBoot定制化打包

需求
spring-boot-maven-plugin并不是Maven自带的插件,而是SpringBoot提供的,用来改变Maven的打包行为,默认情况下Maven调用的是maven-jar-plugin插件的jar目标,生成可运行的jar包。

<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
            <version>2.5.5</version>
		</plugin>
	</plugins>
</build>

插件目标:

插件目标

说明

spring-boot:repackage

默认goal。在mvn package之后,再次打包可执行的jar/war,同时保留mvn package生成的jar/war为.origin

spring-boot:run

运行Spring Boot应用

spring-boot:start

在mvn integration-test阶段,进行Spring Boot应用生命周期的管理

spring-boot:stop

在mvn integration-test阶段,进行Spring Boot应用生命周期的管理

spring-boot:build-info

生成Actuator使用的构建信息文件build-info.properties

Profile详解

项目协同流程:

maven资源打包 maven打包原理_maven资源打包_03


涉及的3套环境:

  • 开发环境:供不同开发工程师开发的不同模块相互调用,内部使用。
  • 测试环境:供测试工程师对各个模块进行测试,内部使用。
  • 生产环境:供最终用户访问,对外提供访问。

外部视角

从外部视角来看,profile可以在下面两种配置文件中配置:

  • setting.xml:全局生效,比如配置JDK1.8
  • pom.xml:当前POM生效

内部视角

从内部视角来看,配置profile有如下语法要求:

语法要求

说明

profiles/profile标签

  • 由于profile天然代表众多可配置中的一个,所以由附属形式的profiles标签统一管理
  • 由于profile标签覆盖了pom.xml中的默认配置,所以profiles标签通常是pom.xml最后的一个标签。

id标签

每个profile都必须有一个id标签,指定该profile的唯一标识 。这个id标签的值会在命令行调用profile时被用到,这个命令格式是:-D

其他允许出现的标签

一个profile可以覆盖项目的最终名称、项目依赖、插件配置等各个方面以影响构建行为。

  • build
  • defaultGoal
  • finalName
  • resources
  • testResources
  • plugins
  • reporting
  • modules
  • dependencyManagement
  • repositories
  • dependencies
  • pluginRepositories
  • properties

激活profile

  1. 列出所有激活的profile
    mvn help:active-profiles
  2. 指定某个具体的profile
    mvn compile -P<profile id>

资源属性过滤

简介

Maven为了能够通过profile实现各不同运行环境切换,提供了一种【资源属性过滤】的机制。通过属性替换实现不同环境使用不同参数。

依赖

依赖范围

标签位置:dependencies/dependency/scope
可选值:compile / test / provided / system / runtime / import

compile 和 test对比

main目录(空间)

test目录(空间)

开发过程(时间)

部署到服务器(时间)

compile

有效

有效

有效

有效

test

无效

有效

有效

无效

说明:

  • 是否有效:可以通过是否可编译成功作为判断标准。
  • 部署到服务器:部署到服务器之后,项目目录下是否存在该依赖的jar包。

PS:

compile 和 provided对比

main目录(空间)

test目录(空间)

开发过程(时间)

部署到服务器(时间)

compile

有效

有效

有效

有效

provided

有效

有效

有效

无效

结论

  • compile:通常使用的第三方框架jar包这样再项目实际运行时真正要用到的jar包,都是以compile范围进行依赖的。
  • test:测试过程中使用的jar包,以test范围以来进行的。比如 junit。
  • provided:在开发过程中需要的“服务器上的jar”包,通常以provided范围依赖,比如servlet-api、jsp-api。而这个范围的jar包之所以不参与部署,不放进war包,是避免和服务器已有的同类jar包产生冲突,同时减轻服务器的负担。

依赖传递

概念:
A依赖B,B依赖C,那么在A没有配置对C的依赖的情况下,A里面能不能直接使用C?

传递原则:
在A依赖B,B依赖C的前提下,C是否能传递到A,取决于B依赖C时设置的依赖范围。

  • B依赖C时使用compile范围:可以传递
  • B依赖C时使用test或者provided范围:不能传递,所以需要这样的jar包时,就必须在需要的地方明确配置依赖才可以。

依赖仲裁

  • 最短路径优先
  • 路径相同时,先声明者优先。

依赖排除

概念:

当A依赖B,B依赖C而且C可以传递到A的时候,A不想要C,需要在A里面把C排除掉,而往往这种情况都是为了避免jar包之间的冲突。

maven资源打包 maven打包原理_maven_04


所以配置以来的排除其实就是阻止某些jar包的传递。

配置方式:

<dependency>
	<groupId>com.lfc</groupId>
	<artifactId>common</artifactId>
	<version>2.1.0</version>
	<!-- 排除的依赖列表 -->
	<exclusions>
		<!-- 排除具体的依赖 -->
		<exclusion>
			<!-- 排除依赖的坐标(不需要写version) -->
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
		</exclusion>
	</exclusions>

</dependency>

依赖继承

概念:
Maven工程之间,A工程集成B工程
B:父工程
A:子工程
本质上是A工程的pom.xml中配置继承了B工程中pom.xml的配置。

作用:
在父工程中统一管理项目中的依赖信息,具体来说是管理依赖信息的版本。简言之:父工程管理依赖,子工程各取所需。
它的背景:

  • 对一个比较大型的项目进行模块拆分。
  • 一个project下面创建很多个module。
  • 每一个module都需要配置自己的依赖信息。

背后的需求:

  • 在每一个module中各自维护各自的依赖信息很容易发生冲突,不易于统一管理。
  • 使用同一个框架内的不同jar包,它们应该是同一个版本,所以整个项目中使用的框架版本需要统一。
  • 使用框架时所需的jar包(依赖信息组合)需要经过长时间的摸索和反复测试,最终确定一个可用的组合,这个耗费很大的精力总结出来的方案不应该在新的项目中重新摸索。

注意:
只有打包方式为pom的 Maven工程才能够管理其他的Maven工程,打包方式为pom的Maven工程中不写业务代码,它是专门管理其他Maven工程的工程。

实际意义:

maven资源打包 maven打包原理_java_05


编写一套符合要求,开发各种功能都能正常工作的雨来组合并不容易。如果公司里有人总结了成熟的方案,在开发新项目时,如果不使用原有的积累,而是重新摸索,会浪费大量的时间。为了提高效率,我们可以使用工程继承的机制,让成熟的依赖组合方案能够保留下来。如图所示,公司级的父工程中管理的就是成熟的依赖组合方案,各个新项目、子系统各取所需即可。

依赖聚合

聚合

概念:
使用一个“总工程”将各个“模块工程”汇集成一个整体对应完整的项目。
从集成关系角度:

  • 父工程
  • 子工程

从聚合关系角度:

  • 总工程
  • 模块工程

目的:

  • 一键执行Maven命令:很多构建命令都可与在“总工程”中一键执行。以mvn install 命令为例,Maven要求有父工程时先安装父工程;有依赖的工程时,先安装被依赖的工程,自己管理这些规则非常麻烦;有了工程聚合之后,在总工程执行mvn install 可以一键完成安装,而且会自动按照正确的顺序执行。
  • 配置聚合之后,各个模块工程会在总工程展示一个列表,让项目中的各个模块一目了然。

聚合的位置:

<modules>
	<module>order</module>
	<module>product</module>
	<module>pay</module>
<modules>

依赖循环问题:
如果A工程以来B工程,B工程以来C工程,C工程反过来又依赖A工程。那么在执行构建时会报错如下:

[ERROR][ERROR] The projects in the reator contains a cyclic reference

Maven约定的目录结构

目录

├── pom.xml
└── src  # 源码目录
    └── main  # 主体程序目录
        ├── java  # Java源代码
        │   └── com  # package目录
        └── resources  # 配置文件
    ├── test  # 单元测试目录
        ├── java  # Java源代码
            └── com # package目录

另外还有一个target目录存放构建输出的结果(class字节码文件、jar包、war包等)。

约定目录结构的意义

Maven为了让构建过程尽可能自动化完成,所以必须约定目录结构。比如进行编译操作:先去java源程序目录读取Java源代码,然后执行编译,最后吧编译的结果存放到target中。

生命周期

作用

为了让构建过程自动化完成,Maven设定了三个生命周期,生命周期中的每一个环节对应构建过程中的一个操作。

三个生命周期

生命周期

作用

环节

Clean

清理相关操作

pre-clean

clean

post-clean

Site

生成相关站点

pre-site

site

post-site

deploy-site

Default

主要构建过程

validate

compile

test

package

verify

install

site

deploy

插件和目标

插件

Maven的核心程序负责宏观调度,不做具体工作。具体工作都是由Maven插件完成的。例如:编译就是由maven-compiler-plugin-3.1.jar插件来完成的。

目标

一个插件可以对应多个目标,而每一个目标都和生命周期中的某一环节对应。
Default生命周期中有compile和test-compile两个和编译相关的环节,这两个环节对应compile和test-compile两个目标,而这两个目标都是由maven-compiler-plugin-3.1.jar插件来执行的。

Nexus

仓库概念

仓库类型

说明

proxy

某个远程仓库的代理

group

存放:通过Nexus获取的第三方jar包

hosted

存放:本团队其他开发人员 部署到Nexus 的jar包

仓库名称

说明

maven-central

Nexus对Maven中央仓库的代理

maven-public

Nexus默认创建,供开发人员下载使用的组仓库

maven-release

Nexus默认创建,供开发人员部署自己jar包的宿主仓库,要求release版本

maven-snapshots

Nexus默认创建,供开发人员部署自己jar包的宿主仓库,要求snapshots版本

将jar包部署到Nexus

<!-- 发布maven私服,需要配合 settings.xml 中 server 节点的配置 -->
    <distributionManagement>
        <repository>
            <id>nexus</id>
            <name>nexus RELEASE</name>
            <url>http://127.0.0.1:8089/nexus/repository/maven_release/</url>
        </repository>
        <snapshotRepository>
            <id>nexus</id>
            <name>nexus SNAPSHOT</name>
            <url>http://127.0.0.1:8089/nexus/repository/maven_snapshot/</url>
        </snapshotRepository>
    </distributionManagement>

执行
mvn deploy

引用上传的jar包

<repositories>
	<repository>
		<id>maven_snapshot</id>
		<url>http://127.0.0.1:8089/nexus/repository/maven_snapshot</url> 
		<releases>
        	<enabled>true</enabled>
      	</releases>
      	<snapshots>
        	<enabled>false</enabled>
      	</snapshots>
	</repository>
</repositories>

生产实践

多模块项目仅打包某子模块

切换到子模块目录再打包

在命令行cd 到子模块的目录(含pom.xml的目录)再执行mvn clean package,即可打包子模块。

在父级目录通过打包选项实现

mvn clean install -pl 单模块名 -am -Dmaven.test.skip=true

指令名

说明

-pl

打包指定模块,以逗号分隔

-am

打包所指定模块的依赖模块

-amd

打包所指定模块的依赖模块的依赖,含有传递依赖

-rf

按指定顺序开始打包

jar包冲突解决

概述

基本思路:

  • 第一步:把彼此冲突的jar包找到
  • 第二步:在冲突的jar包中选定一个,具体做法无非是通过exclusions标签排除依赖,或是明确声明依赖

IDEA的Maven Helper插件

这个插件是IDEA插件,不是Maven插件。它能够给我们罗列出来同一个jar包的不同版本,以及他们的来源。但是对不同的jar包中同名的类没有办法。

Maven的enforcer插件

使用Maven的enforcer插件即可以检测同一个jar包的不同版本,又可以检测不同jar包中的同名的类。

体系外jar包导入

概述

实际开发过程中用到的一些jar包并非用Maven的方式发布,自然也没法通过Maven导入。比如人脸识别通用的jar包、银行sdk的jar包、海康威视jar包等。

方案

  1. 将该jar包安装到Maven仓库
mvn install:install-file -Dfile=[jar包路径] \
-DgroupId=[给该jar包 强行设定坐标groupId] \
-DartifactId=[给该jar包 强行设定坐标artifactI] \
-Dversion=1 \
-Dpackage=jar

总结

实际工作中,主要掌握以下几种操作:

  1. 微服务打包,并通过shell脚本/容器启动该jar包。
  2. 搭建公司的Nexus私服,并引用。
  3. 体系外的jar包导入和引用。