dubbo 扩展机制


dubbo 扩展机制

          

                

                                            

dubbo 扩展原理

         

spi(service provider interface)

使用策略模式,一个接口有多个实现类;

接口使用的实现类不在程序中直接指定,由外部配置

             

java spi加载

一次性加载所有实现类并初始化(有些初始化可能比较耗时,也会造成资源浪费);
java spi加载抛出的异常信息异常可能会被吞掉,导致无法排查出真实出错原因

            

dubbo spi加载:对java spi做了一些改进

加载所有实现类的类名并缓存,但是没有初始化(初始化后,初始化后的实例也会被缓存);
dubbo扩展加载失败会抛出真是异常并打印日志,部分扩展加载失败不会影响其他扩展的加载;
dubbo扩展增加了ioc(通过setter注入其他扩展)、aop(wrapper包装类包含通用逻辑);

            

*************

相关注解

            

@SPI:扩展接口标识

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})   //标注在类、接口、枚举上,一般标注在接口上,表明该接口是个扩展接口
public @interface SPI {

    /**
     * default extension name
     */
    String value() default "";  //默认使用的扩展实现key(扩展文件中实现类对应的key)

    /**
     * scope of SPI, default value is application scope.
     */
    ExtensionScope scope() default ExtensionScope.APPLICATION;
}

           

@Adaptive:从url中提取参数,创建动态扩展类

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD}) //标注在类、接口、枚举、方法上
                                                //如果标注在实现类上(只能标注在一个实现类上,多个会报错),则将该实现类作为默认使用的拓展实现类,不再动态创建自适应类
                                                //如果标注在方法上,则会从url中提取对应参数,创建自适应类
public @interface Adaptive {
    /**
     * Decide which target extension to be injected. The name of the target extension is decided by the parameter passed
     * in the URL, and the parameter names are given by this method.
     * 从url中提取参数,参数的key由value()给出,动态确定要实现的扩展

     * <p>
     * If the specified parameters are not found from {@link URL}, then the default extension will be used for
     * dependency injection (specified in its interface's {@link SPI}).
     * 如果url中没有对应的参数(value()方法给出的参数),就会使用(@SPI("default"))指定的扩展

     * <p>
     * For example, given <code>String[] {"key1", "key2"}</code>:
     * <ol>
     * <li>find parameter 'key1' in URL, use its value as the extension's name</li>
     * <li>try 'key2' for extension's name if 'key1' is not found (or its value is empty) in URL</li>
     * <li>use default extension if 'key2' doesn't exist either</li>
     * <li>otherwise, throw {@link IllegalStateException}</li>
     * </ol>

     * value()不为空的情况
     * value():{"key1","key2"},
     * 先从url中查找key1,如果有key1,提取对用的value作为扩展key
     * 如果没有key1,再查找key2,如果有key2,提取对应的value作为扩展key
     * 如果没找到,就使用默认扩展(@SPI("default"))作为扩展key,
     * 如果@SPI没有指定默认值,则抛出异常

     * If the parameter names are empty, then a default parameter name is generated from interface's
     * class name with the rule: divide classname from capital char into several parts, and separate the parts with
     * dot '.', for example, for {@code org.apache.dubbo.xxx.YyyInvokerWrapper}, the generated name is
     * <code>String[] {"yyy.invoker.wrapper"}</code>.

     * value()为空的情况
     * 根据扩展接口生成默认参数:code org.apache.dubbo.xxx.YyyInvokerWrapper ==> yyy.invoker.wrapper
     * 先根据生成的参数名从url中查找,查找到则提取对应的值
     * 如果没有,使用默认(@SPI("default"))的扩展实现
     * 如果@SPI没有指定默认值,则抛出异常

     * @return parameter names in URL
     */
    String[] value() default {};

}

          

@Aativate:默认激活的扩展实现类

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Activate {
    /**
     * Activate the current extension when one of the groups matches. The group passed into
     * {@link ExtensionLoader#getActivateExtension(URL, String, String)} will be used for matching.
     *
     * @return group names to match
     * @see ExtensionLoader#getActivateExtension(URL, String, String)
     */
    String[] group() default {};  //如果数组中的某个值匹配指定的分组值,
                                  //且同时满足value(如果设置了value),则激活

    /**
     * Activate the current extension when the specified keys appear in the URL's parameters.
     * <p>
     * For example, given <code>@Activate("cache, validation")</code>, the current extension will be return only when
     * there's either <code>cache</code> or <code>validation</code> key appeared in the URL's parameters.
     * </p>
     *
     * @return URL parameter keys
     * @see ExtensionLoader#getActivateExtension(URL, String)
     * @see ExtensionLoader#getActivateExtension(URL, String, String)
     */
    String[] value() default {};    //value不为空时,url中含有value的某个值作为key,且同时满足group,则激活
                                    //value为空时,满足group则激活

    /**
     * Relative ordering info, optional
     * Deprecated since 2.7.0
     *
     * @return extension list which should be put before the current one
     */
    @Deprecated
    String[] before() default {};   //已禁用

    /**
     * Relative ordering info, optional
     * Deprecated since 2.7.0
     *
     * @return extension list which should be put after the current one
     */
    @Deprecated
    String[] after() default {};    //已禁用

    /**
     * Absolute ordering info, optional
     *
     * Ascending order, smaller values will be in the front o the list.
     *
     * @return absolute ordering info
     */
    int order() default 0;     //激活排序(数值越小越靠前,默认为0),
                               //如同时激活多个filter,对filter做先后排序
}

           

过滤器激活

# ActiveLimitFilter:group为consumer、url中含有actives
@Activate(group = CONSUMER, value = ACTIVES_KEY)
public class ActiveLimitFilter implements Filter, Filter.Listener {


# TimeoutFilter:只需要group为provider就可激活
@Activate(group = CommonConstants.PROVIDER)
public class TimeoutFilter implements Filter, Filter.Listener {
  
  

          

*************

拓展加载

   

                       

              

扩展加载说明

每个扩展接口都对应一个extensionLoader缓存对象,没有则创建

# getExtension加载流程
检查name是否为空,为空直接报错;
如果name=true,则创建并返回默认扩展类(@SPI指定的默认扩展类)
根据缓存实现类对应的key从缓存中获取扩展对象,如果没有则创建扩展对象并缓存;
返回创建的扩展实例

# getAdaptiveExtension加载流程
从缓存中获取自适应实现类对象,如果没有则创建自适应类对象;
创建自适应类对象:生成字符串代码,编译器编译成class对象,实例化,初始化、注入扩展依赖;
将创建的自适应对象缓存并返回;

# getActivateExtension加载流程
检查缓存(cachedActivateGroups.size() == 0判断,为0则没有缓存数据),
如果没有缓存数据,则加载所有扩展实现类,将数据缓存(getExtensionClasses());
遍历@Activate集合(cachedActivates),按照匹配规则进行过滤,筛选所有符合条件的激活类;
如果自定义了扩展,可按照自定义的顺序将其添加
如:ext1,default,ext2,顺序为自定义扩展ext1、默认提供的扩展实现类、自定义扩展ext2;
如果自定义的顺序中没有default(ext1,ext2),所有激活类使用activateComparator进行排序;
最后将所有激活类返回

                

ExtensionLoader:扩展加载类,每个扩展接口都会对应一个ExtensionLoader对象

/**
 * {@link org.apache.dubbo.rpc.model.ApplicationModel}, {@code DubboBootstrap} and this class are
 * at present designed to be singleton or static (by itself totally static or uses some static fields).
 * So the instances returned from them are of process or classloader scope. If you want to support
 * multiple dubbo servers in a single process, you may need to refactor these three classes.
 * <p>
 * Load dubbo extensions
 * <ul>
 * <li>auto inject dependency extension </li>  //如果一个扩展实例A依赖扩展实例B,会自动将B注入A
 * <li>au
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值