dubbo SPI机制

来源:互联网 发布:2017网络流行语翻译 编辑:程序博客网 时间:2024/06/05 14:08

参考:http://www.cnblogs.com/heart-king/p/5632524.html

SPI是什么

SPI是为某个接口寻找服务实现的机制。为实现在模块装配的时候不在程序里动态指明,这就需要一种服务发现机制。


原理

java spi和所有实现接口的厂商有一个俗称的约定,只要将META-INF/services文件夹下生成一个和抽象类全名称相同的配置文件,那么厂商的jar包只要在工程路径下就能找到实现类。

JDK的spi机制有一个缺点,就是如果多个厂商的spi实现的jar包都在路径下,那么就要加载所有的实现类,这样很浪费资源。dubbo的目标就是:根据你配置的name获取某一个特定的接口实现,没有用到的其他接口实现就不能被实例化。因此,dubbo就按照SPI机制的原理自己实现了一套扩展机制。dubbo的SPI做到了一下三个方面:

1.可以方便的获取某一个想要的扩展实现。

2.对于扩展实现IOC,依赖注入功能。

3.对扩展采用装饰器模式进行功能增强,类似AOP实现的功能。


dubbo的SPI实现

1.首先定义一个SPI注解类

@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE})public @interface SPI {/**     * 缺省扩展点名。     */String value() default "";}


dubbo里面很多的接口都打了SPI注解,这些注解的实现要从以下三个文件夹下去寻找实现。

META-INF/dubbo/internal/  //dubbo内部实现的各种扩展都放在这个目录了

META-INF/dubbo

META-INF/services/


我们以Protocol接口为例,接口上打上SPI注解,默认扩展点名为dubbo

@SPI("dubbo")public interface Protocol{}

ExtensionLoader

1,ExtensionLoader.getExtensionLoader(Protocol.class)

每个定义的spi的接口都会构建一个ExtensionLoader实例,存储在ConcurrentMap<Class<?>,ExtensionLoader<?>> EXTENSION_LOADERS这个map对象中。

2.LoadExtensionClasses读取扩展点中的实现类

a)先读取SPI注解的value值,有值作为默认扩展实现的key。

b)依次读取路径的文件

META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol

META-INF/dubbo/com.alibaba.dubbo.rpc.Protocol

META-INF/services/com.alibaba.dubbo.rpc.Protocol

3.loadFile逐行读取com.alibaba.dubbo.rpc.Protocol文件中的内容,每行内容以key/value形式存储的。

a)判断类实现上有没有打上@Adaptive实现,如果打上了注解,将此类作为protocol协议的适配器缓存起来,读取下一行。

b)如果类实现没有打上@Adaptive,判断实现类是否存在入参接口的构造器,有的话作为包装类缓存到此ExtensionLoader的Set<Class<?>>集合中,这个其实是个装饰模式。

c)如果即不是适配对象也不是wrapped的对象,那就是扩展点的具体实现对象。查找实现类上有没有打上@Activate注解,有缓存到变量cacheActivates的map中。

4.获取或者创建适配对象getAdaptiveExtension

a)如果cachedAdaptiveClass有值,说明有且仅有一个实现类打了@Adaptive,实例化这个对象返回。

b)如果cachedAdaptiveClass为空,创建适配器字节码。

Dubbo采用统一数据模型com.alibaba.dubbo.common.URL(它是dubbo定义的数据模型不是jdk的类),URL中定义的协议字段protocol,会根据具体业务设置不同的协议。

适配器的作用是根据url.getProtocol()的值extName,去ExtensionLoader.getExtension(extName)选取具体的扩展点实现。

所以能够利用javasist生成适配器的条件:

(1)接口方法中必须至少有一个方法打上了@Adaptive注解。

(2)打上了@Adaptive注解的方法参数必须有URL类型参数或者参数中存在getURL方法。


5.通过createAdaptiveExtensionClassCode生成java源码代码,要被java虚拟机加载执行必须编译成字节码,dubbo提供两种方式执行代码的编译jdk和javassit


6.自动wrap上扩展wrap类


7.IOC

dubbo的ExtensionLoader在加载扩展实现的时候内部实现了简单的ioc机制来实现对扩展实现所依赖的参数注入,

0 0
原创粉丝点击