`

深入剖析 Maven 规则

阅读更多

     网上有很多maven配置和使用的内容,本文不重复讲解,只介绍maven的一些规则,在开发工作中不会被一些问题卡住。

     

一、什么是maven,为什么要用maven

      作为一门编译型语言,和其它编译语言相同,需要进行编译,测试,部署等必须流程,也就是通常说的软件生命周期。我们需要一个工具能够帮我们自动的完成这样一些没有意义的事情,把精力集中在程序开发和业务处理上。C和C++有make,Java对应的是Maven,Ant,Gradle等。Ant已经过时,Gradle比较新,是基于Groovy的一个工具,配置比maven简单,也兼容maven,但目前主流的还是相对成熟的maven。

      另外,Java大型工作,都会依赖一堆第三方类库或框架。比如数据库要依赖jdbc,使用了文件系统,就要引入该文件系统提供的Java API,还包含开源组织比如apache的commons-lang等一些封装好的类库,避免重复造轮子,同时也提高代码可读性。但是我们怎么获取?每个包都在一个自己的网站上,下载链接也不一定一样,而且本身也会依赖其它的东西。如果手工一个个从网站搜索下载,基本不用干活了。所以必须有一个可以自动处理依赖的工具。

       所以maven基本就是解决了两个问题,一个是项目构建,一个是处理依赖。

 

、maven规则

 1、坐标

       maven对于如何识别一个依赖,使用了坐标的概念,坐标一共5个标签,除去不常用的classfier,配置如下:

       

<groupId>org.apache</groupId>
<artifactId>commons-lang</artifactId>
<version>1.4.1</version>
<package>jar</package>

   

    groupId :通常是组织的定义,当然可以随便取,但是不要跟别人的重复。通用建议是,用组织或者公司的域名,反过来                          就可以。比如apache,就是org.apache。

    artifactId:一个组织下面可能会有很多个工程或者组件,标识这个工程的名称

    version: 这个工程的版本,对应Java有两种,比如1.1,或1.0-SNAPSHOT,用于稳定版或快照版。

    package:默认是jar,可以显式定义成别的,比如ear,war,pom,或安卓里的apk,处理pom外,实质都是zip包。

    定义了这三个标签,基本可以全球唯一定位一个工程。

 

2、依赖

     有两种,一个是denpency,一个是dependencyManagerment。

    

     2.1 dependency

     使用dependecy,配置只是把需要依赖的工程的坐标包含进去就可以了,dependencies标签里可定义多个dependency。

     

<dependencies>
  <dependency>
    <groupId>org.apache</groupId>
    <artifactId>commons-lang</artifactId>
    <version>1.4.1</version>
  </dependency>
</dependencies>
    类比于make是基于Makefile,maven是基于pom文件,pom文件是一个标准的xml。在${M2_HOME}/lib/maven-model-builder-3.0.4.jar中,可以找到 /org/apache/maven/model/pom-4.0.0.xml这个文件,maven3项目都继承该配置。

 

    本质是maven有一个中央仓库,执行mvn命令的时候,在当前目录下找到pom文件,读取配置中的依赖坐标,然后去中央仓库查找,找到后放在本地仓库,也就是 .m2/repository中缓存起来。而maven的文件管理,就是把坐标中的点,替换成/,针对上面的例子,就是/org/apache/commons-lang/1.4.1/,从而在使用时能依赖该jar包。

 

      2.2 父pom

      对于多个工程,每个pom都可能依赖相同的包,这样可以创建一个父pom,将重复的dependency放到父pom里。在工程的pom中,一般在开头定义parent, 之后工程就会继承父pom的配置,类似于Java中的重复方法抽象。

       但是父pom,编译完以后,生成的还是pom,并没有实际的东西。配置如下:

       

<parent>
    <groupId>com.demo</groupId>
    <artifactId>parent-pom</artifactId>
    <version>1.0</version>
</parent>
 

 

     2.3 传递性依赖

     对于maven,依赖是有传递性的。比如A 依赖 B,B依赖E , E依赖C(1.0版本),这样A 会默认的依赖 C (1.0版本)。然后A 又依赖 D, D 依赖 C (2.0版本),那么A到底是依赖1.0,还是依赖2.0版本的C?

     为解决传递性依赖,maven默认有两个规则:

     (1)路径最近者优先

      如上面的例子,有两个依赖路径, A -> B -> E -> C(1.0),A -> D -> C (2.0),后面的路径较短,选后面那个

      (2)第一声明者优先

       依赖路径相同时,比如A -> B -> C(1.0),A -> D -> C (2.0),这时路径是相同的,如果pom中B在D前面,就选B依赖的C(1.0).

 

      2.4 可选依赖

      有一种场景,比如 A -> B, B -> X,  B -> Y, 但是X和Y是相互冲突的,B可能是一个持久层隔离的工具包,包含了多种数据库比如Mysql, PgSql,在构建的时候,需要依赖两个工具包,但是运行时,只能使用一个。那么可以定义可选依赖。配置如下:

       

<dependencies>
  <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
       <version>5.5.0</version>
       <optional>true</optional>
  </dependency>
  <dependency>
       <groupId>postgresql</groupId>
       <artifactId>postgresql</artifactId>
       <version>9,4-701.jdbc3</version>
       <optional>true<optional>
  </dependency>
</dependencies>
    这样两个sql的配置只会对B有影响,而不是对依赖B的项目比如A有影响,但是A使用mysql时,必须显式依赖mysql-connector-java。

 

     2.5 依赖冲突

     有一条依赖关系链,比如 A -> B -> C (1.0-SNAPSHOT) , A -> C (1.1),但是并不想让B依赖 C,而是自己显式指定依赖C,那么可以在dependency中使用exclusion排除掉C的snapshot版本。配置如下:

     

<dependencies>
   <groupId>org.apache</groupId>
   <artifactId>commons-lang3</artifactId>
   <version>1.0</version>
   <exclusions>
        <exclusion>
             <groupId>com.coderdream</groupId>
             <artifactId>log4j</artifactId>
        </exclusion>
   </exclusions>
</dependencies>
    这样将指定的依赖的传递性依赖排除,但是该做法必须要很明白,排除掉不会出错,否则在一些场景中会出现不可预料的错误,比如spring依赖的一些模块。

 

 

     2.6 dependencyManagement

     在父pom中,可以定义dependencyManagement,这样在子工程中,不必在指定版本号。

     但是需要注意的是,dependencyManagement本身只声明依赖,不会自动引入,引入是子工程定义的时候配置的。也就是说,使用了dependencyManagement以后,同样的配置会在两个地方出现,只是一个有version,一个没有version。

     这样看起来很不方便,但是有点类似C语言里的宏定义,或者pom中properties里的变量,能够将版本控制在一个配置中,不不必担心子模块依赖版本不同的情况。配置如下:

     

<!-- 父pom -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache</groupId>
            <artifactId>commons-lang</artifactId>
            <version>3.4.1</version>
        </dependency>
    </dependencies>
</dependencyManagement>

<!-- 子pom  -->
<dependency>
   <groupId>org.apache</groupId>
   <artifactId>commons-lang</artifactId>
</dependency>
    当然,这两个配置也可以在同一个文件中出现。只是没有必要

 

 

    2.7 依赖环

    比如 A -> B  -> C ,通常build都是正常的。但是如果有一次,将 C -> A ,这就形成了一个依赖环。需要说明的是,build时候,不会报错。但是C依赖A的那个包的版本,绝对不是最新的。在软件开发里,这样做显然也是不对的。

 

三、maven私服

      每次都从maven的中央镜像中下载,对带宽来说是一件很痛苦的事情。同样,在公司中,很多工程也是依赖的,被依赖的工程需要发布到一个远程仓库中,供其他工程下载。所以类似于远程仓库的概念,很多公司都内部搭建了一个maven镜像,缓存中央镜像的包,同时存储内部的包。常用的是maven官方的nexus。

 

      对于nexus, 除非CM同事,Java开发也并不需要了解太多,只要知道上面能不能搜索到自己想要的包就行。另外,介绍下仓库的url。nexus中,有几种仓库,如下:

      (1)central,代理maven中央仓库

       ( 2 ) releases , 稳定版宿主型仓库

       ( 3 ) 3rd Party, 用于部署无法从公共仓库获得的第三方发布版本

      ( 4 )  public repositories, 将上面策略为release的仓库,url都转换成统一的地址,也就是说,你下载的url是 /nexus/content/group/public/commons-lang.jar,但是在实际文件存储时,并没有public这个目录,这个只是虚拟的url。

 

四、Profile

    在实际工作中,通常会有开发环境,测试环境,生产环境等至少三套环境。用于保证生产环境的稳定。这样,就会导致数据库的配置,以及一些resource的配置完全不同,使用profile可以解决。配置如下:

     

<profiles>
   <profile>
      <id>dev</id>
      <properties>
           <db.driver>com.mysql.jdbc.Driver</db.driver>
           <db.url>jdbc:mysql//localhost:3306/demo</db.url>
           <db.username>dev</db.username>
           <db.password>dev-pwd</db.passwd>
       </properties>
   </profile>

   <profile>
      <id>online</id>
      <properties>
           <db.driver>com.mysql.jdbc.Driver</db.driver>
           <db.url>jdbc:mysql//localhost:3306/demo</db.url>
           <db.username>online</db.username>
           <db.password>online-pwd</db.passwd>
       </properties>
   </profile>
</profiles>

    构建时只需要指定参数-Pdev,就可以将对应的dev的配置文件等拷贝过去,而不是获取其他的配置文件。当然,如果不指定,某些文件可能会找不到,是会报错的。

     

 五、其它  

      其他还有一些小技巧,比如发生重复依赖冲突时,使用分析依赖的命令,mvn dependency:tree, 不想做单元测试时,可以指定 -Dmaven.test.skip=true ,还有maven的依赖范围,是compile,还是provider等等,在实际用上的时候,网上查找即可。

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    maven pom详解

    POM不仅定义了项目的构建规则,还封装了项目的元数据,使得Maven能够智能地处理项目构建过程中的各种需求。本文将围绕给定文件信息中的关键部分进行深度剖析,帮助读者更全面地理解Maven POM的核心要素。 ### 父...

    Mycat-Server-master 源码、可直接在eclipse中调试

    《深入剖析Mycat-Server源码:Eclipse调试与Maven实践》 Mycat,作为一款开源的分布式数据库中间件,广泛应用于大数据环境下的高并发、高性能场景。其核心在于提供数据分片、读写分离以及负载均衡等功能,为大型...

    drools 5.0 src

    - `pom.xml`:Maven 项目的配置文件,定义了项目依赖、构建过程和打包规则,通过它可以了解 Drools 5.0 的构建系统和依赖库。 - `LICENSE-ASL-2.0.txt`:Apache Software License 2.0,表明 Drools 5.0 采用开放...

    spring源码

    《深入剖析Spring源码:Ant与Maven2构建解析》 Spring框架作为Java开发领域中的核心组件,其源码的深度研究对于提升开发者的技术水平至关重要。本篇文章将围绕标题“spring源码”,深入探讨在Ant和Maven2两种构建...

    spring-cloud.zip

    本文将深入剖析以"spring-cloud.zip"为载体的本地测试Demo,揭示其如何集成Eureka、Config、Hystrix、Gateway和OpenFeign等关键组件,实现动态配置,帮助开发者更好地理解和运用Spring Cloud。 首先,Eureka是...

    xwork-assembly-2.1.6-src

    《深入剖析xwork-assembly-2.1.6-src:揭秘源码的奥秘》 在软件开发领域,源码是理解系统运作机制的关键。"xwork-assembly-2.1.6-src"是一个开放源码的项目,它为我们提供了深入了解xwork框架核心功能的机会。这个...

    junit深入

    《Junit 深入探索:源码剖析与测试工具运用》 Junit,作为Java领域最常用的单元测试框架,是每一个开发者必备的技能之一。本文将深入探讨Junit的内在机制,通过源码分析以及实际应用示例,帮助读者更全面地理解和...

    java项目之即时通讯工具源码.zip

    本项目聚焦于Java实现的即时通讯工具,通过对源码的深入剖析,我们可以了解到Java在构建实时通信系统中的核心技术和设计模式。 首先,即时通讯工具的核心在于其通讯协议的实现。Java项目通常会采用TCP或UDP作为传输...

    精选_基于java的班级管理系统_源码打包

    本文将深入剖析一款基于Java开发的班级管理系统,探讨其设计思想、主要功能模块以及关键技术。 Java作为一款跨平台、面向对象的编程语言,因其优秀的性能和丰富的类库,被广泛应用于各种系统的开发,包括班级管理...

    毕业设计论文-淘宝店主交易管理系统的设计与实现.zip

    这篇论文深入剖析了系统的需求分析、系统架构设计、功能模块划分以及具体的实现技术,旨在为电子商务平台上的店主提供便捷的交易管理服务。 首先,论文在需求分析阶段,会详细阐述店主在日常交易中可能遇到的问题,...

    dubbo2.5.x源码

    《深入剖析Dubbo 2.5.x源码》 Dubbo是阿里巴巴开源的一款高性能、轻量级的服务治理框架,主要用于实现分布式服务之间的调用。在2.5.x版本中,Dubbo提供了丰富的功能,包括服务注册与发现、负载均衡、容错机制、监控...

    jTrainer-源码.rar

    本文将深入剖析jTrainer的源码,揭示其设计模式、核心功能以及实现细节,帮助开发者提升对Java和软件工程的理解。 首先,我们需要了解jTrainer的基本架构。作为一个训练工具,jTrainer可能包含了用户界面(UI)、...

    Activiti Designer5.15.0源码

    10. **Maven构建系统**:Activiti项目通常使用Maven进行构建和依赖管理,理解Maven的生命周期和插件系统对于构建和调试源码非常有帮助。 通过对这些知识点的学习和理解,我们可以逐步剖析Activiti Designer 5.15.0...

    《码出高效:Java开发手册》-非扫描版-带目录.pdf.zip

    9. **JVM**:深入剖析JVM的工作原理,包括类加载机制、内存模型、字节码执行、性能优化等方面,有助于理解和调试程序运行问题。 10. **Java标准库**:介绍Java标准库中的各种工具类和框架,如日期时间API、并发工具...

    findbugs源码包

    《深入剖析FindBugs:Google的优秀bug检测工具》 FindBugs,这款源自Google的开源工具,被誉为静态代码分析领域的佼佼者,专用于在Java代码中寻找潜在的错误和不良实践。它通过分析字节码而非源代码,能够发现多种...

    汽车租赁管理系统 源码 不包含sql文件

    本文将深入剖析一款基于Spring、SpringMVC和Mybatis框架的汽车租赁管理系统源码,旨在帮助读者理解其核心架构与功能实现,并探讨Java技术在系统开发中的应用。 首先,让我们了解一下系统的基础框架。Spring是Java...

    基于springboot图书管理系统.zip

    本系统以“基于SpringBoot的图书管理系统”为实例,深入剖析了如何利用Java、SpringBoot、SSM(Spring、SpringMVC、MyBatis)等技术栈构建一个完整的Web应用。同时,考虑到移动互联网的普及,系统还结合微信小程序,...

    dubbo-2.5.3源码

    《深入剖析Dubbo 2.5.3源码》 Dubbo是一款高性能、轻量级的开源Java RPC框架,由阿里巴巴公司开发并贡献给社区。本文将深入探讨Dubbo 2.5.3版本的核心设计理念、主要功能以及关键源码实现。 一、Dubbo概述 Dubbo...

    timezone-boundary-builder-源码.rar

    本文将深度剖析其源码,揭示其内部工作机制,帮助开发者更好地理解和使用这个工具。 1. **项目简介** "timezone-boundary-builder" 是由Google开发的,主要用于生成适用于Java的时区数据。它将原始的IANA时区...

Global site tag (gtag.js) - Google Analytics