Java插件扩展机制之SPI案例讲解

下面就为大家详细讲解“Java插件扩展机制之SPI案例讲解”的完整攻略。

什么是SPI机制

SPI是“Service Provider Interface”的缩写,意为“服务提供者接口”。SPI机制是Java对于插件化实现的一种支持机制,通过约定好的接口,供各个开发者来实现,并由Java自身的ClassLoader机制为我们实现接口的动态实现。

SPI机制的具体实现

1. SPI机制的约束条件

在Java中,对SPI机制的实现是有一定的约束条件的,这些条件主要包括:

  • 在Classpath下,服务接口的全限定名(class)必须保存在META-INF/services/目录下
  • 服务接口的实现类,必须为接口全限定名对应文件中,提供实现类的全限定名

2. SPI机制的应用示例

来通过一个实际的示例来介绍一下如何使用SPI机制。

比如,我们创建一个Jar包,并将这个Jar包放置到应用系统的Classpath路径下。这个Jar包中,我们提供了一个服务的接口com.test.service.UserService和实现类com.test.service.impl.UserServiceImpl

那么我们需要在这个Jar包的META-INF/services/目录下创建一个服务接口的文件com.test.service.UserService,并在这个文件的内容中填写实现类的全限定名com.test.service.impl.UserServiceImpl

此时,在我们调用UserService时,Java就会自动的去寻找 UserService 的的实现类,并将其实例化,返回给我们。这就是SPI机制的具体实现。

3. Java SPI机制的使用场景

Java SPI机制常常被应用于服务的扩展点。例如:

在开发应用时,我们可能需要为不同的数据库提供不同的连接驱动,不同的日志提供不同的实现等服务。这个时候,我们就可以通过SPI机制为这些服务提供扩展点,在Java程序运行时,让用户进行服务的实现。

这样,在源码实现项目时,就不用关心使用哪个具体的实现,这些实现都是由不同的服务提供商来完成的。同时,由这些不同的实现商来完成对访问进行治理和监控也是比较合适的。

示例1

假设现在我们有自己的发现服务的需求,现在有一个公共的接口需要开放,我们希望其他公司提供自己的实现。为此,我们就创建一个接口com.test.Discovery

public interface Discovery {
    void hello();
}

现在我们希望在我们的系统被调用的时候,能够提供一个扩展机制,这样我们就可以选择具体哪一个实现类。

我们创建一个项目叫做spi-server, 并创建一个实现类com.test.impl.DiscoveryImpl

public class DiscoveryImpl implements Discovery {
    public void hello() {
        System.out.println("hello from DiscoveryImpl");
    }
}

到现在为止,我们需要创建一个文件,告诉服务器其他公司的实现方式,这个文件的路径是META-INF/services/com.test.Discovery,内容是类名,如下:

com.test.impl.DiscoveryImpl

现在我们的discover功能已经准备就绪,我们只需要在服务器程序中通过SPI机制来获取对应的实现:

ServiceLoader<Discovery> serviceLoader = ServiceLoader.load(Discovery.class);
for (Discovery discovery : serviceLoader) {
    discovery.hello();
}

现在,当我们的系统被系统调入的时候,就会输出hello from DiscoveryImpl.

示例2

再来一个例子,我们希望让外部厂商来开展支付的组件,而我们实现调用接口。假设我们有一个初始的接口:

public interface Pay {
    void pay();
}

我们接下来就发布接口,并告诉外部厂商,它需要提供一个对应的实现。我们把接口打包后,把这个包交给外部厂商,让他们来编写实现。

外部厂商收到这个包后,需要创建一个类,实现这个接口:

public class AliPay implements Pay {
    public void pay() {
        System.out.println("Ali pay...");
    }
}

然后把这个AliPay类打包成Jar,我们现在需要把这个Jar放到CLASSPATH下,并在Jar包下的META-INF/services目录下,创建一个文件名为com.test.Pay的文件,把AliPay的实现类写入,作为相应接口的实现类。

然后,在我们的公司内部服务中,如下方式调用其中的AliPay:

ServiceLoader<Pay> load = ServiceLoader.load(Pay.class);
Iterator<Pay> iterator = load.iterator();
while (iterator.hasNext()) {
    Pay next = iterator.next();
    next.pay();
}

现在就可以轻松的实现不同外部的调用了。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java插件扩展机制之SPI案例讲解 - Python技术站

(0)
上一篇 2023年6月16日
下一篇 2023年6月16日

相关文章

  • Spring Boot编写拦截器教程实例解析

    下面是“Spring Boot编写拦截器教程实例解析”的完整攻略。 1. 什么是拦截器? 在 Spring Boot 中,拦截器(Interceptor)是一种 AOP(面向切面编程)技术,它可以在请求到达目标方法之前,或者在请求结束之后,实现相应的拦截操作。拦截器可以用来记录日志、验证用户权限、对请求参数进行处理等。 2. Spring Boot 中实现拦…

    Java 2023年5月31日
    00
  • Java字符串拼接详解

    Java字符串拼接详解 在Java中,我们经常需要将多个字符串拼接成一个更长的字符串。Java提供了多种方法来实现字符串拼接。 1. “+”操作符 Java中最简单的字符串拼接方法就是使用“+”操作符。 示例代码: String str1 = "Hello"; String str2 = " World!"; Stri…

    Java 2023年5月26日
    00
  • 基于重定向RedirectAttributes的用法解析

    基于重定向 RedirectAttributes 的用法解析 在 Spring MVC 中,经常会使用重定向来实现一些跳转的功能。而 RedirectAttributes 则是在使用重定向时用于向跳转页面传递数据的对象。 RedirectAttributes 的用法 使用 RedirectAttributes 一般需要按以下步骤进行: 在处理请求的方法中通过…

    Java 2023年6月15日
    00
  • Spring JPA学习之delete方法示例详解

    Spring JPA学习之delete方法示例详解 简介 Spring JPA框架提供了强大的CRUD功能,其中delete方法作为JPA中的删除操作,可以非常方便地删除数据库中的数据。本文将为大家详细讲解Spring JPA的delete方法,并提供两个示例。 方法介绍 删除操作在JPA中使用delete()方法,它有多种实现方式,分别为: 根据实体对象删…

    Java 2023年5月20日
    00
  • boot-admin整合Quartz实现动态管理定时任务

    淄博烧烤爆红出了圈,当你坐在八大局的烧烤摊,面前是火炉、烤串、小饼和蘸料,音乐响起,啤酒倒满,烧烤灵魂的party即将开场的时候,你系统中的Scheduler(调试器),也自动根据设定的Trigger(触发器),从容优雅的启动了一系列的Job(后台定时任务)。工作一切早有安排,又何须费心劳神呢?因为boot-admin早已将Quartz这块肉串在了烤签上!项…

    Java 2023年4月27日
    00
  • java利用正则表达式处理特殊字符的方法实例

    当处理含有特殊字符的字符串时,我们通常会使用正则表达式来进行匹配和替换。而Java提供了了解处理特殊字符的方法,并且使用正则表达式来匹配和替换字符串。下面是详细的步骤: 1. 使用转义字符 当需要处理特殊字符(例如:. 、^、$、+、*、?、{、}、(、)、|、\、[、]等)时,需要借助转义字符来进行正则表达式的编写。 示例: String input = …

    Java 2023年5月27日
    00
  • java.util.NoSuchElementException原因及两种解决方法

    当使用Scanner类从标准输入或文件读取数据时,可能会遇到java.util.NoSuchElementException异常。这个异常被抛出,当Scanner使用next()、nextInt()或nextLine()方法时,输入流中没有更多的输入时抛出。这个异常可能由以下原因引起: Scanner对象没有被正确地初始化或已关闭。如果Scanner对象已经…

    Java 2023年5月20日
    00
  • Spring Boot数据库链接池配置方法

    下面是“Spring Boot数据库连接池配置方法”的完整攻略。 什么是数据库连接池? 数据库连接池就是一个管理和维护数据库连接(Connection)的缓存池,应用程序可以从连接池中取出一个连接来进行数据库操作,使用完毕后再将其放回连接池中等待下一个请求。 常用的数据库连接池有HikariCP, Apache DBCP, 还有 C3P0等。而在Spring…

    Java 2023年6月16日
    00
合作推广
合作推广
分享本页
返回顶部