Dubbo SPI 源码解析

Dubbo SPI

基于Java的SPI机制,Dubbo在其思想的基础上自己实现了一套SPI机制,弥补了Java SPI的缺点,并进行了相应的扩展。

1. Dubbo SPI 改进了 Java SPI 的以下问题:

  • Java SPI是一次性加载、实例化所有的扩展点实现,不支持根据key值去加载、实例化指定的扩展点实现。
  • Java SPI不支持IOC、AOPDubbo SPI则通过自动包装自动装配等特性实现了IOC、AOP
  • ServerLoader在加载类的过程中如果出现异常无法加载没有相关的异常抛出,导致一旦出现问题需要花时间进行定位。

2. Dubbo SPI 的三个特性

2.1. 自动包装

基于装饰器设计模式,通过创建、配置Wrapper类,从而实现对实现类的增强。我们可以将一些公共的逻辑放置在Wrapper类中,从而实现了公共逻辑与业务逻辑的解耦,同时也更易于扩展和维护。

2.2. 自动装配

类似于Spring的IOC依赖注入的功能,在加载扩展点的实现类时,会遍历所有setter方法,尝试着为其注入其他扩展点依赖。

2.3. 自适应

Dubbo使用URL对象传递配置信息,通过在URL对象中配置对应的key-value键值对,从而实现在调用相应方法时能够通过URL中的配置匹配对应的扩展点实现。

2.4. 自动激活

当我们想通过一个配置激活多个扩展点实现时,可以通过@Activate注解来实现,从而简化了配置。

3. 代码示例:

3.1. 车辆接口
package com.dubbo.service;

import org.apache.dubbo.common.extension.SPI;

@SPI
public interface ICarService {
   
    void speed();
}
3.2. 车辆接口的两个实现类AudiServiceBmwService
package com.dubbo.service.impl;

import com.dubbo.service.ICarService;

public class AudiService implements ICarService {
   
    @Override
    public void speed() {
   
        System.out.println("audi drive speed 100KM/H");
    }
}


public class BMWService implements ICarService {
   
    @Override
    public void speed() {
   
        System.out.println("bmw drive speed 200KM/H");
    }
}
3.3. 配置文件

resources\META-INF\services\com.dubbo.service.ICarService

audi=com.dubbo.service.impl.AudiService
bmw=com.dubbo.service.impl.BMWService
3.4. 测试方法
private static void dubboSpi() {
   
    ExtensionLoader<ICarService> extensionLoader = ExtensionLoader.getExtensionLoader(ICarService.class);
    ICarService carService = extensionLoader.getExtension("audi");
    carService.speed();
}

// 输出
audi drive speed 100KM/H

4. 源码解析

4.1 获取扩展点加载器

Main方法

ExtensionLoader.getExtensionLoader(ICarService.class);
ICarService carService = extensionLoader.getExtension("audi");

org.apache.dubbo.common.extension.ExtensionLoader

// key:扩展点接口-扩展点加载器
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();

// 获取扩展点加载器
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
   
    ...
    // 尝试从缓存中获取扩展点加载器
    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);
    }
    // 返回扩展点加载器
    return loader;
}

获取到扩展点加载器后,调用扩展点加载器的getExtension方法获取扩展点实现对象

public T getExtension(String name) {
   
    if (StringUtils.isEmpty(name)) {
   
        throw new IllegalArgumentException("Extension name == null");
    }

    // 如果传入name为true,则获取默认扩展实现
    if ("true".equals(name)) {
   
        return getDefaultExtension();
    }
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值