7 Star 19 Fork 8

一灰灰Blog / SilverSpi

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

SPI框架

本项目工程主要是实现了一个spi的使用框架,借此可以方便的利用spi的思想,实现一些业务场景的区分

设计思路

下图围绕 SpiLoader 为中心,描述了三个主要的流程:

  1. load所有的spi实现
  2. 初始化选择器 selector
  3. 获取spi实现类 (or一个实现类代理)

https://static.oschina.net/uploads/img/201705/26185143_ULnL.png

流程说明

下面就整个实现的流程顺一遍,主要从使用者的角度出发,当定义了一个SPI接口后,到获取spi实现的过程中,上面的这些步骤是怎样串在一起的

流程图

先拿简单的静态获取SPI实现流程说明,先看下这种用法的使用姿势

@Spi
public interface IPrint {
    void print(String str);
}

public class FilePrint implements IPrint {
    @Override
    public void print(String str) {
        System.out.println("file print: " + str);
    }
}

public class ConsolePrint implements IPrint {

    @Override
    public void print(String str) {
        System.out.println("console print: " + str);
    }
}

@Test
public void testPrint() throws NoSpiMatchException {
   SpiLoader<IPrint> spiLoader = SpiLoader.load(IPrint.class);
   IPrint print = spiLoader.getService("ConsolePrint");
   print.print("console---->");
}

SpiLoader<IPrint> spiLoader = SpiLoader.load(IPrint.class);

这行代码触发的action 主要是初始化所有的选择器, 如下图

  • 首先从缓存中查
  • 是否已经初始化过了有则直接返回;
  • 缓存中没有,则进入new一个新的对象出来
    • 解析类上注解 @Spi,初始化 currentSelector
    • 解析所有方法的注解 @SpiAdaptive , 初始化 currentMethodSelector
  • 塞入缓存,并返回

https://static.oschina.net/uploads/img/201705/27140821_19ee.png

IPrint print = spiLoader.getService("ConsolePrint");

根据name获取实现类,具体流程如下

  • 判断是否加载过所有实现类 spiImplClassCacheMap
  • 没有加载,则重新加载所有的实现类
    • 通过jdk的 ServiceLoader.load() 方法获取所有的实现类
    • 遍历实现类,根据 @SpiConf 注解初始化参数,封装 SpiImplWrapper 对象
    • 保存封装的 SpiImplWrapper对象到缓存
  • 执行 currentSelector.select() 方法,获取匹配的实现类

https://static.oschina.net/uploads/img/201705/27150620_EOUL.png

动态编译

项目中实现的动态编译,主要借助的是GroovyEngine来实现,将我们根据SPI接口动态生成的实现代理类当做一个groovy脚本,其核心代码如下

@SuppressWarnings("unchecked")
public static <T> T compile(String code, Class<T> interfaceType, ClassLoader classLoader) throws SpiProxyCompileException {
   GroovyClassLoader loader = new GroovyClassLoader(classLoader);
   Class clz = loader.parseClass(code);

   if (!interfaceType.isAssignableFrom(clz)) {
       throw new IllegalStateException("illegal proxy type!");
   }


   try {
       return (T) clz.newInstance();
   } catch (Exception e) {
       throw new SpiProxyCompileException("init spiProxy error! msg: " + e.getMessage());
   }
}

相关文档

博客系列链接:

空文件

简介

A Java Service Provider Interface (SPI) Framework 展开 收起
Java
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/liuyueyi/SilverSpi.git
git@gitee.com:liuyueyi/SilverSpi.git
liuyueyi
SilverSpi
SilverSpi
master

搜索帮助