专有名词解释
- 扩展点:扩展点实例化的对象,如`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();
}
-
默认扩展
@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);
}
-
注入扩展
@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();
}
-
包装扩展
@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();
}
-
适配类演示
@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();
}
-
适配方法
/**
@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);
}
-
适配方法 @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);
}
-
用法三:被加上@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());
}