Dubbo源码 之 Activate源码分析

目录

                  一、简介:

二、用法

三、源码

四、小结:


一、简介:

@Activate称为自动激活扩展点注解,主要使用在有多个扩展点实现、需要同时根据不同条件被激活的场景中

二、用法

这里列举了@Activate注解不同属性的作用的几种场景,我们首先来看下使用效果。

前期准备:

新建一个接口和五个实现类

@Activate(value = {"activateKey2"}, group = {"order"})
public class ValueActivateImpl implements Robot{

    @Override
    public void sayHello(String url) {
        System.out.println("Hello, I am ValueActivateImpl.");
    }

}

@Activate(order = 2, group = {"order"})
public class Order2ActivateImpl implements Robot{

    @Override
    public void sayHello(String url) {
        System.out.println("Hello, I am Order2ActivateImpl.");
    }

}

@Activate(order = 1, group = {"order"})
public class Order1ActivateImpl implements Robot{

    @Override
    public void sayHello(String url) {
        System.out.println("Hello, I am Order1ActivateImpl.");
    }

}

@Activate(group = {"order"})
//@Adaptive
public class OptimusPrime implements Robot {

    @Override
    public void sayHello(String url) {
        System.out.println("Hello, I am OptimusPrime");
    }

}

@Activate(after = "valueActivateImpl",group = "order")
public class BeforeActivateImpl implements Robot{

    @Override
    public void sayHello(String url) {
        System.out.println("Hello, I am BeforeActivateImpl.");
    }

}

测试main方法

①、@Activate#group

group表示分组如果匹配则激活,目前几个实现类都是group都是order,直接运行结果都被执行,和group匹配的都被执行。

②、@Activate#value

value表示URL有该key值,则激活,在ValueActivateImpl@Activate注解上加上value属性,和url中某个key保持一致。

在Order2ActivateImpl@Activate注解上同样加上value属性,但是和ValueActivateImpl区分开

其他的实现类group我改成其他的了,为了测试结果容易区分

value值和url中的key可以匹配上的才能被执行。

③、@Activate#before after

before表示哪些扩展点要在本扩展点之前激活,也就是当前扩展类是谁的before

after哪些扩展点要在本扩展点之后激活,也就是当前扩展类是谁的after

将代码还原原始状态,先测试执行不加before和after的

@Activate(group = "order")
public class BeforeActivateImpl implements Robot{

    @Override
    public void sayHello(String url) {
        System.out.println("Hello, I am BeforeActivateImpl.");
    }

}

@Activate(group = {"order"})
//@Adaptive
public class OptimusPrime implements Robot {

    @Override
    public void sayHello(String url) {
        System.out.println("Hello, I am OptimusPrime");
    }

}

@Activate(order = 1, group = {"order"})
public class Order1ActivateImpl implements Robot{

    @Override
    public void sayHello(String url) {
        System.out.println("Hello, I am Order1ActivateImpl.");
    }

}

@Activate(order = 2, group = {"order"})
public class Order2ActivateImpl implements Robot{

    @Override
    public void sayHello(String url) {
        System.out.println("Hello, I am Order2ActivateImpl.");
    }

}

@Activate(value = {"activateKey2"}, group = {"order"})
public class ValueActivateImpl implements Robot{

    @Override
    public void sayHello(String url) {
        System.out.println("Hello, I am ValueActivateImpl.");
    }

}

执行得到当前的一种执行时机顺序,然后我们加上before和after看是否能够根据我们的意愿进行执行

其实我就是想把BeforeActivateImpl和OptimusPrime的顺序、Order1和Order2的顺序颠倒。看下效果。符合我们的意愿。

④、@Activate#order

order表示同一组里面的排序,序号越小优先级越高

借助于上面的代码,我把order1和order2的序号改变下

@Activate(order = 2, group = {"order"})
public class Order1ActivateImpl implements Robot{

    @Override
    public void sayHello(String url) {
        System.out.println("Hello, I am Order1ActivateImpl.");
    }

}

@Activate(order = 1, group = {"order"})
public class Order2ActivateImpl implements Robot{

    @Override
    public void sayHello(String url) {
        System.out.println("Hello, I am Order2ActivateImpl.");
    }

}

正常情况下order2应该优先于order1的执行顺序。

三、源码

现在我们从源码的角度分析@Activate的执行原理和各个属性的执行优先级顺序是怎么决定的。

从main方法作为入口我们首先看getExtensionLoader方法

这个方法总的目的就是获取ExtensionLoader,接下来 是其执行步骤:①、校验type如果为空,抛异常、type如果非接口、抛异常

、如果type没有扩展的注解修饰、抛异常。②、从缓存map中取,如果为空,生成ExtensionLoader放入map当中。③,如果缓存中能够取到,直接返回。

然后进入extExtensionLoader.getActivateExtension获取扩展的方法。

public List<T> getActivateExtension(URL url, String[] values, String group) {
        List<T> exts = new ArrayList<>();
        List<String> names = values == null ? new ArrayList<>(0) : Arrays.asList(values);
        if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
            // TODO 加载配置路径下的接口的实现类。
            getExtensionClasses();
            for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
                String name = entry.getKey();
                Activate activate = entry.getValue();
                if (isMatchGroup(group, activate.group())) {
                    T ext = getExtension(name);
                    if (!names.contains(name) && !names.contains(Constants.REMOVE_VALUE_PREFIX + name) && isActive(activate, url)) {
                        exts.add(ext);
                    }
                }
            }
            // TODO 对exts这个list进行排序,排序规则是自己定义的一种优先级顺序
            Collections.sort(exts, ActivateComparator.COMPARATOR);
        }
        List<T> usrs = new ArrayList<>();
        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;
    }
exts用来存放最后返回的扩展类列表。names用来存放我们传进来的values,这里我测试的时候values是没有放值的。

然后看getExtensionClasses方法,用来加载配置路径下的接口的实现类

//getExtensionClasses加载扩展点实现类
    private Map<String, Class<?>> getExtensionClasses() {
        Map<String, Class<?>> classes = cachedClasses.get();
        if (classes == null) {
            synchronized (cachedClasses) {
                classes = cachedClasses.get();
                if (classes == null) {
                    classes = loadExtensionClasses();
                    cachedClasses.set(classes);
                }
            }
        }
        return classes;
    }

主要流程就是从cachedClasses中取classes,DCL检查如果最终还是为空就loadExtensionClasses方法返回值,放进cachedClasses缓存中。进入到cachedClasses方法。

注释写的挺清楚的,应该不用多说。经过这两个方法的调用,主要是进行一些属性变量的额初始化赋值操作,以供使用。

然后回到getActivateExtension方法。我们看到完成了一个排序操作,Collections.sort(exts, ActivateComparator.COMPARATOR);对exts这个list进行排序,排序规则是自己定义的一种优先级顺序,重点关注下ActivateComparator.COMPARATOR,进入到ActivateComparator.COMPARATOR

很明显这是dubbo自己实现了一个比较器,进行两个对象之间的排序规则设定。在排序规则compare中我们很容易看出主要进行了@Activate注解before和after属性、order属性的元素顺序判定。

public int compare(Object o1, Object o2) {
        if (o1 == null && o2 == null) {
            return 0;
        }
        if (o1 == null) {
            return -1;
        }
        if (o2 == null) {
            return 1;
        }
        if (o1.equals(o2)) {
            return 0;
        }
        Activate a1 = o1.getClass().getAnnotation(Activate.class);
        Activate a2 = o2.getClass().getAnnotation(Activate.class);
        if ((a1.before().length > 0 || a1.after().length > 0
                || a2.before().length > 0 || a2.after().length > 0)
                && o1.getClass().getInterfaces().length > 0
                && o1.getClass().getInterfaces()[0].isAnnotationPresent(SPI.class)) {
            ExtensionLoader<?> extensionLoader = ExtensionLoader.getExtensionLoader(o1.getClass().getInterfaces()[0]);
            if (a1.before().length > 0 || a1.after().length > 0) {
                String n2 = extensionLoader.getExtensionName(o2.getClass());
                for (String before : a1.before()) {
                    //o1 在 o2 之前
                    if (before.equals(n2)) {
                        return -1;
                    }
                }
                for (String after : a1.after()) {
                    //o2 在 o1 之前
                    if (after.equals(n2)) {
                        return 1;
                    }
                }
            }
            if (a2.before().length > 0 || a2.after().length > 0) {
                String n1 = extensionLoader.getExtensionName(o1.getClass());
                for (String before : a2.before()) {
                    if (before.equals(n1)) {
                        //o2 在 o1 之前
                        return 1;
                    }
                }
                for (String after : a2.after()) {
                    if (after.equals(n1)) {
                        //o1 在 o2 之前
                        return -1;
                    }
                }
            }
        }
        int n1 = a1 == null ? 0 : a1.order();
        int n2 = a2 == null ? 0 : a2.order();
        // 即使n1等于n2,也永远不会返回0,否则,o1和o2将像HashSet这样在集合中相互覆盖
        return n1 > n2 ? 1 : -1;
    }

然后回到getActivateExtension方法。接下来就是对额外的额指定的names进行获取扩展类放入exts中,我这里么有放值,暂时不做研究。

四、小结:

@Activate注解各个属性声明的值是通过源码中sort方法进行排序的,排序规则是dubbo自己实现的比较规则。除了before、after、order其他的排序规则由jdk实现(默认升序)。

在value、before、after、order值都指定了的情况下首先是jdk实现(默认升序)的扩展类,然后是before、after指定的扩展类,然后是order指定的顺序。

 

个人才疏学浅、信手涂鸦,dubbo框架更多模块解读相关源码持续更新中,感兴趣的朋友请移步至个人公众号,谢谢支持😜😜......

公众号:wenyixicodedog

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值