dubbo基于SPI思想的内核实现
SPI机制
SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口加载实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能,比如数据库访问、日志等都是采用这种形式。一般通用组件为了提升扩展性,基于接口编程,将操作接口形成标准规范,开放多种扩展实现,是组件具有可插拔性,也符合开闭设计原则。
dubbo 的扩展实现很多,比如协议拓展、调用拦截扩展、引用监听拦截拓展等
JDK SPI 机制介绍
举个例子演示下JDK 的SPI
定义一个interface:
package com.momo.jdk.spi;
public interface SPI {
SPI getExtension();
}
实现类:
package com.momo.jdk.spi;
public class HelloSPI implements SPI {
@Override
public SPI getExtension() {
System.out.println("这是 HelloSPI ~~~~~~~");
return new HelloSPI();
}
}
package com.momo.jdk.spi;
public class Hello2SPI implements SPI {
@Override
public SPI getExtension() {
System.out.println("这是 Hello2SPI Hello2SPI Hello2SPI");
return new Hello2SPI();
}
}
ServiceLoader会遍历所有jar查找META-INF/services/ 下定义的类并加载
在META-INF/services 定一个名为接口SPI 的全限定名:com.momo.jdk.spo.SPI 的文件:
[外链图片转存失败(img-OR3eNnHO-1564366186540)(media/15497013856273/15497145191481.jpg)]
内容为:
com.momo.jdk.spi.HelloSPI
com.momo.jdk.spi.Hello2SPI
测试方法:
public class SPITest {
public static void main(String[] args) {
ServiceLoader<SPI> serviceLoader = ServiceLoader.load(SPI.class);
System.out.println("Java SPI");
serviceLoader.forEach(SPI::getExtension);
}
}
运行结果:
[外链图片转存失败(img-vUirpICt-1564366186542)(media/15497013856273/15497146175001.jpg)]
从结果来看,这两个实现类都被加载并且输出了相应内容。接下来看看dubbo的SPI
dubbo SPI 示例
Dubbo 的扩展点加载从 JDK 标准的 SPI (Service Provider Interface) 扩展点发现机制加强而来。
下面我们通过扩展dubbo得filter来看下dubbo的SPI
实现filter:
public class MyTestFilter implements Filter {
private TestSPIDemoService testSPIDemoService;
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
Result result = invoker.invoke(invocation);
System.out.println(testSPIDemoService.getTestSPIResult());
return result;
}
public void setTestSPIDemoService(TestSPIDemoService testSPIDemoService) {
this.testSPIDemoService = testSPIDemoService;
}
}
约定:
在扩展类的 jar 包内,放置扩展点配置文件 META-INF/dubbo/接口全限定名,内容为:配置名=扩展实现类全限定名,多个实现类用换行符分隔。
META-INF/dubbo/:myTest=com.momo.sentinel.spi.MyTestFilter
[外链图片转存失败(img-wEtN29nX-1564366186542)(media/15497013856273/15497233065729.jpg)]
执行结果:
[外链图片转存失败(img-uJhucxrt-1564366186543)(media/15497013856273/15497272535005.jpg)]
在学习dubbo SPI 之前推荐先移步官网dubbo 扩展点加载了解下dubbo的四大特性:扩展点自动包装、扩展点自动装配、扩展点自适应、扩展点自动激活
ExtensionLoader
dubbo扩展机制实现的核心是ExtensionLoader,几乎所有的扩展实现都在这个类里面。每个可扩展接口扩展实现类和实现实例的管理都是通过ExtensionLoader进行,每个接口维护一个单例ExtensionLoader,所有可扩展的接口实现都维护在ExtensionLoader中
唯一获取ExtensionLoader对象的入口就是ExtensionLoader#getExtensionLoader(Class type)方法
@SuppressWarnings("unchecked")
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
if (type == null) {
throw new IllegalArgumentException("Extension type == null");
}
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type (" + type + ") is not interface!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" + type +
") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
}
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
会校验尝试获取Loader的接口是否有@SPI注解,先在缓存中找,如果没有缓存,则调用私有构造方法:
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
这里有个重要对象:objectFactory。这个对象的作用就是自动装配依赖,也就是IOC,可以看出,除了ObjectFactory本身,所有扩展点都有ObjectFactory实例,这个也是通过SPI管理的,它是通过getAdaptiveExtension()方法获取的。
自适应扩展
友情提示:一个拓展接口,有且仅有一个 Adaptive 拓展实现类。
要构建自适应实例,先要有自适应的实现类,实现类有两种实现方式:一种是通过配置文件,一种是通过字节码方式动态生成。配置文件的自适应类通过在实现类上面加@Adaptive注解(例如:Compiler的AdaptiveCompiler实现),字节码生成的自适应类的在方法层面上加@Adaptive注解(例如:LoadBalance)。
private Class<?> getAdaptiveExtensionClass() {
//先通过配置文化加载实现类,并且识别自适应实现类
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
//如果没有通过Adaptive注解标识的自适应实现类,则通过字节码创建
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
加载完配置文件后,检查缓存的自适应实现类,若没有,则通过字节码技术生成自适应类。调用createAdaptiveExtensionClass()方法,实际上是通过拼接class文本,然后通过compiler编译文本生成class。
通过配置文件加载自适应类
private Map<String, Class<?>> loadExtensionClasses() {
// 通过 @SPI 注解,获得默认的拓展实现类名
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
if ((value = value.trim()).length() > 0) {
String[] names = NAME_SEPARATOR.split(value);
//有多个默认实现就抛异常
if (names.length > 1) {
throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
+ ": " + Arrays.toString(names));
}
if (names.length == 1) cachedDefaultName = names[0];
}
}
// 从配置文件中,加载拓展实现类数组
Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
loadDirectory(extensionClasses, DUBBO_DIRECTORY);
loadDirectory(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
// 完整的文件名
String fileName = dir + type.getName();
try {
Enumeration<java.net.URL> urls;
// 获得文件名对应的所有文件数组
ClassLoader classLoader = findClassLoader();
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
// 遍历文件数组
if (urls != null) {
while (urls.hasMoreElements()) {
java.net.URL resourceURL = urls.nextElement();
loadResource(extensionClasses, classLoader, resourceURL);
}
}
} catch (Throwable t) {
logger.error("Exception when load extension class(interface: " +
type + ", description file: " + fileName + ").", t);
}
}
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8"));
try {
String line;
while ((line = reader.readLine()) != null) {
// 跳过当前被注释掉的情况,例如 #spring=xxxxxxxxx
final int ci = line.indexOf('#');
if (ci >= 0) line = line.substring(0, ci);
line = line.trim();
if (line.length() > 0) {
try {
// 拆分,key=value 的配置格式
String name = null;
int i = line.indexOf('=');
if (i > 0) {
name = line.substring(0, i).trim();
line = line.substring(i + 1).trim();
}
if (line.length() > 0) {
loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
}
} catch (Throwable t) {
// 发生异常,记录到异常集合
IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
exceptions.put(line, e);
}
}
}
} finally {
reader.close();
}
} catch (Throwable t) {
logger.error("Exception when load extension class(interface: " +
type + ", class file: " + resourceURL + ") in " + resourceURL, t);
}
}
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
if (!type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Error when load extension class(interface: " +
type + ", class line: " + clazz.getName() + "), class "
+ clazz.getName() + "is not subtype of interface.");
}
if (clazz.isAnnotationPresent(Adaptive.class)) {
// 缓存自适应拓展对象的类到 `cachedAdaptiveClass`
if (cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
} else if (!cachedAdaptiveClass.equals(clazz)) {
throw new IllegalStateException("More than 1 adaptive class found: "
+ cachedAdaptiveClass.getClass().getName()
+ ", " + clazz.getClass().getName());
}
} else if (isWrapperClass(clazz)) {
// 缓存拓展 Wrapper 实现类到 `cachedWrapperClasses`
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
} else {
// 未配置拓展名,自动生成。主要用于兼容 Java SPI 的配置。
clazz.getConstructor();
if (name == null || name.length() == 0) {
name = findAnnotationName(clazz);
if (name.length() == 0) {
throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
}
}
// 获得拓展名,可以是数组,有多个拓展名。
String[] names = NAME_SEPARATOR.split(name);
if (names != null && names.length > 0) {
// 缓存 @Activate 到 `cachedActivates` 。
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
cachedActivates.put(names[0], activate);
}
for (String n : names) {
// 缓存到 `cachedNames`
if (!cachedNames.containsKey(clazz)) {
cachedNames.put(clazz, n);
}
Class<?> c = extensionClasses.get(n);
if (c == null) {
extensionClasses.put(n, clazz);
} else if (c != clazz) {
throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
}
}
}
}
}
自动激活扩展
在dubbo中,某些组件可以同时有多个实现同时加载时,就可以通过@Activate注解自动激活,常见的自动激活扩展,如过滤器Filter,有顺序要求,提供了三个排序属性,before、after和order。还有一些过滤条件,主要是通过分组和key,如provider和consumer的过滤逻辑可能就不一样.
获取激活的扩展对象:
#getActivateExtension(com.alibaba.dubbo.common.URL, String, String)
*/
public List<T> getActivateExtension(URL url, String key) {
return getActivateExtension(url, key, null);
}
public List<T> getActivateExtension(URL url, String[] values, String group) {
List<T> exts = new ArrayList<T>();
List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
// 处理自动激活的拓展对象们
// 判断不存在配置 `"-name"` 。例如,<dubbo:service filter="-default" /> ,代表移除所有默认过滤器。
if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
getExtensionClasses();
for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
String name = entry.getKey();
Activate activate = entry.getValue();
//匹配分组
if (isMatchGroup(group, activate.group())) {
// 获得拓展对象
T ext = getExtension(name);
if (!names.contains(name)
// 判断是否配置移除。例如 <dubbo:service filter="-monitor" />,则 MonitorFilter 会被移除
&& !names.contains(Constants.REMOVE_VALUE_PREFIX + name)
// 判断是否激活
&& isActive(activate, url)) {
exts.add(ext);
}
}
}
// 排序
Collections.sort(exts, ActivateComparator.COMPARATOR);
}
// 处理自定义配置的拓展对象们。例如在 <dubbo:service filter="myTest" /> ,代表需要加入 myTestFilter
List<T> usrs = new ArrayList<T>();
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX)
&& !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
// 将配置的自定义在自动激活的拓展对象们前面。例如,<dubbo:service filter="demo,default,demo2" /> ,则 DemoFilter 就会放在默认的过滤器前面。
if (Constants.DEFAULT_KEY.equals(name)) {
if (!usrs.isEmpty()) {
exts.addAll(0, usrs);
usrs.clear();
}
} else {
// 获得拓展对象
T ext = getExtension(name);
usrs.add(ext);
}
}
}
// 添加到结果集
if (!usrs.isEmpty()) {
exts.addAll(usrs);
}
return exts;
}
这个方法主要工作就是从之前加载配置时缓存的cachedActivates中过滤符合条件的自动激活实例,并根据@Activate的排序规则排序
自动装配(IOC注入)
在创建自适应实例时,都会调用ExtensionLoader的injectExtension方法:
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
//反射获得所有方法
for (Method method : instance.getClass().getMethods()) {
// setting && public 方法
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
/**
* Check {@link DisableInject} to see if we need auto injection for this property
*/
if (method.getAnnotation(DisableInject.class) != null) {
continue;
}
// 获得属性的类型
Class<?> pt = method.getParameterTypes()[0];
try {
//获得属性
String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
// 获得属性值
Object object = objectFactory.getExtension(pt, property);
// 设置属性值
if (object != null) {
method.invoke(instance, object);
}
} catch (Exception e) {
logger.error("fail to inject via method " + method.getName()
+ " of interface " + type.getName() + ": " + e.getMessage(), e);
}
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
其中objectFactory.getExtension(pt, property)
就是获取IOC实例。就是检测扩展实现类有没有通过set方法设置的属性,如果有,就通过ExtensionFactory加载而设置。
ExtensionFactory 自身也是拓展接口,基于 Dubbo SPI 加载具体拓展实现类。
@SPI
public interface ExtensionFactory {
/**
* Get extension.
*
* @param type object type.
* @param name object name.
* @return object instance.
*/
<T> T getExtension(Class<T> type, String name);
}
objectFactory是在构造ExtensionLoader时必须要创建的:是ExtensionFactory的自适应实例。
private ExtensionLoader(Class<?> type) {
this.type = type;
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
来看下AdaptiveExtensionFactory:
public class AdaptiveExtensionFactory implements ExtensionFactory {
/**
* ExtensionFactory 拓展对象集合
*/
private final List<ExtensionFactory> factories;
public AdaptiveExtensionFactory() {
//使用 ExtensionLoader 加载拓展对象实现类。
ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
for (String name : loader.getSupportedExtensions()) {
list.add(loader.getExtension(name));
}
factories = Collections.unmodifiableList(list);
}
@Override
public <T> T getExtension(Class<T> type, String name) {
// 遍历工厂数组,直到获得到属性
for (ExtensionFactory factory : factories) {
T extension = factory.getExtension(type, name);
if (extension != null) {
return extension;
}
}
return null;
}
}
AdaptiveExtensionFactory维护了ExtensionFatocry的非自适应扩展实例数组,扩展实现类的自动装配就是通过对象工厂获取。这些扩展实例其实就两个:SpiExtensionFactory和SpringExtensionFactory。
ExtensionFactory的类实现体系:
SpringExtensionFactory.getExtension方法:
public <T> T getExtension(Class<T> type, String name) {
for (ApplicationContext context : contexts) {
if (context.containsBean(name)) {
Object bean = context.getBean(name);
if (type.isInstance(bean)) {
return (T) bean;
}
}
}
logger.warn("No spring extension (bean) named:" + name + ", try to find an extension (bean) of type " + type.getName());
if (Object.class == type) {
return null;
}
for (ApplicationContext context : contexts) {
try {
return context.getBean(type);
} catch (NoUniqueBeanDefinitionException multiBeanExe) {
logger.warn("Find more than 1 spring extensions (beans) of type " + type.getName() + ", will stop auto injection. Please make sure you have specified the concrete parameter type and there's only one extension of that type.");
} catch (NoSuchBeanDefinitionException noBeanExe) {
if (logger.isDebugEnabled()) {
logger.debug("Error when get spring extension(bean) for type:" + type.getName(), noBeanExe);
}
}
}
logger.warn("No spring extension (bean) named:" + name + ", type:" + type.getName() + " found, stop get bean.");
return null;
}
遍历 contexts ,调用其 ApplicationContext#getBean(name) 方法和ApplicationContext#getBean(type) 获得 Bean 对象,直到成功并且值类型正确。
SpiExtensionFactory.getExtension方法:
@Override
public <T> T getExtension(Class<T> type, String name) {
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
if (!loader.getSupportedExtensions().isEmpty()) {
return loader.getAdaptiveExtension();
}
}
return null;
}
[外链图片转存失败(img-82fnwHjS-1564366186551)(media/15497013856273/15497828409936.jpg)]
自动包装
获取扩展点:getExtension
public T getExtension(String name) {
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Extension name == null");
if ("true".equals(name)) {
// 查找 默认的 拓展对象
return getDefaultExtension();
}
// 从缓存中获得对应的拓展对象
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<Object>());
holder = cachedInstances.get(name);
}
Object instance = holder.get();
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
// 从缓存中未获取到,进行创建缓存对象。
instance = createExtension(name);
//设置创建对象到缓存中
holder.set(instance);
}
}
}
return (T) instance;
}
创建拓展名的拓展对象:createExtension(name)
private T createExtension(String name) {
// 获得拓展名对应的拓展实现类
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
// 从缓存中,获得拓展对象。
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
// 当缓存不存在时,创建拓展对象,并添加到缓存中。
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
// 注入依赖的属性
injectExtension(instance);
// 创建 Wrapper 拓展对象
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
type + ") could not be instantiated: " + t.getMessage(), t);
}
}
看下官网对Wrapper得解释:
Wrapper 类同样实现了扩展点接口,但是 Wrapper 不是扩展点的真正实现。它的用途主要是用于从 ExtensionLoader 返回扩展点时,包装在真正的扩展点实现外。即从 ExtensionLoader 中返回的实际上是 Wrapper 类的实例,Wrapper 持有了实际的扩展点实现类。
扩展点的 Wrapper 类可以有多个,也可以根据需要新增。
通过 Wrapper 类可以把所有扩展点公共逻辑移至 Wrapper 中。新加的 Wrapper 在所有的扩展点上添加了逻辑,有些类似 AOP,即 Wrapper 代理了扩展点。
例如:ListenerExporterWrapper、ProtocolFilterWrapper
先到这里喽~完