dubbo|dubbo源码系列2——spi源码解读(下)
今天是2021年10月1号,在此祝伟大的祖国母亲生日快乐,繁荣昌盛!
上一节对sdk spi机制从源码角度进行了分析,文末留下思考:jdk spi有什么缺点?总结如下:
- 无法按需加载
ServiceLoader通过LazyIterator实现延迟加载,但是加载时仍然是遍历所有的类进行实例化,无法按需加载;
- 多线程非安全
ServiceLoader方法都是static,在并发时可能出现意想不到的线程安全问题;
- demo
- 拓展点分析
- ioc
- aop
- 总结
package xu.jiang.hua.dubbo.api.service;
import org.apache.dubbo.common.extension.SPI;
@SPI("volleyball")
public interface Sport {public void play();
}
定义Sport接口,并且指定默认实现为volleyball.
@SPI
public interface Drink {void drink();
}
1.2、实现 //篮球实现
package xu.jiang.hua.dubbo.api.service.impl;
import xu.jiang.hua.dubbo.api.service.Drink;
import xu.jiang.hua.dubbo.api.service.Sport;
public class BasketBallSport implements Sport {private Drink drink;
public void setDrink(Drink drink) {this.drink = drink;
}@Override
public void play() {System.out.print("运动前喝点饮料补充养分:");
drink.drink();
System.out.println("play basketball");
}
}
//排球实现
package xu.jiang.hua.dubbo.api.service.impl;
import xu.jiang.hua.dubbo.api.service.Sport;
public class VolleyballSport implements Sport {@Override
public void play() {System.out.println("play volleyballSport");
}
}
//FootBallSport
package xu.jiang.hua.dubbo.api.service.impl;
import org.apache.dubbo.common.extension.Adaptive;
import xu.jiang.hua.dubbo.api.service.Sport;
@Adaptive
public class FootBallSport implements Sport {@Override
public void play() {System.out.println("play football");
}
}
并通过@Adaptive标示FootBallSport 为Sport的自适应类。
//运动切面
package xu.jiang.hua.dubbo.api.service.impl;
import xu.jiang.hua.dubbo.api.service.Sport;
public class SportWrapper1 implements Sport {private Sport sport;
public SportWrapper1(Sport sport) {this.sport = sport;
}
@Override
public void play() {System.out.println("运动前1");
sport.play();
System.out.println("运动后1");
}
}
【dubbo|dubbo源码系列2——spi源码解读(下)】//饮料实现
package xu.jiang.hua.dubbo.api.service.impl;
import org.apache.dubbo.common.extension.Adaptive;
import xu.jiang.hua.dubbo.api.service.Drink;
@Adaptive
public class MineralWater implements Drink {@Override
public void drink() {System.out.println("喝矿泉水");
}
}
并通过@Adaptive标示MineralWater为Drink的自适应类。
1.3、配置
- xu.jiang.hua.dubbo.api.service.Sport
basketBall=xu.jiang.hua.dubbo.api.service.impl.BasketBallSport
volleyball=xu.jiang.hua.dubbo.api.service.impl.VolleyballSport
footBall=xu.jiang.hua.dubbo.api.service.impl.FootBallSport
xu.jiang.hua.dubbo.api.service.impl.SportWrapper1
- xu.jiang.hua.dubbo.api.service.Drink
mineralWater=xu.jiang.hua.dubbo.api.service.impl.MineralWater
public class MainTest {public static void main(String[] args) {System.out.println("...........getExtension............");
Sport basketBall = ExtensionLoader.getExtensionLoader(Sport.class).getExtension("basketBall");
basketBall.play();
System.out.println("...........getDefaultExtension............");
Sport defaultSport = ExtensionLoader.getExtensionLoader(Sport.class).getDefaultExtension();
defaultSport.play();
System.out.println("...........getAdaptiveExtension............");
Sport adaptiveSport = ExtensionLoader.getExtensionLoader(Sport.class).getAdaptiveExtension();
adaptiveSport.play();
}
}
文章图片
从执行结果来看,basketBall这个拓展点的方法执行前后有SportWrapper1类进行拦截,同时通过dubbo spi机制注入Drink接口。
因Sport接口上@SPI(“volleyball”)上指定了默认实现,因此getDefaultExtension返回VolleyballSport;
2、拓展点分析 下面以上面demo为例深入源码分析内部实现逻辑。
2.1、getExtensionLoader 可以看到加载任何拓展点都需要先执行getExtensionLoader
public static ExtensionLoader getExtensionLoader(Class type) {//省略非关键代码
ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
if (loader == null) {//new ExtensionLoader(type)
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));
loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
}
return loader;
}
继续分析new ExtensionLoader(type),如下:
private ExtensionLoader(Class> type) {this.type = type;
/** 逻辑解读:
*1、传入的type为非ExtensionFactory时,则执行ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
*2、则再次调用new ExtensionLoader(Class> type),则再次执行ExtensionLoader的构造函数,此时type为ExtensionFactory,objectFactory为null;
*3、根据返回的ExtensionLoader,再执行方法getAdaptiveExtension;
*4、加载META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory的内容,里面有SpiExtensionFactory和AdaptiveExtensionFactory,
*因AdaptiveExtensionFactory被@Adaptive注解标注,则getAdaptiveExtension返回AdaptiveExtensionFactory的实例对象
*5、接下来对AdaptiveExtensionFactory进行实例化,AdaptiveExtensionFactory属性factories仅有SpiExtensionFactory(通过cachedClasses获取)
*/
objectFactory =
(type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
对type为非ExtensionFactory生成的ExtensionLoader,objectFactory为SpiExtensionFactory。
2.2、getExtension
public T getExtension(String name, boolean wrap) {//省略非关键代码
if ("true".equals(name)) {return getDefaultExtension();
}
final Holder
解析来分析createExtension方法(重点)
private T createExtension(String name, boolean wrap) {//A、加载配置返回map,并根据name获取对应的类
Class> clazz = getExtensionClasses().get(name);
if (clazz == null || unacceptableExceptions.contains(name)) {throw findException(name);
}
try {T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {//实例化
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//B、ioc注入
injectExtension(instance);
//C、aop处理
if (wrap) {List> wrapperClassesList = new ArrayList<>();
//找出所有的Wrapper并排序
if (cachedWrapperClasses != null) {wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
//倒叙List
}if (CollectionUtils.isNotEmpty(wrapperClassesList)) {for (Class> wrapperClass : wrapperClassesList) {//获取wrapper注解,如果为非空,则需要判断注解的上的match和mismatch是否与当前name匹配。如果不匹配,不生成aop实例
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
if (wrapper == null
|| (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {/**
* wrapperClass.getConstructor(type).newInstance(instance) 实例化warpper类(aop类),将新生成的
* 实例赋值给instance,从而实现aop
*
* injectExtension 对warpper类实现ioc set
*/
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
}
}initExtension(instance);
return instance;
} catch (Throwable t) {//省略非关键代码
}
}
createExtension方法主要分成以下三部分:
- getExtensionClasses加载配置文件
- ioc处理
- aop处理
2.3、getExtensionClasses
private Map> loadExtensionClasses() {//A、加载当前接口的默认实现类
cacheDefaultExtensionName();
Map> extensionClasses = new HashMap<>();
/**B、加载配置文件
*
* 策略模式,分别加载以下路径:
* 1、META-INF/dubbo/internal/
* 2、META-INF/dubbo
* 3、META-INF/Service
*/
for (LoadingStrategy strategy : strategies) {loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(),
strategy.overridden(), strategy.excludedPackages());
loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"),
strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
}return extensionClasses;
}
第一部分默认实现类的处理:
private void cacheDefaultExtensionName() {final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation == null) {return;
}
//通过注解获取默认值,
String value = https://www.it610.com/article/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中
cachedDefaultName = names[0];
}
}
}
比如Sport有默认实现volleyball,如下所示:
文章图片
再看第二部分加载配置文件,目前支持以下三种路径:
- META-INF/dubbo/internal/
- META-INF/dubbo
- META-INF/Service
为了兼容dubbo移交给apache成为旗下的顶级项目,同时也会将type接口名中的org.apache换成com.alibaba。接下来看loadDirectory方法:
private void loadDirectory(Map> extensionClasses, String dir, String type,
boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) {String fileName = dir + type;
//省略非关键代码
if (urls != null) {while (urls.hasMoreElements()) {java.net.URL resourceURL = urls.nextElement();
//加载Resourece
loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages);
}
}
} catch (Throwable t) {//省略非关键代码
}
}
接下来看loadResource方法
private void loadResource(Map> extensionClasses, ClassLoader classLoader,
java.net.URL resourceURL, boolean overridden, String... excludedPackages) {try {try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {String line;
String clazz = null;
//依次读取里面的内容
while ((line = reader.readLine()) != null) {//#是注释符号,
final int ci = line.indexOf('#');
if (ci >= 0) {line = line.substring(0, ci);
//取注释符号前作为类名
}
line = line.trim();
if (line.length() > 0) {try {String name = null;
int i = line.indexOf('=');
if (i > 0) {name = line.substring(0, i).trim();
clazz = line.substring(i + 1).trim();
} else {clazz = line;
//如果无=,则认为是当前接口的warpper类
}
//加载的类非空且不在排除的类集合里面,则执行loadClass
if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages)) {loadClass(extensionClasses, resourceURL, Class.forName(clazz, true, classLoader), name, overridden);
}
} catch (Throwable t) {//省略非关键代码
}
}
}
}
} catch (Throwable t) {//省略非关键代码
}
}
loadResource说明:依次读取每行,过滤掉注释内容,然后判断当前行是否包含=。如果不包含,则认为该行是该接口Wrapper类(aop实现类),继续看loadClass方法:
private void loadClass(Map> extensionClasses, java.net.URL resourceURL, Class> clazz, String name,
boolean overridden) throws NoSuchMethodException {//省略关键代码
//A、自适应类
if (clazz.isAnnotationPresent(Adaptive.class)) {cacheAdaptiveClass(clazz, overridden);
//cachedAdaptiveClass
//B、判断是否为wrapper类—判断该类是否存在一个参数为该接口的构造函数。如存在,则认为为wrapper类
} else if (isWrapperClass(clazz)) {cacheWrapperClass(clazz);
//cachedWrapperClasses
} else {//省略关键代码
String[] names = NAME_SEPARATOR.split(name);
//一个类可以当做多个拓展点,因此进行切分
if (ArrayUtils.isNotEmpty(names)) {cacheActivateClass(clazz, names[0]);
//cachedActivates
for (String n : names) {cacheName(clazz, n);
//存入map
saveInExtensionClass(extensionClasses, clazz, n, overridden);
}
}
}
}
loadClass可以拆解成三部分:
- Adaptive注解处理
如果该类被@Adaptive注解标注,则将该类保存在以下爱属性中。
private volatile Class> cachedAdaptiveClass = null;
- Wrapper类处理
private boolean isWrapperClass(Class> clazz) {try {//通过加载判断是否存在带接口的构造函数
clazz.getConstructor(type);
return true;
} catch (NoSuchMethodException e) {return false;
}
}
通过判断当前类是否存在以该接口为参数的构造函数。如果存在则认为为wrapper类,如果存在则将该列保存在
private Set> cachedWrapperClasses;
;- 其他处理
将name进行切分,分别存入Map> extensionClasses
中,如下所示:
private void saveInExtensionClass(Map> extensionClasses, Class> clazz, String name, boolean overridden) {Class> c = extensionClasses.get(name);
if (c == null || overridden) {extensionClasses.put(name, clazz);
} else if (c != clazz) {// duplicate implementation is unacceptable
unacceptableExceptions.add(name);
String duplicateMsg =
"Duplicate extension " + type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName();
logger.error(duplicateMsg);
throw new IllegalStateException(duplicateMsg);
}
}
总结一下getExtensionClasses加载配置后的保存情况:
- 接口默认实现类保存在
private String cachedDefaultName;
- 被@Adaptive标注的实现类
private volatile Class> cachedAdaptiveClass = null;
- warpper类
private Set> cachedWrapperClasses;
- 其他类
private final Holder
cachedClasses则作为getExtensionClasses的结果返回。
3、ioc ioc处理位于createExtension方法中,回顾一下createExtension方法:
private T createExtension(String name, boolean wrap) {//加载配置,并根据name返回对应的类
Class> clazz = getExtensionClasses().get(name);
if (clazz == null || unacceptableExceptions.contains(name)) {throw findException(name);
}
try {T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {//实例化
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//ioc注入
injectExtension(instance);
//省略其他
}
通过getExtensionClasses将配置加载到map中并根据name获取对应类,然后进行实例化,实例化后执行injectExtension处理ioc。下面看看injectExtension方法:
private T injectExtension(T instance) {if (objectFactory == null) {return instance;
}try {for (Method method : instance.getClass().getMethods()) {if (!isSetter(method)) {continue;
}
/**
* Check {@link DisableInject} to see if we need auto injection for this property
*/
//set方法如果不想被ioc使用,则通过注解标示
if (method.getAnnotation(DisableInject.class) != null) {continue;
}
Class> pt = method.getParameterTypes()[0];
if (ReflectUtils.isPrimitives(pt)) {continue;
}try {String property = getSetterProperty(method);
//通过type和名字从objectFactory获取
Object object = objectFactory.getExtension(pt, property);
if (object != null) {//反射调用方法
method.invoke(instance, object);
}
} catch (Exception e) {//省略非关键代码
}}
} catch (Exception e) {logger.error(e.getMessage(), e);
}
return instance;
}
接下来看如何通过objectFactory.getExtension(pt, property)从上下文获取实例。根据ExtensionLoader实例化分析可知,objectFactory为AdaptiveExtensionFactory,如下:
文章图片
public T getExtension(Class type, String name) {for (ExtensionFactory factory : factories) {T extension = factory.getExtension(type, name);
if (extension != null) {return extension;
}
}
return null;
}
此时facory中仅有SpiExtensionFactory,执行getExtension方法返回实例。下面看看getExtension如何执行的?
public class SpiExtensionFactory implements ExtensionFactory {@Override
public T getExtension(Class type, String name) {if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {ExtensionLoader loader = ExtensionLoader.getExtensionLoader(type);
/**
* 如果type仅有一个实现类并且类上有一个@Adaptive标注,此时loader.getSupportedExtensions()
* 返回为空,则getExtension返回null。为什么?
*/
if (!loader.getSupportedExtensions().isEmpty()) {//返回自适应类
return loader.getAdaptiveExtension();
}
}
return null;
}}
分析getAdaptiveExtension:
public T getAdaptiveExtension() {Object instance = cachedAdaptiveInstance.get();
//省略非关键代码
synchronized (cachedAdaptiveInstance) {instance = cachedAdaptiveInstance.get();
if (instance == null) {try {//创建adaptiveExtension实例
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {createAdaptiveInstanceError = t;
throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
}return (T) instance;
}
继续分析createAdaptiveExtension:
private T createAdaptiveExtension() {try {//获取adaptiveExtension类并实例化,然后执ioc
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {//省略非关键代码
}
}
重点看getAdaptiveExtensionClass()方法
private Class> getAdaptiveExtensionClass() {getExtensionClasses();
//优先使用被@Adaptive标注的类
if (cachedAdaptiveClass != null) {return cachedAdaptiveClass;
}
//如果当前接口不存在Adaptive注解标注的实现类,那么需要手动编译方法
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
可以看到ioc注入的实例获取的优先级:
- @Adaptive标注的类
- 动态生成自适应类(方法上必须有@Adaptive注解,否则抛异常)。运行时通过传递url指定接口的实现类,如果传递的url未匹配上且有默认实现,则使用默认实现
3.1、@Adaptive在类上
@Adaptive
public class MineralWater implements Drink {@Override
public void drink(URL url) {System.out.println("喝矿泉水");
}
}
文章图片
3.2、@Adaptive在方法上 将MineralWater上的@Adaptive注解去掉,同时方法加上@Adaptive并设定key为drink,则运行通过url里面map参数指定具体的实现。
@SPI("mineralWater")
public interface Drink {@Adaptive({
"drink"})
void drink(URL url);
}
文章图片
private Class> createAdaptiveExtensionClass() {//生成代理类时判断方法上是否有@Adaptive注解修饰,如果没有,则抛出异常
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
ClassLoader classLoader = findClassLoader();
org.apache.dubbo.common.compiler.Compiler compiler =
//AdaptiveCompiler
ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
3.3、自动生成的自适应类
package xu.jiang.hua.dubbo.api.service;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Drink$Adaptive implements xu.jiang.hua.dubbo.api.service.Drink {public void drink(org.apache.dubbo.common.URL arg0){ if (arg0 == null)
throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
//因为接口上指定了默认实现为mineralWater,则如果取不到则使用默认的实现
String extName = url.getParameter("drink", "mineralWater");
if(extName == null)
throw new IllegalStateException("Failed to get extension (xu.jiang.hua.dubbo.api.service.Drink) name from url (" + url.toString() + ") use keys([drink])");
xu.jiang.hua.dubbo.api.service.Drink extension = (xu.jiang.hua.dubbo.api.service.Drink)ExtensionLoader.getExtensionLoader(xu.jiang.hua.dubbo.api.service.Drink.class).getExtension(extName);
extension.drink(arg0);
}
}
文章图片
将生成的自适应类通过反射赋给BasketBallSport实例, 运行时通过URL指定具体的实现:
URL url=URL.valueOf(“http://127.0.0.1”);
url= url.addParameter(“drink”,“mineralWater”);
drink.drink(url);
3.3、ioc总结 通过injectExtension方法和类上的set方法实现依赖注入,获取的实例的优先级如下:
- A、@Adaptive标记类生成的实例;
- B、根据@Adaptive标记的方法自动编译生成自适应类,运行时如果匹配失败且有默认实现类,则使用默认类。
private T createExtension(String name, boolean wrap) {//省略非关键代码
//ioc注入
injectExtension(instance);
//aop处理
if (wrap) {List> wrapperClassesList = new ArrayList<>();
//找出所有的Wrapper并排序
if (cachedWrapperClasses != null) {wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
//倒叙List
}if (CollectionUtils.isNotEmpty(wrapperClassesList)) {for (Class> wrapperClass : wrapperClassesList) {//获取wrapper注解,如果为非空,则需要判断注解的上的match和mismatch是否与当前name匹配。如果不匹配,不生成aop实例
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
if (wrapper == null
|| (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {/**
* wrapperClass.getConstructor(type).newInstance(instance) 实例化warpper类(aop类),将新生成的
* 实例赋值给instance,从而实现aop
*
* injectExtension 对warpper类实现ioc set
*/
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
}
}initExtension(instance);
return instance;
} catch (Throwable t) {}
}
前面getExtensionClasses方法中已经分析过warpper类会保存在
private Set> cachedWrapperClasses;
取出所有的cachedWrapperClasses并排序。接下来重点看
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance))
从warpper类中取出具有接口参数的构造函数,并向构造函数传入当前实例进行warpper类的实例化,然后进行ioc处理(warpper类可能也有依赖注入),然后赋值给instance(前后instance不是同一个对象),如下所示:
文章图片
文章图片
可以看到instantce不是同一个对象,新生成的instance包含之前的instance。
5、总结 每个拓展点都会通过getExtensionLoader生成ExtensionLoader实例。
- getExtension
getExtension通过传入的name实现按需实例化;
- getDefaultExtension
getDefaultExtension返回接口的默认实现, 默认实现的 类名保存在
private String cachedDefaultName;
- getAdaptiveExtension
getDefaultExtension返回接口的自适应类。优先使用@Adaptive标注的类,保存在cachedAdaptiveClass。如果无@Adaptive标记的类,则根据@Adaptive标记的方法自动生成自适应类;
private volatile Class> cachedAdaptiveClass = null;
- ioc
获取当前接口getAdaptiveExtension返回实例进行依赖注入;如果getAdaptiveExtension为空且有默认实现,则使用默认实现,否则不注入;
- aop
根据getExtensionClasses得到接口的warpper类集合实现链式增强并作为新实例返回。
private Set> cachedWrapperClasses;
推荐阅读
- 【欢喜是你·三宅系列①】⑶
- dubbo基本认识
- 你不可不知的真相系列之科学
- 人脸识别|【人脸识别系列】| 实现自动化妆
- Android事件传递源码分析
- 2018-06-13金句系列7(金句结构-改编古现代诗词)
- Quartz|Quartz 源码解析(四) —— QuartzScheduler和Listener事件监听
- Unity和Android通信系列文章2——扩展UnityPlayerActivity
- 乡野村趣系列之烧仙草
- Java内存泄漏分析系列之二(jstack生成的Thread|Java内存泄漏分析系列之二:jstack生成的Thread Dump日志结构解析)