dubbo的SPI使用展示

115 阅读3分钟

专有名词解释


-   扩展点:扩展点实例化的对象,如`new org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol()`
-   扩展点类型:扩展点的接口,如`org.apache.dubbo.rpc.Protocol`
-   扩展点 Class:扩展点的 Class,如`org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol`

1. 根据名称获取扩展

@SPI // 必须加上@SPI注解
public interface DubboSPiService {
    void doSthInDubbo();
}

public class DubboSpiServiceImplA implements DubboSPiService{
    @Override
    public void doSthInDubbo() {
        System.out.println("doSthInDubbo ... A");
    }
}

public class DubboSpiServiceImplB implements DubboSPiService{
    @Override
    public void doSthInDubbo() {
        System.out.println("doSthInDubbo ... B");
    }
}

@Test
public void DubboSpiTest() {
    ExtensionLoader<DubboSPiService> loader = ExtensionLoader.getExtensionLoader(DubboSPiService.class);
    DubboSPiService extension = loader.getExtension("aaa"); // 通过名称获取
    extension.doSthInDubbo();	
}
  1. 默认扩展

@SPI("bbb") // 给定默认值的名称 不能给多个否则报错
public interface DubboSPiService {
    void doSthInDubbo();
}

public class DubboSpiServiceImplA implements DubboSPiService{
    @Override
    public void doSthInDubbo() {
        System.out.println("doSthInDubbo ... A");
    }
}

public class DubboSpiServiceImplB implements DubboSPiService{
    @Override
    public void doSthInDubbo() {
        System.out.println("doSthInDubbo ... B");
    }
}

//获取默认扩展的两种方法
@Test
public void DubboSpiDefaultTest() {
    ExtensionLoader<DubboSPiService> loader = ExtensionLoader.getExtensionLoader(DubboSPiService.class);
    DubboSPiService extension = loader.getExtension("true");
    extension.doSthInDubbo();
    DubboSPiService defaultExtension = loader.getDefaultExtension();
    System.out.println(extension == defaultExtension);
}
  1. 注入扩展

@SPI
public interface InjectService {
    void inject();
}

public class InjectServiceImplA implements InjectService {

    private InjectService injectService;

    public void setInjectService(InjectService injectService) {
        this.injectService = injectService;
    }

    @Override
    public void inject() {
        System.out.println("InjectServiceImplA");
    }
}

@Adaptive
public class InjectServiceImplB implements InjectService {

    @Override
    public void inject() {
        System.out.println("InjectServiceImplB");
    }
}

@Test
public void testInjectExtension() {
    ExtensionLoader<InjectService> loader = ExtensionLoader.getExtensionLoader(InjectService.class);
    InjectService extension = loader.getExtension("aaa");
    extension.inject();
}
  1. 包装扩展

@SPI
public interface WrapService {
    void wrap();
}

public class WrapServiceImplA implements WrapService{

    private WrapService wrapService;

    public WrapServiceImplA(WrapService wrapService) {
        this.wrapService = wrapService;
    }

    @Override
    public void wrap() {
        System.out.println("WrapServiceImplA");
    }
}

public class WrapServiceImplB implements WrapService{

    @Override
    public void wrap() {
        System.out.println("WrapServiceImplB");
    }
}

@Test
public void testWrapExtension() {
    ExtensionLoader<WrapService> loader = ExtensionLoader.getExtensionLoader(WrapService.class);
    WrapService extension = loader.getExtension("bbb");
    extension.wrap();
}
  1. 适配类演示

@SPI
public interface HelloService {
    void sayHello();
}

@Adaptive
public class HelloServiceImplA implements HelloService{
    @Override
    public void sayHello() {
        System.out.println("HelloServiceImplA");
    }
}

public class HelloServiceImplB implements HelloService{
    @Override
    public void sayHello() {
        System.out.println("HelloServiceImplB");
    }
}

@Test
public void testAdaptiveExtension() {
	HelloService extension = ExtensionLoader.getExtensionLoader(HelloService.class).getAdaptiveExtension();
	extension.sayHello();
}
  1. 适配方法


/**

    @Adaptive的value: 字符串数组,URL参数的key值,如果不写默认会生成一个,如接口名HelloService,默认是hello.service
*/
@SPI
public interface HelloService {
    @Adaptive
    void sayHello(URL url);
}

public class HelloServiceImplA implements HelloService{
    @Override
    public void sayHello(URL url) {
        System.out.println("HelloServiceImplA");
    }
}

public class HelloServiceImplB implements HelloService{
    @Override
    public void sayHello(URL url) {
        System.out.println("HelloServiceImplB");
    }
}

@Test
public void testAdaptiveExtension() {
	HelloService extension = ExtensionLoader.getExtensionLoader(HelloService.class).getAdaptiveExtension();
	URL url = URL.valueOf("cba://localhost/abc?hello.service=aaa");
	extension.sayHello(url);
}
  1. 适配方法 @Adaptive的value给指定的值

@SPI
public interface HelloService {
    @Adaptive({"key1","key2"}) //有先后顺序,先按key1在URL找扩展名再按key2找
    void sayHello(URL url);
}

public class HelloServiceImplA implements HelloService{
    @Override
    public void sayHello(URL url) {
        System.out.println("HelloServiceImplA");
    }
}

public class HelloServiceImplB implements HelloService{
    @Override
    public void sayHello(URL url) {
        System.out.println("HelloServiceImplB");
    }
}

@Test
public void testAdaptiveExtension() {
    HelloService extension = ExtensionLoader.getExtensionLoader(HelloService.class).getAdaptiveExtension();
    URL url = URL.valueOf("protocol://localhost/abc?key1=aaa&key2=bbb");
    extension.sayHello(url);
}
  1. 用法三:被加上@Adaptive的方法存在这样一个参数,该参数拥有可以返回URL对象的无参方法
@SPI
public interface HelloService {
    @Adaptive(value = {"key1","key2"})
    void sayHello(URLFactory service);
}

@FunctionalInterface
public interface URLFactory {
    URL getDubboURL();
}

public class HelloServiceImplA implements HelloService{

    @Override
    public void sayHello(URLFactory service) {
        System.out.println("HelloServiceImplA");
    }
}

public class HelloServiceImplB implements HelloService{
    @Override
    public void sayHello(URLFactory service) {
        System.out.println("HelloServiceImplB");
    }
}

@Test
public void testAdaptiveExtension() {
    ExtensionLoader<HelloService> loader = ExtensionLoader.getExtensionLoader(HelloService.class);
    HelloService extension = loader.getAdaptiveExtension();
    URL url = URL.valueOf("protocol://localhost/abc?key1=aaa&key2=bbb");
    extension.sayHello(() -> {return url;});
}

8. ####激活扩展

1)接口需加上@SPI注解
2)实现类上加上@Activate注解
        group 分组 常用producer和consumer 
        value 激活条件 , 
        order 对扩展进行排序 数值越小排名越前

3)对于同一个接口,激活扩展可以有多个
4)通过extensionLoader.getActivateExtension(URL url, String key, String group)获取


@SPI
public interface ActiveService {
    void doSth();
}

@Activate(group = {"active-group"}, order = 1)
public class ActiveServiceImplA implements ActiveService{

    @Override
    public void doSth() {
        System.out.println("call ActiveServiceImpl A");
    }
}

@Activate(group = {"active-group"}, order = 2)
public class ActiveServiceImplB implements ActiveService{
    @Override
    public void doSth() {
        System.out.println("call ActiveServiceImpl B");
    }
}

@Activate(group = {"nonactive-group"}, order = 3)
public class ActiveServiceImplC implements ActiveService{

    @Override
    public void doSth() {
        System.out.println("call ActiveServiceImpl C");
    }
}

/** 

测试分组和排序
call ActiveServiceImpl A
call ActiveServiceImpl B
*/
@Test
public void testActiveExtensionGroup() {
    URL url = URL.valueOf("protocol://localhost");
    ExtensionLoader<ActiveService> loader = ExtensionLoader.getExtensionLoader(ActiveService.class);
    List<ActiveService> extensionList = loader.getActivateExtension(url,"","active-group");
    extensionList.forEach(x -> x.doSth());
}
@SPI
public interface ActiveService {
    void doSth();
}

@Activate(group = {"active-group"}, value = {"k:xxx"}, order = 1)
public class ActiveServiceImplA implements ActiveService{

    @Override
    public void doSth() {
        System.out.println("call ActiveServiceImpl A");
    }
}

@Activate(group = {"active-group"}, value = {"k"}, order = 2)
public class ActiveServiceImplB implements ActiveService{
    @Override
    public void doSth() {
        System.out.println("call ActiveServiceImpl B");
    }
}

@Activate(group = {"nonactive-group"}, order = 3)
public class ActiveServiceImplC implements ActiveService{

    @Override
    public void doSth() {
        System.out.println("call ActiveServiceImpl C");
    }
}


aaa=com.jdeng.dubbo.active.ActiveServiceImplA
bbb=com.jdeng.dubbo.active.ActiveServiceImplB
ccc=com.jdeng.dubbo.active.ActiveServiceImplC



/*
    URL: cache=redis   @Active(value={"cache:redis"})
    URL: cache=redis   @Active(value={"cache"})
    URL: xxx.cache=redis   @Active(value={"cache:redis"})
    URL: xxx.cache=redis   @Active(value={"cache"})
    如果传入了key,除了按照上述规则进行匹配外,还会把url中的key值对应的value的扩展加载进来
*/

@Test
public void testActiveExtensionValueWithoutKey() {
    URL url = URL.valueOf("protocol://localhost?k=aaa");
    ExtensionLoader<ActiveService> loader = ExtensionLoader.getExtensionLoader(ActiveService.class);
    List<ActiveService> extensionList = loader.getActivateExtension(url,"");
    extensionList.forEach(x -> x.doSth());
}

@Test
public void testActiveExtensionValueWithKey() {
    URL url = URL.valueOf("protocol://localhost?k=aaa");
    ExtensionLoader<ActiveService> loader = ExtensionLoader.getExtensionLoader(ActiveService.class);
    List<ActiveService> extensionList = loader.getActivateExtension(url,"k");
    extensionList.forEach(x -> x.doSth());
}

@Test
public void testActiveExtensionValueWithKeyExcludeExtension() {
    URL url = URL.valueOf("protocol://localhost?k=-ccc");
    ExtensionLoader<ActiveService> loader = ExtensionLoader.getExtensionLoader(ActiveService.class);
    List<ActiveService> extensionList = loader.getActivateExtension(url,"k");
    extensionList.forEach(x -> x.doSth());
}