简介
什么是可扩大的应用程序呢?可扩大的意思是不须要批改原始代码,就能够扩大应用程序的性能。咱们将应用程序做成插件或者模块。
这样能够在不批改原利用的根底上,对系统性能进行降级或者定制化。
本文将会向大家介绍如何通过java中的SPI机制实现这种可扩大的应用程序。
SPI简介
SPI的全称是Java Service Provider Interface。是java提供的一种服务发现的机制。
通过遵循相应的规定编写应用程序之后,就能够应用ServiceLoader来加载相应的服务了。
SPI的实现次要分为4个局部:
- Service Provider Interface: SPI是一个interface或者是抽象类,其中定义了咱们须要扩大实现的性能。
- Service Providers:这是SPI的具体实现,提供了具体的实现性能
- SPI Configuration File:SPI的配置文件,通过在配置文件咱们来配置相干的SPI发现信息。
- 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/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!
发表回复