maven详解之坐标与依赖

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

看着简单而又复杂的pom.xml文件,看似熟悉,当自己编写的时候觉得简单,但是看人家项目的时候又觉得复杂的很,现在我们一起来分析这个pom文件。


Maven的坐标为各种构件引入了秩序,任何一个构件都必须明确的定义自己的坐标,maven的坐标包括如下的元素:

groupId: 定义当前Maven项目隶属的实际项目

artifactId: 该元素定义实际项目中的一个Maven项目或模块

version: 该元素定义Maven项目当前所处的版本

packaging: 该元素定义Maven项目的打包方式

classifier: 该元素用来帮助定义构建输出的一些附属构件

注:groupId、artifactId、version、packaging是必须定义的,classifier是不能被直接定义的,因为附属构件不是项目直接默认生成的,而是由附加的插件帮助生成的。


元素详解:

根元素project下的dependencies元素详解:

dependencies可以包含一个或者多个dependency元素,以声明一个或多个项目依赖, 其包含的元素:

groupIdartifactIdversion:依赖的基本坐标,对于任何一个依赖来说,基本的坐标是最重要的,Maven是根据坐标来找到需要的依赖

type: 依赖的类型

scope: 依赖的范围

optional: 标记依赖是否可选(参见可选性依赖)

exclusions: 用来排除传递性依赖(参见依赖的传递性)


依赖范围详解:

Maven在编译项目主代码的时候需要使用一套classpath

Maven在编译和执行测试的时候会使用另外一套classpath

Maven在实际运行项目的时候又会使用一套classpath

依赖范围就是用来控制依赖与这三种classpath(编译classpath、测试classpath、运行classpath)的关系

Maven的6种依赖范围:

compile: 编译依赖范围(默认),对于编译、测试、运行三种classpath都有效

test: 测试依赖范围, 只对测试classpath有效。典型范例:Junit

provided: 已提供依赖范围 对于编译和测试classpath有效,但在运行时无效。典型范例:servlet-api

runtime: 运行时依赖范围 对于测试和运行classpath有效,但在对编译主代码时无效。典型范例:JDBC

system: 系统依赖范围

import: (maven2.0.9及以上): 导入依赖范围,它不会对三种实际的classpath产生影响

依赖范围(Scope)对于编译classpath有效对于测试classpath有效对于运行时classpath有效例子
compileYYYspring-core
test
Y
junit
providedYY
servlet-api
runtime
YYJDBC驱动实现
systemYY
本地的,Maven仓库之外的类库文件


了解了依赖的基本元素和依赖范围之后,我们会发现在我们项目中经常会出现一些默认的配置问题,导致编译和运行失败的情况,现在让我们来学习如何解决这些问题,首先要了解一下依赖的传递性


传递性依赖和依赖范围

简单的说,一般项目中出现问题多数是因为重复的引用或者引用了较低版本的依赖,或者是他们的依赖范围发生了变化。

举个例子来理解传递性依赖:

我们创建了一个Maven Project-----learnDependency,然后我们引入了spring-core这个依赖,然后我们打开spring-core的 pom.xml发现,spring-core也有自己的依赖:commons-logging,而且该依赖没有声明依赖范围,那么默认的就是 compile,所以这时我们就可以说:commons-logging也是learnDependency的一个依赖,这时我们就将这种依赖称之为传递 性依赖,commons-logging是learnDependency的一个传递性依赖。有了传递性依赖,我们就可以在使用的时候不去考虑我们引入的 依赖到底是否需要其它依赖,和是否引入多余的依赖,Maven 会解析各个直接依赖的pom,将必要的间接依赖引入到项目中。


细说传递性依赖

假设:A依赖于B,B依赖于C,那么我们就说A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖。

因为依赖是有依赖范围的,那么对于这种传递性依赖Maven又是如何界定其依赖范围的呢?

当第二直接依赖的范围是compile的时候,传递性依赖的范围与第一直接依赖的范围一致;

当第二直接依赖的范围是test的时候,依赖不会得以传递

当第二直接依赖的范围是provided的时候,只传递第一依赖范围也为provided的依赖,且传递性依赖的范围同样是provided;

当第二直接依赖的范围是runtime的时候,传递性依赖的范围与第一直接依赖的范围一致,但compile除外,此时传递性依赖范围为runtime

 compiletestprovidedruntime
compilecompile

runtime
testtest

test
providedprovided
providedprovided
runtimeruntime

runtime


左侧第一列表示第一直接依赖范围,最上面一行表示第二直接依赖


optional: 有时候我们不想让依赖传递,那么可配置该依赖为可选依赖,将元素optional设置为true即可。


在我们了解了Maven强大的依赖机制之后,我们开始解决问题:

常见问题一:依赖的重复引入

之前说过Maven可以有效的解决依赖的重复引入问题,但是为什么我们在项目还会出现这类问题呢?先让我们来看一下Maven是如何处理重复引入问题的:


情景一:我们在项目中分别引入了2个依赖A和B,A又依赖的C,C又依赖了D,B也依赖了D,但是这个时候C依赖的D和B依赖的D的版本是不同的:

项目----A---C----D

项目----B---D

也就是说,当前项目引入了2次D依赖,那么这时,Maven将采用第一原则:路径最近原则


情景二:我们在项目中分别引入了2个依赖A和B,而A和B又都引入了C,但是,此时A依赖的C和B依赖的C版本是不一致的,那么这个时候Maven如何处理呢?

这时,第一原则已经不起作用了,

在Maven2.0.8及之前的版本中  和 Maven2.0.9之后的版本Maven对于这种情况的处理方式是不一致的

确切的说:

在Maven2.0.8及之前的版本中Maven究竟会解析哪个版本的依赖,这是不确定的

Maven2.0.9之后的版本中,制定了第二原则:第一声明者优先

就是说,它取决于在POM中依赖声明的顺序


这个问题就说明了,为什么我们常常遇到的可以正常运行的项目,然后我们增加了一个看似无关的依赖,然后项目就出现了错误,就是这个传递性依赖搞的鬼!


还要补充说明的一种情况是可选依赖

为什么会有可选依赖呢?是因为某一个项目实现了多个特性,但是我们在面向对象的设计中,有一个原则叫:单一职责性原则,就是强调在一个类只有一项职责,而不是糅合了太多的功能,所以一般这种可选依赖很少会出现。


常见问题二:默认引入的依赖----第二直接依赖的版本过低或者依赖了不稳定的快照

这个问题我们在开发中也经常遇到,在某个第二直接依赖中引入了1.0版本,但是我们现在想使用2.0版本,这时我们要如何解决?

引入一个名词:排除依赖,也可以叫替换依赖

想实现依赖排除,然后替换成自己想要的依赖,这时我们要用到的一个配置是<exclusions> 和<exclusion>,我们可以使用这一元素声明排除依赖,然后显示的声明我们想要的依赖,在<exclusions>中可 以声明一个或多个<exclusion>来排除一个或多个传递性依赖。

注:声明<exclusion>的时候只需要声明groupId和artifactId就能唯一定位依赖图中的某个依赖。

A ------->  B ------×----C(version1.0)

|

C(version2.0)


常见问题三:解决重复的配置

我们在开发中也经常遇到这样的情况,比如在使用spring framework的时候,他们都是来自于同一个项目的不同模块,因此这些依赖的版本都是相同的,而且在将来升级的时候,这些版本也会一起被升级,这时 Maven又提供了一种解决方案------使用properties元素定义Maven属性,然后引用。

示例:

<properties>  <springframework.version>2.5.6</springframework.version>  
</properties>


这个时候我们就可以在声明依赖的时候使用${springframework.version}来替换具体的版本号

<dependency>  <groupId>org.springframework</groupId>  <artifactId>spring-context-support</artifactId>  <version>${springframework.version}</version>  
</dependency>

如何正确的优化依赖

首先我们必须要对maven的依赖处理方式了然于胸,然后我们就可以去除多余的依赖,显示的声明必要的依赖,保证每个构件都只有唯一的版本在依赖中存在

使用命令来查看当前项目的已解析依赖:

mvn dependency : list

经过Maven解析之后,就会构成一个依赖树

也可以使用命令查看当前项目的依赖树:

mvn dependency : tree

使用命令分析当前当前项目的依赖:

mvn dependency : analyze

该命令执行结果的两个重要部分:

Used undeclared dependencies: 表示项目中使用到的,但是没有显示声明的依赖

Unused declared dependencies: 表示项目中未使用的,但显示声明的依赖

注:dependency : analyze只会分析编译主代码和测试代码需要用到的依赖,一些执行测试和运行时需要的依赖它无法发现。


对于项目中的最佳实践,需要自己多多的尝试或者看别人的一些分享,这样对于开发效率会有很大的帮助,当然在项目开发的过程中不断的优化和调整这种方法也未尝不可。

转载于:https://my.oschina.net/u/2418042/blog/491698

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/399821.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EF6源码学习-准备篇

现在对于。net开发人员来说EF已经很流行了&#xff0c;虽然我在2010年的时候就用过EF&#xff0c;也看过几本书&#xff0c;但是还没有仔细研究EF的code&#xff0c; 曾经也尝试阅读EF5的源代码&#xff0c;后来由于时间关系也没有坚持住。现在计划阅读EF6 code first部分的源码…

flask 对excel上传下载操作和文件处理

文件的下载 from flask import send_from_directory excel_bp.route(/get_attachment/<path:filename>) def get_attachment(filename): return send_from_directory(app.config[UPLOAD_FOLDER],filename,as_attachmentTrue) 文件的上传 &#xff08;1&#xff09;ht…

Flask入门之上传文件到服务器

https://www.cnblogs.com/wongbingming/p/6802660.html flask 文件的上传下载和excel操作 Flask入门之上传文件到服务器 今天要做一个简单的页面&#xff0c;可以实现将文件 上传到服务器&#xff08;保存在指定文件夹&#xff09; #Sample.py # coding:utf-8from flask i…

ASP入门(十一)-Session小案例

一般来说&#xff0c;在实际开发中&#xff0c;对于 Session 对象使用最多的就是用户登录部分了&#xff0c;这个案例将简单模拟一个用户登录表单、用户是否登录的判断以及用户退出的一系列功能&#xff0c;它一共分了以下几个页面。 Login.asp (用户登录)、Check.asp (用户是否…

[转]打造自己的LINQ Provider(上):Expression Tree揭秘

概述 在.NET Framework 3.5中提供了LINQ 支持后&#xff0c;LINQ就以其强大而优雅的编程方式赢得了开发人员的喜爱&#xff0c;而各种LINQ Provider更是满天飞&#xff0c;如LINQ to NHibernate、LINQ to Google等&#xff0c;大有“一切皆LINQ”的趋势。LINQ本身也提供了很好的…

2017.9.15 postgresql批量插入造成冲突后执行更新

参考来自&#xff1a;https://stackoverflow.com/questions/40647600/postgresql-multi-value-upserts/46233907#46233907 1.before insert 2.insert sql 3.after insert 注意这里有两个容易出错的点&#xff1a;1.如果label字段不是必填的&#xff0c;要注意语法会不会出错。万…

mybatis动态SQL语句

三、动态SQL语句 有些时候&#xff0c;sql语句where条件中&#xff0c;需要一些安全判断&#xff0c;例如按性别检索&#xff0c;如果传入的参数是空的&#xff0c;此时查询出的结果很可能是空的&#xff0c;也许我们需要参数为空时&#xff0c;是查出全部的信息。这是我们可以…

git 脚本

echo $PWD message$1 content. if [ ! -n "$1" ] ;thenmessagedatemessage$message 推送到服务器echo $message elseecho "$1" figit add . git commit -m "$message " git push 转载于:https://www.cnblogs.com/whm-blog/p/7527271.html

好的积分不等式

转自 http://pxchg1200.is-programmer.com/?page7 转载于:https://www.cnblogs.com/zhangwenbiao/p/4738960.html

Ubuntu 中改变文件的默认打开方式(转)

源自&#xff1a;Ubuntu 中改变文件的默认打开方式 1. 相关配置文件 [plain] view plaincopyprint? 全局配置 /etc/gnome/defaults.list /usr/share/applications/mimeinfo.cache 个人配置 ~/.local/share/applications/mimeapps.list ~/.local/share/applications/mimei…

使用PhpSpreadsheet将Excel导入到MySQL数据库

使用PhpSpreadsheet将Excel导入到MySQL数据库 日常开发中&#xff0c;我们经常遇到这样的场景&#xff0c;需要将一个Excel表格数据如客户信息、学生成绩表导入到系统数据库中&#xff0c;然后在系统中进行进一步操作&#xff0c;如给导入的客户群发短信&#xff0c;统计学生成…

spring-test的简单实用方式

为什么80%的码农都做不了架构师&#xff1f;>>> 1. 通过maven引入spring-test框架 <dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>4.2.0.RELEASE</version> </…

WordPress后台添加侧边栏菜单

https://my.oschina.net/shunshun/blog/78193 https://www.ludou.org/add-admin-menu-in-wordpress.html 添加WordPress顶级管理菜单其实也是一件非常简单的事情&#xff0c;使用两个WordPress内置函数就可以解决问题&#xff0c;分别是add_menu_page()和 add_action()&#xf…

Android 常见错误

2019独角兽企业重金招聘Python工程师标准>>> 1. org.apache.http.conn.HttpHostConnectException: Connection to refused 权限问题: <uses-permission android:name"android.permission.INTERNET"/> 2. 浏览器直接输入url可以get&#xff0c;http …

使用BootStrap框架设置全局CSS样式

一、排版 标题 HTML 中的所有标题标签&#xff0c;<h1> 到 <h6> 均可使用。另外&#xff0c;还提供了 .h1 到 .h6 类&#xff0c;为的是给内联&#xff08;inline&#xff09;属性的文本赋予标题的样式。 <h1>这是一个h1标签</h1><h2>这是一个h2…

SVN初步学习教程

本文目的 让未使用过版本控制器软件或者未使用过subversion软件的人员尽快上手。 subversion的使用技巧很多&#xff0c;这里只总结了最小使用集&#xff0c;即主要的基本功能&#xff0c;能够用来应付日常工作。 因此不涉及subversion服务器端的搭建和配置。 为什么要使用版本…

V2EX大牛的指点

2019独角兽企业重金招聘Python工程师标准>>> first&#xff1a; 我认识一些深圳、杭州、北京的朋友&#xff0c;他们往往更关注以下内容&#xff1a; 1. 代码&#xff08;包括注释&#xff09;的规范性、可维护性 2. 参与一些算法的研究与实现、开源库的创建与维护…

python-实现动态web服务器

# encodingutf-8 import socket from multiprocessing import Process import re import sys# 设置静态文件根目录 HTML_ROOT_DIR ./htmlWSGI_PYTHON_DIR ./wsgipythonclass HTTPServer(object):def __init__(self, application):self.server_socket socket.socket(socket.A…

Android中shape的使用

本人在美工方面一直是比较白痴的&#xff0c;对于一些颜色什么乱七八糟的非常头痛&#xff0c;但是在Android编程中这又是经常涉及到的东西&#xff0c;没办法&#xff0c;只有硬着头皮上。 Android中常常使用shape来定义控件的一些显示属性&#xff0c;今天看了一些shape的使用…

PHP遍历数组的几种方法

这三种方法中效率最高的是使用foreach语句遍历数组。从PHP4开始就引入了foreach结构&#xff0c;是PHP中专门为遍历数组而设计的语句&#xff0c;推荐大家使用。先分别介绍这几种方法 PHP中遍历数组有三种常用的方法&#xff1a; 一、使用for语句循环遍历数组&#xff1b; 二、…