dubboSPI扩展机制自适应

扩展点自适应

介绍

  ExtensionLoader注入的依赖扩展点是一个Adaptive实例,直到扩展点方法执行时才决定调用是哪一个扩展点实现。
  dubbo使用url对象传递对象信息,包含key和value。
  扩展点方法调用会有URL参数(或是参数有URL成员)这样依赖的扩展点也可以从URL拿到配置信息,所有的扩展点自己定好配置的 Key后,配置信息从URL上从最外层传入。URL在配置传递上即是一条总线。

@Adaptive注解

  表示该类是一个扩展类(Adaptive实例),不需要生成代理方法直接使用即可。
  在方法上则表示该方法需生成代理, 此时就需要用到上面提到的URL参数。
  如果作用在方法会帮我们在运行时动态生成一个Adaptive实例(只包含扩展方法的),如果作用在类上就相当于自己定义了一个现成的。

注解在实现类上

  表示该类是一个扩展类,不需要生成代理方法直接使用即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 扩展的接口
@SPI
public interface AdaptiveService {
void sayHello();
}

// 是扩展类
@Adaptive
public class AdaptiveServiceImpl implements AdaptiveService {

@Override
public void sayHello(){
System.out.println("hello");
}
}

// 同样需要文件
// 文件名为接口全限定名
// 内容为key=value,value为实现类全限定名
AdaptiveService=com.lin.extendAdaptive.extend.impl.AdaptiveServiceImpl

// 启动类
public class ExtendAdaptiveMain {

public static void main(String[] args) {
ExtensionLoader<AdaptiveService> extensionLoader = ExtensionLoader.getExtensionLoader(AdaptiveService.class);
AdaptiveService adaptiveExtension = extensionLoader.getAdaptiveExtension();
adaptiveExtension.sayHello();
}
}

注解在接口方法上

  在方法上则表示该方法需生成代理, 此时就需要用到上面提到的URL参数。
  当注解在接口方法上时,方法中需要传入一个URL参数,或者包装有URL参数时,会通过动态编译获得一个Adaptive实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 接口
@SPI
public interface MethodAdaptiveService {

@Adaptive({"key"})
void sayHello(URL url);
}

// 实现类
public class MethodAdaptiveServiceImpl implements MethodAdaptiveService {

@Override
public void sayHello(URL url){
System.out.println("method");
}
}

// META—INF文件与注解在类上时相同
MethodAdaptiveService=com.lin.extendAdaptive.extend.impl.MethodAdaptiveServiceImpl

// 启动
public static void main(String[] args) {
ExtensionLoader<MethodAdaptiveService> extensionLoader = ExtensionLoader.getExtensionLoader(MethodAdaptiveService.class);
MethodAdaptiveService adaptiveExtension = extensionLoader.getAdaptiveExtension();
HashMap hashMap = new HashMap();
// key与接口中注解的key相同,value与文件中声明的名称相同
hashMap.put("key","MethodAdaptiveService");
URL url = new URL("dubbo","localhost",8080,hashMap);
adaptiveExtension.sayHello(url);
}

// 生成的实例
package com.lin.extendAdaptive.extend;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class MethodAdaptiveService$Adaptive implements com.lin.extendAdaptive.extend.MethodAdaptiveService {
public void sayHello(org.apache.dubbo.common.URL arg0) {
if (arg0 == null)
throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
String extName = url.getParameter("key");
if(extName == null)
throw new IllegalStateException("Failed to get extension (com.lin.extendAdaptive.extend.MethodAdaptiveService) name from url (" + url.toString() + ") use keys([key])");
com.lin.extendAdaptive.extend.MethodAdaptiveService extension = (com.lin.extendAdaptive.extend.MethodAdaptiveService)ExtensionLoader.getExtensionLoader(com.lin.extendAdaptive.extend.MethodAdaptiveService.class).getExtension(extName);
extension.sayHello(url);
}
}, dubbo version: 2.7.1, current host: 192.168.139.15

  程序运行时,会经过动态编译过程生成MethodAdaptiveService对应的Adaptive实例,即MethodAdaptiveService$Adaptive。
  就是在程序运行过程中,根据条件,通过拼接字符串的形式生成java源码,然后进行编译获得对应的实例。


扩展点自动注入

有bug稍后。