Dubbo源码分析–基于SPI的可扩展框架
dubbo是阿里巴巴开源出来的一套分布式服务框架,该框架可以比较方便的实现分布式服务的开发,调用等,该框架的教程地址为
http://dubbo.io/Home-zh.htm
代码已经托管到github上。
正好项目里使用了一套网关的框架来做分布式服务开发,该网关的框架是在dubbo的基础上改造而来的,改dubbo默认的基于netty的分布式服务调用为将请求写入到redis队列中,而在处理方则订阅对应的队列,处理完成后,再将结果写回到redis中,从而返回给客户端,由于使用了redis来作为队列,因此可以起到一定的缓冲的作用,起到一定程度上的削峰填谷。
由于该框架是在dubbo的基础上开发的,利用闲暇的时间下载了dubbo的源码大致的翻了一遍,结合dubbo的用户手册,看了一遍看得不明所以;正好最近处于项目的间隙期,因此仔细的研读了一遍代码,感觉收获颇多。。下面简单的记录下自己关于SPI方面的理解。
dubbo的SPI机制是在标准的jdk的SPI的机制上扩展加强而来的
SPI的实现在dubbo中由以下几个annotation来实现。
1. SPI 注解,,使用SPI注解来标识一个扩展点,该注解一般是打在接口上的,DUBBO的扩展点都是基于接口的。
2. Adaptive注解 该注解主要作用在方法上,使用该注解可以根据方法的参数值来调用的具体的实现类的对应方法
3. Activate 注解,该注解一般作用在实现类上,使用该注解一般是对于Filter类型的类,来决定是该类是否加入到Filter的执行器责任链中
SPI机制实现的核心类
ExtensionLoader, 该类是SPI机制实现的核心类,该类提供了以下静态方法getExtensionLoader(Class type),该方法返回了加载此class的ExtensionLoader, 通过该ExtensionLoader来创建对应的type的类的实例,
该类还提供了以下方法来获取对应的加载类的实例
1. getAdaptiveExtension(String name)
通过该方法来获取该type的具有adaptive过的扩展实现,也即是调用返回的实例的方法的时候,如果方法上有Adaptive注解,则会在方法调用的时候才会根据方法的参数调用到对应的实例,
该方法一般用在一些高层次的代理实现中,如ReferenceConfig中包含有如下定义
private static final Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
Protocol有很多个实现类,但是ReferenceConfig作为服务提供方的一个接口实例,此时并不知道该调用哪个实现类,当生成一个refprotocol来代表所有的实现类,当调用到该类中的export方法的时候,再根据方法的参数来决定调用到哪个具体的实现类中,相当于一种高级别的代理。
这种模式是如何实现的呢,
查看getAdaptiveExtend的实现类发现最终调用到
createAdaptiveExtensionClassCode方法来创建该接口的具体的Class的实例,通过该Class实例来创建对应的类实例。而createAdaptiveExtensionClassCode的方法可以看到,在方法中使用java代码拼出了一个类, 在该方法主要是根据传入的接口,生成一个该接口的实现类, 而在实现类中主要根据接口中的方法中是否有Adaptive注解,如果有该注解则对生成一个该方法的代理方法,如果没有Adaptive注解,这实现的方法中抛出异常,如果有Adaptive注解则生成对应的代理后的方法,,如Protocol接口的代理类为如下
package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException(
"method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException(
"method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public com.alibaba.dubbo.rpc