dubbo学习篇之dubbo内核解析(二)Adaptive

dubbo的内核

dubbo所有功能都是基于dubbo内核之上完成的,dubbo内核由四部分构成,分别为SPI,Adaptive,Wrapper,Activate。
而dubbo的内核设计原则,也是我们所熟悉的aop,ioc与动态编译compiler,这些称之为dubbo的内核原理。

Adaptive

Adaptive 机制,即扩展类的自适应机制。即其可以指定想要加载的扩展名,也可以不指定。若不指定,则直接加载默认的扩展类。即其会自动匹配,做到自适应。其是通过@Adaptive注解实现的。

@Adaptive 注解

@Adaptive 注解可以修饰类与方法,其作用相差很大。

@Adaptive 类注解
实现的例子

接口和实现类继承SPI的例子添加Adaptive类

/**
 * Adaptive类不属于Order的业务实现类。
 * 本质上是对于功能接口的修饰类。
 * 该类提供了Order接口的自适应取得方式
 */
@Adaptive
public class AdaptiveOrder implements Order {

    // 支付方式
    private String orderWay;

    public String getOrderWay() {
        return orderWay;
    }

    public void setOrderWay(String orderWay) {
        this.orderWay = orderWay;
    }

    @Override
    public void pay() {
        // 取得类加载器
        ExtensionLoader<Order> loader = ExtensionLoader.getExtensionLoader(Order.class);

        Order order;
        if (StringUtils.isEmpty(orderWay)) {
            // 若没有指定则调用默认的扩展类即@SPI中指定的
            order = loader.getDefaultExtension();
        } else {
            // 若指定则按照指定的功能性前缀进行加载
            order = loader.getExtension(orderWay);
        }
        order.pay();
    }
}

在服务提供者文件中添加
adaptive=com.demo.adaptive.service.impl.AdaptiveOrder

编写main方法

public class Main {

    public static void main(String[] args) {
        ExtensionLoader<Order> loader = ExtensionLoader.getExtensionLoader(Order.class);
        AdaptiveOrder order =(AdaptiveOrder) loader.getAdaptiveExtension();
        order.pay();
        // 输出使用支付宝支付
    }
}
跟踪源码总结生成过程
从缓存中取得ExtensionLoader,若不存在则创建ExtensionLoader并放入缓存中。
        // private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
调用ExtensionLoader.getAdaptiveExtension尝试取得Adaptive类
    public T getAdaptiveExtension() {
        // 先查看Adaptive缓存是否已经生成
        Object instance = cachedAdaptiveInstance.get();
        if (instance == null) {
            if (createAdaptiveInstanceError == null) {
                // 双重检查锁
                synchronized (cachedAdaptiveInstance) {
                    instance = cachedAdaptiveInstance.get();
                    if (instance == null) {
                        try {
                            // 没有生成的话,进行Adaptive的创建
                            instance = createAdaptiveExtension();
                            // 将创建好的类放入缓存
                            cachedAdaptiveInstance.set(instance);
                        } catch (Throwable t) {
                            createAdaptiveInstanceError = t;
                            throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
                        }
                    }
                }
            } else {
                throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
            }
        }
        // 返回Adaptive类实例
        return (T) instance;
    }
Adaptive类构建
    private T createAdaptiveExtension() {
        try {
            // 构建过程在getAdaptiveExtensionClass中
            // injectExtension为Adaptive类的依赖注入过程
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
        }
    }

Adaptive创建过程中体现出来@Adaptive在方法上与类上最大的区别

    private Class<?> getAdaptiveExtensionClass() {
        // 该流程与SPI一致即获取所有的服务提供者,并将有@Adaptive标识的类放入缓存
        getExtensionClasses();
        // 缓存不为空即存在有@Adaptive修饰的类直接返回该类的Class对象
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        // 不存在@Adaptive修饰的类则动态编译生成@Adaptive类
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }
为Adaptive类中符合条件的属性进行依赖注入
  • 类型为SPI修饰的功能性接口
  • 该SPI接口必须含有@Adaptive修饰方法或者类
返回组装成功的Adaptive实例
@Adaptive 方法注解
实现的例子

服务接口

/**
 * 该注解为标识注解,代表该类为SPI
 * 且value值代表默认提供者为服务提供者文件中定义为alipay的服务实现类
 */
@SPI("alipay")
public interface Order {
    @Adaptive
    void pay(URL url);
}

提供者

import com.demo.adaptive.service.Order;
import org.apache.dubbo.common.URL;

public class AlipayOrder implements Order {

    @Override
    public void pay(URL url) {
        System.out.println("使用支付宝支付");
    }
}
import com.demo.adaptive.service.Order;
import org.apache.dubbo.common.URL;

public class WechatOrder implements Order {
    @Override
    public void pay(URL url) {
        System.out.println("使用微信支付");
    }
}

服务提供者文件

alipay=com.demo.adaptive.service.impl.AlipayOrder
wechat=com.demo.adaptive.service.impl.WechatOrder

编写main函数

public class Main {

    public static void main(String[] args) {
        ExtensionLoader<Order> loader = ExtensionLoader.getExtensionLoader(Order.class);
        Order order = loader.getAdaptiveExtension();
        order.pay(URL.valueOf("xxx://127.0.0.1/xxx?order=wechat"));
    }
}
与类注解的区别

整体处理流程上是一致的唯一区别在于创建Adaptive类实例时,用的是动态编译生成了Adaptive类
下面是生成规则

package<SPI 接口所在包>;

public class SPI 接口名$Adpative implements SPI 接口 {
    public adaptiveMethod(arg0, arg1, ...) {
        // 注意,下面的判断仅对 URL 类型,或可以获取到 URL 类型值的参数进行判断
        // 例如,dubbo 的 Invoker 类型中就包含有 URL 属性
        if (arg1 == null) throw new IllegalArgumentException(异常信息)if (arg1.getUrl() == null) throw new IllegalArgumentException(异常信息);
        URL url = arg1.getUrl();
        // 其会根据@Adaptive 注解上声明的 Key 的顺序,从 URL 获取 Value,
        // 作为实际扩展类。若有默认扩展类,则获取默认扩展类名;否则获取
        // 指定扩展名名。
        String extName = url.get 接口名() == null ? 默认扩展前辍名 : url.get 接口名();
        if (extName == null) throw new IllegalStateException(异常信息);
        SPI 接口 extension = ExtensionLoader.getExtensionLoader(SPI 接口.class)
                .getExtension(extName);
        return extension.adaptiveMethod(arg0, arg1, ...);
    }

    public unAdaptiveMethod(arg0, arg1, ...) {
        throw new UnsupportedOperationException(异常信息);
    }
}

从这里也可以看出这里调用哪一个服务提供者是由URL中参数决定的。

  1. 如果参数没有指定,则调用SPI默认的服务提供者
  2. 如果指定了则根据服务提供者文件中定义的KEY去调用
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

加班狂魔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值