概述
JDK SPI
SPI全称Service Provider Interface,是提供厂商做插件开发的,如数据库驱动。
Java SPI使用了策略模式,一个接口多种实现。同时具体实现不在程序中指定,而是在程序之外的配置文件配置。
具体实现过程:
1. 新建一个名称为driver的maven工程,定义一个DatabaseDriver接口及对应的方法,打成jar包,供后续实现依赖
public interface DatabaseDriver {
String buildConection(String msg);
}
2. 新建一个名称为mysql-driver的maven工程,在pom中引入driver工程的依赖,然后创建DatabaseDriver的实现类
public class MysqlDriver implements DatabaseDriver {
@Override
public String buildConection(String msg) {
return "MySQL Driver:" + msg;
}
}
3. 在mysql-driver工程main文件夹下创建资源文件夹resources,然后再创建目录META-INF/services,在该目录下创建以要实现接口全路径命名的文件:如com.xxx.spi.DatabaseDriver,文件内容为接口的实现的全路径名:com.xxx.spi.MysqlDriver
4. 新建一个名称为java-spi-test的工程,在pom中加入前面两个项目的依赖,可通过以下方式调用具体实现:
public static void main( String[] args ) {
ServiceLoader<DatabaseDriver> serviceLoader = ServiceLoader.load(DatabaseDriver.class);
for (DatabaseDriver databaseDriver : serviceLoader) {
System.out.println(databaseDriver.buildConection("hello"));
}
}
最后输出:MySQL Driver:hello
由此可以看出main方法中通过java.util.ServiceLoader可以获得接口的所有实现,具体使用哪种实现由用户决定。
Dubbo SPI
Dubbo 的扩展点机制是在 JDK SPI 机制上做了改进,引用官网的一段话:
Dubbo 改进了 JDK 标准的 SPI 的以下问题:
- JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
- 如果扩展点加载失败,连扩展点的名称都拿不到了。比如:JDK 标准的 ScriptEngine,通过 getName() 获取脚本类型的名称,但如果 RubyScriptEngine 因为所依赖的 jruby.jar 不存在,导致 RubyScriptEngine 类加载失败,这个失败原因被吃掉了,和 ruby 对应不起来,当用户执行 ruby 脚本时,会报不支持 ruby,而不是真正失败的原因。
- 增加了对扩展点 IoC 和 AOP 的支持,一个扩展点可以直接 setter 注入其它扩展点。
约定:
在扩展类的 jar 包内,在资源路径META-INF/dubbo(或META-INF/services、META-INF/dubbo/internal)下放置扩展点配置文件,文件名称为接口全限定名且无后缀,文件内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔。
如果要定义dubbo SPI接口,需要在接口上添加@SPI注解,value为默认实现。
@SPI("dubbo")
public interface Protocol {
int getDefaultPort();
@Adaptive
<T> Exporter<T> export(Invoker<T> var1) throws RpcException;
@Adaptive
<T> Invoker<T> refer(Class<T> var1, URL var2) throws RpcException;
void destroy();
}
以实现org.apache.dubbo.rpc.Protocol接口为例:
1. 首先定义实现类com.xxx.dubbo.spi.impl.MyProtocolImpl
public class MyProtocolImpl implements Protocol {
@Override
public int getDefaultPort() {
return 8888;
}
@Override
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
return null;
}
@Override
public <T> Invoker<T> refer(Class<T> aClass, URL url) throws RpcException {
return null;
}
@Override
public void destroy() {
}
}
2. 然后在resources/META-INF/dubbo(或META-INF/services、META-INF/dubbo/internal)目录下创建名称为org.apache.dubbo.rpc.Protocol的配置文件(接口的全限定名)
配置文件内容为:myprotocol=com.xxx.dubbo.spi.impl.MyProtocolImpl(key=value方式)
3. 最后可以通过以下方式调用dubbo的SPI实现类:
public static void main(String[] args) {
Protocol myprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("myprotocol");
// 输出实现类中的端口号8888
System.out.println(myprotocol.getDefaultPort());
}
最后
以上就是帅气玫瑰为你收集整理的JDK SPI与Dubbo SPI的实现的全部内容,希望文章能够帮你解决JDK SPI与Dubbo SPI的实现所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复