网上有很多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等等,在实际用上的时候,网上查找即可。
相关推荐
POM不仅定义了项目的构建规则,还封装了项目的元数据,使得Maven能够智能地处理项目构建过程中的各种需求。本文将围绕给定文件信息中的关键部分进行深度剖析,帮助读者更全面地理解Maven POM的核心要素。 ### 父...
《深入剖析Mycat-Server源码:Eclipse调试与Maven实践》 Mycat,作为一款开源的分布式数据库中间件,广泛应用于大数据环境下的高并发、高性能场景。其核心在于提供数据分片、读写分离以及负载均衡等功能,为大型...
- `pom.xml`:Maven 项目的配置文件,定义了项目依赖、构建过程和打包规则,通过它可以了解 Drools 5.0 的构建系统和依赖库。 - `LICENSE-ASL-2.0.txt`:Apache Software License 2.0,表明 Drools 5.0 采用开放...
《深入剖析Spring源码:Ant与Maven2构建解析》 Spring框架作为Java开发领域中的核心组件,其源码的深度研究对于提升开发者的技术水平至关重要。本篇文章将围绕标题“spring源码”,深入探讨在Ant和Maven2两种构建...
本文将深入剖析以"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框架核心功能的机会。这个...
《Junit 深入探索:源码剖析与测试工具运用》 Junit,作为Java领域最常用的单元测试框架,是每一个开发者必备的技能之一。本文将深入探讨Junit的内在机制,通过源码分析以及实际应用示例,帮助读者更全面地理解和...
本项目聚焦于Java实现的即时通讯工具,通过对源码的深入剖析,我们可以了解到Java在构建实时通信系统中的核心技术和设计模式。 首先,即时通讯工具的核心在于其通讯协议的实现。Java项目通常会采用TCP或UDP作为传输...
本文将深入剖析一款基于Java开发的班级管理系统,探讨其设计思想、主要功能模块以及关键技术。 Java作为一款跨平台、面向对象的编程语言,因其优秀的性能和丰富的类库,被广泛应用于各种系统的开发,包括班级管理...
这篇论文深入剖析了系统的需求分析、系统架构设计、功能模块划分以及具体的实现技术,旨在为电子商务平台上的店主提供便捷的交易管理服务。 首先,论文在需求分析阶段,会详细阐述店主在日常交易中可能遇到的问题,...
《深入剖析Dubbo 2.5.x源码》 Dubbo是阿里巴巴开源的一款高性能、轻量级的服务治理框架,主要用于实现分布式服务之间的调用。在2.5.x版本中,Dubbo提供了丰富的功能,包括服务注册与发现、负载均衡、容错机制、监控...
本文将深入剖析jTrainer的源码,揭示其设计模式、核心功能以及实现细节,帮助开发者提升对Java和软件工程的理解。 首先,我们需要了解jTrainer的基本架构。作为一个训练工具,jTrainer可能包含了用户界面(UI)、...
10. **Maven构建系统**:Activiti项目通常使用Maven进行构建和依赖管理,理解Maven的生命周期和插件系统对于构建和调试源码非常有帮助。 通过对这些知识点的学习和理解,我们可以逐步剖析Activiti Designer 5.15.0...
9. **JVM**:深入剖析JVM的工作原理,包括类加载机制、内存模型、字节码执行、性能优化等方面,有助于理解和调试程序运行问题。 10. **Java标准库**:介绍Java标准库中的各种工具类和框架,如日期时间API、并发工具...
《深入剖析FindBugs:Google的优秀bug检测工具》 FindBugs,这款源自Google的开源工具,被誉为静态代码分析领域的佼佼者,专用于在Java代码中寻找潜在的错误和不良实践。它通过分析字节码而非源代码,能够发现多种...
本文将深入剖析一款基于Spring、SpringMVC和Mybatis框架的汽车租赁管理系统源码,旨在帮助读者理解其核心架构与功能实现,并探讨Java技术在系统开发中的应用。 首先,让我们了解一下系统的基础框架。Spring是Java...
本系统以“基于SpringBoot的图书管理系统”为实例,深入剖析了如何利用Java、SpringBoot、SSM(Spring、SpringMVC、MyBatis)等技术栈构建一个完整的Web应用。同时,考虑到移动互联网的普及,系统还结合微信小程序,...
《深入剖析Dubbo 2.5.3源码》 Dubbo是一款高性能、轻量级的开源Java RPC框架,由阿里巴巴公司开发并贡献给社区。本文将深入探讨Dubbo 2.5.3版本的核心设计理念、主要功能以及关键源码实现。 一、Dubbo概述 Dubbo...
本文将深度剖析其源码,揭示其内部工作机制,帮助开发者更好地理解和使用这个工具。 1. **项目简介** "timezone-boundary-builder" 是由Google开发的,主要用于生成适用于Java的时区数据。它将原始的IANA时区...