前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从maven依赖定义顺序到Java spi机制,这些你忽略了的细节

从maven依赖定义顺序到Java spi机制,这些你忽略了的细节

作者头像
品茗IT
发布2023-10-22 15:13:32
2900
发布2023-10-22 15:13:32
举报
文章被收录于专栏:品茗IT品茗IT

从maven依赖定义顺序到Java spi机制,这些你忽略了的细节

一、起因

故事是这样的,新建一个SpringBoot项目的时候,把依赖都加进去之后,run起来,报错了!!

代码语言:javascript
复制
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultValidator' 
defined in class path resource [org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.class]: 
Invocation of init method failed; nested exception is java.lang.AbstractMethodError: 
org.apache.bval.jsr303.ConfigurationImpl.getDefaultParameterNameProvider()Ljavax/validation/ParameterNameProvider;

震惊!同样的依赖和配置竟然跑出不同的结果!

在这里插入图片描述
在这里插入图片描述

查原因:我加入的hibernate-validator竟然无效。

经过一系列试探,得出结论:两个依赖的顺序写反了,导致hibernate-validator并没有起作用。那么,到底是为什么呢? 这就牵扯到了maven依赖定义顺序和Java spi机制,请耐心观看下面的讲解。

如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以加入我们的java学习圈,点击即可加入,共同学习,节约学习时间,减少很多在学习中遇到的难题。

二、maven相同jar包的依赖顺序

我们在工作中的项目都是分模块的,而且模块之间又互相依赖,这个时候我们可能会引入相同的依赖 ,这时maven取那个依赖呢?这就是maven依赖的原则:

  1. 路径不同间接依赖中maven采用的是路径最短者优先

顾名思义,就是谁短谁先,一个项目test依赖了a和b两个jar包。其中a-b-c1.0, d-e-f-c1.1 。由于c1.0路径最短,所以项目test最后使用的是c1.0。

  1. 路径相同间接依赖中maven采用的是依赖定义顺序从上到下

如果 a-b-c1.0 , d-e-c1.1 这样路径都一样怎么办?其实maven的作者也没那么傻,会以在pom文件中申明的顺序那选,如果pom文件中先申明了d再申明了a,test项目最后依赖的会是c1.

所以maven依赖原则总结起来就两条:路径最短,申明顺序其次。

可以理解为,按顺序解析依赖,并记录下路径长度,然后更短的去覆盖。

然而,这次的错误跟这个并没有关系。

三、maven打包顺序

上面已经提到,路径相同,间接依赖中maven采用的是依赖定义顺序从上到下,那不同jar包,顺序是怎样的呢?

很明显,从上到下不是更容易控制么?和上面的理解一样,按顺序解析依赖,并记录下路径长度,然后更短的去覆盖。

日常中多模块打包时候,我们需要打包完依赖子模块,才能继续打包后面的模块。

所以,这里我们发现,hibernate-validator是在org.apache.bval.jsr303.ApacheValidationProvider之后的,这样,hibernate-validator的文件就不会去覆盖META-INF/services下的javax.validation.spi.ValidationProvider文件。

如图,

在这里插入图片描述
在这里插入图片描述

这个文件是干什么用的呢,这就牵扯到了Java spi机制。

四、Java spi机制

SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制,常用于创建可扩展、可替换组件的应用程序,是java中模块化插件化的关键。这些SPI的接口是由Java核心库来提供,而SPI的实现则是作为Java应用所依赖的jar包被包含进类路径(CLASSPATH)中。例如:JDBC的实现mysql就是通过maven被依赖进来。

SPI 框架包含3个基本组件:

  • 服务接口 Service Interface
  • 服务接口的实现类,Service Provider
  • 服务加载器 Service Loader

一张图,教你怎么使用Java spi:

在这里插入图片描述
在这里插入图片描述

使用方法:

  1. 代码编写: 既然是spi,那么就必须先定义好接口。其次,就是定义好接口的实现类。
  2. 创建一个文件夹: 在项目的\src\main\resources\下创建\META-INF\services目录,类似上面hibernate-validator的文件夹。hibernate-validator的文件的META-INF/services:
在这里插入图片描述
在这里插入图片描述

3.文件夹下增加配置文件: 在上面META-INF\services的目录下再增加一个配置文件,这个文件名必须以接口的全限定类名保持一致,例如:javax.validation.spi.ValidationProvider,文件中写明实现类

4.使用JDK来载入 使用JDK提供的ServiceLoader.load()来加载配置文件中的描述信息,完成类加载操作。

代码语言:javascript
复制
ServiceLoader<HelloService> loaders = ServiceLoader.load(HelloService.class);
for (HelloService helloService : loaders) {
    helloService.hello();
}

四、结论

JAR包依赖顺序影响相同实现的spi的顺序,调整下就行了。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-09-03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 从maven依赖定义顺序到Java spi机制,这些你忽略了的细节
    • 一、起因
    • 二、maven相同jar包的依赖顺序
    • 三、maven打包顺序
    • 四、Java spi机制
    • 四、结论
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档