今天是2021年10月1號,在此祝偉大的祖國母親生日快樂,繁榮昌盛!
上一節對sdk spi機制從原始碼角度進行了分析,文末留下思考:jdk spi有什么缺點?總結如下:
-
無法按需加載
ServiceLoader通過LazyIterator實作延遲加載,但是加載時仍然是遍歷所有的類進行實體化,無法按需加載;
-
多執行緒非安全
ServiceLoader方法都是static,在并發時可能出現意想不到的執行緒安全問題;
針對以上問題,dubbo在借鑒sdk spi的基礎上,通過分離配置加載和實體化實作按需加載,并且提供了ioc以及aop,進行功能增強,接下來看看dubbo如何實作相關功能?本節安排如下:
- demo
- 拓展點分析
- ioc
- aop
- 總結
1、demo
1.1、介面
//運動介面
package xu.jiang.hua.dubbo.api.service;
import org.apache.dubbo.common.extension.SPI;
@SPI("volleyball")
public interface Sport {
public void play();
}
定義Sport介面,并且指定默認實作為volleyball.
@SPI
public interface Drink {
void drink();
}
1.2、實作
//籃球實作
package xu.jiang.hua.dubbo.api.service.impl;
import xu.jiang.hua.dubbo.api.service.Drink;
import xu.jiang.hua.dubbo.api.service.Sport;
public class BasketBallSport implements Sport {
private Drink drink;
public void setDrink(Drink drink) {
this.drink = drink;
}
@Override
public void play() {
System.out.print("運動前喝點飲料補充養分:");
drink.drink();
System.out.println("play basketball");
}
}
//排球實作
package xu.jiang.hua.dubbo.api.service.impl;
import xu.jiang.hua.dubbo.api.service.Sport;
public class VolleyballSport implements Sport {
@Override
public void play() {
System.out.println("play volleyballSport");
}
}
//FootBallSport
package xu.jiang.hua.dubbo.api.service.impl;
import org.apache.dubbo.common.extension.Adaptive;
import xu.jiang.hua.dubbo.api.service.Sport;
@Adaptive
public class FootBallSport implements Sport {
@Override
public void play() {
System.out.println("play football");
}
}
并通過@Adaptive標示FootBallSport 為Sport的自適應類,
//運動切面
package xu.jiang.hua.dubbo.api.service.impl;
import xu.jiang.hua.dubbo.api.service.Sport;
public class SportWrapper1 implements Sport {
private Sport sport;
public SportWrapper1(Sport sport) {
this.sport = sport;
}
@Override
public void play() {
System.out.println("運動前1");
sport.play();
System.out.println("運動后1");
}
}
//飲料實作
package xu.jiang.hua.dubbo.api.service.impl;
import org.apache.dubbo.common.extension.Adaptive;
import xu.jiang.hua.dubbo.api.service.Drink;
@Adaptive
public class MineralWater implements Drink {
@Override
public void drink() {
System.out.println("喝礦泉水");
}
}
并通過@Adaptive標示MineralWater為Drink的自適應類,
1.3、配置
-
xu.jiang.hua.dubbo.api.service.Sport
basketBall=xu.jiang.hua.dubbo.api.service.impl.BasketBallSport
volleyball=xu.jiang.hua.dubbo.api.service.impl.VolleyballSport
footBall=xu.jiang.hua.dubbo.api.service.impl.FootBallSport
xu.jiang.hua.dubbo.api.service.impl.SportWrapper1 -
xu.jiang.hua.dubbo.api.service.Drink
mineralWater=xu.jiang.hua.dubbo.api.service.impl.MineralWater
1.4、運行結果
public class MainTest {
public static void main(String[] args) {
System.out.println("...........getExtension............");
Sport basketBall = ExtensionLoader.getExtensionLoader(Sport.class).getExtension("basketBall");
basketBall.play();
System.out.println("...........getDefaultExtension............");
Sport defaultSport = ExtensionLoader.getExtensionLoader(Sport.class).getDefaultExtension();
defaultSport.play();
System.out.println("...........getAdaptiveExtension............");
Sport adaptiveSport = ExtensionLoader.getExtensionLoader(Sport.class).getAdaptiveExtension();
adaptiveSport.play();
}
}

從執行結果來看,basketBall這個拓展點的方法執行前后有SportWrapper1類進行攔截,同時通過dubbo spi機制注入Drink介面,
因Sport介面上@SPI(“volleyball”)上指定了默認實作,因此getDefaultExtension回傳VolleyballSport;
2、拓展點分析
下面以上面demo為例深入原始碼分析內部實作邏輯,
2.1、getExtensionLoader
可以看到加載任何拓展點都需要先執行getExtensionLoader
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
//省略非關鍵代碼
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
//new ExtensionLoader<T>(type)
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
繼續分析new ExtensionLoader(type),如下:
private ExtensionLoader(Class<?> type) {
this.type = type;
/** 邏輯解讀:
* 1、傳入的type為非ExtensionFactory時,則執行ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
* 2、則再次呼叫new ExtensionLoader(Class<?> type),則再次執行ExtensionLoader的建構式,此時type為ExtensionFactory,objectFactory為null;
* 3、根據回傳的ExtensionLoader,再執行方法getAdaptiveExtension;
* 4、加載META-INF/dubbo/internal/org.apache.dubbo.common.extension.ExtensionFactory的內容,里面有SpiExtensionFactory和AdaptiveExtensionFactory,
* 因AdaptiveExtensionFactory被@Adaptive注解標注,則getAdaptiveExtension回傳AdaptiveExtensionFactory的實體物件
* 5、接下來對AdaptiveExtensionFactory進行實體化,AdaptiveExtensionFactory屬性factories僅有SpiExtensionFactory(通過cachedClasses獲取)
*/
objectFactory =
(type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
對type為非ExtensionFactory生成的ExtensionLoader,objectFactory為SpiExtensionFactory,
2.2、getExtension
public T getExtension(String name, boolean wrap) {
//省略非關鍵代碼
if ("true".equals(name)) {
return getDefaultExtension();
}
final Holder<Object> holder = getOrCreateHolder(name);
Object instance = holder.get();
//雙重檢查
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
//創建拓展實體
instance = createExtension(name, wrap);
holder.set(instance);
}
}
}
return (T) instance;
}
決議來分析createExtension方法(重點)
private T createExtension(String name, boolean wrap) {
//A、加載配置回傳map,并根據name獲取對應的類
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null || unacceptableExceptions.contains(name)) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
//實體化
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//B、ioc注入
injectExtension(instance);
//C、aop處理
if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList<>();
//找出所有的Wrapper并排序
if (cachedWrapperClasses != null) {
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);//倒敘List
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
for (Class<?> wrapperClass : wrapperClassesList) {
//獲取wrapper注解,如果為非空,則需要判斷注解的上的match和mismatch是否與當前name匹配,如果不匹配,不生成aop實體
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
if (wrapper == null
|| (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
/**
* wrapperClass.getConstructor(type).newInstance(instance) 實體化warpper類(aop類),將新生成的
* 實體賦值給instance,從而實作aop
*
* injectExtension 對warpper類實作ioc set
*/
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
}
}
initExtension(instance);
return instance;
} catch (Throwable t) {
//省略非關鍵代碼
}
}
createExtension方法主要分成以下三部分:
- getExtensionClasses加載組態檔
- ioc處理
- aop處理
將加載配置和實體化分開,從而實作按需實體化,避免不必要的資源浪費(相比jdk spi的改進點),先接下來看看內部如何實作的?
2.3、getExtensionClasses
private Map<String, Class<?>> loadExtensionClasses() {
//A、加載當前介面的默認實作類
cacheDefaultExtensionName();
Map<String, Class<?>> extensionClasses = new HashMap<>();
/**B、加載組態檔
*
* 策略模式,分別加載以下路徑:
* 1、META-INF/dubbo/internal/
* 2、META-INF/dubbo
* 3、META-INF/Service
*/
for (LoadingStrategy strategy : strategies) {
loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(),
strategy.overridden(), strategy.excludedPackages());
loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"),
strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
}
return extensionClasses;
}
第一部分默認實作類的處理:
private void cacheDefaultExtensionName() {
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中
cachedDefaultName = names[0];
}
}
}
比如Sport有默認實作volleyball,如下所示:

再看第二部分加載組態檔,目前支持以下三種路徑:
- META-INF/dubbo/internal/
- META-INF/dubbo
- META-INF/Service
為了兼容dubbo移交給apache成為旗下的頂級專案,同時也會將type介面名中的org.apache換成com.alibaba,接下來看loadDirectory方法:
private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type,
boolean extensionLoaderClassLoaderFirst, boolean overridden, String... excludedPackages) {
String fileName = dir + type;
//省略非關鍵代碼
if (urls != null) {
while (urls.hasMoreElements()) {
java.net.URL resourceURL = urls.nextElement();
//加載Resourece
loadResource(extensionClasses, classLoader, resourceURL, overridden, excludedPackages);
}
}
} catch (Throwable t) {
//省略非關鍵代碼
}
}
接下來看loadResource方法
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader,
java.net.URL resourceURL, boolean overridden, String... excludedPackages) {
try {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), StandardCharsets.UTF_8))) {
String line;
String clazz = null;
//依次讀取里面的內容
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();
clazz = line.substring(i + 1).trim();
} else {
clazz = line;//如果無=,則認為是當前介面的warpper類
}
//加載的類非空且不在排除的類集合里面,則執行loadClass
if (StringUtils.isNotEmpty(clazz) && !isExcluded(clazz, excludedPackages)) {
loadClass(extensionClasses, resourceURL, Class.forName(clazz, true, classLoader), name, overridden);
}
} catch (Throwable t) {
//省略非關鍵代碼
}
}
}
}
} catch (Throwable t) {
//省略非關鍵代碼
}
}
loadResource說明:依次讀取每行,過濾掉注釋內容,然后判斷當前行是否包含=,如果不包含,則認為該行是該介面Wrapper類(aop實作類),繼續看loadClass方法:
private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name,
boolean overridden) throws NoSuchMethodException {
//省略關鍵代碼
//A、自適應類
if (clazz.isAnnotationPresent(Adaptive.class)) {
cacheAdaptiveClass(clazz, overridden);//cachedAdaptiveClass
//B、判斷是否為wrapper類—判斷該類是否存在一個引數為該介面的建構式,如存在,則認為為wrapper類
} else if (isWrapperClass(clazz)) {
cacheWrapperClass(clazz);//cachedWrapperClasses
} else {
//省略關鍵代碼
String[] names = NAME_SEPARATOR.split(name);//一個類可以當做多個拓展點,因此進行切分
if (ArrayUtils.isNotEmpty(names)) {
cacheActivateClass(clazz, names[0]);//cachedActivates
for (String n : names) {
cacheName(clazz, n);
//存入map
saveInExtensionClass(extensionClasses, clazz, n, overridden);
}
}
}
}
loadClass可以拆解成三部分:
-
Adaptive注解處理
如果該類被@Adaptive注解標注,則將該類保存在以下愛屬性中,
private volatile Class<?> cachedAdaptiveClass = null; -
Wrapper類處理
private boolean isWrapperClass(Class<?> clazz) {
try {
//通過加載判斷是否存在帶介面的建構式
clazz.getConstructor(type);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
通過判斷當前類是否存在以該介面為引數的建構式,如果存在則認為為wrapper類,如果存在則將該列保存在private Set<Class<?>> cachedWrapperClasses;;
- 其他處理
將name進行切分,分別存入Map<String, Class<?>> extensionClasses中,如下所示:
private void saveInExtensionClass(Map<String, Class<?>> extensionClasses, Class<?> clazz, String name, boolean overridden) {
Class<?> c = extensionClasses.get(name);
if (c == null || overridden) {
extensionClasses.put(name, clazz);
} else if (c != clazz) {
// duplicate implementation is unacceptable
unacceptableExceptions.add(name);
String duplicateMsg =
"Duplicate extension " + type.getName() + " name " + name + " on " + c.getName() + " and " + clazz.getName();
logger.error(duplicateMsg);
throw new IllegalStateException(duplicateMsg);
}
}
總結一下getExtensionClasses加載配置后的保存情況:
- 介面默認實作類保存在
private String cachedDefaultName;
- 被@Adaptive標注的實作類
private volatile Class<?> cachedAdaptiveClass = null;
- warpper類
private Set<Class<?>> cachedWrapperClasses;
- 其他類
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
cachedClasses則作為getExtensionClasses的結果回傳,
3、ioc
ioc處理位于createExtension方法中,回顧一下createExtension方法:
private T createExtension(String name, boolean wrap) {
//加載配置,并根據name回傳對應的類
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null || unacceptableExceptions.contains(name)) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
//實體化
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
//ioc注入
injectExtension(instance);
//省略其他
}
通過getExtensionClasses將配置加載到map中并根據name獲取對應類,然后進行實體化,實體化后執行injectExtension處理ioc,下面看看injectExtension方法:
private T injectExtension(T instance) {
if (objectFactory == null) {
return instance;
}
try {
for (Method method : instance.getClass().getMethods()) {
if (!isSetter(method)) {
continue;
}
/**
* Check {@link DisableInject} to see if we need auto injection for this property
*/
//set方法如果不想被ioc使用,則通過注解標示
if (method.getAnnotation(DisableInject.class) != null) {
continue;
}
Class<?> pt = method.getParameterTypes()[0];
if (ReflectUtils.isPrimitives(pt)) {
continue;
}
try {
String property = getSetterProperty(method);
//通過type和名字從objectFactory獲取
Object object = objectFactory.getExtension(pt, property);
if (object != null) {
//反射呼叫方法
method.invoke(instance, object);
}
} catch (Exception e) {
//省略非關鍵代碼
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return instance;
}
接下來看如何通過objectFactory.getExtension(pt, property)從背景關系獲取實體,根據ExtensionLoader實體化分析可知,objectFactory為AdaptiveExtensionFactory,如下:

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;
}
此時facory中僅有SpiExtensionFactory,執行getExtension方法回傳實體,下面看看getExtension如何執行的?
public class SpiExtensionFactory implements ExtensionFactory {
@Override
public <T> T getExtension(Class<T> type, String name) {
if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
/**
* 如果type僅有一個實作類并且類上有一個@Adaptive標注,此時loader.getSupportedExtensions()
* 回傳為空,則getExtension回傳null,為什么?
*/
if (!loader.getSupportedExtensions().isEmpty()) {
//回傳自適應類
return loader.getAdaptiveExtension();
}
}
return null;
}
}
分析getAdaptiveExtension:
public T getAdaptiveExtension() {
Object instance = cachedAdaptiveInstance.get();
//省略非關鍵代碼
synchronized (cachedAdaptiveInstance) {
instance = cachedAdaptiveInstance.get();
if (instance == null) {
try {
//創建adaptiveExtension實體
instance = createAdaptiveExtension();
cachedAdaptiveInstance.set(instance);
} catch (Throwable t) {
createAdaptiveInstanceError = t;
throw new IllegalStateException("Failed to create adaptive instance: " + t.toString(), t);
}
}
}
}
return (T) instance;
}
繼續分析createAdaptiveExtension:
private T createAdaptiveExtension() {
try {
//獲取adaptiveExtension類并實體化,然后執ioc
return injectExtension((T) getAdaptiveExtensionClass().newInstance());
} catch (Exception e) {
//省略非關鍵代碼
}
}
重點看getAdaptiveExtensionClass()方法
private Class<?> getAdaptiveExtensionClass() {
getExtensionClasses();
//優先使用被@Adaptive標注的類
if (cachedAdaptiveClass != null) {
return cachedAdaptiveClass;
}
//如果當前介面不存在Adaptive注解標注的實作類,那么需要手動編譯方法
return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
可以看到ioc注入的實體獲取的優先級:
- @Adaptive標注的類
- 動態生成自適應類(方法上必須有@Adaptive注解,否則拋例外),運行時通過傳遞url指定介面的實作類,如果傳遞的url未匹配上且有默認實作,則使用默認實作
下面就以以上面兩種情況進行演示:
3.1、@Adaptive在類上
@Adaptive
public class MineralWater implements Drink {
@Override
public void drink(URL url) {
System.out.println("喝礦泉水");
}
}

3.2、@Adaptive在方法上
將MineralWater上的@Adaptive注解去掉,同時方法加上@Adaptive并設定key為drink,則運行通過url里面map引數指定具體的實作,
@SPI("mineralWater")
public interface Drink {
@Adaptive({"drink"})
void drink(URL url);
}

private Class<?> createAdaptiveExtensionClass() {
//生成代理類時判斷方法上是否有@Adaptive注解修飾,如果沒有,則拋出例外
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
ClassLoader classLoader = findClassLoader();
org.apache.dubbo.common.compiler.Compiler compiler =
//AdaptiveCompiler
ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
3.3、自動生成的自適應類
package xu.jiang.hua.dubbo.api.service;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Drink$Adaptive implements xu.jiang.hua.dubbo.api.service.Drink {
public void drink(org.apache.dubbo.common.URL arg0) {
if (arg0 == null)
throw new IllegalArgumentException("url == null");
org.apache.dubbo.common.URL url = arg0;
//因為介面上指定了默認實作為mineralWater,則如果取不到則使用默認的實作
String extName = url.getParameter("drink", "mineralWater");
if(extName == null)
throw new IllegalStateException("Failed to get extension (xu.jiang.hua.dubbo.api.service.Drink) name from url (" + url.toString() + ") use keys([drink])");
xu.jiang.hua.dubbo.api.service.Drink extension = (xu.jiang.hua.dubbo.api.service.Drink)ExtensionLoader.getExtensionLoader(xu.jiang.hua.dubbo.api.service.Drink.class).getExtension(extName);
extension.drink(arg0);
}
}

將生成的自適應類通過反射賦給BasketBallSport實體, 運行時通過URL指定具體的實作:
URL url=URL.valueOf(“http://127.0.0.1”);
url= url.addParameter(“drink”,“mineralWater”);
drink.drink(url);
3.3、ioc總結
通過injectExtension方法和類上的set方法實作依賴注入,獲取的實體的優先級如下:
- A、@Adaptive標記類生成的實體;
- B、根據@Adaptive標記的方法自動編譯生成自適應類,運行時如果匹配失敗且有默認實作類,則使用默認類,
4、aop
aop處理同樣位于createExtension方法中,回顧一下createExtension方法:
private T createExtension(String name, boolean wrap) {
//省略非關鍵代碼
//ioc注入
injectExtension(instance);
//aop處理
if (wrap) {
List<Class<?>> wrapperClassesList = new ArrayList<>();
//找出所有的Wrapper并排序
if (cachedWrapperClasses != null) {
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);//倒敘List
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
for (Class<?> wrapperClass : wrapperClassesList) {
//獲取wrapper注解,如果為非空,則需要判斷注解的上的match和mismatch是否與當前name匹配,如果不匹配,不生成aop實體
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
if (wrapper == null
|| (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
/**
* wrapperClass.getConstructor(type).newInstance(instance) 實體化warpper類(aop類),將新生成的
* 實體賦值給instance,從而實作aop
*
* injectExtension 對warpper類實作ioc set
*/
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
}
}
initExtension(instance);
return instance;
} catch (Throwable t) {
}
}
前面getExtensionClasses方法中已經分析過warpper類會保存在
private Set<Class<?>> cachedWrapperClasses;
取出所有的cachedWrapperClasses并排序,接下來重點看
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance))
從warpper類中取出具有介面引數的建構式,并向建構式傳入當前實體進行warpper類的實體化,然后進行ioc處理(warpper類可能也有依賴注入),然后賦值給instance(前后instance不是同一個物件),如下所示:


可以看到instantce不是同一個物件,新生成的instance包含之前的instance,
5、總結
每個拓展點都會通過getExtensionLoader生成ExtensionLoader實體,
-
getExtension
getExtension通過傳入的name實作按需實體化;
-
getDefaultExtension
getDefaultExtension回傳介面的默認實作, 默認實作的 類名保存在
private String cachedDefaultName; -
getAdaptiveExtension
getDefaultExtension回傳介面的自適應類,優先使用@Adaptive標注的類,保存在cachedAdaptiveClass,如果無@Adaptive標記的類,則根據@Adaptive標記的方法自動生成自適應類;
private volatile Class<?> cachedAdaptiveClass = null;
-
ioc
獲取當前介面getAdaptiveExtension回傳實體進行依賴注入;如果getAdaptiveExtension為空且有默認實作,則使用默認實作,否則不注入; -
aop
根據getExtensionClasses得到介面的warpper類集合實作鏈式增強并作為新實體回傳,
private Set<Class<?>> cachedWrapperClasses;
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/305166.html
標籤:其他
下一篇:致敬一位好老師
