title: Dubbo SPI机制分析【二】
tags: Dubbo,SPI,源码
grammar_cjkRuby: true
上回Dubbo SPI机制分析【一】分析了ExtensionLoader.getExtensionLoader.getAdaptiveExtension
的过程,接下来继续分析ExtensionLoader.getExtension
:
源码分析
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
createExtension
private T createExtension(String name) {
//加载所有拓展点实现类,然后根据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);
//进行包装类封装
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);
}
}
这段代码一共做了这么几件事:
-
加载拓展点实现类
-
实例化拓展点实现类,并且进行注入
-
遍历当前拓展点的包装类,并且将当前
name
对应的拓展点实例作为参数传入该包装类实例的构造函数,将该包装类实例化,如图
1539354624379.png
-
最后返回实例
总结
至此,getExtension
分析完毕,主要需要注意的一点就是,通过此方法返回的实例最后可能会通过包装类进行包装,做一些特殊处理,形成一个链式调用,最后才会真正调用到特定实例的具体方法。
那么还有个问题,对于
ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()
这段代码,最后返回的Protocol类型,具体是怎样的呢?
-首先通过getAdaptiveExtension
获取到的是Protocol$Adaptive
:
package com.wl.dubbo;
/**
* @Author: liumenglong
* @Date: 2018/9/29 22:48
* @Description:
*/
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {
throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
if (arg1 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;
//根据URL获取到对应的拓展名,如果没有指定,则默认取“dubbo”
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
//根据拓展名获取对应的拓展点实现类
com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
//调用实际拓展点的refer方法,如DubboProtocol
return extension.refer(arg0, arg1);
}
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
com.alibaba.dubbo.common.URL url = arg0.getUrl();
//根据URL获取到对应的拓展名,如果没有指定,则默认取“dubbo”
String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
if (extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
//根据拓展名获取对应的拓展点实现类
com.alibaba.dubbo.rpc.Protocol extension =
(com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.
getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
//调用实际拓展点的export方法,如DubboProtocol
return extension.export(arg0);
}
}
查看方法export
,最后的调用还是需要先获得具体的Protocol:
//根据拓展名获取对应的拓展点实现类
com.alibaba.dubbo.rpc.Protocol extension =
(com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.
getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
那么也就是说最后需要通过getExtension
来获取特定的Protocol
,而此时extName
为dubbo
,那么应该返回的就是DubboProtocol
,然而在上面分析我们可以知道,DubboProtcol
在实例化之后,需要经过包装类的封装,因此通过此方法最后返回的Protocol
是ProtocolListenerWrapper

网友评论