首页 > 编程语言 >Java SPI机制学习之开发实例

Java SPI机制学习之开发实例

时间:2023-11-11 19:22:39浏览次数:43  
标签:Java service 实现 接口 SPI 实例 UserService

原创/朱季谦

在该文章正式开始前,先对 Java SPI是什么做一个简单的介绍。

SPI,是Service Provider Interface的缩写,即服务提供者接口,它允许开发人员定义一组接口,并由供应方或者第三方提供具体实现。这种机制能够让应用程序动态加载及执行各种接口实现。

根据名字来理解,比较抽象,举一个例子来说明。

假如,假如Maven项目里有这样一个interface接口,接口全名“com.zhu.service.UserService”——

package com.zhu.service;

public interface UserService {
    void getName();
}

创建一个“com.zhu.service.impl.AUserServiceImpl”实现类——

public class AUserServiceImpl implements UserService {
    @Override
    public void getName() {
        System.out.println("这是A用户姓名");
    }
}

接着在resource资源里,创建一个META-INF.services目录,在该目录里,创建一个文件名与接口com.zhu.service.UserService一致的文件——

该com.zhu.service.UserService文件里写下com.zhu.service.impl.UserServiceImpl类名字——

这时候,就可以基于Java SPI动态加载到接口的实现类并执行了,我们写一个简单的测试类做验证——

public class Test {
    public static void main(String[] args) {
        ServiceLoader<UserService> serviceLoader = ServiceLoader.load(UserService.class);
        for (UserService service : serviceLoader) {
            service.getName();
        }
    }
}

执行该代码,ServiceLoader会加载到META-INF.services目录下的配置文件,找到对应接口全名文件,读取文件里的类名,再通过反射就可以进行实现类的实例化。既然能找到实现类的对象,那么不就可以基于父类引用指向子类对象,进而调用到实现类的getName()方法。该方法里执行打印语句 System.out.println("打印用户姓名"),打印结果如下,说明基于接口UserService,在程序动态加载并执行UserService接口实现。

Java SPI的机制玩法,就如上文这一整个过程的实现。

该机制存在一个缺陷,假如该接口对应的文件存在多份实现类,那么,它都会一起执行了。

我们增加多一个实现类BUserServiceImpl——

public class BUserServiceImpl implements UserService {
    @Override
    public void getName() {
        System.out.println("这是B用户姓名");
    }
}

然后,在resource资源里的META-INF.services目录接口对应com.zhu.service.UserService文件里,将BUserServiceImpl实现类的全名增加到文件里——

其他原有的代码无需改动,直接执行Test的main方法,打印结果如下,可以看到,新增的BUserServiceImpl实现类的getName()也被运行了。

这就说明,Java SPI机制会将文件里配置的所有实现类都动态加载运行,稍微思考了一下,不难发现,若当中某个实现类的getName()出现异常,那么后面还没有执行到的其他实现类就会终止了。

因此,Dubbo框架在设计SPI机制时,只是参考了Java SPI的实现,但没有照搬,相比Java,Dubbo增强了SPI机制,可以针对请求动态得选择需要的接口实现类来运行,更加灵活方便。我在自己的另一边原创博文中,详细介绍过Dubbo SPI的原理,感兴趣的小伙伴可以阅读——Dubbo2.7的Dubbo SPI实现原理细节》

SPI机制的优点很明显,当我们需要基于已有接口新增一个实现类功能时,只需要新增一个实现类代码,无需在原有代码逻辑上做改动,就可以实现新增类的功能逻辑了。

这种场景比较适合在报表或者处理Excel文档情况下,需针对一个新报表或者Excel做相应定制化处理,只需要基于SPI已有接口新增一个实现类即可。我会在后续文章中,将过去应用到SPI的实践经验做一下总结。

标签:Java,service,实现,接口,SPI,实例,UserService
From: https://www.cnblogs.com/zhujiqian/p/17826211.html

相关文章

  • 来世再不选Java!
    危机感距离上一次找工作面试已经过去快2年了,那时候正值疫情肆虐,虽然还未感受到“寒潮来临”的苗头,但最终还是成功通过了几轮面试,顺利签约。在目前公司待了2年了,在大环境的影响下,没有加薪、没有年终(这个真的很伤)、各种项目混乱、技术快停滞不前,年末又要过一年了,又离35进一步了,终危......
  • 在构造函数里面,如果不写return的话默认就是返回创建的实例对象
    如果以下程序的输出结果是false,则①式可以替换为()consttest={rules:false};functionBuild(){this.rules=true;①}constbuild=newBuild();console.log(build.rules);Areturnfalse;Breturnthis.rules;Creturntest;D什么都不做正确答......
  • 来世再不选Java!
    危机感距离上一次找工作面试已经过去快2年了,那时候正值疫情肆虐,虽然还未感受到“寒潮来临”的苗头,但最终还是成功通过了几轮面试,顺利签约。在目前公司待了2年了,在大环境的影响下,没有加薪、没有年终(这个真的很伤)、各种项目混乱、技术快停滞不前,年末又要过一年了,又离35进一步了,终危......
  • java 转 嵌入式 java转嵌入式软件
    java转嵌入式java转嵌入式软件 转载mob64ca14040d222023-10-0718:39:21文章标签java转嵌入式嵌入式移植ARM移植JREjava文章分类Java后端开发阅读数79 前言因公司项目需求,需要在zynq7000平台下运行javaweb程序,所以需要移植java环境。走过的坑:最先的想法......
  • 一个很漂亮的鼠标移动特效,Javascript 脚本,可惜复制到博客园配置适配效果不好
    一个很漂亮的鼠标移动特效,Javascript脚本,可惜复制到博客园配置适配效果不好,暂时记录一下<!DOCTYPEhtml><html><head><metacharset="utf-8"><title>小白教程(json.cn)</title></head><body><script>varStats=function(){var......
  • java开发历史-Java是一种面向对象的编程语言
    Java是一种面向对象的编程语言,由SunMicrosystems于1995年推出。它具有跨平台、安全强大、可移植性强等特点,被广泛应用于企业级Web应用开发、移动应用开发、大数据处理、人工智能等领域。作为一种高级编程语言,Java可以用于开发各种类型的应用程序,包括桌面应用程序、Web应用程序、......
  • JavaScript的BOM和DOM对象操作与设置顶级窗口------前端
    准备一个用来嵌入的HTML页面<!DOCTYPEhtml><!--这是HTML的注释--><htmllang="en"id="myHtml"> <head> <!--这里不是设置了编码,而是告诉浏览器,用什么编码方式打开文件避免乱码--> <metacharset="UTF-8"> <metaname="viewport&q......
  • IDEA 导入jpbc库报错 java: 程序包it.unisa.dia.gas.jpbc不存在
    直接拷贝jars文件夹和lib文件夹至java项目中后报错运行后报错内容如下:解决方法:在项目最外层的.iml文件中合适的位置添加下述内容:<orderEntrytype="module-library"exported=""><library><CLASSES><rooturl="file://$MODULE_DIR$/lib&qu......
  • JavaScript--事件监听
     事件绑定 dom属性绑定  <inputtype="button"id="btn"value="点我">  <script>    //document.getElementById('myImgine').src='images/open.jpg';    document.getElementById("btn&......
  • JavaSEday05 泛型,数据结构,List,Set集合
    javSEday05泛型,数据结构,List,Set今日目标泛型使用数据结构ListSet1泛型1.1泛型的介绍泛型是一种类型参数,专门用来保存类型用的最早接触泛型是在ArrayList,这个E就是所谓的泛型了。使用ArrayList时,只要给E指定某一个类型,里面所有用到泛型的地方都会被......