dubbo自定義SPI
為什么dubbo要自己設(shè)計一套SPI脖含?
- JDK標(biāo)準(zhǔn)的SPI會一次性實例化擴展點所有實現(xiàn)比规,如果有擴展實現(xiàn)初始化很耗時守屉,而且沒用上也加載夷野,會很浪費資源;
- 增加了對擴展點IOC和AOP的支持荣倾,一個擴展點可以直接setter注入其它擴展點悯搔。
- 這是原始JDK spi的代碼
ServiceLoader<Command> serviceLoader=ServiceLoader.load(Command.class);
for(Command command:serviceLoader){
command.execute();
}
dubbo在原來的基礎(chǔ)上設(shè)計了以下功能:
- 原始JDK spi不支持緩存;dubbo設(shè)計了緩存對象:spi的key與value 緩存在
cachedInstances
對象里面舌仍,它是一個ConcurrentMap妒貌; - 原始JDK spi不支持默認值,dubbo設(shè)計默認值:
@SPI("dubbo")
代表默認的spi對象铸豁。例如:
Protocol的@SPI("dubbo")
就是DubboProtocol
,通過ExtensionLoader.getExtensionLoader(Protocol.class).getDefaultExtension()
拿默認對象 - jdk要用for循環(huán)判斷對象灌曙,dubbo設(shè)計getExtension靈活方便,動態(tài)獲取spi對象节芥。例如:
ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(spi的key)
來提取對象; - 原始JDK spi不支持 AOP功能在刺,dubbo設(shè)計增加了AOP功能,在
cachedWrapperClasses
,在原始spi類头镊,包裝了XxxxFilterWrapper XxxxListenerWrapper
蚣驼; - 原始JDK spi不支持 IOC功能,dubbo設(shè)計增加了IOC,通過set注入:
injectExtension(T instance)
相艇。
Dubbo的SPI約定
擴展點的配置都放到\META-INF\dubbo\internal
路徑下隙姿,且文件名為擴展接口的包名+接口名;文件內(nèi)容為:擴展名=實現(xiàn)類的包名+類名厂捞,例Protocol的SPI配置:
\META-INF\dubbo\internal\com.alibaba.dubbo.rpc.Protocol
injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=com.alibaba.dubbo.rpc.support.MockProtocol
擴展點類型
dubbo為了實現(xiàn)IOC和AOP输玷,設(shè)計了多種功能不同的擴展點。我們可以根據(jù)擴展點功能的不同把擴展點大致分成4類:
擴展點類型 | 說明 |
---|---|
Adaptive | 含有Adaptive注解的擴展點 |
Wrapper | 含有構(gòu)造函數(shù)的參數(shù)為擴展點接口類型的擴展點 1.Filter 2.Listener |
Activate | 含有Activate注解的擴展點 |
其他 | 普通擴展點 |
如Protocol的所有擴展點如下:
injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=com.alibaba.dubbo.rpc.support.MockProtocol
我們可以按照上面的規(guī)則將所有的Protocol擴展點分類:
擴展點類型 | 名稱 |
---|---|
Adaptive | Protocol$Adaptive(動態(tài)編譯) |
Wrapper | filter靡馁,listener |
其他 | injvm欲鹏,registry,dubbo臭墨,mock |
通過ExtensionLoader.getExtensionLoader(Protpcol.class).getAdaptiveExtension()
創(chuàng)建Protpcol的默認擴展點“dubbo”赔嚎,而如果我們調(diào)用得到的這個實例的方法,它的實際調(diào)用流程卻是
Protocol$Adaptive->ProtocolFilterWrapper->ProtocolListenerWrapper->DubboProtocol
似乎跟Spring的AOP很像胧弛,跟一下源碼尤误,來一探究竟。
源碼分析
- dubbo spi 的目的:獲取一個指定實現(xiàn)類的對象结缚。
- 途徑:
ExtensionLoader.getExtension(String name)
- 實現(xiàn)路徑:
getExtensionLoader(Class<T> type)
就是為該接口new 一個ExtensionLoader损晤,然后緩存起來。
getAdaptiveExtension()
獲取一個擴展類红竭,如果@Adaptive注解在類上就是一個裝飾類尤勋;如果注解在方法上就是一個動態(tài)代理類喘落,例如Protocol$Adaptive對象。
getExtension(String name)
獲取一個指定擴展點的對象最冰。
在dubbo的源碼中隨處可見獲取擴展點的例子,我們看下面加載Protocol.class的擴展點dubbo
的例子瘦棋。
package com.alibaba.dubbo.rpc;
@SPI("dubbo")
public interface Protocol {
int getDefaultPort();
@Adaptive
<T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
@Adaptive
<T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
void destroy();
}
- 在
META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol
中可以知道Protocol.class
有很多擴展點,其中就有名為dubbo的擴展點暖哨。
injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
registry=com.alibaba.dubbo.registry.integration.RegistryProtocol
dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock=com.alibaba.dubbo.rpc.support.MockProtocol
1. 獲取擴展點加載器
首先認識一下擴展點加載器赌朋,他的靜態(tài)變量是一些全局的緩存,私有變量會在第一次獲取該擴展點實例的時候初始化
public class ExtensionLoader<T> {
private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);
/***所有ExtensionLoader共享變量***/
//擴展點的文件路徑
private static final String SERVICES_DIRECTORY = "META-INF/services/";
//擴展點的文件路徑
private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
//擴展點的文件路徑
private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
//緩存所有的ExtensionLoader篇裁,key是擴展點的接口類型
private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
//緩存擴展點的一個實例
private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();
// ==============================
/*****當(dāng)前ExtensionLoader的私有變量****/
//擴展點的接口類型
private final Class<?> type;
//擴展點IOC的實例來源
private final ExtensionFactory objectFactory;
//普通擴展點的名稱
private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String,Class<?>>>();
private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
//adaptive的類
private volatile Class<?> cachedAdaptiveClass = null;
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
//擴展點的默認名稱@SPI中的value
private String cachedDefaultName;
//緩存adaptive實例
private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
//緩存包裝類型的擴展點
private Set<Class<?>> cachedWrapperClasses;
getExtensionLoader()首先從緩存中獲取該擴展點的ExtensionLoader箕慧,如果緩存中不存在創(chuàng)建并緩存起來且key為擴展點的接口類型。
- 執(zhí)行流程分析
-----------------------ExtensionLoader.getExtensionLoader(Class<T> type)
ExtensionLoader.getExtensionLoader(Container.class)
-->this.type = type;
-->objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
-->ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()
-->this.type = type;
-->objectFactory =null;
/**
* @Author pengyunlong
* @Description 靜態(tài)方法茴恰,單例模式
* 首先從緩存中獲取擴展點加載器颠焦,如果緩存中不存在則創(chuàng)建
* @param
* @Date 2018/6/11 11:36
*/
@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) {
//緩存中部存在則創(chuàng)建
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
/**
* @Author pengyunlong
* @Description 構(gòu)造方法
* 擴展點加載器
* @param
* @Date 2018/6/7 18:38
*/
private ExtensionLoader(Class<?> type) {
//當(dāng)前擴展點的接口類型必須,含有SPI注解
this.type = type;
//objectFactory IOC需要從這個變量中加載對象實例并注入
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
執(zhí)行以上代碼完成了2個屬性的初始化
- 每個一個ExtensionLoader都包含了2個值: type 和 objectFactory
Class<?> type;
:要加載擴展點的接口
ExtensionFactory objectFactory
:為dubbo的IOC提供所有對象 - new 一個ExtensionLoader 存儲在
ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS
關(guān)于這個objectFactory的一些細節(jié):
- objectFactory就是通過
ExtensionLoader.getExtensionLoader(ExtensionFactory.class)
來實現(xiàn)的往枣,它的objectFactory=null伐庭; - objectFactory實際上是ExtensionFactory.class的Adaptive擴展。
getAdaptiveExtension()
獲取一個擴展類分冈,如果@Adaptive注解在類上就是一個裝飾類圾另;如果注解在方法上就是一個動態(tài)代理類。而在ExtensionFactory.class
的所有擴展實現(xiàn)中AdaptiveExtensionFactory類上有@Adaptive注解雕沉,所以ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension()
得到的就是AdaptiveExtensionFactory實例集乔。AdaptiveExtensionFactory為dubbo的IOC提供所有對象,內(nèi)部包含其他兩個擴展點SpiExtensionFactory,SpringExtensionFactory坡椒,后面會通過它們加載spring和dubbo中的實例注入到目標(biāo)對象的屬性中扰路;
【Dubbo】Adaptive
/**
* AdaptiveExtensionFactory
*/
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
/**
* @Author pengyunlong
* @Description 獲取到其他ExtensionFactory的實現(xiàn),并創(chuàng)建ExtensionFactory的實例
* SpiExtensionFactory倔叼,SpringExtensionFactory
* @param
* @Date 2018/6/7 17:58
*/
public AdaptiveExtensionFactory() {
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);
}
/**
* @Author pengyunlong
* @Description 從ExtensionFactory實例中(包括spring容器和spi)汗唱,加載擴展點指定擴展點實例
* @param
* @Date 2018/6/7 18:01
*/
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;
}
}
/**
* SpiExtensionFactory
*/
public class SpiExtensionFactory implements ExtensionFactory {
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;
}
}
package com.alibaba.dubbo.config.spring.extension;
/**
* SpringExtensionFactory
*/
public class SpringExtensionFactory implements ExtensionFactory {
@SuppressWarnings("unchecked")
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;
}
}
}
return null;
}
}
2.加載指定的擴展點
首先從緩存中獲取,如果緩存中不存在則通過createExtension(name)
創(chuàng)建并加入緩存
- 代碼執(zhí)行流程
-----------------------getExtension(String name)
getExtension(String name) //指定對象緩存在cachedInstances丈攒;get出來的對象wrapper對象哩罪,例如protocol就是ProtocolFilterWrapper和ProtocolListenerWrapper其中一個。
-->createExtension(String name)
-->getExtensionClasses()
-->injectExtension(T instance)//dubbo的IOC反轉(zhuǎn)控制巡验,就是從spi和spring里面提取對象賦值际插。
-->objectFactory.getExtension(pt, property)
-->SpiExtensionFactory.getExtension(type, name)
-->ExtensionLoader.getExtensionLoader(type)
-->loader.getAdaptiveExtension()
-->SpringExtensionFactory.getExtension(type, name)
-->context.getBean(name)
-->injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance))//AOP的簡單設(shè)計
/**
* Find the extension with the given name. If the specified name is not found, then {@link IllegalStateException}
* will be thrown.
* 根據(jù)擴展點名稱找到指定的擴展點,首先從緩存中獲取显设,如果緩存中不存在則創(chuàng)建
*/
@SuppressWarnings("unchecked")
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) {
//創(chuàng)建擴展點實例
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
創(chuàng)建擴展點實例
創(chuàng)建擴展點實例的過程:加載字節(jié)碼->創(chuàng)建實例-> 注入屬性->包裝框弛,所以我們最后拿到的擴展點實例其實有可能是一個包裝類。dubbo的IOC通過set注入完成敷硅,AOP通過wapper包裝完成功咒。
/**
* @Description
* 加載字節(jié)碼
* 創(chuàng)建實例
* 注入屬性
* 包裝
*/
@SuppressWarnings("unchecked")
private T createExtension(String name) {
//1.獲取指定擴展點的Class
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
//2.創(chuàng)建擴展點實例
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//3.實現(xiàn)dubbo IOC功能愉阎,從spring和dubbo中注入屬性到擴展點實例中來
injectExtension(instance);
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
for (Class<?> wrapperClass : wrapperClasses) {
//4.實現(xiàn)dubbo AOP功能,包裝擴展點實例
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);
}
}
- 解析該擴展點的類名
從三個路徑加載spi配置的class到緩存中绞蹦,META-INF/dubbo/internal/
力奋、META-INF/dubbo/
、META-INF/services/
幽七。loadfile()
加載過程中還會解析class中包含的注解來填充一些緩存變量景殷。
變量名 | 值 |
---|---|
cachedAdaptiveClass | 含有Adaptive注解的class |
cachedWrapperClasses | 無adative注解,并且構(gòu)造函數(shù)包含目標(biāo)接口(type)類型的class |
cachedActivates | 剩下的類含有Activate注解的class |
cachedNames | 其余的class |
/**
* @Author pengyunlong
* @Description 如果緩存為空則加載所有的擴展class并緩存起來
* @param
* @Date 2018/6/7 17:08
*/
private Map<String, Class<?>> getExtensionClasses() {
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
/**
* @Author pengyunlong
* @Description 從三個路徑加載spi配置的class到緩存中澡屡,cachedDefaultName為spi注解的value
* META-INF/dubbo/internal/ META-INF/dubbo/ META-INF/services/
* @param
* @Date 2018/6/7 17:18
*/
// synchronized in getExtensionClasses
private Map<String, Class<?>> loadExtensionClasses() {
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation != null) {
String value = defaultAnnotation.value();
if (value != null && (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<?>>();
loadFile(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
loadFile(extensionClasses, DUBBO_DIRECTORY);
loadFile(extensionClasses, SERVICES_DIRECTORY);
return extensionClasses;
}
通過把配置文件META-INF/dubbo/internal/com.alibaba.dubbo.rpc. Protocol
(fileName = dir + type.getName();
)的內(nèi)容猿挚,存儲在緩存變量里面。
關(guān)于loadfile的一些細節(jié)
cachedAdaptiveClass
如果這個class含有adative注解就賦值驶鹉,例如ExtensionFactory绩蜻,而例如Protocol在這個環(huán)節(jié)是沒有的。cachedWrapperClasses
只有當(dāng)該class無adative注解室埋,并且構(gòu)造函數(shù)包含目標(biāo)接口(type)類型办绝,例如protocol里面的spi就只有ProtocolFilterWrapper和ProtocolListenerWrapper
能命中cachedActivates
剩下的類,包含Activate注解cachedNames
剩下的類就存儲在這里姚淆。
/**
* @Author pengyunlong
* @Description 從指定目錄讀取Spi配置文件孕蝉,分析class并加入緩存
* 1.cachedAdaptiveClass 含有Adaptive注解的class
* 2.cachedWrapperClasses 含有指定參數(shù)的構(gòu)造方法的class
* 3.cachedActivates 含有Activate注解的class
* 4.cachedNames 其余的class
* @param
* @Date 2018/6/7 17:13
*/
private void loadFile(Map<String, Class<?>> extensionClasses, String dir){
String fileName = dir + type.getName();
//遍歷SPI文件的每一行配置
while ((line = reader.readLine()) != null) {
Class<?> clazz = Class.forName(line, true, classLoader);
//擴展點實例類上有@Adaptive注解直接設(shè)置cachedAdaptiveClass
if (clazz.isAnnotationPresent(Adaptive.class)) {
if(cachedAdaptiveClass == null) {
cachedAdaptiveClass = clazz;
} else if (! cachedAdaptiveClass.equals(clazz)) {
throw new
}
try {
clazz.getConstructor(type);
//如果擴展點實例的是含有type類型參數(shù)的構(gòu)造方法則加入cachedWrapperClasses集合中
Set<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
} catch (NoSuchMethodException e) {
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
cachedActivates.put(names[0], activate);
}
//其余情況則將擴展點類名加入cachedNames,key為class
for (String n : names) {
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
}
}
}
}
}
- 創(chuàng)建實例并加入緩存
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
IOC注入
這一步主要是實現(xiàn)dubbo自己的IOC腌逢,遍歷擴展實例的方法查找set方法降淮,然后從spring和dubbo容器中查找對應(yīng)屬性值,并反射調(diào)用set方法將屬性注入到擴展點的實例中搏讶。
/**
* @Author pengyunlong
* @Description 含有set開頭的方法則動態(tài)屬性注入
* @param
* @Date 2018/6/7 17:50
*/
private T injectExtension(T instance) {
try {
if (objectFactory != null) {
for (Method method : instance.getClass().getMethods()) {
//尋找set方法
if (method.getName().startsWith("set")
&& method.getParameterTypes().length == 1
&& Modifier.isPublic(method.getModifiers())) {
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;
}
前面說到在ExtensionLoader的構(gòu)造方法中
objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
所以objectFactory 是ExtensionFactory的擴展點(AdaptiveExtensionFactory佳鳖、SpiExtensionFactory、SpringExtensionFactory
)中的一個媒惕,而AdaptiveExtensionFactory
含有@Adaptive
所以通過getAdaptiveExtension
拿到的實際是AdaptiveExtensionFactory
腋颠。
Object object = objectFactory.getExtension(pt, property);
這句代碼主要就是通過SpiExtensionFactory和SpringExtensionFactory來查找property實例。AdaptiveExtensionFactory.getExtension
會從SpiExtensionFactory吓笙、SpringExtensionFactory
中查找指定類型或名稱實現(xiàn)類淑玫。
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
private final List<ExtensionFactory> factories;
/**
* @Author pengyunlong
* @Description 獲取到其他ExtensionFactory的實現(xiàn),并創(chuàng)建ExtensionFactory的實例
* SpiExtensionFactory面睛,SpringExtensionFactory
* @param
* @Date 2018/6/7 17:58
*/
public AdaptiveExtensionFactory() {
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);
}
/**
* @Author pengyunlong
* @Description 從ExtensionFactory實例中(包括spring容器和spi)絮蒿,加載擴展點指定擴展點實例
* @param
* @Date 2018/6/7 18:01
*/
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;
}
}
最后通過method.invoke(instance, object);
實現(xiàn)注入,這樣擴展點的實例就創(chuàng)建并注入完成了。
IOC說明
- dubbo擴展未知類的屬性來源分為:spi 和spring
spi的擴展對象存儲在SpiExtensionFactory
spring的擴展對象存儲在 SpringExtensionFactory - SpringExtensionFactory的設(shè)計初衷:
a. 設(shè)計的目的:方便開發(fā)者對擴展未知類的配置(可以用spi配置也可以spring bean實現(xiàn))
b. SpringExtensionFactory在provider發(fā)布或consumer引用一個服務(wù)的時候叁鉴,會把spring的容器托付給SpringExtensionFactory中去.具體代碼為:ReferenceBean.setApplicationContext 和 ServiceBean.setApplicationContext
c. 當(dāng)SpiExtensionFactory沒有獲取到對象的時候會遍歷SpringExtensionFactory中的spring容器來獲取要注入的對象土涝。
具體代碼:AdaptiveExtensionFactory.getExtension
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
SpringExtensionFactory.addApplicationContext(applicationContext);
}
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;
}
- SpringExtensionFactory目前的作用?
SpringExtensionFactory前期的設(shè)計初衷非常好幌墓,但是后來執(zhí)行偏離了但壮,沒有按這個初衷去落地冀泻。因為從這SpringExtensionFactory.getExtension代碼(如下:)可以看出,是從ApplicationContext獲取對象的。
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;
}
}
}
return null;
}
但是目前這套系統(tǒng)沒有配置spring對象的任何痕跡蜡饵;甚至連配置自定義filter類弹渔,也無法實現(xiàn)spring bean配置,只能spi配置溯祸。
AOP包裝
我們在第1步加載字節(jié)碼的時候已經(jīng)填充了wrapperClasses這個緩存變量肢专,而且這個緩存中的所有class均含有以擴展點接口類型為方法參數(shù)的構(gòu)造方法(clazz.getConstructor(type);不會拋出異常
)。遍歷所有的wrapper,嵌套循環(huán)生成包裝類焦辅。
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
for (Class<?> wrapperClass : wrapperClasses) {
//4.實現(xiàn)dubbo AOP功能,包裝擴展點實例
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
實際上在這里就是ProtocolFilterWrapper
和ProtocolListenerWrapper
對DubboProtocol
的循環(huán)包裝博杖。
public class ProtocolFilterWrapper implements Protocol {
private final Protocol protocol;
public ProtocolFilterWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}
...
}
public class ProtocolListenerWrapper implements Protocol {
private final Protocol protocol;
public ProtocolListenerWrapper(Protocol protocol) {
if (protocol == null) {
throw new IllegalArgumentException("protocol == null");
}
this.protocol = protocol;
}
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
return protocol.export(invoker);
}
return new ListenerExporterWrapper<T>(protocol.export(invoker),
Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
.getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
}
....
}
總結(jié)
至此獲取擴展點實例的過程就全部完成了
參考資料
SPI
https://blog.csdn.net/sigangjun/article/details/79071850