下面就为大家详细讲解“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技术站