Maven指南(二)POM文件说明 及依赖管理

POM
  pom是Maven工作的基本单元,每个项目只会有一个pom.xml文件,其中包含项目对象、构建流程和其它配置信息。当构建项目时,Maven通过读取pom.xml获取配置信息然后执行相应的有序操作。

超级POM
  Maven自带了一个Super POM,也是Maven的默认POM。除非明确设置,否则所有POM都会扩展Super POM,这意味着在Super POM中的配置信息将由所有子项目继承。Super Pom文件通常位于 maven安装目录\lib\maven-model-builder-3.5.2.jar\org\apache\maven\model\pom-4.0.0.xml,其中声明了Maven的远程仓库地址https://repo.maven.apache.org/maven2/ 、项目默认构建路径等信息。
注:在没有指定仓库位置的情况下,将继承Super POM中的存储库配置http://repo.maven.apache.org/maven2。但如果公司搭建了内部存储仓库(也称私服),就可以通过配置指定从私服上下载依赖,私服在这里起到一个代理的作用。
下面是摘取自pom-4.0.0.xml的相关配置

<project>
  <modelVersion>4.0.0</modelVersion>
  <!-- 依赖中央仓库 -->
  <repositories>
    <repository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
      <!-- 仓库为Maven2 3的标准结构-->
      <layout>default</layout>
      <!-- 不下载snapshot版本的库-->
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>
 
  <!-- 插件中央仓库 -->
  <pluginRepositories>
    <pluginRepository>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>    
      <layout>default</layout>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <!-- 永不检查jar包的更新状态 -->
      <releases>
        <updatePolicy>never</updatePolicy>
      </releases>
    </pluginRepository>
  </pluginRepositories>
  <!-- 构建信息配置:这里也是Maven标准目录结构的声明 -->
  <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>${project.basedir}/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>
    <!-- ...... -->
  </build>
   <!-- ...... -->
</project>

 最小POM
  一个最小的pom文件至少需要配置modelVersion、groupId(组ID)、artifactId(项目ID)、version四个标识,其中后三者的组合代表了(在Maven中)项目的唯一坐标。其中groupId定义项目所属组织,artifactId定义当前项目在组中的唯一ID。
  以常见的spring为例,它们的groupId相同,但artifactId不一样。

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 热部署 -->
<dependency>
	<groupId> org.springframework.boot </groupId>
	<artifactId> spring-boot-devtools </artifactId>
	<optional>true</optional>
</dependency>

  同样的,如果你公司有一个项目a,它由很多组件构件,有核心组件b,公共组件c等,那么它们的groupId就都可以定义成com.youcompany.a,然后artifactId就可以core、comment等等。 
  

POM继承
   
maven支持pom之间继承,通常由父pom.xml进行公共配置,子pom中配置项目独需信息即可,父pom的打包方式必须为pom。实际开发中,有时会对项目按层结构或按模块进行拆分,拆分成多个子项目,这种情况下,子项目一般都有相同的groupid和vesion,并且会有一些公共的依赖,这种情况下父pom的存在就很有必要。

POM聚合
 当需要一次性打包多个项目(模块)时,而不是一个一个执行mvn命令,可以用聚合的方式,聚合POM的打包方式也必须是pom。为了方便构建,通常聚合模块作为项目的顶层项目,而其它子项目作为聚合目录下的子目录存在,这点会在POM聚合与继承的进行说明。

POM聚合与继承
  通常同时构建的多个项目(模块)间是存在继承关系的,这种情况下就可以结合使用POM聚合与继承,也就是一个pom即是父pom同时也是一个聚合POM。这里简述一个实际案例,原有项目emptablerate按公司规范需要按层+模块拆分成多个项目,拆分后如下(创建流程:先创建一个父项目,在其pom中包含其它子项目),默认情况下子项目会作为聚合项目的子目录存在。
     构建时,直接在父项目上执行mvn命令即会一次性对所有模块进行构建。

...
	<properties>
		<emptseatrate.version>0.0.1-SNAPSHOT</emptseatrate.version>
	</properties>
	
	<modelVersion>4.0.0</modelVersion>
	<groupId>cn.cloudwalk.emptyseatrate</groupId>
	<artifactId>cloudwalk-emptyseatrate-parent</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>pom</packaging>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.4.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

    <!-- 聚合其它模块 -->
	<modules>
		<module>cloudwalk-emptyseatrate-web</module>
		<module>cloudwalk-emptyseatrate-service</module>
		<module>cloudwalk-emptyseatrate-interface</module>
		<module>cloudwalk-emptyseatrate-data</module>
		<module>cloudwalk-emptyseatrate-common</module>
	</modules>
	
	<!-- 所有子项目直接继承的依赖 -->
	<dependencies>
		<!-- apache工具包 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
		</dependency>
		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
			<version>3.2.2</version>	
		</dependency>
....

依赖管理
   
   依赖管理是Maven的核心功能之一,它提供了dependency:analyze(依赖分析插件)以分析和管理依赖关系。
  依赖传递:由于每个项目都有pom.xml文件,所以Maven可以通过依赖传递来发现所有依赖。
       依赖冲突:当有循环依赖时Maven会通过依赖级别数量进行限制;当有重复依赖时,Maven取依赖关系树中的深度最浅的那个依赖库,如果深度一样则取第一个声明的依赖库。如果依赖的库版本不一样,此时可手动进行依赖关系管理,强制指定使用的版本,或者直接包含某依赖项。  
  依赖范围Scope(想要理解依赖范围,建议先了解Maven构建的生命周期):主要有6种

  • compile:默认的scope,代表在应用编译、测试、运行其间都将该jar(pom最终也是jar)加入到classpath中。
  • provide:代表在应用编译、测试期间需要依赖该项,但实际运行时由运行环境提供,如servlet-api.jar,运行时由Tomcat容器提供,不需要打包。当某个依赖由运行环境提供了时可用该配置。
  • runtime:表示在测试、运行时依赖该项,但编译期间不需要。如JDBC驱动的实现jar在编译期间不需要。
  • test:只有在测试代码的编译和运行阶段需要依赖它。如jutil.jar
  • system:与provide一样,但它是用来指定外部依赖项,而不是本地仓库中的依赖项, 所以它需要通过systemPath来指定依赖项路径。
  • import

  依赖传递时依赖范围确定:下面是Maven官网上关于依赖传递时依赖范围的说明,假设A对B依赖范围为compile,B对C依赖范围为provided,则说明A运行时不需要C(A的编译和测试只需要B的参与就行),但C应该由容器提供,所以在A的环境中C应该已经存在,这种情况下A和C才是无依赖的情况,否则运行时将报出异常。关于这块建议参考:https://seanzhou.iteye.com/blog/1688740

第1列表示A对B的依赖范围
第1行表示B对C的依赖范围
交叉格表示A对C的依赖范围,-表示无依赖关系
compileprovidedruntimetest
compilecompile(*)-runtime-
providedprovided-provided-
runtimeruntime-runtime-
testtest-test-


       依赖排除:<exclusions>...</exclusions>,依赖排除可以手动控制依赖关系,包括排除、指定、替换依赖等。

  可选依赖:<optional>true</optional>,可选依赖项不会被传递。通常不建议使用它,使用可选依赖的场景是某一个项目实现了多个特性,如支持多种数据库,包括Mysql、Oracle驱动包等,但最终使用的时候只会是其中一个,这种情况下可以用option,但更好的做法是针对不同数据库提供不同的jar包。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值