首页 > 图灵资讯 > 技术篇>正文

Java SPI机制总结系列之开发入门实例

2023-11-13 15:42:50

原创/朱季谦<br>在文章正式开始之前,先对 Java 简单介绍一下SPI是什么。<br>

SPI,是Service Provider Interface的缩写,即服务提供者接口,字面上是抽象的。您可以理解,该机制就像Spring容器一样,通过IOC将对象的创建交给Spring容器。如果需要获得某个类别的对象,可以从Spring容器中取出使用。同样,在SPI机制中,它提供了一个类似于Spring容器的角色,称为[服务提供商]。在代码运行过程中,如果您想使用服务实现对象来实现一个接口,您只需将相应的接口类型交给服务提供商即可。服务提供商将动态加载并实现接口的所有服务实现对象。<br>如下图所示,服务提供商的角色。image

举个例子来说明。

假设,假设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文件一致——image

该com.zhu.service.commerservice文件.zhu.service.impl.Userserviceimple名称——image

此时可以基于Java SPI动态加载到接口实现类并执行。我们写了一个简单的测试类来验证它——

public class Test {    public static void main(String[] args) {    ServiceLoader<UserService> serviceLoader = ServiceLoader.load(UserService.class);    Iterator<UserService> serviceIterator = serviceLoader.iterator();    while (serviceIterator.hasNext()) {         UserService service = serviceIterator.next();         service.getName();    }}    }}

Serviceloader将执行该代码加载到META-INF.services目录下的配置文件,找到相应接口的全名文件,读取文件中的类名,然后通过反射实现类实例化。既然能找到实现类的对象,那么就不能基于父类引用指向子类的对象,然后调用实现类的getname()方法。该方法执行打印语句 System.out.println("打印用户姓名"),打印结果如下:在程序动态加载和执行UserService接口时,基于接口UserService的打印结果如下。image

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实现类的全名添加到文件中——image

其他原始代码不需要更改,直接执行testmain方法,打印结果如下,可以看到新的buserserviceimpl实现类getname()也运行。image

这就说明,Java SPI机制将动态加载和运行文件中配置的所有实现类。经过一点思考,不难发现,如果一个实现类的getname()出现异常,未执行的其他实现类将终止。<br>因此,在设计SPI机制时,Dubo框架只参考Java SPI的实现,但没有复制。与Java相比,Dubbo增强了SPI机制,可以根据需求动态选择所需的接口实现类,更加灵活方便。我在另一边的原创博客文章中详细介绍了Dubo 有兴趣的朋友可以阅读SPI的原理-Dubo2.7.Dubbo SPI实现原理细节<br>SPI机制的优点是显而易见的。当我们需要基于现有接口添加一个实现代码时,我们只需要添加一个实现代码,而不需要改变原始代码的逻辑,新类的功能逻辑可以实现。<br>这种场景更适合在报告或处理Excel文档时定制新报告或Excel,只需根据SPI现有接口添加一个实现类。<br>这种场景更适合在报告或处理Excel文档时定制新报告或Excel,只需根据SPI现有接口添加一个实现类。在后续文章中,我将总结过去应用于SPI的实践经验。

上一篇 Dubbo2.7的Dubbo SPI实现原理细节
下一篇 springboot集成EasyPoi,实现Excel/Word的导入导出

文章素材均来源于网络,如有侵权,请联系管理员删除。