Motan的兩個(gè)注解
- Spi,在Motan中如果要使用SPI機(jī)制咬腋,則暴露出來的接口要使用@Spi注解標(biāo)注细睡,并且可以指定該接口的的實(shí)現(xiàn)者在創(chuàng)建對(duì)象時(shí)是用單例還是多例創(chuàng)建。
- SpiMeta 帝火,這個(gè)注解是加載實(shí)現(xiàn)類上的溜徙,用來標(biāo)注該實(shí)現(xiàn)類的SPI名稱湃缎,后續(xù)可以通過該名稱來獲取一個(gè)服務(wù)。(一個(gè)接口會(huì)有很多實(shí)現(xiàn)類蠢壹,可以標(biāo)注每個(gè)實(shí)現(xiàn)類自己的名稱)
SPI的核心處理類是motan-core中的ExtensionLoader
這里跟java的SPI相似的地方是嗓违,都要在實(shí)現(xiàn)類所在的包中增加META-INF/services/目錄,并在該目錄下增加SPI的描述图贸。
- 主入口:
// 通過getExtensionLoader獲取一個(gè)類型的Loader蹂季,
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
checkInterfaceType(type);
// 先看是否已經(jīng)存在該類型的Loader
ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoaders.get(type);
if (loader == null) {
// 不存在,這里會(huì)創(chuàng)建一個(gè)該類型Loader的實(shí)例疏日,并保存在extensionLoaders中
loader = initExtensionLoader(type);
}
return loader;
}
- 獲取SPI的提供者(獲取接口實(shí)現(xiàn)類的實(shí)例)
public T getExtension(String name) {
// 這里會(huì)去META-INF/services/目錄下查找當(dāng)前l(fā)oader要加載類型的所有SPI提供者的描述文件(第一次執(zhí)行偿洁,且執(zhí)行一次)
checkInit();
if (name == null) {
return null;
}
try {
Spi spi = type.getAnnotation(Spi.class);
// 是單例,這里會(huì)創(chuàng)建該名稱所對(duì)應(yīng)類的示例并緩存沟优,主要是多了緩存這一步
if (spi.scope() == Scope.SINGLETON) {
return getSingletonInstance(name);
} else {
Class<T> clz = extensionClasses.get(name);
if (clz == null) {
return null;
}
// 非單例涕滋,每次都創(chuàng)建新對(duì)象
return clz.newInstance();
}
} catch (Exception e) {
failThrows(type, "Error when getExtension " + name, e);
}
return null;
}
- getSingletonInstance的處理
private T getSingletonInstance(String name) throws InstantiationException, IllegalAccessException {
// 先從緩存找
T obj = singletonInstances.get(name);
// 找到返回
if (obj != null) {
return obj;
}
// 沒有,則找到改名稱所對(duì)應(yīng)的類
Class<T> clz = extensionClasses.get(name);
if (clz == null) {
return null;
}
synchronized (singletonInstances) {
obj = singletonInstances.get(name);
if (obj != null) {
return obj;
}
// 創(chuàng)建示例挠阁,并緩存
obj = clz.newInstance();
singletonInstances.put(name, obj);
}
// 返回創(chuàng)建的示例
return obj;
}
java的SPI不需要注解
- 核心包(jar)中提供一個(gè)接口
- 在其他包(jar)中寫實(shí)現(xiàn)類宾肺,在jar的META-INF/services/目錄下增加SPI配置文件
- 通過ServiceLoader<T> s = ServiceLoader.load(T.class);獲取接口的實(shí)際實(shí)現(xiàn)類
java的SPI只能通過類型獲取實(shí)現(xiàn)者,最后要根據(jù)類型來確定使用哪個(gè)實(shí)現(xiàn)類來處理業(yè)務(wù)侵俗。
Motan通過SpiMeta注解增加類實(shí)現(xiàn)類的名稱锨用,所以可以根據(jù)名稱來獲取,能更好的解耦隘谣。