dubbu 扩展注解_Dubbo SPI之Activate详解

前期准备

一. 增加pom

com.alibaba

dubbo

2.5.3

二. 添加代码重要声明:本节演示的源码来自于网络的一片文章,看例子讲解的很透彻,很能说明问题就直接引用过来了,没法注明出处,如果有知道的请和我联系下,我添加上——尊重原创,从我做起

1. shuqi.dubbotest.spi.adaptive.AdaptiveExt2  作为需要被扩展的接口,注意要加上@SPI注解package shuqi.dubbotest.spi.activate;import com.alibaba.dubbo.common.extension.SPI;

@SPIpublic interface ActivateExt1 {    String echo(String msg);

}

2. 上面接口的五个实现类

a. shuqi.dubbotest.spi.activate.ActivateExt1Impl1package shuqi.dubbotest.spi.activate;import com.alibaba.dubbo.common.extension.Activate;/**

* @author linyang on 18/4/20.

*/@Activate(group = {"default_group"})public class ActivateExt1Impl1 implements ActivateExt1 {    public String echo(String msg) {        return msg;

}

}

b. shuqi.dubbotest.spi.activate.GroupActivateExtImplpackage shuqi.dubbotest.spi.activate;import com.alibaba.dubbo.common.extension.Activate;/**

* @author linyang on 18/4/20.

*/@Activate(group = {"group1", "group2"})public class GroupActivateExtImpl implements ActivateExt1 {    public String echo(String msg) {        return msg;

}

}

c. shuqi.dubbotest.spi.activate.OrderActivateExtImpl1package shuqi.dubbotest.spi.activate;import com.alibaba.dubbo.common.extension.Activate;/**

* @author linyang on 18/4/20.

*/@Activate(order = 2, group = {"order"})public class OrderActivateExtImpl1 implements ActivateExt1 {    public String echo(String msg) {        return msg;

}

}

d. shuqi.dubbotest.spi.activate.OrderActivateExtImpl2package shuqi.dubbotest.spi.activate;import com.alibaba.dubbo.common.extension.Activate;/**

* @author linyang on 18/4/20.

*/@Activate(order = 1, group = {"order"})public class OrderActivateExtImpl2 implements ActivateExt1 {    public String echo(String msg) {        return msg;

}

}

e. shuqi.dubbotest.spi.activate.ValueActivateExtImplpackage shuqi.dubbotest.spi.activate;import com.alibaba.dubbo.common.extension.Activate;/**

* @author linyang on 18/4/20.

*/@Activate(value = {"value1"}, group = {"value"})public class ValueActivateExtImpl implements ActivateExt1 {    public String echo(String msg) {        return msg;

}

}

3. 在Resource目录下,添加/META-INF/dubbo/internal/shuqi.dubbotest.spi.activate.ActivateExt1文件,里面的内容group=shuqi.dubbotest.spi.activate.GroupActivateExtImpl

value=shuqi.dubbotest.spi.activate.ValueActivateExtImpl

order1=shuqi.dubbotest.spi.activate.OrderActivateExtImpl1

order2=shuqi.dubbotest.spi.activate.OrderActivateExtImpl2

shuqi.dubbotest.spi.activate.ActivateExt1Impl1

上车 just do it!

测试一:@Activate注解中声明group@Test    public void testDefault() {

ExtensionLoader loader = ExtensionLoader.getExtensionLoader(ActivateExt1.class);

URL url = URL.valueOf("test://localhost/test");        //查询组为default_group的ActivateExt1的实现

List list = loader.getActivateExtension(url, new String[]{}, "default_group");

System.out.println(list.size());

System.out.println(list.get(0).getClass());

}1class shuqi.dubbotest.spi.activate.ActivateExt1Impl1

测试二:@Activate注解中声明多个group@Test    public void test2() {

URL url = URL.valueOf("test://localhost/test");        //查询组为group2的ActivateExt1的实现

List list = ExtensionLoader.getExtensionLoader(ActivateExt1.class).getActivateExtension(url, new String[]{}, "group2");

System.out.println(list.size());

System.out.println(list.get(0).getClass());

}1class shuqi.dubbotest.spi.activate.GroupActivateExtImpl

测试三:@Activate注解中声明了group与value@Test    public void testValue() {

URL url = URL.valueOf("test://localhost/test");        //根据   key = value1,group =  value

//@Activate(value = {"value1"}, group = {"value"})来激活扩展

url = url.addParameter("value1", "value");

List list = ExtensionLoader.getExtensionLoader(ActivateExt1.class).getActivateExtension(url, new String[]{}, "value");

System.out.println(list.size());

System.out.println(list.get(0).getClass());

}1class shuqi.dubbotest.spi.activate.ValueActivateExtImpl

测试四:@Activate注解中声明了order,低的排序优先级搞@Test    public void testOrder() {

URL url = URL.valueOf("test://localhost/test");

List list = ExtensionLoader.getExtensionLoader(ActivateExt1.class).getActivateExtension(url, new String[]{}, "order");

System.out.println(list.size());

System.out.println(list.get(0).getClass());

System.out.println(list.get(1).getClass());

}2class shuqi.dubbotest.spi.activate.OrderActivateExtImpl2class shuqi.dubbotest.spi.activate.OrderActivateExtImpl1

结论:从上面的几个测试用例,可以得到下面的结论:1. 根据loader.getActivateExtension中的group和搜索到此类型的实例进行比较,如果group能匹配到,就是我们选择的,也就是在此条件下需要激活的。2. @Activate中的value是参数是第二层过滤参数(第一层是通过group),在group校验通过的前提下,如果URL中的参数(k)与值(v)中的参数名同@Activate中的value值一致或者包含,那么才会被选中。相当于加入了value后,条件更为苛刻点,需要URL中有此参数并且,参数必须有值。3.@Activate的order参数对于同一个类型的多个扩展来说,order值越小,优先级越高。

源码分析

下面我们带着上面的结论,看一下源码。上篇文章我们我们说了ExtensionLoader.getExtensionLoader(ActivateExt1.class)这一步做的,今天我们从他的下一步讲起getActivateExtension/**

* Get activate extensions.

*

* @param url    url

* @param values extension point names

* @param group  group

* @return extension list which are activated

* @see com.alibaba.dubbo.common.extension.Activate

*/

public List getActivateExtension(URL url, String[] values, String group) {        List exts = new ArrayList();        /**

* 将传递过来的values包装成List类型的names

*/

List names = values == null ? new ArrayList(0) : Arrays.asList(values);        /**

* 包装好的数据中不包含"-default"

*/

if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {            /**

* 获取这个类型的数据的所有扩展信息

*/

getExtensionClasses();            for (Map.Entry entry : cachedActivates.entrySet()) {                /**

* 获取扩展的名称

*/

String name = entry.getKey();                /**

* 获取扩展的注解

*/

Activate activate = entry.getValue();                /**

* 判断group是否属于范围

*

* 1. 如果activate注解的group没有设定,直接返回true

* 2. 如果设定了,需要和传入的额group进行比较,看是否

* 包含其中,如果包含,返回true

*

*/

if (isMatchGroup(group, activate.group())) {                    /**

* group 校验通过了,从缓存中获取此name对应的实例

*/

T ext = getExtension(name);                    /**

* names 不包含 遍历此时的name

*/

if (!names.contains(name)                            /**

* names中不包含"-default"

*/

&& !names.contains(Constants.REMOVE_VALUE_PREFIX + name)                            /**

* 通过URL判断这个activate注解是激活的

*/

&& isActive(activate, url)) {                        /**

* 增加扩展

*/

exts.add(ext);

}

}

}            /**

* 按照Activate的方式进行排序,注意order

*/

Collections.sort(exts, ActivateComparator.COMPARATOR);

}        /**

* 借用usrs这个临时变量,进行循环往exts中塞具体的ext的对象。

* 如果碰到了"default"就添加到头部,清空usrs这个临时变量。

* 如果没有"default"那么usrs不会清空,所以下面有个if,说usrs不为空

* 将里面的内容增加到exts中

*/

List usrs = new ArrayList();        for (int i = 0; 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.isEmpty()) {

exts.addAll(0, usrs);

usrs.clear();

}

} else {

T ext = getExtension(name);

usrs.add(ext);

}

}

}        if (!usrs.isEmpty()) {

exts.addAll(usrs);

}        return exts;

}

看到了我们属性的方法getExtensionClasses获取这个类型所有的扩展类,随后利用了cachedActivates变量,不知道大家还有没有印象,他的赋值也是再getExtensionClasses方法里面的Activate activate = clazz.getAnnotation(Activate.class);if (activate != null) {    //存在,就往cachedActivates里面添加名称与注解

cachedActivates.put(names[0], activate);

}

回顾完毕,我们继续说。首先会校验group,对应的方法是isMatchGroup/**

* 判断group是否属于范围

* 1. 如果activate注解的group没有设定,直接返回true

* 2. 如果设定了,需要和传入的额group进行比较,看是否

* 包含其中,如果包含,返回true

*/

private boolean isMatchGroup(String group, String[] groups) {        if (group == null || group.length() == 0) {            return true;

}        if (groups != null && groups.length > 0) {            for (String g : groups) {                if (group.equals(g)) {                    return true;

}

}

}        return false;

}

如果activate注解的group没有设定,直接返回true,如果设定了,需要和传入的额group进行比较,看是否包含其中,如果包含,返回true,这个点可以看一下测试方法一和二。group 验证完后,根据name获取具体的扩展。随后验证一下是否激活的方法isActive,主要就是根据@Activate注解中的value和URL中的参数的对应做的。private boolean isActive(Activate activate, URL url) {        String[] keys = activate.value();        /**

* 如果@Activate注解中的value是空的直接返回true

*/

if (keys.length == 0) {            return true;

}        /**

* 从activate.value()拿到的数据进行遍历

*/

for (String key : keys) {            /**

* 从URL中获取参数,进行遍历,如果有一个参数同key一致,或者是以.key的方式结尾。

*

*/

for (Map.Entry entry : url.getParameters().entrySet()) {                String k = entry.getKey();                String v = entry.getValue();                if ((k.equals(key) || k.endsWith("." + key))

&& ConfigUtils.isNotEmpty(v)) {                    return true;

}

}

}        return false;

}

如果@Activate注解中的value是空的直接返回true,如果有值,会遍历判断,从URL中获取参数,进行遍历,如果有一个参数同key一致,或者是以.key的方式结尾,并且url中这个k对应的v有有意义的值,同样返回true,说道这里,我们可以看一下测试三,说的就是这个功能。group和value都验证通过后,就可以添加到exts集合中了,随后进行了排序Collections.sort(exts, ActivateComparator.COMPARATOR) 这个可以看一下测试方法四。当所有的过滤条件都通过后,就可以返回了。

相比于@Adaptive来说,@Activate简单一点,处理逻辑也没那么烦乱。

适用场景

主要用在filter上,有的filter需要在provider边需要加的,有的需要在consumer边需要加的,根据URL中的参数指定,当前的环境是provider还是consumer,运行时决定哪些filter需要被引入执行。

作者:数齐

链接:https://www.jianshu.com/p/bc523348f519

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值