成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

Dubbo SPI機(jī)制和IOC

Scorpion / 626人閱讀

摘要:要構(gòu)建自適應(yīng)實(shí)例,先要有自適應(yīng)的實(shí)現(xiàn)類(lèi),實(shí)現(xiàn)類(lèi)有兩種方式一種通過(guò)配置文件,一種是通過(guò)是字節(jié)碼的方式動(dòng)態(tài)生成。

SPI機(jī)制

SPI,即(service provider interface)機(jī)制,有很多組件的實(shí)現(xiàn),如日志、數(shù)據(jù)庫(kù)訪問(wèn)等都是采用這樣的方式,一般通用組件為了提升可擴(kuò)展性,基于接口編程,將操作接口形成標(biāo)準(zhǔn)規(guī)范,但是可以開(kāi)放多種擴(kuò)展實(shí)現(xiàn),這種做法也符合開(kāi)閉設(shè)計(jì)原則,使組件具有可插撥特性。不同的廠商或組織可以基于規(guī)范推出自己的實(shí)現(xiàn),只需要在自己的jar包中通過(guò)配置文件和相應(yīng)的實(shí)現(xiàn)類(lèi)即可以實(shí)現(xiàn)擴(kuò)展。甚至開(kāi)發(fā)者自己也可以很方便對(duì)框架進(jìn)行定制化實(shí)現(xiàn)。

JDK SPI介紹

JDK實(shí)現(xiàn)spi服務(wù)查找: ServiceLoader。
舉個(gè)例子:
首先定義下示例接口

package com.example;

public interface Spi {

       booleanisSupport(String name);

       String sayHello();

}

ServiceLoader會(huì)遍歷所有jar查找META-INF/services/com.example.Spi文件

A廠商提供實(shí)現(xiàn)

package com.a.example;

public class SpiAImpl implements Spi {

       publicboolean isSupport(String name) {

              return"SPIA".equalsIgnoreCase(name.trim()); 

}

public String syaHello() {

       return “hello 我是廠商A”;

}

}

在A廠商提供的jar包中的META-INF/services/com.example.Spi文件內(nèi)容為:

com.a.example.SpiAImpl #廠商A的spi實(shí)現(xiàn)全路徑類(lèi)名

B廠商提供實(shí)現(xiàn)

package com.b.example;

public class SpiBImpl implements Spi {

       publicboolean isSupport(String name) {

              return"SPIB".equalsIgnoreCase(name.trim()); 

}

public String syaHello() {

       return “hello 我是廠商B”;

}

}

在B廠商提供的jar包中的META-INF/services/com.example.Spi文件內(nèi)容為:

com.b.example.SpiBImpl #廠商B的spi實(shí)現(xiàn)全路徑類(lèi)名

ServiceLoader.load(Spi.class)讀取廠商A、B提供jar包中的文件,ServiceLoader實(shí)現(xiàn)了Iterable接口可通過(guò)while for循環(huán)語(yǔ)句遍歷出所有實(shí)現(xiàn)。

一個(gè)接口多種實(shí)現(xiàn),就如策略模式一樣提供了策略的實(shí)現(xiàn),但是沒(méi)有提供策略的選擇, 使用方可以根據(jù)isSupport方法根據(jù)業(yè)務(wù)傳入廠商名來(lái)選擇具體的廠商。

public class SpiFactory {

       //讀取配置獲取所有實(shí)現(xiàn)

       privatestatic ServiceLoader spiLoader = ServiceLoader.load(Spi.class);

       //根據(jù)名字選取對(duì)應(yīng)實(shí)現(xiàn)

       publicstatic Spi getSpi(String name) {

              for(Spi spi : spiLoader) {

                     if(spi.isSupport(name) ) {

                            returnspi;

                     }

              }

              returnnull;

}

}
Duddo SPI
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)加載失敗,連擴(kuò)展點(diǎn)的名稱(chēng)都拿不到了。

增加了對(duì)擴(kuò)展點(diǎn) IoC 和 AOP 的支持,一個(gè)擴(kuò)展點(diǎn)可以直接 setter 注入其它擴(kuò)展點(diǎn)。

示例

在擴(kuò)展類(lèi)的jar包內(nèi),放置擴(kuò)展點(diǎn)配置文件 META-INF/dubbo/接口全限定名,內(nèi)容為:配置名=擴(kuò)展實(shí)現(xiàn)類(lèi)全限定名,多個(gè)實(shí)現(xiàn)類(lèi)用換行符分隔。

以擴(kuò)展 Dubbo 的協(xié)議為例,在協(xié)議的實(shí)現(xiàn) jar 包內(nèi)放置文本文件:META-INF/dubbo/com.alibaba.dubbo.rpc.Protocol,內(nèi)容為:

xxx=com.alibaba.xxx.XxxProtocol

實(shí)現(xiàn)類(lèi)內(nèi)容:

package com.alibaba.xxx;

import com.alibaba.dubbo.rpc.Protocol;

public class XxxProtocol implemenets Protocol { 
    // ...
}
ExtensionLoad

dubbo擴(kuò)展機(jī)制的實(shí)現(xiàn)核心類(lèi)是ExtensionLoad,幾乎所有擴(kuò)展實(shí)現(xiàn)都在這個(gè)類(lèi)里面。每個(gè)可擴(kuò)展接口的擴(kuò)展實(shí)現(xiàn)類(lèi)和實(shí)現(xiàn)實(shí)例的都管理通過(guò)是ExtensionLoad進(jìn)行,每個(gè)接口維護(hù)一個(gè)單例的ExtensionLoad,所有可擴(kuò)展接口的實(shí)現(xiàn)都維護(hù)在ExtensionLoad中,如下所示:

/**
 * SPI 類(lèi)和ExtensionLoader映射
 */
private static final ConcurrentMap, ExtensionLoader> EXTENSION_LOADERS = new ConcurrentHashMap, ExtensionLoader>();

在單例模式中,最典型的實(shí)現(xiàn)就是通過(guò)私有構(gòu)造方法實(shí)現(xiàn)的:

private ExtensionLoader(Class type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

在dubbo擴(kuò)展點(diǎn)實(shí)現(xiàn)過(guò)程中,有幾個(gè)重要的特性需要提前了解一下:

擴(kuò)展點(diǎn)自動(dòng)包裝

自動(dòng)包裝擴(kuò)展點(diǎn)的 Wrapper 類(lèi)。ExtensionLoader 在加載擴(kuò)展點(diǎn)時(shí),如果加載到的擴(kuò)展點(diǎn)有拷貝構(gòu)造函數(shù),則判定為擴(kuò)展點(diǎn) Wrapper 類(lèi)。

Wrapper類(lèi)內(nèi)容:

package com.alibaba.xxx;

import com.alibaba.dubbo.rpc.Protocol;

public class XxxProtocolWrapper implemenets Protocol {
    Protocol impl;

    public XxxProtocol(Protocol protocol) { impl = protocol; }

    // 接口方法做一個(gè)操作后,再調(diào)用extension的方法
    public void refer() {
        //... 一些操作
        impl.refer();
        // ... 一些操作
    }

    // ...
}

Wrapper 類(lèi)同樣實(shí)現(xiàn)了擴(kuò)展點(diǎn)接口,但是 Wrapper 不是擴(kuò)展點(diǎn)的真正實(shí)現(xiàn)。它的用途主要是用于從 ExtensionLoader 返回?cái)U(kuò)展點(diǎn)時(shí),包裝在真正的擴(kuò)展點(diǎn)實(shí)現(xiàn)外。即從 ExtensionLoader 中返回的實(shí)際上是 Wrapper 類(lèi)的實(shí)例,Wrapper 持有了實(shí)際的擴(kuò)展點(diǎn)實(shí)現(xiàn)類(lèi)。這個(gè)是典型的裝飾者模式,即真正的實(shí)現(xiàn)類(lèi)是被包裝在Wrapper之中,Wrapper類(lèi)還做一些其它事情。

擴(kuò)展點(diǎn)自動(dòng)裝配

加載擴(kuò)展點(diǎn)時(shí),自動(dòng)注入依賴(lài)的擴(kuò)展點(diǎn)。加載擴(kuò)展點(diǎn)時(shí),擴(kuò)展點(diǎn)實(shí)現(xiàn)類(lèi)的成員如果為其它擴(kuò)展點(diǎn)類(lèi)型,ExtensionLoader 在會(huì)自動(dòng)注入依賴(lài)的擴(kuò)展點(diǎn)。ExtensionLoader 通過(guò)掃描擴(kuò)展點(diǎn)實(shí)現(xiàn)類(lèi)的所有 setter 方法來(lái)判定其成員。即 ExtensionLoader 會(huì)執(zhí)行擴(kuò)展點(diǎn)的拼裝操作。這個(gè)類(lèi)似于Spring的IOC,后面會(huì)專(zhuān)門(mén)介紹。

擴(kuò)展點(diǎn)自適應(yīng)

在調(diào)用過(guò)程,自動(dòng)選擇一個(gè)擴(kuò)展實(shí)現(xiàn)執(zhí)行,一個(gè)擴(kuò)展點(diǎn)只允許有一個(gè)自適應(yīng)實(shí)現(xiàn)。dubbo通過(guò)@Adaptive注解標(biāo)定自適應(yīng)實(shí)現(xiàn),這個(gè)注解可以在實(shí)現(xiàn)類(lèi)上,也可以在方法上。比如ExtensionFactory的自適應(yīng)實(shí)現(xiàn)就是通過(guò)在實(shí)現(xiàn)類(lèi)AdaptiveExtensionFactory上加@Adaptive注解實(shí)現(xiàn)的:

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
   ...
}

如 Cluster就是通過(guò)在方法加@Adaptive實(shí)現(xiàn)的:

@SPI(FailoverCluster.NAME)
public interface Cluster {

    /**
     * Merge the directory invokers to a virtual invoker.
     * 
     * @param 
     * @param directory
     * @return cluster invoker
     * @throws RpcException
     */
    @Adaptive
     Invoker join(Directory directory) throws RpcException;

}

這兩種方式的自適應(yīng)擴(kuò)展類(lèi)的實(shí)現(xiàn)方式也不同,在類(lèi)上加注解是通過(guò)在實(shí)現(xiàn)上標(biāo)識(shí)該類(lèi)為自適應(yīng)實(shí)現(xiàn)類(lèi),而在方法上加注解的,是通過(guò)動(dòng)態(tài)代碼生成自適應(yīng)實(shí)現(xiàn)類(lèi)。

擴(kuò)展點(diǎn)自動(dòng)激活

對(duì)于集合類(lèi)擴(kuò)展點(diǎn),比如:Filter, InvokerListener, ExportListener, TelnetHandler, StatusChecker 等,可以同時(shí)加載多個(gè)實(shí)現(xiàn),此時(shí),可以用自動(dòng)激活來(lái)簡(jiǎn)化配置

在ExtensionLoader中比較重要的公用方法就是這些:

getExtensionLoader

getAdaptiveExtension

getActivateExtension

下面就詳細(xì)剖析一下ExtensionLoader的實(shí)現(xiàn)流程。

獲取ExtensionLoader流程

每個(gè)可擴(kuò)展接口對(duì)應(yīng)的ExtensionLoader都是單例,唯一獲取ExtensionLoader對(duì)象的入口就是ExtensionLoader::getExtensionLoader方法,如主要流程圖:

首先通過(guò)ExtensionLoader::getExtensionLoader

public static  ExtensionLoader getExtensionLoader(Class type) {
        if (type == null)
            throw new IllegalArgumentException("Extension type == null");
        if(!type.isInterface()) {
            throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
        }
        if(!withExtensionAnnotation(type)) {
            throw new IllegalArgumentException("Extension type(" + type + 
                    ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
        }
        
        ExtensionLoader loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader(type));
            loader = (ExtensionLoader) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }

會(huì)校驗(yàn)嘗試獲取Loader的接口是否有@SPI注解,先在緩存中找,如果沒(méi)有緩存,則調(diào)用私有構(gòu)造方法:

private ExtensionLoader(Class type) {
        this.type = type;
        objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
    }

這里有個(gè)重要的對(duì)象objectFactory,這個(gè)對(duì)象的作用就是自動(dòng)裝配依賴(lài),也就是IOC,可以看出,除了ObjectFactory本身,所有擴(kuò)展點(diǎn)都有ObjectFactory實(shí)例,這個(gè)也是通過(guò)SPI管理的,它是通過(guò)getAdaptiveExtension()方法獲取,這就是后面要介紹自適應(yīng)擴(kuò)展實(shí)現(xiàn),有關(guān)ObjectFactory的內(nèi)容會(huì)在后面IOC中詳細(xì)分析。

自適應(yīng)擴(kuò)展

我們從getAdaptiveExtension()方法切入,這個(gè)方法要完成的任務(wù)就是獲取該擴(kuò)展點(diǎn)的自適應(yīng)實(shí)現(xiàn)實(shí)例,其流程如下圖所示:

主要完成以下工作:

1.檢查自適應(yīng)緩存是否存在。

2.如果緩存未命中,則開(kāi)始自適應(yīng)例構(gòu)建過(guò)程。

3.要構(gòu)建自適應(yīng)實(shí)例,先要有自適應(yīng)的實(shí)現(xiàn)類(lèi),實(shí)現(xiàn)類(lèi)有兩種方式:一種通過(guò)配置文件,一種是通過(guò)是字節(jié)碼的方式動(dòng)態(tài)生成。

配置文件配置的自適應(yīng)類(lèi)通過(guò)在實(shí)現(xiàn)類(lèi)上面加@Adaptive注解,如

.....
@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
}

字節(jié)碼生成的自適應(yīng)實(shí)現(xiàn)類(lèi)是在方法層面@Adaptive注解,如

@SPI("dubbo")
public interface Protocol {
    
    ....省略代碼
    @Adaptive
     Exporter export(Invoker invoker) throws RpcException;
    @Adaptive
     Invoker refer(Class type, URL url) throws RpcException;
    void destroy();

}

4.優(yōu)先加載配置文件,將自適應(yīng)實(shí)現(xiàn)類(lèi)緩存在cachedAdaptiveClass中,同時(shí)通過(guò)加載配置文件,也將激活實(shí)現(xiàn)緩存在cachedActivates之中,這個(gè)在后面的激活實(shí)現(xiàn)中有用到。將包裝類(lèi)實(shí)例緩存在cachedWrapperClasses??梢院?jiǎn)單一窺加載配置文件的代碼

private void loadFile(Map> extensionClasses, String dir) {
        String fileName = dir + type.getName();
        try {
            Enumeration urls;
            ClassLoader classLoader = findClassLoader();
            if (classLoader != null) {
                urls = classLoader.getResources(fileName);
            } else {
                urls = ClassLoader.getSystemResources(fileName);
            }
            if (urls != null) {
                while (urls.hasMoreElements()) {
                    java.net.URL url = urls.nextElement();
                    try {
                        BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
                        try {
                            String line = 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();
                                            line = line.substring(i + 1).trim();
                                        }
                                        if (line.length() > 0) {
                                            Class clazz = Class.forName(line, true, classLoader);
                                            //配置的實(shí)現(xiàn)必須實(shí)現(xiàn)該接口
                                            if (! type.isAssignableFrom(clazz)) {
                                                throw new IllegalStateException("Error when load extension class(interface: " +
                                                        type + ", class line: " + clazz.getName() + "), class " 
                                                        + clazz.getName() + "is not subtype of interface.");
                                            }
                                            if (clazz.isAnnotationPresent(Adaptive.class)) {
                                                //如果是自適應(yīng)實(shí)現(xiàn)
                                                if(cachedAdaptiveClass == null) {
                                                    cachedAdaptiveClass = clazz;
                                                } else if (! cachedAdaptiveClass.equals(clazz)) {
                                                    //只允許有一個(gè)自適應(yīng)實(shí)現(xiàn)類(lèi)
                                                    throw new IllegalStateException("More than 1 adaptive class found: "
                                                            + cachedAdaptiveClass.getClass().getName()
                                                            + ", " + clazz.getClass().getName());
                                                }
                                            } else {
                                                //如果不是自適應(yīng)類(lèi)
                                                try {
                                                    //判斷是不是包裝類(lèi),即是否有接口的構(gòu)造方法
                                                    clazz.getConstructor(type);
                                                    Set> wrappers = cachedWrapperClasses;
                                                    if (wrappers == null) {
                                                        cachedWrapperClasses = new ConcurrentHashSet>();
                                                        wrappers = cachedWrapperClasses;
                                                    }
                                                    wrappers.add(clazz);
                                                } catch (NoSuchMethodException e) {
                                                    //不是包裝類(lèi)
                                                    clazz.getConstructor();
                                                    if (name == null || name.length() == 0) {
                                                        //找到Extension注解
                                                        name = findAnnotationName(clazz);
                                                        if (name == null || name.length() == 0) {
                                                            //如果Extension注解沒(méi)有默認(rèn)名稱(chēng),則根據(jù)類(lèi)的名稱(chēng)關(guān)系判斷
                                                            if (clazz.getSimpleName().length() > type.getSimpleName().length()
                                                                    && clazz.getSimpleName().endsWith(type.getSimpleName())) {
                                                                //如果實(shí)現(xiàn)類(lèi)和接口有名稱(chēng)上關(guān)系,比如XXImpl則將后面的作為實(shí)現(xiàn)類(lèi)標(biāo)識(shí)
                                                                name = clazz.getSimpleName().substring(0, clazz.getSimpleName().length() - type.getSimpleName().length()).toLowerCase();
                                                            } else {
                                                                throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + url);
                                                            }
                                                        }
                                                    }
                                                    String[] names = NAME_SEPARATOR.split(name);
                                                    if (names != null && names.length > 0) {
                                                        Activate activate = clazz.getAnnotation(Activate.class);
                                                        if (activate != null) {
                                                            cachedActivates.put(names[0], activate);
                                                        }
                                                        for (String n : names) {
                                                            if (! cachedNames.containsKey(clazz)) {
                                                                cachedNames.put(clazz, n);
                                                            }
                                                            Class c = extensionClasses.get(n);
                                                            if (c == null) {
                                                                extensionClasses.put(n, clazz);
                                                            } else if (c != clazz) {
                                                                throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    } catch (Throwable t) {
                                        IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + url + ", cause: " + t.getMessage(), t);
                                        exceptions.put(line, e);
                                    }
                                }
                            } // end of while read lines
                        } finally {
                            reader.close();
                        }
                    } catch (Throwable t) {
                        logger.error("Exception when load extension class(interface: " +
                                            type + ", class file: " + url + ") in " + url, t);
                    }
                } // end of while urls
            }
        } catch (Throwable t) {
            logger.error("Exception when load extension class(interface: " +
                    type + ", description file: " + fileName + ").", t);
        }
    }

5.加載完配置文件后,檢查緩存的自適應(yīng)實(shí)現(xiàn)類(lèi),若沒(méi)有,則通過(guò)字節(jié)碼技術(shù)生成自適應(yīng)類(lèi)。調(diào)用createAdaptiveExtensionClass()方法,實(shí)際上是通過(guò)拼接class文本,然后通過(guò)compiler編譯文本生成class,這里又是一個(gè)自適應(yīng)的類(lèi)AdaptiveCompiler。

private Class getAdaptiveExtensionClass() {
        //先通過(guò)配置文化加載實(shí)現(xiàn)類(lèi),并且識(shí)別自適應(yīng)實(shí)現(xiàn)類(lèi)
        getExtensionClasses();
        if (cachedAdaptiveClass != null) {
            return cachedAdaptiveClass;
        }
        //如果沒(méi)有通過(guò)Adaptive注解標(biāo)識(shí)的自適應(yīng)實(shí)現(xiàn)類(lèi),則通過(guò)字節(jié)碼創(chuàng)建
        return cachedAdaptiveClass = createAdaptiveExtensionClass();
    }
....省略代碼
private Class createAdaptiveExtensionClass() {
        String code = createAdaptiveExtensionClassCode();
        ClassLoader classLoader = findClassLoader();
        com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }
@Adaptive
public class AdaptiveCompiler implements Compiler {

    private static volatile String DEFAULT_COMPILER;

    public static void setDefaultCompiler(String compiler) {
        DEFAULT_COMPILER = compiler;
    }

    public Class compile(String code, ClassLoader classLoader) {
        Compiler compiler;
        ExtensionLoader loader = ExtensionLoader.getExtensionLoader(Compiler.class);
        String name = DEFAULT_COMPILER; // copy reference
        if (name != null && name.length() > 0) {
            compiler = loader.getExtension(name);
        } else {
            compiler = loader.getDefaultExtension();
        }
        return compiler.compile(code, classLoader);
    }

}

下面是通過(guò)字節(jié)碼動(dòng)態(tài)生成的Protocol接口的自適應(yīng)擴(kuò)展Protocol$Adpative:

package com.alibaba.dubbo.rpc;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {
public void destroy() {throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker {
if (arg0 == null) 
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null) 
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");com.alibaba.dubbo.common.URL url = arg0.getUrl();
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) 
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");

com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
return extension.export(arg0);
}

public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws java.lang.Class {

if (arg1 == null) throw new IllegalArgumentException("url == null");
com.alibaba.dubbo.common.URL url = arg1;

String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );

if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");

com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);

return extension.refer(arg0, arg1);
}

public void destroyServer() {
throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroyServer() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
}
}
自動(dòng)激活擴(kuò)展

在dubbo中,某些組件可以同時(shí)有多個(gè)實(shí)現(xiàn)同時(shí)加載時(shí),就可以通過(guò)@Activate注解自動(dòng)激活,常見(jiàn)的自動(dòng)激活擴(kuò)展,如過(guò)濾器Filter,有順序要求,提供了三個(gè)排序?qū)傩?,before、after和order。還有一些過(guò)濾條件,主要是通過(guò)分組和key,如Provider和consumer的過(guò)濾邏輯可能就不一樣,Activate的源碼如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Activate {
    /**
     * Group過(guò)濾條件。
     */
    String[] group() default {};

    
    String[] value() default {};

    /**
     * 排序信息,可以不提供。
     */
    String[] before() default {};

    /**
     * 排序信息,可以不提供。
     */
    String[] after() default {};

    /**
     * 排序信息,可以不提供。
     */
    int order() default 0;
}

在ExtensionLoader中,有三個(gè)重載獲取激活擴(kuò)展實(shí)現(xiàn)的方法:

public List getActivateExtension(URL url, String[] values, String group)

public List getActivateExtension(URL url, String[] values)

public List getActivateExtension(URL url, String key, String group)

后面兩個(gè)也是通過(guò)調(diào)用第一個(gè)重載方法實(shí)現(xiàn),下面來(lái)分析一下它的源碼:

public List getActivateExtension(URL url, String[] values, String group) {
        List exts = new ArrayList();
        List names = values == null ? new ArrayList(0) : Arrays.asList(values);
        if (! names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
            getExtensionClasses();
            for (Map.Entry entry : cachedActivates.entrySet()) {
                String name = entry.getKey();
                Activate activate = entry.getValue();
                if (isMatchGroup(group, activate.group())) {
                    T ext = getExtension(name);
                    if (! names.contains(name)
                            && ! names.contains(Constants.REMOVE_VALUE_PREFIX + name) 
                            && isActive(activate, url)) {
                        exts.add(ext);
                    }
                }
            }
            Collections.sort(exts, ActivateComparator.COMPARATOR);
        }
        List usrs = new ArrayList();
        for (int i = 0; i < names.size(); i ++) {
            String name = names.get(i);
            if (! name.startsWith(Constants.REMOVE_VALUE_PREFIX)
                    && ! names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
                if (Constants.DEFAULT_KEY.equals(name)) {
                    if (usrs.size() > 0) {
                        exts.addAll(0, usrs);
                        usrs.clear();
                    }
                } else {
                    T ext = getExtension(name);
                    usrs.add(ext);
                }
            }
        }
        if (usrs.size() > 0) {
            exts.addAll(usrs);
        }
        return exts;
    }

這個(gè)方法所做的工作無(wú)非就是在之前加載配置時(shí)緩存的cachedActivates中過(guò)濾查詢(xún)符合條件的自動(dòng)激動(dòng)實(shí)例,并根據(jù)@Activate注解中配置的排序規(guī)則排序。

IOC注入

在創(chuàng)建自適應(yīng)實(shí)例時(shí),都會(huì)調(diào)用ExtensionLoader的injectExtension方法:

private T createAdaptiveExtension() {
        try {
            //傳入自適應(yīng)實(shí)例注入到ExtensionLoader
            return injectExtension((T) getAdaptiveExtensionClass().newInstance());
        } catch (Exception e) {
            throw new IllegalStateException("Can not create adaptive extenstion " + type + ", cause: " + e.getMessage(), e);
        }
    }
    
private T injectExtension(T instance) {
        try {
            //必須要有對(duì)象工廠
            if (objectFactory != null) {
                for (Method method : instance.getClass().getMethods()) {
                    if (method.getName().startsWith("set")
                            && method.getParameterTypes().length == 1
                            && Modifier.isPublic(method.getModifiers())) {
                        Class pt = method.getParameterTypes()[0];
                        try {
                            String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                            Object object = objectFactory.getExtension(pt, property);
                            if (object != null) {
                                method.invoke(instance, object);
                            }
                        } catch (Exception e) {
                            logger.error("fail to inject via method " + method.getName()
                                    + " of interface " + type.getName() + ": " + e.getMessage(), e);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }    

然后我們看到了ExtensionFactory對(duì)象,dubbo中的IOC實(shí)例是通過(guò)ExtensionFactory實(shí)現(xiàn)的,其實(shí)就是檢測(cè)擴(kuò)展實(shí)現(xiàn)類(lèi)有沒(méi)有通過(guò)set方法設(shè)置的屬性,如果有,就通過(guò)ExtensionFactory加載而設(shè)置。
ExtensionFactory的類(lèi)實(shí)現(xiàn)體系:

在構(gòu)造ExtensionLoader對(duì)象時(shí),有個(gè)對(duì)象extensionFactory是必須要?jiǎng)?chuàng)建的,可以看到它就是用自適應(yīng)實(shí)例,而ExtensionFatocry的自適應(yīng)實(shí)例便是AdaptiveExtensionFactory,通過(guò)下面它的源碼,我們可以發(fā)現(xiàn),它維護(hù)了其他非自適應(yīng)擴(kuò)展實(shí)例,其實(shí)也就兩個(gè)SpiExtensionFactory和SpringExtensionFactory。嘗試用這兩個(gè)實(shí)例去加載,加載到便返回。

@Adaptive
public class AdaptiveExtensionFactory implements ExtensionFactory {
    
    private final List factories;
    
    public AdaptiveExtensionFactory() {
        ExtensionLoader loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
        List list = new ArrayList();
        for (String name : loader.getSupportedExtensions()) {
            list.add(loader.getExtension(name));
        }
        factories = Collections.unmodifiableList(list);
    }

    public  T getExtension(Class type, String name) {
        for (ExtensionFactory factory : factories) {
            T extension = factory.getExtension(type, name);
            if (extension != null) {
                return extension;
            }
        }
        return null;
    }

}

ExtensionFatocry 可以理解為對(duì)象工廠,只不過(guò)這里的對(duì)應(yīng)就是Dubbo中的擴(kuò)展Extension,AdaptiveExtensionFactory可以理解為通用擴(kuò)展實(shí)現(xiàn)獲取的入口,至于具體的獲取方式分為兩種,如果一種是通過(guò)Dubbo 自己的SPI方式加載到的擴(kuò)展,同時(shí)還支持復(fù)用Srping 的方式,可以看看這兩種實(shí)現(xiàn)的代碼便可知:

public class SpiExtensionFactory implements ExtensionFactory {

    public  T getExtension(Class type, String name) {
        if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
            ExtensionLoader loader = ExtensionLoader.getExtensionLoader(type);
            if (loader.getSupportedExtensions().size() > 0) {
                return loader.getAdaptiveExtension();
            }
        }
        return null;
    }

}

public class SpringExtensionFactory implements ExtensionFactory {
    
    private static final Set contexts = new ConcurrentHashSet();
    
    public static void addApplicationContext(ApplicationContext context) {
        contexts.add(context);
    }

    public static void removeApplicationContext(ApplicationContext context) {
        contexts.remove(context);
    }

    @SuppressWarnings("unchecked")
    public  T getExtension(Class type, String name) {
        for (ApplicationContext context : contexts) {
            if (context.containsBean(name)) {
                Object bean = context.getBean(name);
                if (type.isInstance(bean)) {
                    return (T) bean;
                }
            }
        }
        return null;
    }

}
總結(jié)

作為貫穿整個(gè)Dubbo設(shè)計(jì)始終的思想,SPI在整個(gè)框架中隨處可見(jiàn),本文圍繞ExtensionLoader擴(kuò)展點(diǎn)機(jī)制,通過(guò)一些dubbo組件擴(kuò)展示例,分析了其核心源碼和流程。希望可以對(duì)于理解Dubbo的擴(kuò)展點(diǎn)乃至dubbo源碼解析過(guò)程中有所幫助,最后總結(jié)幾點(diǎn):

對(duì)于每個(gè)擴(kuò)展點(diǎn),只維護(hù)一個(gè)ExtensionLoad,具體擴(kuò)展實(shí)現(xiàn)類(lèi)和實(shí)例,都是通過(guò)相應(yīng)的ExtensionLoader獲取的。

針對(duì)每個(gè)擴(kuò)展實(shí)現(xiàn)的實(shí)例都是單例的,所以在擴(kuò)展實(shí)現(xiàn)時(shí)應(yīng)保證線程安全。

自適應(yīng)實(shí)現(xiàn)只能有一個(gè),自適應(yīng)實(shí)現(xiàn)類(lèi)獲取有兩種方式,一種是通過(guò)配置文件,這種就是針對(duì)@Adaptive注解在類(lèi)級(jí)別的時(shí),而@Adaptive注解在方法級(jí)別時(shí),自適應(yīng)實(shí)現(xiàn)類(lèi)就需要通過(guò)字符碼動(dòng)態(tài)生成。

自動(dòng)激活擴(kuò)展實(shí)現(xiàn)可以有多個(gè),一般情況下,采用自動(dòng)激動(dòng)方式擴(kuò)展的一般都會(huì)有多個(gè),正因?yàn)橛卸鄠€(gè),自動(dòng)激動(dòng)擴(kuò)展實(shí)現(xiàn)可能有順序性,且可以分組。

參考

http://dubbo.apache.org/books...
https://blog.csdn.net/jdluoji...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69282.html

相關(guān)文章

  • Dubbo Spi機(jī)制

    摘要:為了實(shí)現(xiàn)在模塊裝配的時(shí)候,不在模塊里寫(xiě)死代碼,就需要一種服務(wù)發(fā)現(xiàn)機(jī)制。就提供了這樣一種機(jī)制為某個(gè)接口尋找服務(wù)實(shí)現(xiàn),有點(diǎn)類(lèi)似思想,將裝配的控制權(quán)移到代碼之外。即接口文件的全類(lèi)名。五示例遵循上述第一條第點(diǎn),這里為接口文件,其中和為兩個(gè)實(shí)現(xiàn)類(lèi)。 一、Dubbo內(nèi)核 Dubbo內(nèi)核主要包含SPI、AOP、IOC、Compiler。 二、JDK的SPI 1.spi的設(shè)計(jì)目標(biāo): 面向?qū)ο蟮脑O(shè)計(jì)里...

    mrli2016 評(píng)論0 收藏0
  • 聊聊Dubbo - Dubbo可擴(kuò)展機(jī)制實(shí)戰(zhàn)

    摘要:今天我想聊聊的另一個(gè)很棒的特性就是它的可擴(kuò)展性。的擴(kuò)展機(jī)制在的官網(wǎng)上,描述自己是一個(gè)高性能的框架。接下來(lái)的章節(jié)中我們會(huì)慢慢揭開(kāi)擴(kuò)展機(jī)制的神秘面紗。擴(kuò)展擴(kuò)展點(diǎn)的實(shí)現(xiàn)類(lèi)。的定義在配置文件中可以看到文件中定義了個(gè)的擴(kuò)展實(shí)現(xiàn)。 摘要: 在Dubbo的官網(wǎng)上,Dubbo描述自己是一個(gè)高性能的RPC框架。今天我想聊聊Dubbo的另一個(gè)很棒的特性, 就是它的可擴(kuò)展性。 Dubbo的擴(kuò)展機(jī)制 在Dub...

    techstay 評(píng)論0 收藏0
  • dubbo擴(kuò)展點(diǎn)機(jī)制

    摘要:在中配置,以配置為例整個(gè),最先使用的地方從里面讀取這個(gè)配置使用接口的中獲取具體的實(shí)現(xiàn)類(lèi)中有兩個(gè)值當(dāng)主線程被外部終止時(shí),會(huì)觸發(fā),執(zhí)行的與方法通知下面的鎖操作,主線程正常走完代碼,并最終停止。 spring是如何啟動(dòng)容器的 常見(jiàn)的一種在本地使用main方法啟動(dòng)spring的方法 public static void main(String[] args) throws Except...

    Rindia 評(píng)論0 收藏0
  • dubbo擴(kuò)展點(diǎn)的IOC

    摘要:屬性上篇文章中,提到在獲取擴(kuò)展點(diǎn)接口對(duì)應(yīng)的的時(shí)候,會(huì)執(zhí)行私有構(gòu)造函數(shù)。因?yàn)榇藭r(shí)是,即當(dāng)為時(shí),即我們可以看出,所有非擴(kuò)展點(diǎn)接口都會(huì)執(zhí)行對(duì)應(yīng)的實(shí)例的方法返回一個(gè)實(shí)例,即對(duì)象。 spring是如何獲得容器中管理的類(lèi)的 拿到applicationContext,就可以調(diào)用getBean方法來(lái)獲得Spring的bean對(duì)象了 public class SpringContextUtil impl...

    Zoom 評(píng)論0 收藏0
  • dubbo源碼解析(二)Dubbo擴(kuò)展機(jī)制SPI

    摘要:二注解該注解為了保證在內(nèi)部調(diào)用具體實(shí)現(xiàn)的時(shí)候不是硬編碼來(lái)指定引用哪個(gè)實(shí)現(xiàn),也就是為了適配一個(gè)接口的多種實(shí)現(xiàn),這樣做符合模塊接口設(shè)計(jì)的可插拔原則,也增加了整個(gè)框架的靈活性,該注解也實(shí)現(xiàn)了擴(kuò)展點(diǎn)自動(dòng)裝配的特性。 Dubbo擴(kuò)展機(jī)制SPI 前一篇文章《dubbo源碼解析(一)Hello,Dubbo》是對(duì)dubbo整個(gè)項(xiàng)目大體的介紹,而從這篇文章開(kāi)始,我將會(huì)從源碼來(lái)解讀dubbo再各個(gè)模塊的實(shí)...

    DirtyMind 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<