• Dubbo源码学习(二)


    @Adaptive注解

    在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类。

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    public @interface Adaptive {
        String[] value() default {};
    }
    

    @Adaptive注解可以加载实现类的类上或方法上。下面可以通过源码去分析,先放结论:

    • 注解在实现类上时,提供一种标识表名此实现类并不提供具体的业务实现,而是一个该接口的适配器。例如AdaptiveCompiler、AdaptiveExtensionFactory。
    • 注解在接口方法上时,根据某种规则动态生成代码,动态适配。例如Protocol接口

    主要方法

    T getAdaptiveExtension()

    调用流程

    T getAdaptiveExtension()         //在cachedAdaptiveInstance缓存中获取,获取不到则进入下一步创建
        -> T createAdaptiveExtension()      
            -> getAdaptiveExtensionClass()      //加载完配置文件后,会在cachedAdaptiveClass缓存中获取,获取不到则创建
                -> getExtensionClasses()          //如果第一次,则加载配置文件
                -> createAdaptiveExtensionClass()   
                    -> createAdaptiveExtensionClassCode()   //动态生成代码
                    -> Compiler.compile(String code, ClassLoader classLoader)   //编译动态生成的代码
            -> injectExtension(T instance)          //注入
    

    cachedAdaptiveClass缓存是@Adaptive注解在类上的缓存,所以上述代码的大致就是:

    • 如果@Adaptive注解在类上,则直接返回这个类的实例
    • 如果@Adaptive注解在方法上,则动态生成一个类。

    createAdaptiveExtensionClassCode()

    动态生成的代码比较长,但是主要的逻辑就是通过Adaptive注解的value属性去设置该接口的Adaptive的规则, Dubbo中的服务调用的所有数据均可以从URL获取(Dubbo的URL总线模式),那么需要Dubbo帮我们动态生成adaptive的扩展接口的方法入参必须包含URL,这样才能根据运行状态动态选择具体实现。 一个简单的生成类如下代码:

    @Adaptive({"key1", "key2"})
    String yell(URL url, String s);
    
    public String yell(URL arg0, String arg1) {
        if (arg0 == null) {
            throw new IllegalArgumentException("url == null");
        }
        URL url = arg0;
        String extName = url.getParameter("key1", url.getParameter("key2", "impl1"));
        if(extName == null) {
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.common.extensionloader.ext1.SimpleExt) name from url(" + url.toString() + ") use keys([key1, key2])");
        }
        SimpleExt extension = (SimpleExt)ExtensionLoader.getExtensionLoader(SimpleExt.class).getExtension(extName);
        return extension.yell(arg0, arg1);
    }
    

    @Ac 大专栏  Dubbo源码学习(二)tivate注解

    可以看到ExtesionLoader中还有一些与@Active注解相关的方法。

    • List getActivateExtension(URL url, String key)
    • List getActivateExtension(URL url, String key, String group)
    • List getActivateExtension(URL url, String[] values, String group)

    可以看出,这些方法都是根据url的某些条件获取一个实现类的列表。@Activate注解主要用处是标注在插件接口实现类上,用来配置该扩展实现类激活条件。 在Dubbo框架里面的Filter的各种实现类都通过Activate标注,用来描述该Filter什么时候生效。下面是一些例子:

    • MonitorFilter( @Activate(group = {Constants.PROVIDER, Constants.CONSUMER}) ) 用来告诉Dubbo框架这个Filter是在服务提供端和消费端会生效的;
    • TimeoutFilter( @Activate(group = Constants.PROVIDER) )则是只在服务提供端生效,消费端是不会调用该Filter;
    • ValidationFilte( @Activate(group = { Constants.CONSUMER, Constants.PROVIDER }, value = Constants.VALIDATION_KEY, order = 10000) ) 要激活的条件除了在消费端和服务提供端激活,value 表明了URL参数中必须包含validation才会被激活。order 即激活顺序。

    getActivateExtension的实现

    代码很简单,就做了下简单的注释。

    public List<T> getActivateExtension(URL url, String[] values, String group) {
        List<T> exts = new ArrayList<T>();
        List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
        if (! names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {  //"-default"
            getExtensionClasses();      //未加载配置文件的加载一遍
            for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
                String name = entry.getKey();
                Activate activate = entry.getValue();
                if (isMatchGroup(group, activate.group())) {    //如果符合指定的group
                    T ext = getExtension(name);
                    if (! names.contains(name)
                            && ! names.contains(Constants.REMOVE_VALUE_PREFIX + name) 
                            && isActive(activate, url)) {
                        exts.add(ext);
                    }
                }
            }
            Collections.sort(exts, ActivateComparator.COMPARATOR);      //排序
        }
        List<T> usrs = new ArrayList<T>();
        for (int i = 0; i < names.size(); i ++) {
        	String name = names.get(i);
            if (! name.startsWith(Constants.REMOVE_VALUE_PREFIX)
            		&& ! names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
            	if (Constants.DEFAULT_KEY.equals(name)) {
            		if (usrs.size() > 0) {
             		exts.addAll(0, usrs);
             		usrs.clear();
            		}
            	} else {
             	    T ext = getExtension(name);
             	    usrs.add(ext);
            	}
            }
        }
        if (usrs.size() > 0) {
        	exts.addAll(usrs);
        }
        return exts;
    }
    

  • 相关阅读:
    整数划分递归模板
    最近点对算法模板
    计算几何模板
    poj1269---直线位置关系
    poj1017----模拟
    MVC 提交List 集合 注意对应的参数名称
    使用 WebClient 來存取 GET,POST,PUT,DELETE,PATCH 網路資源
    对路径访问拒绝,要加上具体filename/c.png
    sql 列集合
    百度地图 Infowidow 内容(content 下标签) 点击事件
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12239807.html
Copyright © 2020-2023  润新知