文章目录

  • 简介
  • SPI简介
  • SPI的普通java实现
  • SPI在JPMS模块化系统下的实现
  • 总结

简介

什么是可扩展的应用程序呢?可扩展的意思是不需要修改原始代码,就可以扩展应用程序的功能。我们将应用程序做成插件或者模块。

这样可以在不修改原应用的基础上,对系统功能进行升级或者定制化。

本文将会向大家介绍如何通过java中的SPI机制实现这种可扩展的应用程序。

SPI简介

SPI的全称是Java Service Provider Interface。是java提供的一种服务发现的机制。

通过遵循相应的规则编写应用程序之后,就可以使用ServiceLoader来加载相应的服务了。

SPI的实现主要分为4个部分:

  1. Service Provider Interface: SPI是一个interface或者是抽象类,其中定义了我们需要扩展实现的功能。
  2. Service Providers:这是SPI的具体实现,提供了具体的实现功能
  3. SPI Configuration File:SPI的配置文件,通过在配置文件我们来配置相关的SPI发现信息。
  4. ServiceLoader: ServiceLoader是用来加载和发现服务的java类,并提供了很多有用的方法。

SPI的普通java实现

讲完SPI的定义,大家可能还是不清楚SPI到底是做什么的,又该怎么使用它。

不用急,我们下面通过一个例子来说明。

首先创建一个module:SPI-service,里面主要定义了一个ModuleService接口:

public interface ModuleService {}

然后再分别创建两个module,作为ModuleService的实现:

public class ModuleServiceA implements ModuleService {public ModuleService getModuleService(){return new ModuleServiceA();}
}
public class ModuleServiceB implements ModuleService {public ModuleService getModuleService(){return new ModuleServiceB();}
}

接着分别在两个module中创建META-INF/services文件夹,并且在里面创建两个以 Service Provider Interface限定名为名字的文件,这里文件名是:com.flydean.base.service.ModuleService,文件里面存放的是SPI的具体实现类:

com.flydean.base.servicea.ModuleServiceA
com.flydean.base.serviceb.ModuleServiceB

最后,我们需要创建一个使用SPI的类:

public class ModuleController {public static void main(String[] args) {List<ModuleService> moduleServices = ServiceLoader.load(ModuleService.class).stream().map(ServiceLoader.Provider::get).collect(toList());log.info("{}", moduleServices);}
}

为了更好的展示扩展应用的实际使用,我们分别创建4个模块。在实际应用中,只需要将这些jar包加入应用程序的classpath即可。

运行看下输出结果:

[com.flydean.base.servicea.ModuleServiceA@16f65612,
com.flydean.base.serviceb.ModuleServiceB@311d617d]

从结果看到,我们获得了两个ModuleService。证明系统扩展成功。

SPI在JPMS模块化系统下的实现

上面我们讲的是基本的操作,考虑一下,如果是在JDK9之后,引入了JPMS模块化系统之后,应该怎么使用SPI呢?

代码肯定是一样,我们需要修改的是SPI配置文件。

如果在JPMS中,我们就不需要使用META-INF/services了,我们只需要创建相应的module-info.java文件即可。

先看下SPI模块的module-info.java文件:

module com.flydean.service {exports com.flydean.service;
}

这个模块我们对外暴露了service package,供其他模块调用。

接下来是SPI的实现模块:

module com.flydean.servicea {requires com.flydean.service;provides com.flydean.service.ModuleService with com.flydean.servicea.ModuleServiceA;exports com.flydean.servicea;
}

这里我们使用了provides命令,定义了两个类的关联关系。

最后是调用的模块:

module com.flydean.controller {uses com.flydean.service.ModuleService;requires com.flydean.service;requires lombok;requires slf4j.api;
}

这里我们使用uses关键词来引用ModuleService。

总结

本文介绍了SPI在模块化和非模块化系统中的应用。

本文中的例子:learn-java-base-9-to-20

本文已收录于 http://www.flydean.com/java-spi-for-extensible-app/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

在java中使用SPI创建可扩展的应用程序相关推荐

  1. java数组创建后大小能改变吗,在Java中,数组创建成功以后,其大小(??? )(能/不能)改变...

    在Java中,数组创建成功以后,其大小(??? )(能/不能)改变 答: 不能 新民主主义革命最基本的动力是(). 答:中国无产阶级 病人,男性,36岁.尿蛋白(++++),全身水肿1个月,测血压16 ...

  2. 浅析Java中对象的创建与对象的数据类型转换

    这篇文章主要介绍了Java中对象的创建与对象的数据类型转换,是Java入门学习中的基础知识,需要的朋友可以参考下 Java:对象创建和初始化过程 1.Java中的数据类型     Java中有3个数据 ...

  3. Java 中的目录创建处理

    Java 中的目录创建处理 java中的File类,提供了2个api用于处理目录创建,分别是mkdir和mkdirs. File file = new File(path); boolean resu ...

  4. java 中数组的创建 数组遍历 以及数组的输出(打印)

    什么是数组? 如果我们需要创建一个 int 类型变量,那么我们只需要 int a; 如果我们需要创建五个 int 类型变量,那么我们只需要int a1; int a2; int a3; int a4; ...

  5. Java中线程的创建有两种方式

    Java中继承thread类与实现Runnable接口的区别 Java中线程的创建有两种方式: 1.  通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2.  通过 ...

  6. Dubbo源码分析(三)Dubbo中的SPI和自适应扩展机制

    前言 我们在往期文章中,曾经深入分析过Java的SPI机制,它是一种服务发现机制.具体详见:深入理解JDK的SPI机制 在继续深入Dubbo之前,我们必须先要明白Dubbo中的SPI机制.因为有位大神 ...

  7. (面经总结)一篇文章带你整理面试过程中关于Java 中多线程的创建方式的最全整理

    文章目录 一.Java线程的创建方式 二.继承Thread类 三.实现 Runnable 接口 四.通过ExecutorService和`Callable`实现有返回值的线程 五.基于线程池 六.面试 ...

  8. java 中线程的创建方式

    如果说在java中创建线程的有几种方式的话,归根结底我认为就两种方式 1.继承Thread类,重写run方法 继承Thread类,如下图重写了run()方法 通过start()方法来启动线程 最后的输 ...

  9. java中字符串的创建_【转载】 Java中String类型的两种创建方式

    本文转载自 https://www.cnblogs.com/fguozhu/articles/2661055.html Java中String是一个特殊的包装类数据有两种创建形式: String s ...

最新文章

  1. 局域网共享的解决方法
  2. GNSS用户设备的组成及原理——以GPS用户设备为例
  3. video 微信 标签层级过高_什么是微信小程序二级分销系统?如何玩转?
  4. PHP数组 转 对象/对象 转 数组
  5. 深圳罗湖区:拟重点发展区块链金融技术 推动数字人民币国际合作
  6. Android中文API(142) —— Gravity
  7. 网站选择按钮点击无反应?_Win10系统电脑鼠标左键单击没有反应的解决办法
  8. spark mlib行矩阵(RowMatrix)入门
  9. svg.draw.js draw rectangle 画矩形
  10. 微信信息轰炸【简易版】
  11. Excel创建多个并列柱状图,并加次级坐标轴
  12. 酷炫网页按钮,炫酷变色效果(附源码)
  13. 绝对值函数可导点的判断
  14. 微信小程序正式上线,服务端请求必须HTTPS
  15. sun.misc.BASE64Encoder详解
  16. ubuntu 编译opencv
  17. 爬取大众点评黄焖鸡米饭的数据
  18. 文献阅读(84)PFA-ScanNet
  19. Unity学习 — Unity与LeanCloud数据存储
  20. 微分方程求解 matlab,4MATLAB常微分方程求解.ppt

热门文章

  1. c# websocket 心跳重连_websocket的简单使用
  2. 树的同构(c语言静态链表实现)
  3. 针对某游戏保护DebugPort清零的一次逆向
  4. C++ 学习之函数重载、基于const的重载
  5. 手把手教你玩转SOCKET模型:重叠I/O篇
  6. 恢复SQLSERVER被误删除的数据
  7. 手写带注册中心的rpc框架(Netty版和Socket版)
  8. 今日推荐:如何设计一个支撑数亿用户的系统
  9. 实战:如何对磁盘和网络IO进行评估、监控、定位和优化?
  10. 优化传输文件的性能- -零拷贝