dubbo SPI功能解析(一)

265 阅读2分钟

SPI配置说明

如果需要扩展Dubbo Protocol接口实现,需要在自己的扩展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 implements Protocol { 
    // ...
}

SPI的扩展配置都是通过配置标签属性来实现的

<dubbo:protocol name="xxx" />

SPI特性

SPI自动包装SPI Auto Wrap

package com.alibaba.xxx;
 
import com.alibaba.dubbo.rpc.Protocol;
 
public class XxxProtocolWrapper implements Protocol {
    Protocol impl;
 
    public XxxProtocolWrapper(Protocol protocol) { impl = protocol; }
 
    //after interface method is executed,the method in extension will be executed
    public void refer() {
        //... some operation
        impl.refer();
        // ... some operation
    }
 
    // ...
}

SPI包装器实现类也实现了SPI接口,包装器类名必须以Wrapper结尾,构造器方法需要传入真正的SPI实现类,当通过ExtensionLoader SPI实现类加载器加载SPI实现类时,会自动返回具体实现类的包装实现,通过这种方式类型了类似Spring AOP的功能。包装器实现类可以有多个,这样可以实现链式结构。

最典型的实现见ProtocolFilterWrapper将Protocol协议生成的Invoker实现包装了一层Filter过滤器链

SPI依赖注入(自动加载)

public interface CarMaker {
    Car makeCar();
}
 
public interface WheelMaker {
    Wheel makeWheel();
}

假设有两个SPI接口CarMaker,WheelMaker如上 CarMaker implementation:

public class RaceCarMaker implements CarMaker {
    WheelMaker wheelMaker;
 
    public setWheelMaker(WheelMaker wheelMaker) {
        this.wheelMaker = wheelMaker;
    }
 
    public Car makeCar() {
        // ...
        Wheel wheel = wheelMaker.makeWheel();
        // ...
        return new RaceCar(wheel, ...);
    }
}

当通过ExtensionLoader来加载CarMaker实现时,会自动加载WheelMaker的实现类设置到wheelMaker的属性中实现依赖注入的功能,如果WheelMaker有多个实现类,会创建WheelMaker自适应实现作为实现类。如果只有一个实现类既为该实现类。

SPI自适应实现

public interface CarMaker {
    Car makeCar(URL url);
}
 
public interface WheelMaker {
    Wheel makeWheel(URL url);
}

public class RaceCarMaker implements CarMaker {
    WheelMaker wheelMaker;
 
    public setWheelMaker(WheelMaker wheelMaker) {
        this.wheelMaker = wheelMaker;
    }
 
    public Car makeCar(URL url) {
        // ...
        Wheel wheel = wheelMaker.makeWheel(url);
        // ...
        return new RaceCar(wheel, ...);
    }
}

可以看到SPI接口实现类方法都增加了URL参数,最关键的Wheel wheel = wheelMaker.makeWheel(url); wheelMaker自适应类实现了一个薄薄的代理层,会根据Url对象中预定义的key,默认使用SPI的类名简称 url.get("wheelMaker")获取真正的实现名称,然后通过ExtensionLoader获取真实实现名对应的实现类。 dubbo将XML配置中所有的信息都封装在URL中,自适应实现类通过修改XML配置切换具体实现类的。