Dubbo源码篇07---SPI神秘的面纱---原理篇---下
- 引言
- 根据name获取扩展实例对象
- 获取默认扩展实例对象
- 按条件批量获取扩展实例对象
- 实例演示
- 小结
引言
上篇文章: Dubbo源码篇06—SPI神秘的面纱—原理篇—上 我们追踪了getAdaptiveExtension
获取自适应扩展点的整个流程,整个流程核心如下:
private T createAdaptiveExtension() {
T instance = (T) getAdaptiveExtensionClass().newInstance();
instance = postProcessBeforeInitialization(instance, null);
injectExtension(instance);
instance = postProcessAfterInitialization(instance, null);
initExtension(instance);
return instance;
}
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
因为自适应扩展点在dubbo中的用意是用来实现运行时动态选择实现类的,所以不会对自适应扩展点赋予AOP能力,从上面的流程中我们也没有发现哪里存在Wrapper机制的处理。
所以本文我们顺着普通扩展类加载流程,来过一遍dubbo对AOP的处理过程:
ApplicationModel applicationModel = ApplicationModel.defaultModel();
ExtensionLoader<FrameWork> extensionLoader = applicationModel.getExtensionLoader(FrameWork.class);
FrameWork frameWork = extensionLoader.getExtension("guice");
根据name获取扩展实例对象
根据传入的name作为serviceKey去加载对应的扩展实现:
public T getExtension(String name) {
//第二个参数表明是否对当前扩展类启动Wrapper装饰
T extension = getExtension(name, true);
if (extension == null) {
throw new IllegalArgumentException("Not find extension: " + name);
}
return extension;
}
public T getExtension(String name, boolean wrap) {
...
//如果name为true,那么去获取默认扩展实现
if ("true".equals(name)) {
return getDefaultExtension();
}
String cacheKey = name;
if (!wrap) {
cacheKey += "_origin";
}
//查询缓存--没有新建一个Holder返回
final Holder<Object> holder = getOrCreateHolder(cacheKey);
Object instance = holder.get();
//缓存有,直接返回,否则进入创建逻辑
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//创建扩展类的核心方法
instance = createExtension(name, wrap);
holder.set(instance);
}
}
}
return (T) instance;
}
private T createExtension(String name, boolean wrap) {
//getExtensionClasses方法上篇文章解析过了,这里跳过
Class<?> clazz = getExtensionClasses().get(name);
//如果没有key=name的扩展实现,则抛出异常
if (clazz == null || unacceptableExceptions.contains(name)) {
throw findException(name);
}
try {
// 判断对应的扩展实现类型是否已经创建过了实例对象--确保单例性
T instance = (T) extensionInstances.get(clazz);
//如果只是解析了SPI文件,构成了<name,class>缓存,下一步就是为当前扩展类型构建<class,signleInstance>缓存
if (instance == null) {
//利用instantiationStrategy实例化扩展实例对象---具体逻辑在InstantiationStrategy中
//实例化逻辑比较简单: 要不就是默认构造,要么构造函数可以有参数,但是参数类型必须是ScopeModel子类
extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));
instance = (T) extensionInstances.get(clazz);
//前后置处理--依赖注入
instance = postProcessBeforeInitialization(instance, name);
injectExtension(instance);
instance = postProcessAfterInitialization(instance, name);
}
//和自适应扩展点创建的不同逻辑: 判断是否需要对当前扩展实例进行装饰
if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList<>();
//当前扩展类相关wrapper类型搜集工作在getExtensionClasses中完成
if (cachedWrapperClasses != null) {
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
}
//wrapper class搜集是满足存在一个单参数的拷贝构造函数,并且参数类型为当前扩展类类型
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
//不断循环,套娃创建一层层的装饰器对象
for (Class<?> wrapperClass : wrapperClassesList) {
//Wrapper注解用于实现按条件装饰
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
//如果wrapper class类上不存在Wrapper注解,那么表示装饰不需要满足任何条件
//否则,需要判断条件是否满足,满足才会进行装饰
boolean match = (wrapper == null) ||
((ArrayUtils.isEmpty(wrapper.matches()) || ArrayUtils.contains(wrapper.matches(), name)) &&
!ArrayUtils.contains(wrapper.mismatches(), name));
if (match) {
//满足则进入装饰流程
//1.实例化当前装饰类,采用的是单参的拷贝构造函数
//2.执行依赖注入流程
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
//3.执行后置处理流程
instance = postProcessAfterInitialization(instance, name);
}
}
}
}
// Warning: After an instance of Lifecycle is wrapped by cachedWrapperClasses, it may not still be Lifecycle instance, this application may not invoke the lifecycle.initialize hook.
//调用初始化接口---注意上面警告信息,也就是说经过包装后,我们的包装对象未必继承lifecycle接口,因此初始化调用也就不会发生了
initExtension(instance);
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
获取默认扩展实例对象
采用@SPI注解中的val值,作为serviceKey去加载对应的扩展实现:
public T getDefaultExtension() {
//加载SPI文件,构建相关缓存,如: <name,class>
getExtensionClasses();
//cachedDefaultName来自@SPI注解中的val值
if (StringUtils.isBlank(cachedDefaultName) || "true".equals(cachedDefaultName)) {
return null;
}
//这个流程上面讲过了
return getExtension(cachedDefaultName);
}
按条件批量获取扩展实例对象
到现在为止,我们还差extensionLoader.getActivateExtensions()
流程没有讲解,下面我们来看看按条件批量获取扩展实例对象是怎样实现的:
public List<T> getActivateExtension(URL url, String key, String group) {
//根据传入的key从url中提取出value值
String value = url.getParameter(key);
//如果value不为空,则按照","分割,作为serviceKey
return getActivateExtension(url, StringUtils.isEmpty(value) ? null : COMMA_SPLIT_PATTERN.split(value), group);
}
public List<T> getActivateExtension(URL url, String[] values, String group) {
checkDestroyed();
// solve the bug of using @SPI's wrapper method to report a null pointer exception.
Map<Class<?>, T> activateExtensionsMap = new TreeMap<>(activateComparator);
List<String> names = values == null ? new ArrayList<>(0) : asList(values);
Set<String> namesSet = new HashSet<>(names);
if (!namesSet.contains(REMOVE_VALUE_PREFIX + DEFAULT_KEY)) {
//集合条件缓存构建: <serviceKey,groups> 和 <serviceKey,keyParis>
if (cachedActivateGroups.size() == 0) {
synchronized (cachedActivateGroups) {
// cache all extensions
if (cachedActivateGroups.size() == 0) {
//加载当前扩展类对应的SPI资源文件,并建立好相关缓存映射,此处主要为cachedActivates映射
//cachedActivates缓存了<serviceKey,@Activate注解> (serviceKey就是我们在SPI文件: serviceKey=serivceImpl全类名)
//如果配置文件中没有指定serviceKey,那么为@Extension注解中指定的val值,如果没有注解,那么就为实现类的简单类名
getExtensionClasses();
//依次处理当前扩展类下所有标注了@Activate注解的实现类
for (Map.Entry<String, Object> entry : cachedActivates.entrySet()) {
//key为serviceKey
String name = entry.getKey();
//activate注解
Object activate = entry.getValue();
String[] activateGroup, activateValue;
//提取注解中的值
if (activate instanceof Activate) {
activateGroup = ((Activate) activate).group();
activateValue = ((Activate) activate).value();
} else if (activate instanceof com.alibaba.dubbo.common.extension.Activate) {
activateGroup = ((com.alibaba.dubbo.common.extension.Activate) activate).group();
activateValue = ((com.alibaba.dubbo.common.extension.Activate) activate).value();
} else {
continue;
}
//缓存<serviceKey,groups>映射,即激活当前实现类,需要满足哪些分组要求(满足其一即可)
cachedActivateGroups.put(name, new HashSet<>(Arrays.asList(activateGroup)));
//缓存<serviceKey,keyParis>映射
//activate注解中的value属性有两种写法: key1:val1 或者 key2
//前者表示URL中存在key1=val1的键值对才算满足条件
//后置表示URL中存在key2即满足条件
String[][] keyPairs = new String[activateValue.length][];
for (int i = 0; i < activateValue.length; i++) {
if (activateValue[i].contains(":")) {
keyPairs[i] = new String[2];
String[] arr = activateValue[i].split(":");
keyPairs[i][0] = arr[0];
keyPairs[i][1] = arr[1];
} else {
keyPairs[i] = new String[1];
keyPairs[i][0] = activateValue[i];
}
}
cachedActivateValues.put(name, keyPairs);
}
}
}
}
// traverse all cached extensions
//遍历<serviceKey,groups>映射
cachedActivateGroups.forEach((name, activateGroup) -> {
// 如果函数调用中传入的group匹配条件为空,或者group存在于groups集合,则满足分组匹配这个条件
if (isMatchGroup(group, activateGroup)
//nameSet是从传入函数中的key,从url中获取value后,按照","分割,得到的集合
//这里去掉serviceKey=name的处理,因为该逻辑会在下面被处理
&& !namesSet.contains(name)
&& !namesSet.contains(REMOVE_VALUE_PREFIX + name)
//从<serviceKey,keyParis>集合中获取激活当前扩展实现类,需要满足哪些用户自定义条件
//这里判断逻辑就是: 如果用户指定的是形如@Active(value="key1:value1, key2:value2")
//那么会从url先中取出key1的值,与value1进行比较,相等直接返回true,否则取出key2值继续判断,也就是说这里是任意条件满足就返回true
//如果用户注解中只指定了@Active(value="key1"),那么只要url中存在key1,就满足条件
&& isActive(cachedActivateValues.get(name), url)) {
//如果分组条件和用户自定义条件都满足,则加入activateExtensionsMap集合<class,Instance>
activateExtensionsMap.put(getExtensionClass(name), getExtension(name));
}
});
}
if (namesSet.contains(DEFAULT_KEY)) {
...
} else {
// add extensions, will be sorted by its order
for (int i = 0; i < names.size(); i++) {
String name = names.get(i);
if (!name.startsWith(REMOVE_VALUE_PREFIX)
&& !namesSet.contains(REMOVE_VALUE_PREFIX + name)) {
if (!DEFAULT_KEY.equals(name)) {
//<serviceKey,class>集合中包含serviceKey=name
if (containsExtension(name)) {
//则将serviceKey=name的扩展实现类也加入结果集合
activateExtensionsMap.put(getExtensionClass(name), getExtension(name));
}
}
}
}
//返回最终得到的集合扩展实现类集合
return new ArrayList<>(activateExtensionsMap.values());
}
}
上面这一大段看下来可能会比较懵逼,但是没关系,下图详细解释了按照激活条件筛选的整个流程:
- 如果某个serviceKey对应的keyParis为空,也就是说用户没有自定义匹配条件,那么该条件分支默认返回true。
- 如果函数传入的group为空,那么不考虑分组匹配条件,该条件分支默认返回true
注意: 放入结果集合前,扩展类的获取调用的是getExtension方法,意味着按条件批量获取扩展实例对象场景下,实现类是享有AOP(Wrapper机制)支持的:
activateExtensionsMap.put(getExtensionClass(name), getExtension(name));
实例演示
- 扩展接口,及其实现类
@SPI("spring")
public interface FrameWork {
@Adaptive
String getName(URL url);
String getInfo();
}
@Activate(value = {"name:dhy","age:18"},group = "test")
public class Guice implements FrameWork{
@Override
public String getName(URL url) {
return "guice";
}
@Override
public String getInfo() {
return "google 开源的轻量级IOC框架";
}
}
@Activate(value = {"name","sex"},group = "test")
public class Spring implements FrameWork{
@Override
public String getName(URL url) {
return "spring";
}
@Override
public String getInfo() {
return "流行的Spring框架";
}
}
@Activate(group = "prod")
public class SpringBoot implements FrameWork{
@Override
public String getName(URL url) {
return "springBoot";
}
@Override
public String getInfo() {
return "自动化的SpringBoot框架";
}
}
- SPI文件内容
spring=com.adaptive.Spring
springBoot=com.adaptive.SpringBoot
guice=com.adaptive.Guice
- 测试类
class ActivateTest {
@Test
void activateTest() {
ApplicationModel applicationModel = ApplicationModel.defaultModel();
ExtensionLoader<FrameWork> extensionLoader = applicationModel.getExtensionLoader(FrameWork.class);
List<FrameWork> frameWorkList = extensionLoader.getActivateExtension(URL.valueOf("dubbo://127.0.0.1:80/?age=18"), "", "test");
frameWorkList.forEach(frameWork -> {
System.out.println(frameWork.getInfo());
});
}
}
大家可自行更改参数条件,测试其他分支。
小结
本文主要带领大家过了一遍普通扩展类的加载流程,看到了普通扩展类加载与自适应扩展点加载的不同的之处,区别在于自适应扩展点没有Wrapper机制支持,这是因为自适应扩展点设计的本意是运行时根据条件动态选择扩展类。
@Acativate注解按运行时条件决定是否激活当前扩展实现类,并且可以激活满足条件的所有扩展实现类,所以是按条件批量激活。
按条件批量激活的扩展实现类只是在普通扩展类基础上加了一层按条件激活,因此满足条件时,最终获取按条件激活的扩展实现类也是调用的getExtension方法,可知也是享有dubbo提供的Wrapper机制支持的。
自适应扩展点是通过方法参数传入URL,在自适应扩展点内部根据条件判断选择哪个扩展实现。而按条件激活扩展,是在getActivateExtension方法内部进行的条件判断,这一点大家需要注意一下。
普通扩展类,自适应扩展点和按条件激活的扩展类加载,三种方式都享有依赖注入和前后置处理支持。