广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java和Dubbo的SPI机制原理解析
  • 275
分享到

Java和Dubbo的SPI机制原理解析

2024-04-02 19:04:59 275人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

SPI: 简单理解就是,你一个接口有多种实现,然后在代码运行时候,具体选用那个实现,这时候我们就可以通过一些特定的方式来告诉程序寻用那个实现类,这就是SPI。 JAVA的SPI 全称

SPI: 简单理解就是,你一个接口有多种实现,然后在代码运行时候,具体选用那个实现,这时候我们就可以通过一些特定的方式来告诉程序寻用那个实现类,这就是SPI。

JAVA的SPI

全称为 Service Provider Interface,是一种服务发现机制。它是约定在 Classpath 下的 META-INF/services/ 目录里创建一个以服务接口命名的文件,然后文件里面记录的是此 jar 包提供的具体实现类的全限定名。

这样当我们引用了某个 jar 包的时候就可以去找这个 jar 包的 META-INF/services/ 目录,再根据接口名找到文件,然后读取文件里面的内容去进行实现类的加载与实例化。

例如:

java的jdbc就使用了SPI机制,当我项目种应用了Mysql的连接jar时候,就会去去mysql-connector-java.jar下的META-INF/services/ 目录查找java.sql.Driver名的文件,然后加载里面全类名的类。如果使用oracle连接驱动时候,就会去ojdbc.jar下面去找java.sql.Driver文件里的配置的全类名。

在这里插入图片描述

在这里插入图片描述

并且通过idea的智能提示功能,也能看到,在你切换不同连接的jar包时候,Driver接口实现类是不同的。

使用mysql的连接驱动:

在这里插入图片描述

切换到oracle的连接驱动:

在这里插入图片描述

Java的SPI机制源码分析

下面这段代码,以jdbc的SPI为例,可以作为debug的入口:


package com.example.demo;

import java.sql.Connection;
import java.sql.DriverManager;

public class JDBCMain {
  private static final String URL = "jdbc:mysql://localhost:3306/test?useSSL=true&useUnicode=true&characterEncoding=UTF-8";

  public static void main(String[] args) throws Exception{
    Connection conn = DriverManager.getConnection(URL, "root", "123456");
  }
}

在使用DriverManager.getConnection()方法时候,会加载并初始化DriverManager类,此类是jdbc使用SPI的核心类。

1.DriverManager类初始化,调用static代码块,执行DriverManager#loadInitialDrivers()方法

在这里插入图片描述

2.使用javaSPI的核心类ServiceLoader#load()和以及其内部实现了Iterator的LazyIterator#hasNext()和
LazyIterator#next(),加载接口的具体实现类。

在这里插入图片描述

ServiceLoader.load()整个代码流程,如下图。其实就是给LazyIterator类的赋值属性,是那个接口要进行SPI,使用的类加载器是哪一个。

在这里插入图片描述 

driversIterator.hasNext()和driversIterator.next()方法负责类实际类的加载

  •  driversIterator.hasNext()最后实际是调到了LazyIterator.hasNext();
  • driversIterator.next()最后实际是调到了LazyIterator.next();

hashNext()方法读到SPI的配置文件里的全类名

在这里插入图片描述

next()方法最后通过反射创建出具体实现类的实例

在这里插入图片描述

总结

  1. jdbc的SPI,通过DriverManager类静态代码块执行loadInitialDrivers()方法
  2. 然后通过ServiceLoader.load()拿到具体的接口,以及类加载器。
  3. 通过实现了Iterator类的LazyIterator类的hasNext方法读取配置文件,拿到接口的具体实现全类名
  4. 在next()方法内部,通过反射机制,由实现类的全类名,加载具体实现类。

代码实战java SPI

DemoService接口


public interface DemoService {
  String sayHello(String msg);
} 

XiaoHongDemoServiceImpl实现类


public class XiaoHongDemoServiceImpl implements DemoService {
  @Override
  public String sayHello(String msg) {
    return "xiaohong:"+msg;
  }
}

ZhangSanDemoServiceImpl实现类


public class ZhangSanDemoServiceImpl implements DemoService {
  @Override
  public String sayHello(String msg) {
    return "zhangsan:"+msg;
  }
}

定义SPI配置文件

在这里插入图片描述

最后使用


public class DemoMain {
  public static void main(String[] args) {
    ServiceLoader<DemoService> serviceLoad = ServiceLoader.load(DemoService.class);
    Iterator<DemoService> iterator = serviceLoad.iterator();
    while (iterator.hasNext()){
      DemoService demoService = iterator.next();
      String returnStr = demoService.sayHello("lzc贼帅!!!!");
      System.out.println(returnStr);
    }
  }
}

执行结果:

在这里插入图片描述

java SPI劣势,会加载SPI配置文件里定义的所有配置类,如果用不上该类,也会加载。通俗点讲,就是无法按需加载。

dubbo的SPI

dubbo SPI使用

需要先引入dubbo相关的依赖

1.定义接口
通过dubbo的SPI注解标注定义的接口


@SPI("xiaohong")
public interface DubboSPIService {

  void sayHello();
}

2.多个实现类


public class XiaoHongDubboSPIServiceImpl implements DubboSPIService {
  @Override
  public void sayHello() {
    System.out.println("小红说:lzc贼帅!");
  }
}

public class XiaoMingDubboSPIServiceImpl implements DubboSPIService {
  @Override
  public void sayHello() {
    System.out.println("小明说:lzc贼帅!");
  }
}

3.定义dubbo SPI配置文件
META-INF/dubbo目录下定义接口全类名的文件,配置key-value的实现

Dubbo 对配置文件目录的约定,不同于 Java SPI ,Dubbo 分为了三类目录。

META-INF/services/ 目录:该目录下的 SPI 配置文件是为了用来兼容 Java SPI 。
META-INF/dubbo/ 目录:该目录存放用户自定义的 SPI 配置文件。
META-INF/dubbo/internal/ 目录:该目录存放 Dubbo 内部使用的 SPI 配置文件。

在这里插入图片描述

4.使用


public class DubboSPIMain {
  public static void main(String[] args) {
  //default,会取@SPI注解里定义的key对应的实现
//    DubboSPIService defaultExtensionService = ExtensionLoader.getExtensionLoader(DubboSPIService.class).getDefaultExtension();
//    defaultExtensionService.sayHello();
    DubboSPIService dubboSPIService = ExtensionLoader.getExtensionLoader(DubboSPIService.class).getExtension("xiaoming");
    dubboSPIService.sayHello();
  }
}

结果:

在这里插入图片描述

源码分析

ExtensionLoader.getExtensionLoader(DubboSPIService.class).getExtension("xiaoming");
dubbo SPI的核心就是ExtensionLoader类

1.ExtensionLoader#getExtensionLoader()

该方法主要是,从一个map里取key为当前传进来的接口Class的value(value是ExtensionLoader对象),如果取不到,我们就往这个map里put一份这样的key-value。value是new ExtensionLoader(type)传进去的type是接口的Class对象,最后会赋值给ExtensionLoader对象的type属性,后面会用到

在这里插入图片描述

2.拿到ExtensionLoader对象后,通过ExtensionLoader#getExtension()获取具体的实现的实例

首先会取缓存里拿,没拿到就调用createExtension()方法取创建所需要的实例,最后塞入缓存。

在这里插入图片描述

3.createExtension方法

通过getExtension(“xiaoming”)传进来的name=xiaoming,从SPI配置文件获取到所需要实现类的全类名,通过反射拿到实现类的Class对象,最后通过反射拿到相应的实例。核心是getExtensionClasses()方法。

在这里插入图片描述

4.getExtensionClasses()

getExtensionClasses()方法返回一个Map,key为SPI配置文件中的key,value为SPI配置文件中,实现类的Class对象。

可以看到,代码中用来大量的缓存机制,的双检查。cacheDefaultExtensionName()方法里会拿到SPI注解上配置的默认key,然后赋值给cachedDefaultName属性,如果使用getDefaultExtension()时候会使用到strategies,其实是通过java得SPI拿到得一个数组

在这里插入图片描述

5.循环三个SPI文件得目录,分别调用loadDirectory方法

fileName最后在三次循环里,会拼出三个路径,META-INF/dubbo/com.example.demo.service.DubboSPIService,这一个才是正确得路径,然后获得配置文件得绝对路径。然后会执行loadResource()方法读取SPI配置文件

  • META-INF/dubbo/com.example.demo.service.DubboSPIService
  • META-INF/services/com.example.demo.service.DubboSPIService
  • META-INF/dubbo/internal/com.example.demo.service.DubboSPIService

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

6.loadResource()读取SPI配置文件

一行一行读配置文件里得key-value,然后通过Class.forName()获取类得Class对象。然后put到第四步定义得空Map,extensionClasses这个Map里,再返回到第三步得getExtensionClasses()方法。

在这里插入图片描述

好了,今天先到这里,凌晨了。。。Adaptive 注解 - 自适应扩展下次有时间再写。

到此这篇关于Java和Dubbo的SPI机制原理解析的文章就介绍到这了,更多相关Java和Dubbo的SPI内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java和Dubbo的SPI机制原理解析

本文链接: https://www.lsjlt.com/news/122120.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java和Dubbo的SPI机制原理解析
    SPI: 简单理解就是,你一个接口有多种实现,然后在代码运行时候,具体选用那个实现,这时候我们就可以通过一些特定的方式来告诉程序寻用那个实现类,这就是SPI。 JAVA的SPI 全称...
    99+
    2022-11-11
  • 解析Apache Dubbo的SPI实现机制
    目录一、SPI1.1、JDK自带SPI实现1.2、Dubbo SPI二、加载-ExtensionLoader2.1、获取ExtensionLoader的实例2.2、加载扩展类2.2....
    99+
    2022-11-12
  • Dubbo 系列JDK SPI 原理解析
    目录正文为什么要使用SPI?什么是 SPIJDK SPI 机制JDK SPI原理为什么不直接使用 JDK SPI正文 上一篇文章讲到了如何去找到 Dubbo 源码的调试入口,如果你...
    99+
    2023-02-24
    Dubbo JDK SPI原理 Dubbo JDK SPI
  • Java Spring Dubbo三种SPI机制的区别
    目录前言SPI 有什么用?​JDK SPI​Dubbo SPISpring SPI​对比​前言 SPI 全称为 Service Provider Interface,是一种服务发现机...
    99+
    2022-11-13
  • 浅析Java中的SPI原理
    在面向对象的程序设计中,模块之间交互采用接口编程,通常情况下调用方不需要知道被调用方的内部实现细节,因为一旦涉及到了具体实现,如果需要换一种实现就需要修改代码,这违反了程序设计的&q...
    99+
    2022-11-13
  • 如何理解Java中的SPI机制
    本篇内容介绍了“如何理解Java中的SPI机制”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!SPI的概念SPI在Java中的全称为Servi...
    99+
    2023-06-15
  • Dubbo原理和机制详解(非常全面)
    Dubbo是一款Java RPC框架,致力于提供高性能的RPC远程服务调用方案。Dubbo 作为主流的微服务框架之一,为开发人员带来了非常多的便利。 本文我们重点详解 Dubbo 的原理机制 @mikechen 目录 Dubbo核心功能D...
    99+
    2023-09-12
    dubbo java 分布式 后端 架构
  • dubbo的超时机制原理
    本篇内容主要讲解“dubbo的超时机制原理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“dubbo的超时机制原理”吧!在工作中碰到一个业务接口时间比较长,需要修...
    99+
    2022-10-19
  • SpringBoot的SPI机制源码解析
    目录一、从java类加载机制说起1.1 双亲委派模型1.2 双亲委派模型缺陷1.3 使用线程上下文类加载器(ContextClassLoader)加载1.4 使用类加载器加载资源文件...
    99+
    2022-12-21
    SpringBoot SPI机制 SpringBoot SPI
  • 怎么进行Java SPI机制的分析
    这篇文章将为大家详细讲解有关怎么进行Java SPI机制的分析,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。为什么需要SPI?思考一个场景,我们封装了一套服务,别人通过引入我们写好...
    99+
    2023-06-22
  • Java进阶之SPI机制的示例分析
    这篇文章将为大家详细讲解有关Java进阶之SPI机制的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、前言SPI的英文全称为Service Provider Interface,字面意思为服务提...
    99+
    2023-06-15
  • java开发分布式服务框架Dubbo原理机制详解
    目录前言Dubbo框架有以下部件ConsumerProviderRegistryMonitorContainer架构高可用性框架设计服务暴露过程服务消费过程前言 在介绍Dubbo之前...
    99+
    2022-11-12
  • java开发分布式服务框架Dubbo原理机制的示例分析
    这篇文章给大家分享的是有关java开发分布式服务框架Dubbo原理机制的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。前言在介绍Dubbo之前先了解一下基本概念:Dubbo是一个RPC框架,RPC,即Re...
    99+
    2023-06-25
  • 一文带你了解Java中的SPI机制
    目录1: SPI机制简介2: SPI原理3: 使用场景4: 源码论证5: 实战6: 优缺点6.1 优点6.2 缺点1: SPI机制简介 SPI 全称是 ...
    99+
    2023-05-15
    Java SPI机制原理 Java SPI机制使用 Java SPI机制
  • java框架基础之SPI机制实现及源码解析
    目录1 定义2 案例实现标准接口厂商的具体接口实现3 SPI机制源码分析3.1 load加载过程3.2 实例化过程1 定义 SPI 的全名为 Service Pr...
    99+
    2022-11-13
  • Java插件扩展机制之SPI的示例分析
    这篇文章给大家分享的是有关Java插件扩展机制之SPI的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。什么是SPISPI ,全称为 Service Provider Interface,是一种服务发现机制...
    99+
    2023-06-20
  • zookeeper的watch机制原理解析
    目录一、Watch机制介绍二、zkCli客户端使⽤watch2.1、get -w命令详解2.2、ls -w命令详解2.3、ls -R -w命令详解三、curator客户端使⽤watc...
    99+
    2022-11-13
  • Dubbo retries 超时重试机制的问题原因分析及解决方案
    目录异常日志异常原因解决方案Dubbo超时重试机制异常日志 [com.alibaba.dubbo.rpc.filter.TimeoutFilter] -  [DUBBO] ...
    99+
    2022-11-13
  • Android6.0 消息机制原理解析
    消息都是存放在一个消息队列中去,而消息循环线程就是围绕这个消息队列进入一个无限循环的,直到线程退出。如果队列中有消息,消息循环线程就会把它取出来,并分发给相应的Handler进...
    99+
    2022-06-06
    消息机制 Android
  • SpringbootFatJa原理机制源码解析
    目录一、概述二、标准的 jar 包结构三、探索JarLauncher3.1 只能拷贝出来一份儿3.2 携带程序所依赖的jar而非仅class四、 自定义类加载器的运行机制4.1 指定...
    99+
    2022-12-26
    Springboot FatJa原理机制 Springboot FatJa
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作