亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

1. 源碼分析---SOFARPC可擴(kuò)展的機(jī)制SPI

U2FsdGVkX1x / 2504人閱讀

摘要:是螞蟻金服開源的一個(gè)框架,相比它沒有這么多歷史的包袱,代碼更加簡(jiǎn)潔,設(shè)計(jì)思路更加清晰,更加容易去理解其中的代碼。

原文鏈接:https://www.cnblogs.com/luozh...

這幾天離職在家,正好沒事可以瘋狂的輸出一下,本來(lái)想寫DUBBO的源碼解析的,但是發(fā)現(xiàn)寫DUBBO源碼的太多了,所以找一個(gè)寫的不那么多的框架,所以就選中SOFARPC這個(gè)框架了。

SOFARPC是螞蟻金服開源的一個(gè)RPC框架,相比DUBBO它沒有這么多歷史的包袱,代碼更加簡(jiǎn)潔,設(shè)計(jì)思路更加清晰,更加容易去理解其中的代碼。

那么為什么要去重寫原生的SPI呢?官方給出了如下解釋:

按需加載

可以有別名

可以有優(yōu)先級(jí)進(jìn)行排序和覆蓋

可以控制是否單例

可以在某些場(chǎng)景下使用編碼

可以指定擴(kuò)展配置位置

可以排斥其他擴(kuò)展點(diǎn)

整個(gè)流程如下:

我們以ConsumerBootstrap為例:

先要有一個(gè)抽象類:

@Extensible(singleton = false)
public abstract class ConsumerBootstrap {
    ....
}

指定擴(kuò)展實(shí)現(xiàn)類:

@Extension("sofa")
public class DefaultConsumerBootstrap extends ConsumerBootstrap {
    ...
}

擴(kuò)展描述文件META-INF/services/sofa-rpc/com.alipay.sofa.rpc.bootstrap.ConsumerBootstrap

sofa=com.alipay.sofa.rpc.bootstrap.DefaultConsumerBootstrap

當(dāng)這些準(zhǔn)備完成后,直接調(diào)用即可。

ConsumerBootstrap sofa =  ExtensionLoaderFactory.getExtensionLoader(ConsumerBootstrap.class).getExtension("sofa");

接下來(lái)我們看看ExtensionLoaderFactory的源碼

    /**
     * All extension loader {Class : ExtensionLoader}
     * 這個(gè)map里面裝的是所有ExtensionLoader
     */
    private static final ConcurrentMap LOADER_MAP = new ConcurrentHashMap();


    public static  ExtensionLoader getExtensionLoader(Class clazz, ExtensionLoaderListener listener) {
        ExtensionLoader loader = LOADER_MAP.get(clazz);
        if (loader == null) {
            //get不到則加上鎖
            synchronized (ExtensionLoaderFactory.class) {
                //防止其他線程操作再get一次
                loader = LOADER_MAP.get(clazz);
                if (loader == null) {
                    loader = new ExtensionLoader(clazz, listener);
                    LOADER_MAP.put(clazz, loader);
                }
            }
        }
        return loader;
    }

然后我們看一下ExtensionLoader這個(gè)類的構(gòu)造器

    protected ExtensionLoader(Class interfaceClass, boolean autoLoad, ExtensionLoaderListener listener) {
        //如果正在執(zhí)行關(guān)閉,則將屬性置空后直接返回
        if (RpcRunningState.isShuttingDown()) {
            this.interfaceClass = null;
            this.interfaceName = null;
            this.listener = null;
            this.factory = null;
            this.extensible = null;
            this.all = null;
            return;
        }
        // 接口為空,既不是接口,也不是抽象類
        if (interfaceClass == null ||
                !(interfaceClass.isInterface() || Modifier.isAbstract(interfaceClass.getModifiers()))) {
            throw new IllegalArgumentException("Extensible class must be interface or abstract class!");
        }
        //當(dāng)前加載的接口類名
        this.interfaceClass = interfaceClass;
        //接口名字
        this.interfaceName = ClassTypeUtils.getTypeStr(interfaceClass);
        this.listener = listener;
        //接口上必須要有Extensible注解
        Extensible extensible = interfaceClass.getAnnotation(Extensible.class);
        if (extensible == null) {
            throw new IllegalArgumentException(
                    "Error when load extensible interface " + interfaceName + ", must add annotation @Extensible.");
        } else {
            this.extensible = extensible;
        }
        // 如果是單例,那么factory不為空
        this.factory = extensible.singleton() ? new ConcurrentHashMap() : null;
        //這個(gè)屬性里面是這個(gè)接口的所有實(shí)現(xiàn)類
        this.all = new ConcurrentHashMap>();
        if (autoLoad) {
            //獲取到擴(kuò)展點(diǎn)加載的路徑
            List paths = RpcConfigs.getListValue(RpcOptions.EXTENSION_LOAD_PATH);
            for (String path : paths) {
                //根據(jù)路徑加載文件
                loadFromFile(path);
            }
        }
    }

拿到所有的擴(kuò)展點(diǎn)加載的路徑后進(jìn)入到loadFromFile中進(jìn)行文件的加載

    protected synchronized void loadFromFile(String path) {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Loading extension of extensible {} from path: {}", interfaceName, path);
        }
        // 默認(rèn)如果不指定文件名字,就是接口名
        String file = StringUtils.isBlank(extensible.file()) ? interfaceName : extensible.file().trim();
        String fullFileName = path + file;
        try {
            ClassLoader classLoader = ClassLoaderUtils.getClassLoader(getClass());
            loadFromClassLoader(classLoader, fullFileName);
        } catch (Throwable t) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("Failed to load extension of extensible " + interfaceName + " from path:" + fullFileName,
                    t);
            }
        }
    }
    
    
    protected void loadFromClassLoader(ClassLoader classLoader, String fullFileName) throws Throwable {
        Enumeration urls = classLoader != null ? classLoader.getResources(fullFileName)
            : ClassLoader.getSystemResources(fullFileName);
        // 可能存在多個(gè)文件。
        if (urls != null) {
            while (urls.hasMoreElements()) {
                // 讀取一個(gè)文件
                URL url = urls.nextElement();
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Loading extension of extensible {} from classloader: {} and file: {}",
                        interfaceName, classLoader, url);
                }
                BufferedReader reader = null;
                try {
                    reader = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));
                    String line;
                    while ((line = reader.readLine()) != null) {
                        readLine(url, line);
                    }
                } catch (Throwable t) {
                    if (LOGGER.isWarnEnabled()) {
                        LOGGER.warn("Failed to load extension of extensible " + interfaceName
                            + " from classloader: " + classLoader + " and file:" + url, t);
                    }
                } finally {
                    if (reader != null) {
                        reader.close();
                    }
                }
            }
        }
    }

接下來(lái)進(jìn)入到readLine,這個(gè)方法主要是讀取prop文件里面的每一行記錄,并加載該實(shí)現(xiàn)類的類文件校驗(yàn)完后將文件添加到all屬性中

    protected void readLine(URL url, String line) {
        //讀取文件里面的一行記錄,并將這行記錄用=號(hào)分割
        String[] aliasAndClassName = parseAliasAndClassName(line);
        if (aliasAndClassName == null || aliasAndClassName.length != 2) {
            return;
        }
        //別名
        String alias = aliasAndClassName[0];
        //包名
        String className = aliasAndClassName[1];
        // 讀取配置的實(shí)現(xiàn)類
        Class tmp;
        try {
            tmp = ClassUtils.forName(className, false);
        } catch (Throwable e) {
            if (LOGGER.isWarnEnabled()) {
                LOGGER.warn("Extension {} of extensible {} is disabled, cause by: {}",
                    className, interfaceName, ExceptionUtils.toShortString(e, 2));
            }
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Extension " + className + " of extensible " + interfaceName + " is disabled.", e);
            }
            return;
        }
        if (!interfaceClass.isAssignableFrom(tmp)) {
            throw new IllegalArgumentException("Error when load extension of extensible " + interfaceName +
                " from file:" + url + ", " + className + " is not subtype of interface.");
        }
        Class implClass = (Class) tmp;

        // 檢查是否有可擴(kuò)展標(biāo)識(shí)
        Extension extension = implClass.getAnnotation(Extension.class);
        if (extension == null) {
            throw new IllegalArgumentException("Error when load extension of extensible " + interfaceName +
                " from file:" + url + ", " + className + " must add annotation @Extension.");
        } else {
            String aliasInCode = extension.value();
            if (StringUtils.isBlank(aliasInCode)) {
                // 擴(kuò)展實(shí)現(xiàn)類未配置@Extension 標(biāo)簽
                throw new IllegalArgumentException("Error when load extension of extensible " + interfaceClass +
                    " from file:" + url + ", " + className + ""s alias of @Extension is blank");
            }
            if (alias == null) {
                // spi文件里沒配置,用代碼里的
                alias = aliasInCode;
            } else {
                // spi文件里配置的和代碼里的不一致
                if (!aliasInCode.equals(alias)) {
                    throw new IllegalArgumentException("Error when load extension of extensible " + interfaceName +
                        " from file:" + url + ", aliases of " + className + " are " +
                        "not equal between " + aliasInCode + "(code) and " + alias + "(file).");
                }
            }
            // 接口需要編號(hào),實(shí)現(xiàn)類沒設(shè)置
            if (extensible.coded() && extension.code() < 0) {
                throw new IllegalArgumentException("Error when load extension of extensible " + interfaceName +
                    " from file:" + url + ", code of @Extension must >=0 at " + className + ".");
            }
        }
        // 不可以是default和*
        if (StringUtils.DEFAULT.equals(alias) || StringUtils.ALL.equals(alias)) {
            throw new IllegalArgumentException("Error when load extension of extensible " + interfaceName +
                " from file:" + url + ", alias of @Extension must not "default" and "*" at " + className + ".");
        }
        // 檢查是否有存在同名的
        ExtensionClass old = all.get(alias);
        ExtensionClass extensionClass = null;
        if (old != null) {
            // 如果當(dāng)前擴(kuò)展可以覆蓋其它同名擴(kuò)展
            if (extension.override()) {
                // 如果優(yōu)先級(jí)還沒有舊的高,則忽略
                if (extension.order() < old.getOrder()) {
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("Extension of extensible {} with alias {} override from {} to {} failure, " +
                            "cause by: order of old extension is higher",
                            interfaceName, alias, old.getClazz(), implClass);
                    }
                } else {
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("Extension of extensible {} with alias {}: {} has been override to {}",
                            interfaceName, alias, old.getClazz(), implClass);
                    }
                    // 如果當(dāng)前擴(kuò)展可以覆蓋其它同名擴(kuò)展
                    extensionClass = buildClass(extension, implClass, alias);
                }
            }
            // 如果舊擴(kuò)展是可覆蓋的
            else {
                if (old.isOverride() && old.getOrder() >= extension.order()) {
                    // 如果已加載覆蓋擴(kuò)展,再加載到原始擴(kuò)展
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("Extension of extensible {} with alias {}: {} has been loaded, ignore origin {}",
                            interfaceName, alias, old.getClazz(), implClass);
                    }
                } else {
                    // 如果不能被覆蓋,拋出已存在異常
                    throw new IllegalStateException(
                        "Error when load extension of extensible " + interfaceClass + " from file:" + url +
                            ", Duplicate class with same alias: " + alias + ", " + old.getClazz() + " and " + implClass);
                }
            }
        } else {
            extensionClass = buildClass(extension, implClass, alias);
        }
        if (extensionClass != null) {
            // 檢查是否有互斥的擴(kuò)展點(diǎn)
            for (Map.Entry> entry : all.entrySet()) {
                ExtensionClass existed = entry.getValue();
                if (extensionClass.getOrder() >= existed.getOrder()) {
                    // 新的優(yōu)先級(jí) >= 老的優(yōu)先級(jí),檢查新的擴(kuò)展是否排除老的擴(kuò)展
                    String[] rejection = extensionClass.getRejection();
                    if (CommonUtils.isNotEmpty(rejection)) {
                        for (String rej : rejection) {
                            existed = all.get(rej);
                            if (existed == null || extensionClass.getOrder() < existed.getOrder()) {
                                continue;
                            }
                            ExtensionClass removed = all.remove(rej);
                            if (removed != null) {
                                if (LOGGER.isInfoEnabled()) {
                                    LOGGER.info(
                                        "Extension of extensible {} with alias {}: {} has been reject by new {}",
                                        interfaceName, removed.getAlias(), removed.getClazz(), implClass);
                                }
                            }
                        }
                    }
                } else {
                    String[] rejection = existed.getRejection();
                    if (CommonUtils.isNotEmpty(rejection)) {
                        for (String rej : rejection) {
                            if (rej.equals(extensionClass.getAlias())) {
                                // 被其它擴(kuò)展排掉
                                if (LOGGER.isInfoEnabled()) {
                                    LOGGER.info(
                                        "Extension of extensible {} with alias {}: {} has been reject by old {}",
                                        interfaceName, alias, implClass, existed.getClazz());
                                    return;
                                }
                            }
                        }
                    }
                }
            }

            loadSuccess(alias, extensionClass);
        }
    }

加載完文件后我們?cè)倩氐?/p>

ConsumerBootstrap sofa =  ExtensionLoaderFactory.getExtensionLoader(ConsumerBootstrap.class).getExtension("sofa");

進(jìn)入到getExtension方法中

    public ExtensionClass getExtensionClass(String alias) {
        return all == null ? null : all.get(alias);
    }

    public T getExtension(String alias) {
        //從all屬性中拿到加載的class
        ExtensionClass extensionClass = getExtensionClass(alias);
        if (extensionClass == null) {
            throw new SofaRpcRuntimeException("Not found extension of " + interfaceName + " named: "" + alias + ""!");
        } else {
            //在加載class的時(shí)候,校驗(yàn)了是否是單例,如果是單例,那么factory不為null
            if (extensible.singleton() && factory != null) {
                T t = factory.get(alias);
                if (t == null) {
                    synchronized (this) {
                        t = factory.get(alias);
                        if (t == null) {
                            //實(shí)例化
                            t = extensionClass.getExtInstance();
                            //放入到factory,單例的class下次直接拿就好了,不需要重新創(chuàng)建
                            factory.put(alias, t);
                        }
                    }
                }
                return t;
            } else {
                //實(shí)例化
                return extensionClass.getExtInstance();
            }
        }
    }

我們進(jìn)入到ExtensionClass看看getExtInstance方法

    /**
     * 服務(wù)端實(shí)例對(duì)象(只在是單例的時(shí)候保留)
     * 用volatile修飾,保證了可見性
     */
    private volatile transient T       instance;
    
    /**
     * 得到服務(wù)端實(shí)例對(duì)象,如果是單例則返回單例對(duì)象,如果不是則返回新創(chuàng)建的實(shí)例對(duì)象
     *
     * @param argTypes 構(gòu)造函數(shù)參數(shù)類型
     * @param args     構(gòu)造函數(shù)參數(shù)值
     * @return 擴(kuò)展點(diǎn)對(duì)象實(shí)例 ext instance
     */
    public T getExtInstance(Class[] argTypes, Object[] args) {
        if (clazz != null) {
            try {
                if (singleton) { // 如果是單例
                    if (instance == null) {
                        synchronized (this) {
                            if (instance == null) {
                                //通過反射創(chuàng)建實(shí)例
                                instance = ClassUtils.newInstanceWithArgs(clazz, argTypes, args);
                            }
                        }
                    }
                    return instance; // 保留單例
                } else {
                    //通過反射創(chuàng)建實(shí)例
                    return ClassUtils.newInstanceWithArgs(clazz, argTypes, args);
                }
            } catch (Exception e) {
                throw new SofaRpcRuntimeException("create " + clazz.getCanonicalName() + " instance error", e);
            }
        }
        throw new SofaRpcRuntimeException("Class of ExtensionClass is null");
    }

看完了SOFARPC的擴(kuò)展類實(shí)現(xiàn)后感覺代碼寫的非常的整潔,邏輯非常的清晰,里面有很多可以學(xué)習(xí)的地方,比如線程安全用到了雙重檢查鎖和volatile保證可見性。

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

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

相關(guān)文章

  • 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)目大體的介紹,而從這篇文章開始,我將會(huì)從源碼來(lái)解讀dubbo再各個(gè)模塊的實(shí)...

    DirtyMind 評(píng)論0 收藏0
  • 螞蟻金服啟動(dòng)分布式中間件開源計(jì)劃,用于快速構(gòu)建金融級(jí)云原生架構(gòu)

    摘要:在螞蟻金服內(nèi)部是被所有在線應(yīng)用的使用的服務(wù)調(diào)用框架,截止年雙十一,已經(jīng)被螞蟻多個(gè)系統(tǒng)所使用,生產(chǎn)環(huán)境發(fā)布的服務(wù)數(shù)量超過了個(gè)。 原文地址:http://www.sohu.com/a/2288043... 我們很高興地宣布,今天螞蟻金服啟動(dòng)分布式中間件(Scalable Open Financial Architecture,以下簡(jiǎn)稱 SOFA 中間件)的開源計(jì)劃! SOFA 是螞蟻金服自...

    frank_fun 評(píng)論0 收藏0
  • dubbo之SPI

    摘要:簡(jiǎn)介全稱為,是一種服務(wù)發(fā)現(xiàn)機(jī)制。的本質(zhì)是將接口實(shí)現(xiàn)類的全限定名配置在文件中,并由服務(wù)加載器讀取配置文件,加載實(shí)現(xiàn)類。不過,并未使用原生的機(jī)制,而是對(duì)其進(jìn)行了增強(qiáng),使其能夠更好的滿足需求。并未使用,而是重新實(shí)現(xiàn)了一套功能更強(qiáng)的機(jī)制。 1、SPI簡(jiǎn)介 SPI 全稱為 Service Provider Interface,是一種服務(wù)發(fā)現(xiàn)機(jī)制。SPI 的本質(zhì)是將接口實(shí)現(xiàn)類的全限定名配置在文件中...

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

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

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

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

0條評(píng)論

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