前言
在Dubbo SPI中是通過Wrapper實現AOP,對於AOP相信大家都不陌生,這裏不做的過多的介紹,我們主要來了解Dubbo SPI中是如何使用Wrapper類以及實現的細節。
使用場景
Dubbo 中的一個擴展接口可以有多個擴展實現類,這些擴展實現類可能會包含一些相同的邏輯,如果在每個實現類中都寫一遍,那麼這些重複代碼就會變得很難維護。因此Dubbo提供的自動包裝特性(Wrapper),來解決這個問題。 Dubbo將多個擴展實現類的公共邏輯,抽象到Wrapper類中,同時Wrapper也實現了擴展接口,在獲取真正的擴展實現對象時,相當於在其外面包裝一層Wrapper對象,可以理解成一層裝飾器,通過這樣就可以在方法執行前後調用公共方法,也是一種AOP的體現。
舉個栗子
定義接口;
@SPI
public interface WrapperDemo {
void test();
}
定義接口實現;
public class WrapperDemoImpl implements WrapperDemo{
@Override
public void test() {
System.out.println("WrapperDemoImpl test 方法執行");
}
}
創建計算耗時包裝類以及Order包裝類;
public class CalWasteTimeWrapper implements WrapperDemo {
private WrapperDemo wrapperDemo;
public CalWasteTimeWrapper(WrapperDemo wrapperDemo) {
this.wrapperDemo = wrapperDemo;
}
@Override
public void test() {
System.out.println("執行cal wrapper");
System.out.println("執行統計耗時開始");
long startTime = System.currentTimeMillis();
wrapperDemo.test();
System.out.println("執行耗時" + (System.currentTimeMillis() - startTime));
}
}
public class OrderWrapper implements WrapperDemo {
private WrapperDemo wrapperDemo;
public OrderWrapper(WrapperDemo wrapperDemo) {
this.wrapperDemo = wrapperDemo;
}
@Override
public void test() {
System.out.println("執行order wrapper");
wrapperDemo.test();
}
}
定義配置文件;
wrapperDemo=org.dubbo.spi.example.wrapper.WrapperDemoImpl
calWasteTimeWrapper=org.dubbo.spi.example.wrapper.CalWasteTimeWrapper
orderWrapper=org.dubbo.spi.example.wrapper.OrderWrapper
測試,這裏我們會發現wrapper的順序,越往下的越先被調用;
public class Test {
public static void main(String[] args) {
WrapperDemo wrapperDemo = ExtensionLoader
.getExtensionLoader(WrapperDemo.class)
.getExtension("wrapperDemo");
wrapperDemo.test();
}
}
源碼
關於源碼部分我們開始介紹時候已經帶出來過關於包裝類相關的介紹,這裏我們主要挑重點代碼進行介紹,核心可以分爲兩步,一步是加載時候,另外執行代碼創建時候;
加載
加載就是在loadClass方法時候擴展類加載,判斷是否是包裝類進行加載,將所有的包裝類的信息加載到ConcurrentHashSet中,對於包裝類的判斷也很簡單,就是判斷該類裏面是否有type類型的構造參數,如果有就是包裝類,否則會拋出異常, 返回false;
//包裝類判斷
else if (isWrapperClass(clazz)) {
//緩存包裝類
cacheWrapperClass(clazz);
}
//使用ConcurrentHashSet緩存
private void cacheWrapperClass(Class<?> clazz) {
if (cachedWrapperClasses == null) {
cachedWrapperClasses = new ConcurrentHashSet<>();
}
cachedWrapperClasses.add(clazz);
}
//判斷是否是包裝類
private boolean isWrapperClass(Class<?> clazz) {
try {
clazz.getConstructor(type);
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
創建
創建部分是在createExtension方法中,對包裝類進行創建,對於instance最後生成是WrapperDemo類型對象,裏面包含OrderWrapper和CalWasteTimeWrapper對象,所以在最後調用的時候都進行輸出,於是乎就有了Aop的效果;
@SuppressWarnings("unchecked")
private T createExtension(String name, boolean wrap) {
//從配置文件中加載所有擴展類,形成配置項名稱與配置類的映射關係
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);
if (wrap) {
//創建Wrapper擴展對象
List<Class<?>> wrapperClassesList = new ArrayList<>();
if (cachedWrapperClasses != null) {
wrapperClassesList.addAll(cachedWrapperClasses);
wrapperClassesList.sort(WrapperComparator.COMPARATOR);
Collections.reverse(wrapperClassesList);
}
if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
for (Class<?> wrapperClass : wrapperClassesList) {
Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
if (wrapper == null
|| (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
//將當前instance作爲參數創建wrapper實例,然後向wrapper實例中注入屬性值
//並將wrapper實例賦值給instance
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
}
}
//環境初始化
initExtension(instance);
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
type + ") couldn't be instantiated: " + t.getMessage(), t);
}
}
結束
歡迎大家點點關注,點點贊!