開(kāi)篇
?SPI全稱為Service Provider Interface,是一種服務(wù)提供機(jī)制,比如在現(xiàn)實(shí)中我們經(jīng)常會(huì)有這種場(chǎng)景,就是對(duì)于一個(gè)規(guī)范定義方而言(可以理解為一個(gè)或多個(gè)接口),具體的服務(wù)實(shí)現(xiàn)方是不可知的(可以理解為對(duì)這些接口的實(shí)現(xiàn)類),那么在定義這些規(guī)范的時(shí)候,就需要規(guī)范定義方能夠通過(guò)一定的方式來(lái)獲取到這些服務(wù)提供方具體提供的是哪些服務(wù),而SPI就是進(jìn)行這種定義的。
JDK SPI例子
說(shuō)明:
首先規(guī)范制定方會(huì)定義一個(gè)接口org.apache.jdk.spi.example.IHello 。
其次在項(xiàng)目目錄下的META-INF/service名稱為org.apache.jdk.spi.example.IHello的文件,包含SPI實(shí)現(xiàn)接口全路徑。
通過(guò)ServiceLoader加載訪問(wèn)調(diào)用即可。
對(duì)于jdk的SPI,其主要存在兩個(gè)問(wèn)題,為每個(gè)接口提供的服務(wù)一般盡量只提供一個(gè),因?yàn)閖dk的SPI默認(rèn)會(huì)將所有目標(biāo)文件中定義的所有子類都讀取到返回使用;當(dāng)定義多個(gè)子類實(shí)現(xiàn)時(shí),無(wú)法動(dòng)態(tài)的根據(jù)配置來(lái)使用不同的配置。
---- 定義接口
package org.apache.jdk.spi.example;
public interface IHello {
void sayHello();
}
---- 定義實(shí)現(xiàn)1
package org.apache.jdk.spi.example;
public class HelloImpl1 implements IHello {
@Override
public void sayHello() {
System.out.println("我是Impl1");
}
}
---- 定義實(shí)現(xiàn)2
package org.apache.jdk.spi.example;
public class HelloImpl2 implements IHello {
@Override
public void sayHello() {
System.out.println("我是Impl2");
}
}
---- META-INF/services目錄文件 org.apache.jdk.spi.example.IHello
org.apache.jdk.spi.example.HelloImpl1
org.apache.jdk.spi.example.HelloImpl2
---- 測(cè)試文件內(nèi)容
package org.apache.jdk.spi.example;
import java.util.Iterator;
import java.util.ServiceLoader;
public class ServiceLoaderDemo {
public static void main(String[] args){
ServiceLoader<IHello> s = ServiceLoader.load(IHello.class);
Iterator<IHello> iHelloIterator = s.iterator();
while (iHelloIterator.hasNext()) {
IHello iHello = iHelloIterator.next();
iHello.sayHello();
}
}
}

Dubbo SPI例子
定義PlantsWater的接口并通過(guò)@SPI注解進(jìn)行注解,注解可選擇帶默認(rèn)值。
將watering()方法使用@Adaptive注解進(jìn)行了標(biāo)注,表示該方法在自動(dòng)生成的子類中是需要?jiǎng)討B(tài)實(shí)現(xiàn)的方法。
增加grant()方法是為了表明不帶@Adaptive在自動(dòng)生成的子類方法內(nèi)部會(huì)拋出異常。
為PlantsWater增加兩個(gè)實(shí)現(xiàn),AppleWater和BananaWater,實(shí)際調(diào)用通過(guò)參數(shù)控制。
在META-INF/dubbo下創(chuàng)建一個(gè)文件,該文件的名稱是目標(biāo)接口的全限定名,這里是org.apache.dubbo.spi.example.PlantsWater,在該文件中需要指定該接口所有可提供服務(wù)的子類。
定義主函數(shù)ExtensionLoaderDemo模擬SPI調(diào)用的驗(yàn)證。
----定義基礎(chǔ)應(yīng)用類
public interface Fruit {}
public class Apple implements Fruit {}
public class Banana implements Fruit{}
----定義SPI類
@SPI("banana")
public interface PlantsWater {
Fruit grant();
@Adaptive
String watering(URL url);
}
public class AppleWater implements PlantsWater {
public Fruit grant() {
return new Apple();
}
public String watering(URL url) {
System.out.println("watering apple");
return "watering finished";
}
}
public class BananaWater implements PlantsWater {
public Fruit grant() {
return new Banana();
}
public String watering(URL url) {
System.out.println("watering banana");
return "watering success";
}
}
----resources文件 org.apache.dubbo.spi.example.PlantsWater
apple=org.apache.dubbo.spi.example.AppleWater
banana=org.apache.dubbo.spi.example.BananaWater
------測(cè)試代碼內(nèi)容
public class ExtensionLoaderDemo {
public static void main(String[] args) {
// 首先創(chuàng)建一個(gè)模擬用的URL對(duì)象
URL url = URL.valueOf("dubbo://192.168.0.101:20880?plants.water=apple");
// 通過(guò)ExtensionLoader獲取一個(gè)PlantsWater對(duì)象,getAdaptiveExtension已經(jīng)加載了所有SPI類
PlantsWater plantsWater = ExtensionLoader.getExtensionLoader(PlantsWater.class)
.getAdaptiveExtension();
// 使用該P(yáng)lantsWater調(diào)用其"自適應(yīng)標(biāo)注的"方法,獲取調(diào)用結(jié)果
String result = plantsWater.watering(url);
System.out.println(result);
}
}
-----實(shí)際輸出內(nèi)容
十月 11, 2019 7:48:51 下午 org.apache.dubbo.common.logger.LoggerFactory info
信息: using logger: org.apache.dubbo.common.logger.jcl.JclLoggerAdapter
watering apple
watering finished
Process finished with exit code 0

JDK 和 Dubbo SPI簡(jiǎn)單對(duì)比
Dubbo 的擴(kuò)展點(diǎn)加載是基于JDK 標(biāo)準(zhǔn)的 SPI 擴(kuò)展點(diǎn)發(fā)現(xiàn)機(jī)制增強(qiáng)而來(lái)的,Dubbo 改進(jìn)了 JDK 標(biāo)準(zhǔn)的 SPI 的以下問(wèn)題:
JDK 標(biāo)準(zhǔn)的 SPI 會(huì)一次性實(shí)例化擴(kuò)展點(diǎn)所有實(shí)現(xiàn),如果有擴(kuò)展實(shí)現(xiàn)初始化很耗時(shí),但如果沒(méi)用上也加載,會(huì)很浪費(fèi)資源。
如果擴(kuò)展點(diǎn)加載失敗,就失敗了,給用戶沒(méi)有任何通知。比如:JDK 標(biāo)準(zhǔn)的ScriptEngine,如果Ruby ScriptEngine 因?yàn)樗蕾嚨?jruby.jar 不存在,導(dǎo)致 Ruby ScriptEngine 類加載失敗,這個(gè)失敗原因被吃掉了,當(dāng)用戶執(zhí)行 ruby 腳本時(shí),會(huì)報(bào)空指針異常,而不是報(bào)Ruby ScriptEngine不存在。
增加了對(duì)擴(kuò)展點(diǎn) IoC 和 AOP 的支持,一個(gè)擴(kuò)展點(diǎn)可以直接 setter 注入其它擴(kuò)展點(diǎn)。
Dubbo SPI實(shí)現(xiàn)原理
dubbo對(duì)于SPI的實(shí)現(xiàn)主要是在ExtensionLoader這個(gè)類中,這個(gè)類主要有三個(gè)方法:
- getExtension():主要用于獲取名稱為name的對(duì)應(yīng)的子類的對(duì)象,這里如果子類對(duì)象如果有AOP相關(guān)的配置,這里也會(huì)對(duì)其進(jìn)行封裝;
- getAdaptiveExtension():使用定義的裝飾類來(lái)封裝目標(biāo)子類,具體使用哪個(gè)子類可以在定義的裝飾類中通過(guò)一定的條件進(jìn)行配置;
- getExtensionLoader():加載當(dāng)前接口的子類并且實(shí)例化一個(gè)ExtensionLoader對(duì)象。
public T getExtension(String name);
public T getAdaptiveExtension();
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type);
getExtension()
- getExtension()方法的主要作用是獲取name對(duì)應(yīng)的子類對(duì)象返回。
- 其實(shí)現(xiàn)方式是首先讀取定義文件中的子類,然后根據(jù)不同的子類對(duì)象的功能的不同,比如使用@Adaptive修飾的裝飾類和用于AOP的Wrapper類,將其封裝到不同的緩存中。
- 最后根據(jù)傳入的name獲取其對(duì)應(yīng)的子類對(duì)象,并且使用相應(yīng)的Wrapper類對(duì)其進(jìn)行封裝。
如下是getExtension()方法的源碼:
public T getExtension(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Extension name == null");
}
// 如果名稱為true,則返回默認(rèn)的子類對(duì)象,這里默認(rèn)的子類對(duì)象的name定義在目標(biāo)接口的@SPI注解中
if ("true".equals(name)) {
return getDefaultExtension();
}
// 查看當(dāng)前是否已經(jīng)緩存有保存目標(biāo)對(duì)象的實(shí)例的Holder對(duì)象,緩存了則直接返回,
// 沒(méi)緩存則創(chuàng)建一個(gè)并緩存起來(lái)
final Holder<Object> holder = getOrCreateHolder(name);
Object instance = holder.get();
// 如果無(wú)法從Holder中獲取目標(biāo)對(duì)象的實(shí)例,則使用雙檢查法為目標(biāo)對(duì)象創(chuàng)建一個(gè)實(shí)例
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
// 創(chuàng)建name對(duì)應(yīng)的子類對(duì)象的實(shí)例
instance = createExtension(name);
holder.set(instance);
}
}
}
return (T) instance;
}
public T getDefaultExtension() {
getExtensionClasses();
if (StringUtils.isBlank(cachedDefaultName) || "true".equals(cachedDefaultName)) {
return null;
}
// 通過(guò)cachedDefaultName去獲取對(duì)應(yīng)的子類實(shí)例
return getExtension(cachedDefaultName);
}
private void cacheDefaultExtensionName() {
// cachedDefaultName取自SPI的參數(shù)當(dāng)中
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation == null) {
return;
}
String value = 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 = names[0];
}
}
}
- 關(guān)于對(duì)于目標(biāo)對(duì)象的獲取,首先是從緩存里取,沒(méi)取到才會(huì)進(jìn)行創(chuàng)建。
- 這里需要說(shuō)明的是,如果傳入的name為true,那么就會(huì)返回默認(rèn)的子類實(shí)例,而默認(rèn)的子類實(shí)例是通過(guò)其名稱進(jìn)行映射的,該名稱存儲(chǔ)在目標(biāo)接口的@SPI注解中。
createExtension()方法的源碼:
private T createExtension(String name) {
// 獲取當(dāng)前名稱對(duì)應(yīng)的子類類型,如果不存在,則拋出異常
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
// 獲取當(dāng)前class對(duì)應(yīng)的實(shí)例,如果緩存中不存在,則實(shí)例化一個(gè)并緩存起來(lái)
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
// 為生成的實(shí)例通過(guò)其set方法注入對(duì)應(yīng)的實(shí)例,這里實(shí)例的獲取方式不僅可以通過(guò)SPI的方式
// 也可以通過(guò)Spring的bean工廠獲取
injectExtension(instance);
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (CollectionUtils.isNotEmpty(wrapperClasses)) {
for (Class<?> wrapperClass : wrapperClasses) {
// 實(shí)例化各個(gè)wrapper對(duì)象,并將目標(biāo)對(duì)象通過(guò)wrapper的構(gòu)造方法傳入,
// 另外還會(huì)通過(guò)wrapper對(duì)象的set方法對(duì)其依賴的屬性進(jìn)行注入
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
在createExtension()方法中,其主要做了三件事:
- 加載定義文件中的各個(gè)子類,然后將目標(biāo)name對(duì)應(yīng)的子類返回后進(jìn)行實(shí)例化。
- 通過(guò)目標(biāo)子類的set方法為其注入其所依賴的bean,這里既可以通過(guò)SPI,也可以通過(guò)Spring的BeanFactory獲取所依賴的bean,injectExtension(instance)。
- 獲取定義文件中定義的wrapper對(duì)象,然后使用該wrapper對(duì)象封裝目標(biāo)對(duì)象,并且還會(huì)調(diào)用其set方法為wrapper對(duì)象注入其所依賴的屬性。
關(guān)于wrapper對(duì)象,這里需要說(shuō)明的是,其主要作用是為目標(biāo)對(duì)象實(shí)現(xiàn)AOP。wrapper對(duì)象有兩個(gè)特點(diǎn):
- a. 與目標(biāo)對(duì)象實(shí)現(xiàn)了同一個(gè)接口;
- b. 有一個(gè)以目標(biāo)接口為參數(shù)類型的構(gòu)造函數(shù)。這也就是上述createExtension()方法最后封裝wrapper對(duì)象時(shí)傳入的構(gòu)造函數(shù)實(shí)例始終可以為instance實(shí)例的原因。
getExtensionClasses()方法的源碼
private Map<String, Class<?>> getExtensionClasses() {
Map<String, Class<?>> classes = cachedClasses.get();
if (classes == null) {
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
// 加載定義文件,并且將定義的類按照功能緩存在不同的屬性中,即:
// a. 目標(biāo)class類型緩存在cachedClasses;
// b. wrapper的class類型緩存在cachedWrapperClasses;
// c. 用于裝飾的class類型緩存在cachedAdaptiveClass;
classes = loadExtensionClasses();
cachedClasses.set(classes);
}
}
}
return classes;
}
private Map<String, Class<?>> loadExtensionClasses() {
// 獲取目標(biāo)接口上通過(guò)@SPI注解定義的默認(rèn)子類對(duì)應(yīng)的名稱,并將其緩存在cachedDefaultName中
cacheDefaultExtensionName();
// 分別在META-INF/dubbo/internal、META-INF/dubbo、META-INF/services目錄下
// 獲取定義文件,并且讀取定義文件中的內(nèi)容,這里主要是通過(guò)META-INF/dubbo/internal
// 獲取目標(biāo)定義文件
Map<String, Class<?>> extensionClasses = new HashMap<>();
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
return extensionClasses;
}
private void cacheDefaultExtensionName() {
// 獲取目標(biāo)接口上通過(guò)@SPI注解定義的默認(rèn)子類對(duì)應(yīng)的名稱,并將其緩存在cachedDefaultName中
final SPI defaultAnnotation = type.getAnnotation(SPI.class);
if (defaultAnnotation == null) {
return;
}
String value = 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 = names[0];
}
}
}
- loadExtensionClasses()主要是分別從三個(gè)目錄中讀取定義文件,讀取該文件,并且進(jìn)行緩存。
loadDirectory()方法的源碼:
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
String fileName = dir + type;
try {
Enumeration<java.net.URL> urls;
ClassLoader classLoader = findClassLoader();
// 加載定義文件
if (classLoader != null) {
urls = classLoader.getResources(fileName);
} else {
urls = ClassLoader.getSystemResources(fileName);
}
if (urls != null) {
while (urls.hasMoreElements()) {
// 對(duì)定義文件進(jìn)行遍歷,依次加載定義文件的內(nèi)容
java.net.URL resourceURL = urls.nextElement();
loadResource(extensionClasses, classLoader, resourceURL);
}
}
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", description file: " + fileName + ").", t);
}
}
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
try {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
String line;
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();
line = line.substring(i + 1).trim();
}
if (line.length() > 0) {
loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
}
} catch (Throwable t) {
IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
exceptions.put(line, e);
}
}
}
}
} catch (Throwable t) {
logger.error("Exception occurred when loading extension class (interface: " +
type + ", class file: " + resourceURL + ") in " + resourceURL, t);
}
}
- 這里主要是對(duì)每個(gè)目錄進(jìn)行加載,然后依次加載定義文件的內(nèi)容,而對(duì)定義文件內(nèi)容的處理主要是在loadResource()方法中,在對(duì)文件中每一行記錄進(jìn)行處理之后,其其最終是調(diào)用的loadClass()方法加載目標(biāo)class的。
loadClass()方法的源碼
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
// 如果加載得到的子類不是目標(biāo)接口的實(shí)現(xiàn)類,則拋出異常
if (!type.isAssignableFrom(clazz)) {
throw new IllegalStateException("Error occurred when loading extension class (interface: " +
type + ", class line: " + clazz.getName() + "), class "
+ clazz.getName() + " is not subtype of interface.");
}
// 如果子類上標(biāo)注有@Adaptive注解,說(shuō)明其是一個(gè)裝飾類,則將其緩存在cachedAdaptiveClass中,
// 需要注意的是,一個(gè)接口只能為其定義一個(gè)裝飾類
if (clazz.isAnnotationPresent(Adaptive.class)) {
cacheAdaptiveClass(clazz);
// 這里判斷子類是否是一個(gè)wrapper類,判斷方式就是檢查其是否有只含一個(gè)目標(biāo)接口類型參數(shù)的構(gòu)造函數(shù),
// 有則說(shuō)明其是一個(gè)AOP的wrapper類
} else if (isWrapperClass(clazz)) {
cacheWrapperClass(clazz);
} else {
// 走到這里說(shuō)明當(dāng)前子類不是一個(gè)功能型的類,而是最終實(shí)現(xiàn)具體目標(biāo)的子類
clazz.getConstructor();
if (StringUtils.isEmpty(name)) {
name = findAnnotationName(clazz);
if (name.length() == 0) {
throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
}
}
String[] names = NAME_SEPARATOR.split(name);
if (ArrayUtils.isNotEmpty(names)) {
// 緩存ActivateClass類
cacheActivateClass(clazz, names[0]);
// 將目標(biāo)子類緩存到extensionClasses中
for (String n : names) {
cacheName(clazz, n);
saveInExtensionClass(extensionClasses, clazz, n);
}
}
}
}
private void cacheActivateClass(Class<?> clazz, String name) {
// 獲取子類上的@Activate注解,該注解的主要作用是對(duì)子類進(jìn)行分組的,
// 對(duì)于分組之后的子類,可以通過(guò)getActivateExtension()來(lái)獲取
Activate activate = clazz.getAnnotation(Activate.class);
if (activate != null) {
cachedActivates.put(name, activate);
} else {
// 兼容alibaba版本的注解
com.alibaba.dubbo.common.extension.Activate oldActivate = clazz.getAnnotation(com.alibaba.dubbo.common.extension.Activate.class);
if (oldActivate != null) {
cachedActivates.put(name, oldActivate);
}
}
}
private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name) {
// 將目標(biāo)子類緩存到extensionClasses中
Class<?> c = extensionClasses.get(name);
if (c == null) {
extensionClasses.put(name, clazz);
} else if (c != clazz) {
String duplicateMsg = "Duplicate extension " + type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName();
logger.error(duplicateMsg);
throw new IllegalStateException(duplicateMsg);
}
}
loadClass()方法主要作用是對(duì)子類進(jìn)行劃分,這里主要?jiǎng)澐殖闪巳糠郑?/p>
- 使用@Adaptive注解標(biāo)注的裝飾類;
- 包含有目標(biāo)接口類型參數(shù)構(gòu)造函數(shù)的wrapper類
- 目標(biāo)處理具體業(yè)務(wù)的子類。
總結(jié)而言,getExtension()方法主要是獲取指定名稱對(duì)應(yīng)的子類。在獲取過(guò)程中,首先會(huì)從緩存中獲取是否已經(jīng)加載過(guò)該子類,如果沒(méi)加載過(guò)則通過(guò)定義文件加載,并且使用獲取到的wrapper對(duì)象封裝目標(biāo)對(duì)象返回。
getAdaptiveExtension()
ExtensionLoader在加載了定義文件之后會(huì)對(duì)子類進(jìn)行一個(gè)劃分,使用@Adaptive進(jìn)行標(biāo)注的子類和使用@Adaptive標(biāo)注子類方法。
使用@Adaptive進(jìn)行標(biāo)注的子類該子類的作用主要是用于對(duì)目標(biāo)類進(jìn)行裝飾的,從而實(shí)現(xiàn)一定的目的。
使用@Adaptive進(jìn)行標(biāo)注的方法,其使用的方式主要是在目標(biāo)接口的某個(gè)方法上進(jìn)行標(biāo)注,這個(gè)時(shí)候,dubbo就會(huì)通過(guò)javassist字節(jié)碼生成工具來(lái)動(dòng)態(tài)的生成目標(biāo)接口的子類對(duì)象,該子類會(huì)對(duì)該接口中標(biāo)注了@Adaptive注解的方法進(jìn)行重寫(xiě),而其余的方法則默認(rèn)拋出異常,通過(guò)這種方式可以達(dá)到對(duì)特定的方法進(jìn)行修飾的目的。
getAdaptiveExtension()方法源碼
public T getAdaptiveExtension() {
// 從緩存中獲取裝飾類的實(shí)例,存在則直接返回,不存在則創(chuàng)建一個(gè)緩存起來(lái),然后返回
Object instance = cachedAdaptiveInstance.get();
if (instance == null) {
if (createAdaptiveInstanceError != null) {
throw new IllegalStateException("Failed to create adaptive instance: " +
createAdaptiveInstanceError.toString(),
createAdaptiveInstanceError);
}
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
// 創(chuàng)建一個(gè)裝飾類的實(shí)例
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
}
return (T) instance;
}
-
從緩存中獲取目標(biāo)類的實(shí)例,不存在則創(chuàng)建一個(gè)該實(shí)例。
createAdaptiveExtension()方法源碼
private T createAdaptiveExtension() {
try {
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
}
private Class<?> getAdaptiveExtensionClass() {
// 獲取目標(biāo)extensionClasses,如果無(wú)法獲取到,則在定義文件中進(jìn)行加載
getExtensionClasses();
// 如果目標(biāo)類型有使用@Adaptive標(biāo)注的子類型,則直接使用該子類作為裝飾類
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
// 如果目標(biāo)類型沒(méi)有使用@Adaptive標(biāo)注的子類型,則嘗試在目標(biāo)接口中查找是否有使用@Adaptive標(biāo)注的
// 方法,如果有,則為該方法動(dòng)態(tài)生成子類裝飾代碼
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
private Class<?> createAdaptiveExtensionClass() {
// 創(chuàng)建子類代碼的字符串對(duì)象
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
// 獲取當(dāng)前dubbo SPI中定義的Compiler接口的子類對(duì)象,默認(rèn)是使用javassist,
// 然后通過(guò)該對(duì)象來(lái)編譯生成的code,從而動(dòng)態(tài)生成一個(gè)class對(duì)象
ClassLoader classLoader = findClassLoader();
org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
createAdaptiveExtension()首先委托給getAdaptiveExtensionClass()方法獲取一個(gè)裝飾類實(shí)例,然后通過(guò)injectExtension()方法調(diào)用該實(shí)例的set方法來(lái)注入其所依賴的屬性值。
對(duì)于沒(méi)有使用@Adaptive標(biāo)注的子類時(shí),才會(huì)使用Javassist來(lái)為目標(biāo)接口生成其子類的裝飾方法。
對(duì)于使用@Adaptive標(biāo)注的子類時(shí),直接返回子類。
createAdaptiveExtensionClass()動(dòng)態(tài)生成目標(biāo)接口的子類字符串,然后通過(guò)javassit來(lái)編譯該子類字符串,從而動(dòng)態(tài)生成目標(biāo)class。
getExtensionLoader()
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 an interface!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type (" + type +
") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
}
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
- 對(duì)于ExtensionLoader的獲取,其實(shí)現(xiàn)過(guò)程比較簡(jiǎn)單,主要是從緩存中獲取,如果緩存不存在,則實(shí)例化一個(gè)并且緩存起來(lái)。
ExtensionLoader加載流程圖
