溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Dubbo的SPI機(jī)制介紹以及Dubbo的IOC依賴(lài)注入實(shí)例

發(fā)布時(shí)間:2021-06-26 14:28:44 來(lái)源:億速云 閱讀:524 作者:chen 欄目:大數(shù)據(jù)

這篇文章主要講解了“Dubbo的SPI機(jī)制介紹以及Dubbo的IOC依賴(lài)注入實(shí)例”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Dubbo的SPI機(jī)制介紹以及Dubbo的IOC依賴(lài)注入實(shí)例”吧!

1、Dubbo的IOC例子

@Test
public void test1(){
    ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
    AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
    URL url = URL.valueOf("test://localhost/test");
    adaptiveExtension.echo("d", url);
}

public class DubboAdaptiveExt implements AdaptiveExt {

    // dubbo中有依賴(lài)AdaptiveExt類(lèi)型的變量
    private AdaptiveExt adaptiveExt;

    public void setAdaptiveExt(AdaptiveExt adaptiveExt) {
        this.adaptiveExt = adaptiveExt;
    }

    @Override
    public String echo(String msg, URL url) {
        System.out.println(this.adaptiveExt.echo(msg, url));
        return "dubbo";
    }
}
// 此時(shí)ThriftAdaptiveExt上面是標(biāo)注了@Adaptive注解的
@Adaptive
public class ThriftAdaptiveExt implements AdaptiveExt {
    @Override
    public String echo(String msg, URL url) {
        return "thrift";
    }
}

2、Dubbo的IOC需要用到的ExtensionFactory

Spring的IOC中,給生成的bean注入依賴(lài),是調(diào)用context.getBean(name)去獲得要注入的bean.Dubbo的IOC類(lèi)似,它通過(guò)ExtensionFactory類(lèi)型的變量objectFactory去dubbo中獲取bean,核心代碼objectFactory.getExtension(pt, property).下面先分析一下objectFactory的創(chuàng)建過(guò)程.objectFactory需要用到SpringExtensionFactory和SpiExtensionFactory.先看一下ExtenionFactory的實(shí)現(xiàn)類(lèi),如下圖.下面通過(guò)源碼分析objectFactory的生成過(guò)程.

Dubbo的SPI機(jī)制介紹以及Dubbo的IOC依賴(lài)注入實(shí)例

這里的getExtensionLoader()詳細(xì)分析可以參見(jiàn): Dubbo的SPI機(jī)制分析1-SPI加載class

ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);

public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
    // 刪去一些不必要的代碼,詳細(xì)分析可以看前面幾篇分析
    // 從緩存中獲取與拓展類(lèi)對(duì)應(yīng)的ExtensionLoader
    ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    if (loader == null) {
        // 若緩存未命中,則創(chuàng)建一個(gè)新的實(shí)例,創(chuàng)建新的實(shí)例時(shí)會(huì)走
        EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
        loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
    }
    return loader;
}

 private ExtensionLoader(Class<?> type) {
    this.type = type;
    // 這里的type是AdaptiveExt.class,所以會(huì)執(zhí)行后面的代碼,加載并創(chuàng)建SpiExtensionFactory和SpringExtensionFactory
    objectFactory = (type == ExtensionFactory.class ? null : 
	                     ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}
public T getAdaptiveExtension() {
    Object instance = cachedAdaptiveInstance.get();
    if (instance == null) {
        if (createAdaptiveInstanceError == null) {
            synchronized (cachedAdaptiveInstance) {
                instance = cachedAdaptiveInstance.get();
                if (instance == null) {
                    try {
                        // 創(chuàng)建自適應(yīng)拓展代理類(lèi)對(duì)象并放入緩存,這里創(chuàng)建的就是ExtensionFactory的自適應(yīng)拓展對(duì)象
                        instance = createAdaptiveExtension();
                        cachedAdaptiveInstance.set(instance);
                    } catch (Throwable t) {
                        // 拋異常
                    }
                }
            }
        }
    }
    return (T) instance;
}
 private T createAdaptiveExtension() {
    try {
        // 分為3步:1是創(chuàng)建自適應(yīng)拓展代理類(lèi)Class對(duì)象,2是通過(guò)反射創(chuàng)建對(duì)象,3是給創(chuàng)建的對(duì)象按需依賴(lài)注入
        return injectExtension((T) getAdaptiveExtensionClass().newInstance());
    } catch (Exception e) {
        // 拋異常
    }
}

getExtensionClasses()方法詳細(xì)分析可以參見(jiàn): Dubbo的SPI機(jī)制分析1-SPI加載class

private Class<?> getAdaptiveExtensionClass() {
    // 這里前面文章已經(jīng)分析過(guò)了,它會(huì)去加載默認(rèn)目錄下的ExtensionFactory的實(shí)現(xiàn)類(lèi),總共有3個(gè),目錄是
    // META-INF/dubbo/internal/,該目錄對(duì)應(yīng)兩個(gè)文件,文件內(nèi)容見(jiàn)下,由于AdaptiveExtensionFactory上面
    // 標(biāo)注了@Adaptive注解,所以它優(yōu)先級(jí)最高,它就是ExtensionFactory的默認(rèn)實(shí)現(xiàn)類(lèi)
    getExtensionClasses();
    // 如果有標(biāo)注了@Adaptive注解實(shí)現(xiàn)類(lèi),那么cachedAdaptiveClass不為空,直接返回
    if (cachedAdaptiveClass != null) {
        // 這里直接返回,cachedAdaptiveClass = AdaptiveExtensionFactory.class
        return cachedAdaptiveClass;
    }
    // 不會(huì)再走這一步
    return cachedAdaptiveClass = createAdaptiveExtensionClass();
}
文件1內(nèi)容:
// 其中AdaptiveExtensionFactory上面標(biāo)注了@Adaptive注解
adaptive=com.alibaba.dubbo.common.extension.factory.AdaptiveExtensionFactory
spi=com.alibaba.dubbo.common.extension.factory.SpiExtensionFactory

文件2內(nèi)容:
spring=com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
// 分析完了getAdaptiveExtensionClass(),它是返回AdaptiveExtensionFactory,接下來(lái)newInstance會(huì)調(diào)用它默認(rèn)的構(gòu)造方法
return injectExtension((T) getAdaptiveExtensionClass().newInstance());

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
    // 里面維護(hù)SpringExtensionFactory和SpiExtensionFactory
    private final List<ExtensionFactory> factories;

    public AdaptiveExtensionFactory() {
        ExtensionLoader<ExtensionFactory> loader = 
                                    ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
        for (String name : loader.getSupportedExtensions()) {
            // 分別給SpringExtensionFactory和SpiExtensionFactory創(chuàng)建對(duì)象并放入list中
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }
}

3、Dubbo的IOC源碼分析

// 上面已經(jīng)分析過(guò)了第一行代碼,這里面會(huì)創(chuàng)建ExtensionFactory類(lèi)型的變量objectFactory,這里面維護(hù)了一個(gè)list,
// list里面有SpringExtensionFactory和SpiExtensionFactory類(lèi)型的實(shí)例,Dubbo的IOC獲取bean就是通過(guò)這兩個(gè)變量去獲取的
ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");

public T getExtension(String name) {
    // 刪去一些代碼
    if (instance == null) {
        synchronized (holder) {
            instance = holder.get();
            if (instance == null) {
                // 創(chuàng)建拓展實(shí)例
                instance = createExtension(name);
                holder.set(instance);
            }
        }
    }
    return (T) instance;
}
private T createExtension(String name) {
    // 從配置文件中加載所有的拓展類(lèi),可得到“配置項(xiàng)名稱(chēng)”到“配置類(lèi)”的映射關(guān)系表
    // 這里我們指定了名字dubbo,并不是通過(guò)getAdaptiveExtension方法去獲得自適應(yīng)拓展類(lèi),這點(diǎn)要區(qū)分
    // 所以這里拿到的是com.alibaba.dubbo.demo.provider.adaptive.impl.DubboAdaptiveExt
    Class<?> clazz = getExtensionClasses().get(name);
    if (clazz == null) {
        throw findException(name);
    }
    try {
        // 也是嘗試先從緩存獲取,獲取不到通過(guò)反射創(chuàng)建一個(gè)并放到緩存中
        T instance = (T) EXTENSION_INSTANCES.get(clazz);
        if (instance == null) {
            // 這里直接通過(guò)反射創(chuàng)建DubboAdaptiveExt的實(shí)例,然后給他依賴(lài)注入
            EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
            instance = (T) EXTENSION_INSTANCES.get(clazz);
        }
        
        // 依賴(lài)注入
        injectExtension(instance);
        
        return instance;
    } 
}
private T injectExtension(T instance) {
 // 這里為了排版好看,刪去一些異常捕捉拋出代碼
 // objectFactory就是我們前面分析的,它里面維護(hù)了SpringExtensionFactory和SpiExtensionFactory類(lèi)型的實(shí)例
 if (objectFactory != null) {
    // 遍歷DubboAdaptiveExt實(shí)例的所有方法,尋找set開(kāi)頭且參數(shù)為1個(gè),且方法權(quán)限為public的方法
    for (Method method : instance.getClass().getMethods()) {
        if (method.getName().startsWith("set") && method.getParameterTypes().length == 1
                                               && Modifier.isPublic(method.getModifiers())) {
            
            // 獲取參數(shù)類(lèi)型,這里是AdaptiveExt.class
            Class<?> pt = method.getParameterTypes()[0];
            
            // 獲取屬性名,這里是adaptiveExt
            String property = method.getName().length() > 3 ? 
                              method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
            // 獲取容器中AdaptiveExt.class類(lèi)型的名字為adaptiveExt的實(shí)例
            Object object = objectFactory.getExtension(pt, property);
            // 獲取之后通過(guò)反射賦值
            if (object != null) {
                 method.invoke(instance, object);
            }
         }   
    }
 }
 return instance;
}
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {

    private final List<ExtensionFactory> factories;

    @Override
    public <T> T getExtension(Class<T> type, String name) {
        // 遍歷factory中所有的ExtensionFactory,先從SpiExtensionFactory中獲取,獲取不到在去Spring容器中獲取
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }
}

這里獲取自適應(yīng)拓展可以參考: Dubbo的SPI機(jī)制分析2-Adaptive詳解

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);
            if (!loader.getSupportedExtensions().isEmpty()) {
                // 先看SpiExtensionFactory怎么獲取,它是通過(guò)getAdaptiveExtension()去自適應(yīng)獲取,根本
                // 沒(méi)有用到name,所以這里返回ThriftAdaptiveExt的實(shí)例
                return loader.getAdaptiveExtension();
            }
        }
        return null;
    }
}
public class SpringExtensionFactory implements ExtensionFactory {
    // 可以看到Spring是先根據(jù)名字去取,取不到再根據(jù)類(lèi)型去取
    @Override
    public <T> T getExtension(Class<T> type, String name) {
        for (ApplicationContext context : contexts) {
            if (context.containsBean(name)) {
                Object bean = context.getBean(name);
                if (type.isInstance(bean)) {
                    return (T) bean;
                }
            }
        }

        for (ApplicationContext context : contexts) {
            try {
                return context.getBean(type);
            }
        }
        return null;
    }
}
// 所以這段代碼輸出:thrift
@Test
public void test1(){
    ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);
    AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
    URL url = URL.valueOf("test://localhost/test");
    adaptiveExtension.echo("d", url);
}

4、測(cè)試通過(guò)URL依賴(lài)注入

 /**
 * 測(cè)試通過(guò)URL依賴(lài)注入,將ThriftAdaptiveExt類(lèi)上面的注解注釋掉,同時(shí)給AdaptiveExt方法加上注解@Adaptive("t")
 */
@Test
public void test5(){
    ExtensionLoader<AdaptiveExt> loader = ExtensionLoader.getExtensionLoader(AdaptiveExt.class);

    Map<String, String> map = new HashMap<>();
    // t這個(gè)key就是根據(jù)@Adaptive("t")定的,兩者要一致
    map.put("t", "cloud");
    URL url = new URL("", "", 1, map);
    AdaptiveExt adaptiveExtension = loader.getExtension("dubbo");
    adaptiveExtension.echo(" ", url);
}

上述代碼輸出spring cloud,創(chuàng)建完DubboAdaptiveExt的實(shí)例給其注入依賴(lài)時(shí),調(diào)用injectExtension(instance),因?yàn)闆](méi)有了@Adaptive標(biāo)注的類(lèi),所以需要Dubbo自己生成自適應(yīng)拓展代理類(lèi)Class,生成過(guò)程可以參考: Dubbo的SPI機(jī)制分析2-Adaptive詳解.生成的代理類(lèi)中有這樣一句關(guān)鍵代碼: String extName = url.getParameter("t", "dubbo"),因?yàn)閡rl中有這個(gè)t參數(shù),所以最后會(huì)調(diào)用cloud所對(duì)應(yīng)的SpringCloudAdaptiveExt的echo方法,輸出spring cloud.

感謝各位的閱讀,以上就是“Dubbo的SPI機(jī)制介紹以及Dubbo的IOC依賴(lài)注入實(shí)例”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Dubbo的SPI機(jī)制介紹以及Dubbo的IOC依賴(lài)注入實(shí)例這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI