Dubbo自定义标签和扩展点

2018-05-21  本文已影响0人  是我_7b3f

       Alibaba   Dubbo是开源的分布式服务治理框架,提供了服务注册,服务发现,动态配置和路由的功能。

Spring自定义标签

通过自定义标签,跟Spring无缝结合,自定义标签需要两个部分:在项目的resource/META-INF包里面配置2个文件spring.handlers和spring.schemas

spring.handlers 的内容:

http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

定义了解析标签的类com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

spring.schemas的内容:

http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd

用一个url来映射我们配置好的文件

dubbo.xsd的内容:

DubboNamespaceHandler继承了Spring的NamespaceHandlerSupport接口 init方法注册了各个标签的解析器 ,根据解析生成对应的BeanDefinition,这样就可以在Spring中使用自定义的标签

扩展点

JDK的ServiceLoader

JDK提供给我们一套扩展点机制,通过ServiceLoader遍历所有jar查找META-INF/services目录下实现某个接口的实现类,现在以Spark中的一个例子说明

       这里就用ServiceLoader加载所有的DataSourceRegister然后判断每个对象的shortName()是否给定的值,这样我们可以实现自己的数据源。

Dubbo的ExtensionLoader

我们一般用ExtensionLoader.getExtensionLoader(***.class)开始获取扩展点。

type 必须不为空且为接口还得有SPI注解,先从缓存中有该接口对应的ExtensionLoader,如果没有的话new一个 ,然后放进缓存中。返回这个ExtensionLoader。

看一下实例化的过程:

会用到ExtensionFactory接口的Adaptive实现 看一下getAdaptiveExtension方法

先判断是否已经存在,然后加锁再判断,如果依旧不存在,调用createAdaptiveExtension方法生成一个并缓存。

cachedClasses定义:

如果还没有设置则调用loadExtensionClasses方法加载

先判断SPI注释中参数不能大于1,赋值给成员变量cachedDefaultName,作为缺省的实现

loadFile方法中三个常数如下:

看一下loadFile:

先读取文件中的内容

根据配置反射得出clazz

clazz必须是type的实现类,如果有Adaptive注解则判断cachedAdaptiveCalss是否为空,如果为空,赋值给cachedAdaptiveCalss,否则系统中会有两个cachedAdaptiveCalss,抛出异常提示。

这里根据type接口作为参数找到一个包装类,如果有则加入wrapper这个Set中,这里的ConcurrentHashSet是Dubbo自己根据JDK的ConcurrentHashMap实现的

如果不是包装类

这里主要是给cachedActivities加入有Activite注解的类,并且映射class和name以及name和class。

返回前面getAdaptiveExtensionClass方法,如果我们前面缓存了cachedAdaptiveClass就直接返回cachedAdaptiveClass。调用injectExtension方法进行注入:

通过反射给set调用set方法赋值。

如果没有cachedAdaptiveClass则通过字节码生成器生成

需要至少有一个方法有Adaptive注解

实现的思想是根据方法的参数URL,Invocation等不同加载对同的扩展点

比如:Protocol生成以下:

class Protocol$Adpative implements Protocol{  

    public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException{  

if (arg0 == null)  {   

throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invokerargument == null");   

        }  

        if (arg0.getUrl() == null) {   

            throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");   

        }  

com.alibaba.dubbo.common.URLurl = arg0.getUrl();  

StringextName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );  

if(extName == null) {  

            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");   

        }  

com.alibaba.dubbo.rpc.Protocolextension = (com.alibaba.dubbo.rpc.Protocol)com.alibaba.dubbo.common.ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);  

        return extension.export(arg0);  

    }  

    public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0,com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException{  

if (arg1 == null)  {   

throw new IllegalArgumentException("url == null");   

        }  

com.alibaba.dubbo.common.URLurl = arg1;  

StringextName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );  

if(extName == null) {  

            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");   

        }  

com.alibaba.dubbo.rpc.Protocolextension = (com.alibaba.dubbo.rpc.Protocol)com.alibaba.dubbo.common.ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);  

        return extension.refer(arg0, arg1);  

    }

看一下getExtension

如果缓存有则返回,没有则调用createExtension生成一个在缓存

先对该name的扩展点实例化,然后判断时候有Wrapper的包装类,如果有,则一层层包装,最后返回一个包装类,而不是name的扩展点实例,这里我们可以实现自己的逻辑。

上一篇 下一篇

猜你喜欢

热点阅读