从ExtensionLoader理解Dubbo扩展机制

Dubbo的扩展机制是怎么实现的?最简单的回答就是@SPI. Dubbo的插件化思路来源于Java SPI.

JAVA SPI 机制

SPI的全名为Service Provider Interface. 大多数人可能不了解,因为它是JDK针对插件或者厂商的。java spi机制的思想就是:

我们的系统的抽象模块(接口),往往有很多不同方案的实现。如日志模块,jdbc模块等。而在面向对象的设计里,我们一般都要做模块解耦,面向接口编程。但如果要切换接口的不同实现,就可能需要改动代码。为了实现模块的自动装配而不硬编码,就需要一种服务发现机制,这就有了java spi.

java spi 约定:当我们实现了一个接口,在jar包的 META-INF/services 目录下放一个以该接口命名的文件,文件的内容是 该接口的具体实现类。当外部程序装配jar包时,就通过这个文件找到具体的实现类,完成模块的注入。而这个服务发现的过程就用的是 java.util.ServiceLoader.

JAVA SPI 举例

接口:

package com.my.spi;
public interface Search {
   public List serch(String keyword);
} 

实现:

A的实现:com.A.spi.impl.FileSearch

B的实现:  com.B.spi.impl.DBSearch

文件:

A- jar包 META-INF/services目录下文件com.my.spi.Search 内容为:com.A.spi.impl.FileSearch

B- jar包 META-INF/services目录下文件com.my.spi.Search 内容为:com.B.spi.impl.DBSearch

使用:

package com.xyz.factory;
import java.util.Iterator;
import java.util.ServiceLoader;
import my.xyz.spi.Search;
public class SearchFactory {
    private SearchFactory() {
    }
    public static Search newSearch() {
        Search search = null;
        ServiceLoader<Search> serviceLoader = ServiceLoader.load(Search.class);
        Iterator<Search> searchs = serviceLoader.iterator();
        if (searchs.hasNext()) {
            search = searchs.next();
        }
        return search;
    }
}  
  1. package my.xyz.test;
    import java.util.Iterator;
    import java.util.ServiceLoader;
    import com.xyz.factory.SearchFactory;
    import my.xyz.spi.Search;
    public class SearchTest {
        public static void main(String[] args) {
            Search search = SearchFactory.newSearch();
            search.serch("java spi test");
        }
    }  

Dubbo的扩展点机制:ExtensionLoader和SPI

Dubbo的扩展点加载从JDK标准的SPI(Service Provider Interface)扩展点发现机制加强而来。

Dubbo改进了JDK标准的SPI的以下问题:

  • JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源。
  • 如果扩展点加载失败,连扩展点的名称都拿不到了。比如:JDK标准的ScriptEngine,通过getName();获取脚本类型的名称,但如果RubyScriptEngine因为所依赖的jruby.jar不存在,导致RubyScriptEngine类加载失败,这个失败原因被吃掉了,和ruby对应不起来,当用户执行ruby脚本时,会报不支持ruby,而不是真正失败的原因。
  • 增加了对扩展点IoC和AOP的支持,一个扩展点可以直接setter注入其它扩展点。

Dubbo提供了一个@SPI  扩展注解,它达到的功能和java的spi一样,不过它的服务发现用的不是 ServiceLoader,而是自己实现的ExtensionLoader.

约定:

在扩展类的jar包内,放置扩展点配置文件:META-INF/dubbo/接口全限定名,内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔。

(注意:这里的配置文件是放在你自己的jar包内,不是dubbo本身的jar包内,Dubbo会全ClassPath扫描所有jar包内同名的这个文件,然后进行合并)

扩展Dubbo的协议示例:

在协议的实现jar包内放置文本文件:META-INF/dubbo/com.alibaba.dubbo.rpc.Protocol,内容为:

xxx=com.alibaba.xxx.XxxProtocol

实现类内容:

package com.alibaba.xxx;

import com.alibaba.dubbo.rpc.Protocol;

public class XxxProtocol implemenets Protocol {

    // ...

}

注意: 扩展点使用单一实例加载(请确保扩展实现的线程安全性),Cache在ExtensionLoader中。

ExtensionLoader的实现

ExtensionLoader 通过其loadFile方法,加载 META-INF/internal/ ,MEAT-INF/dubbo/,META-INF/services/目录下的配置文件(接口全名为文件名),将扩展类加载并缓存。

  1. @SPI注解用在接口上, 来表明接口实现是可扩展的。这种标记有@SPI的接口,就是可扩展点
  2. 在dubbo中,扩展点默认存在三种实现: Adaptive, Wrapped ,以及normal实现。 其中normal实现就是第三方实现的有特定功能的接口实现。 Adaptive和Wrapped都是对这些normal实现的适配和包装。 Adaptive是某种意义上的集成和适配。Wrapped是包装和代理,有些aop的意思。可以在dubbo源码中找几个默认的adaptive和wrapped实现看看源码。
  3. 其中扩展点实现类还支持@Activate注解,指明了扩展点实现类被激活的加载条件。

getAdaptiveExtensionClass流程:

1.先找缓存

2.缓存没有,loadExtension From file (只能有一个实现类被@Adaptive标注)

3. loadFile后还是没有,动态生成(Xxx$Adaptive implements Xxx)。(接口方法至少有一个标注了@Adaptive,且只动态生成有标记的方法)

时间: 2024-12-09 17:26:06

从ExtensionLoader理解Dubbo扩展机制的相关文章

Dubbo源码分析系列-扩展机制的实现

Spring可扩展Schema 像标签dubbo:monitor.dubbo:service.dubbo:provider等怎么读的,读完之后怎么又是怎么解析的呢? 以上标签都是基于Spring可扩展Schema提供的自定义配置 下面举个例子 1)创建JavaBean 首先设计好配置项,通过JavaBean来建模,如类People public class People { private String name; private Integer age; } 2)编写XSD文件 XSD文件是X

聊聊Dubbo - Dubbo可扩展机制实战

摘要: 在Dubbo的官网上,Dubbo描述自己是一个高性能的RPC框架.今天我想聊聊Dubbo的另一个很棒的特性, 就是它的可扩展性. 1. Dubbo的扩展机制 在Dubbo的官网上,Dubbo描述自己是一个高性能的RPC框架.今天我想聊聊Dubbo的另一个很棒的特性, 就是它的可扩展性. 如同罗马不是一天建成的,任何系统都一定是从小系统不断发展成为大系统的,想要从一开始就把系统设计的足够完善是不可能的,相反的,我们应该关注当下的需求,然后再不断地对系统进行迭代.在代码层面,要求我们适当的对

聊聊Dubbo - Dubbo可扩展机制源码解析

摘要: 在Dubbo可扩展机制实战中,我们了解了Dubbo扩展机制的一些概念,初探了Dubbo中LoadBalance的实现,并自己实现了一个LoadBalance.是不是觉得Dubbo的扩展机制很不错呀,接下来,我们就深入Dubbo的源码,一睹庐山真面目. 在Dubbo可扩展机制实战中,我们了解了Dubbo扩展机制的一些概念,初探了Dubbo中LoadBalance的实现,并自己实现了一个LoadBalance.是不是觉得Dubbo的扩展机制很不错呀,接下来,我们就深入Dubbo的源码,一睹庐

理解 Dubbo SPI 扩展机制

写在前面 最近接触了 gRPC 体会到虽然众多 RPC 框架各有各的特点但是他们提供的特性和功能有很多的相似之处 , 这就说明他们面对同样的分布式系统带来的问题.从 2016 年左右开始接触到 dubbo ,基本停留在使用的层面,对 dubbo 的设计以及着重要解决的问题都没有系统的研究过,通过对 dubbo 和其他类似 RPC 产品的系统学习 ,学习分布式系统中面临的共同问题以及解决之道. 微内核架构 微内核架构 (Microkernel architecture) 模式也被称为插件架构 (P

Dubbo 扩展点加载机制:从 Java SPI 到 Dubbo SPI

SPI 全称为 Service Provider Interface,是一种服务发现机制.当程序运行调用接口时,会根据配置文件或默认规则信息加载对应的实现类.所以在程序中并没有直接指定使用接口的哪个实现,而是在外部进行装配. 要想了解 Dubbo 的设计与实现,其中 Dubbo SPI 加载机制是必须了解的,在 Dubbo 中有大量功能的实现都是基于 Dubbo SPI 实现解耦,同时也使得 Dubbo 获得如此好的可扩展性. Java SPI 通过完成一个 Java SPI 的操作来了解它的机

Dubbo中SPI扩展机制解析

dubbo的SPI机制类似与Java的SPI,Java的SPI会一次性的实例化所有扩展点的实现,有点显得浪费资源. dubbo的扩展机制可以方便的获取某一个想要的扩展实现,每个实现都有自己的name,可以通过name找到具体的实现. 每个扩展点都有一个@Adaptive实例,用来注入到依赖这个扩展点的某些类中,运行时通过url参数去动态判断最终选择哪个Extension实例用. dubbo的SPI扩展机制增加了对扩展点自动装配(类似IOC)和自动包装(类似AOP)的支持. 标注了@Activat

理解Java ClassLoader机制(转载)

当JVM(Java虚拟机)启动时,会形成由三个类加载器组成的初始类加载器层次结构: bootstrap classloader                |       extension classloader                |       system classloader bootstrap classloader -引导(也称为原始)类加载器,它负责加载Java的核心类. 在Sun的JVM中,在执行java的命令中使用-Xbootclasspath选项或使用 - D

理解Python命名机制

理解Python命名机制 本文最初发表于恋花蝶的博客(http://blog.csdn.net/lanphaday),欢迎转载,但必须保留此声明且不得用于商业目的.谢谢. 引子 我热情地邀请大家猜测下面这段程序的输出: class A(object): def __init__(self): self.__private() self.public() def __private(self): print 'A.__private()' def public(self): print 'A.pu

AppCan Widget插件扩展机制

AppCan Widget插件扩展机制,通过AppCan平台生成的应用,可以理解为一个Widget包(即在IDE创建项目是看到的'phone'文件夹),和一个AppCan平台中间件组成的.通常的情况下,一个应用是由一个Widget+AppCan构成,那么,有没有可能说'n个Widget+AppCan'的机制呢,答应是肯定的,这就是Widget 插件机制,是针对主widget以及普通widget的一种增强性的扩展机制,可以将具有特定功能的widget封装成一个单独的widget包存放到plugin