Dubbo實例注入過程
更新時間:2025年11月08日 10:32:16 作者:hello_zzw
文章主要介紹了Dubbo框架中ExtensionLoader類的創(chuàng)建、初始化、后處理和注入擴展點的詳細(xì)過程,特別是通過AdaptiveExtensionInjector進行注入的部分
Dubbo實例注入
org.apache.dubbo.common.extension.ExtensionLoader#createExtension
/**
* 根據(jù)指定擴展點名稱去創(chuàng)建擴展點實例對象
*/
@SuppressWarnings("unchecked")
private T createExtension(String name, boolean wrap) {
// getExtensionClasses 為當(dāng)前 SPI 接口的所有實現(xiàn)類的類信息集合
// 通過指定的擴展點名稱 name 來獲取與之對應(yīng)的實現(xiàn)類類信息
Class<?> clazz = getExtensionClasses().get(name);
// 若找不到對應(yīng)的擴展點,或者當(dāng)初加載時擴展點有重復(fù)名稱拋出異常
if (clazz == null || unacceptableExceptions.contains(name)) {
throw findException(name);
}
try {
// extensionInstances 為當(dāng)前 SPI 接口已經(jīng)經(jīng)過實例化的實例對象集合
// 然后通過指定的擴展點名稱看看有沒有與之對應(yīng)的已經(jīng)曾經(jīng)創(chuàng)建好的實例對象
T instance = (T) extensionInstances.get(clazz);
// 若找不到,說明沒有緩存,從而則說明該擴展點名稱也是首次使用
if (instance == null) {
// 通過并發(fā) Map 的 putIfAbsent 方法以線程安全的形式,
// 來保證該實現(xiàn)類只會創(chuàng)建一個實例對象,實例對象是反射方式創(chuàng)建出來的
extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));
// 獲取剛剛創(chuàng)建的實例對象
instance = (T) extensionInstances.get(clazz);
// 初始化前置處理,即將原始的對象進行前置包裝等處理
instance = postProcessBeforeInitialization(instance, name);
// 擴展點注入
injectExtension(instance);
// 初始化后置處理,即將已初始化實例化注入的對象進行后置包裝等處理
instance = postProcessAfterInitialization(instance, name);
}
// wrap 是否需要進行裝飾器包裝
if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList<>();
// 看看是否有裝飾器包裝類,即實現(xiàn)類中單一參數(shù)的構(gòu)造方法是不是 SPI 接口
if (cachedWrapperClasses != null) {
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
// 循環(huán)裝飾器包裝類,進行層層套娃包裝
for (Class<?> wrapperClass : wrapperClassesList) {
// 裝飾器類上是否 Wrapper 注解
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
// 1. 沒有 wrapper 注解,需要進行包裝
// 2. wrapper 中的 matches 字段值為空沒有內(nèi)容,需要進行包裝
// 3. wrapper 中的 matches 字段值不為空并包含入?yún)?name 值,并且 mismatches 字段值不包含 name 值,需要進行包裝
// 4. 其他情況,可能就是瞎寫亂配,導(dǎo)致無法進行包裝之類的
boolean match = (wrapper == null)
|| ((ArrayUtils.isEmpty(wrapper.matches())
|| ArrayUtils.contains(wrapper.matches(), name))
&& !ArrayUtils.contains(wrapper.mismatches(), name));
// 如果匹配成功,則進行包裝
if (match) {
// 針對包裝的類再次進行實例注入
instance = injectExtension(
(T) wrapperClass.getConstructor(type).newInstance(instance));
// 針對包裝類,同樣進行后置處理
instance = postProcessAfterInitialization(instance, name);
}
}
}
}
// Warning: After an instance of Lifecycle is wrapped by cachedWrapperClasses, it may not still be Lifecycle
// instance, this application may not invoke the lifecycle.initialize hook.
initExtension(instance);
return instance;
} catch (Throwable t) {
throw new IllegalStateException(
"Extension instance (name: " + name + ", class: " + type + ") couldn't be instantiated: "
+ t.getMessage(),
t);
}
}
org.apache.dubbo.common.extension.ExtensionLoader#postProcessBeforeInitialization
/**
* 初始化前置處理方法
*/
@SuppressWarnings("unchecked")
private T postProcessBeforeInitialization(T instance, String name) throws Exception {
// 存在擴展后處理器時,循環(huán)處理所有的后置處理器
if (extensionPostProcessors != null) {
for (ExtensionPostProcessor processor : extensionPostProcessors) {
// 循環(huán)調(diào)用所有后置處理器中的初始化前置方法
instance = (T) processor.postProcessBeforeInitialization(instance, name);
}
}
// 返回處理后的對象
return instance;
}
/**
* 初始化后置處理方法
*/
@SuppressWarnings("unchecked")
private T postProcessAfterInitialization(T instance, String name) throws Exception {
// 如果實例實現(xiàn)了ExtensionAccessorAware,自動注入extensionDirector作為擴展訪問器
if (instance instanceof ExtensionAccessorAware) {
((ExtensionAccessorAware) instance).setExtensionAccessor(extensionDirector);
}
// 存在擴展后處理器時,循環(huán)處理所有的后置處理器
if (extensionPostProcessors != null) {
for (ExtensionPostProcessor processor : extensionPostProcessors) {
// 循環(huán)調(diào)用所有后置處理器中的初始化后置方法
instance = (T) processor.postProcessAfterInitialization(instance, name);
}
}
return instance;
}
org.apache.dubbo.common.extension.ExtensionLoader#injectExtension
/**
* 注入擴展點的方法
*/
private T injectExtension(T instance) {
if (injector == null) {
return instance;
}
try {
// 循環(huán)處理實例對象的所有public方法
for (Method method : instance.getClass().getMethods()) {
// 只處理set開頭,public修飾,只有一個參數(shù)的方法
if (!isSetter(method)) {
continue;
}
// 不處理帶有DisableInject注解的方法
if (method.isAnnotationPresent(DisableInject.class)) {
continue;
}
// 過濾掉實現(xiàn)自ScopeModelAware的方法
if (method.getDeclaringClass() == ScopeModelAware.class) {
continue;
}
// 過濾掉 ScopeModelAware、ExtensionAccessorAware 的方法
if (instance instanceof ScopeModelAware || instance instanceof ExtensionAccessorAware) {
if (ignoredInjectMethodsDesc.contains(ReflectUtils.getDesc(method))) {
continue;
}
}
// 獲取第一個參數(shù)
Class<?> pt = method.getParameterTypes()[0];
// 基礎(chǔ)類型不做處理
if (ReflectUtils.isPrimitives(pt)) {
continue;
}
try {
// 獲取set方法對應(yīng)的屬性
// set方法大于三個分字符時,去除set后抽字母小寫
// 小于等于三個字符時,返回""
String property = getSetterProperty(method);
// 根據(jù)參數(shù)類型、屬性名稱 從容器中獲取對應(yīng)的實例對象
Object object = injector.getInstance(pt, property);
if (object != null) {
// 獲取到實例對象時,使用set方法設(shè)置到對象中
method.invoke(instance, object);
}
} catch (Exception e) {
logger.error(
COMMON_ERROR_LOAD_EXTENSION,
"",
"",
"Failed to inject via method " + method.getName() + " of interface " + type.getName() + ": "
+ e.getMessage(),
e);
}
}
} catch (Exception e) {
logger.error(COMMON_ERROR_LOAD_EXTENSION, "", "", e.getMessage(), e);
}
return instance;
}
org.apache.dubbo.common.extension.inject.AdaptiveExtensionInjector
@Override
public void initialize() throws IllegalStateException {
// 獲取【擴展點注入器】的加載器
ExtensionLoader<ExtensionInjector> loader = extensionAccessor.getExtensionLoader(ExtensionInjector.class);
injectors = loader.getSupportedExtensions().stream()
// 從加載器中拿出所有的可被使用的注冊器實現(xiàn)類
.map(loader::getExtension)
// 包裝在不可變集合中
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
}
@Override
public <T> T getInstance(final Class<T> type, final String name) {
// 循環(huán)所有的擴展點注入器
return injectors.stream()
// 從容器中根據(jù)類型加名字獲取實例對象
.map(injector -> injector.getInstance(type, name))
.filter(Objects::nonNull)
// 獲取到第一個就結(jié)束
.findFirst()
.orElse(null);
}
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot中實現(xiàn)上傳文件的功能簡單示例
這篇文章主要給大家介紹了關(guān)于springboot中實現(xiàn)上傳文件功能的相關(guān)資料,在Spring Boot中實現(xiàn)文件上傳下載功能相對簡單,文中給出了代碼示例,需要的朋友可以參考下2023-09-09
關(guān)于使用Lambda表達式簡化Comparator的使用問題
這篇文章主要介紹了關(guān)于使用Lambda表達式簡化Comparator的使用問題,文中圖文講解了Comparator對象的方法,需要的朋友可以參考下2023-04-04
Spring?Boot?結(jié)合?WxJava?實現(xiàn)文章上傳微信公眾號草稿箱與群發(fā)
本文將詳細(xì)介紹如何使用SpringBoot框架結(jié)合WxJava開發(fā)工具包,實現(xiàn)文章上傳到微信公眾號草稿箱以及群發(fā)功能,感興趣的朋友一起看看吧2025-07-07

