Dubbo中SPI基础——Cooma微容器

本贴最后更新于 3052 天前,其中的信息可能已经物是人非

     最近,项目中使用了dubbo来实现服务化,所以近几天学习了dubbo相关的内容。dubbo是一个方便扩展的服务框架,所以在dubbo的架构设计中始终保持了良好的依赖扩展机制:微内核+插件。简而言之就是让扩展者可以和项目开发者拥有一样的灵活度,这也是dubbo得以迅速流行的一个必要条件。要想实现这种自由度,除了在架构分层组件上要保持高内聚低耦合外,底层也需要一套强大的类管理工具。在javaEE世界里,把这份工作做到极致的也已经有成熟的标准规范:OSGi。不过OSGi并不完全适配dubbo的需求,而且这玩意儿也有些过于重了,所以在此基础上,dubbo结合JDK标准的SPI机制设计出来一个轻量级的实现:Cooma。

关于Cooma

Cooma是一个极简、灵活的开源Java微容器(microcontainer)实现。以下是摘自Cooma官网的相关描述:

概念上极简独立

  • 完全割除与容器不相关的概念。
  • 审视已有的概念,谨慎引入新概念。

实现上简单直白

  • 实现代码 少于1000行(不含代码注释)。使用sloccount统计0.2.1版本的实现代码是 780行。
  • 保持代码可读性。
  • 不考虑没有实际应用的概念。
  • 谨慎对待性能优化;不能因此打乱代码的简单性。

集成上的简易灵活

  • 保持灵活的扩展性。
  • 开发者友好。
  • 集成是否简易是设计是否良好的有效指标。

功能

  • 以插件方式加载扩展
  • 支持依赖扩展点的自动加载(扩展的IOC)
  • 可以有扩展点Wrapper,为扩展写公共Filter代码(扩展的AOP)
  • 统一的配置方式来配置各级扩展点
  • 查询插件实现
  • 支持配置方式/编程方式

核心概念

  • Extension Point,扩展点,要扩展的接口
  • Extension,扩展,即扩展点的实现
  • Extension Instance,扩展实例,即扩展点实现类的实例,# ExtensionLoader中维护了Extension Instance的 单例。
  • Extension Adaptive Instance,扩展的自适应实例
  • Extension Wrapper,所有扩展点实现调用时都会先触发的执行

简单示例

示例的扩展点是Car,有两个扩展点实现RacingCarSportCar

1) 接口类

package com.alibaba.demo.cooma;

import com.alibaba.cooma.Extension;

@Extension
public interface Car {
void run();
}

2) 实现类

package com.alibaba.demo.cooma;

public class RacingCar implements Car {
public void run() {
System.out.println("RacingCar Running...");
}
}
package com.alibaba.demo.cooma;

public class SportCar implements Car {
public void run() {
System.out.println("SportCar Running...");
}
}

3) 扩展点配置文件

在类路径的META-INF/extensions/添加配置文件 com.alibaba.demo.cooma.Car(文件名是接口的全限定名,即包括包名的接口名)。
给出扩展点实现的名称和实现类的信息。

内容:

racing=com.alibaba.demo.cooma.RacingCar
sport=com.alibaba.demo.cooma.SportCar

4) Main代码

ExtensionLoader<Car> extensionLoader = ExtensionLoader.getExtensionLoader(Car.class);

Car racingCar = extensionLoader.getExtension("racing"); // 获取指定名的扩展实例
racingCar.run();

Car sportCar = extensionLoader.getExtension("sport"); // 获取指定名的扩展实例
sportCar.run();

上面代码的运行结果,如下:

RacingCar Running...
SportCar Running...

说明

ExtensionLoader维护扩展点实现实例的 单例,即getExtension方法对于同一个扩展点实现名返回的实例是同一个。
# 后面会说到Wrapper,当使用Wrapper功能时,getExtension方法返回的是Wrapper实例。

实现的代码中和Cooma相关的内容是:

  1. 扩展点接口上要加上@Extension注解。如果没有此注解ExtensionLoader调用会出异常,拒绝管理。
  2. 在类路径的META-INF/extensions/添加配置文件 com.alibaba.demo.cooma.Car(文件名是接口的全限定名),给出扩展点实现的名称和实现类的信息。

这个使用方式可以通过扩展点实现名获得 单个接口的指定实现。实现的项目中往往会有多个扩展点配合。这样就需要扩展点中引用其它的扩展点,即注入相关的扩展点。在说明这个功能前,说明一下扩展点的“自适应实例(Adaptive Instance)”的功能。

关于Dubbo

首先先看一下dubbo的SPI部分的代码结构:

 dubbo_spi

其中,Activate #自动激活加载扩展的注解;Adaptive #自适应扩展点的注解;ExtensionFactory #扩展点对象生成工厂接口;ExtensionLoader #扩展点加载器,扩展点的查找,校验,加载等核心逻辑的实现类;SPI #扩展点注解。

我们首先看一下最重要的ExtensionLoader文件。

 private ExtensionLoader(Class<?> type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }
    

以上是ExtensionLoader的构造方法,其中它初始化了type和objectFactory,前者为要作为扩展点的接口类型,后者表示要如何获取指定名称的扩展点实例(工厂类),目前dubbo提供了2个实现类(AdaptiveExtensionFactory,SpiExtensionFactory)。

 @SuppressWarnings("unchecked")
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        if (type == null)
            throw new IllegalArgumentException("Extension type == null");
        if(!type.isInterface()) {
            throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
        }
        if(!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type(" + type + 
                    ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
        }
    ExtensionLoader&lt;T&gt; loader = (ExtensionLoader&lt;T&gt;) EXTENSION_LOADERS.get(type);
    if (loader == null) {
        EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader&lt;T&gt;(type));
        loader = (ExtensionLoader&lt;T&gt;) EXTENSION_LOADERS.get(type);
    }
    return loader;
}</pre>

以上这个方法是通过type获取到相应的loader。type与loader的对应关系是存储在一个ConcurrentMap中的。

具体的调用关系可以见下图(图片来自于网络)

spi_调用

 

  • Dubbo

    Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,是 [阿里巴巴] SOA 服务化治理方案的核心框架,每天为 2,000+ 个服务提供 3,000,000,000+ 次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点。

    60 引用 • 82 回帖 • 596 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...