motan源碼分析二:使用spi機制進行類載入_motan

來源:互聯網
上載者:User
motan源碼分析二:使用spi機制進行類載入

在motan的源碼中使用了很多的spi機制進行對象的建立,下面我們來具體分析一下它的實現方法。

1.在實際的jar包的\META-INF\services目錄中引入相關的檔案,例如下圖中,我解壓了core的jar檔案後,獲得到的相應檔案清單:

2.以第一節中的ConfigHandler為例來分析,開啟上圖中的com.weibo.api.motan.config.handler.ConfigHandler檔案,檔案內容標識著ConfigHandler介面的實作類別為:com.weibo.api.motan.config.handler.SimpleConfigHandler 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # #  Copyright  2009 - 2016  Weibo, Inc. # #    Licensed under the Apache License, Version  2.0  (the  "License" ); #    you may not use  this  file except in compliance with the License. #    You may obtain a copy of the License at # #        http: //www.apache.org/licenses/LICENSE-2.0 # #    Unless required by applicable law or agreed to in writing, software #    distributed under the License is distributed on an  "AS IS"  BASIS, #    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #    See the License  for  the specific language governing permissions and #    limitations under the License. #   com.weibo.api.motan.config.handler.SimpleConfigHandler

3.在第一節中,建立ConfigHandler對象的代碼是這樣的:

        ConfigHandler configHandler = ExtensionLoader.getExtensionLoader(ConfigHandler.class).getExtension(MotanConstants.DEFAULT_VALUE);

4.開始進入到實際的載入代碼核心部分,首先來看一下類載入器的具體實現:

    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {        checkInterfaceType(type);//基礎性檢查        ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoaders.get(type);//之前是否已經載入過此載入器        if (loader == null) {            loader = initExtensionLoader(type);//第一次載入        }        return loader;    }    private static <T> void checkInterfaceType(Class<T> clz) {        if (clz == null) {            failThrows(clz, "Error extension type is null");        }        if (!clz.isInterface()) {            failThrows(clz, "Error extension type is not interface");        }        if (!isSpiType(clz)) {            failThrows(clz, "Error extension type without @Spi annotation");        }    }    public static synchronized <T> ExtensionLoader<T> initExtensionLoader(Class<T> type) {        ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoaders.get(type);        if (loader == null) {            loader = new ExtensionLoader<T>(type);//新建立一個載入器            extensionLoaders.putIfAbsent(type, loader);            loader = (ExtensionLoader<T>) extensionLoaders.get(type);        }        return loader;    }

5.下面我們將進入到載入器的內部,分析具體的實現:

    private ExtensionLoader(Class<T> type) {        this(type, Thread.currentThread().getContextClassLoader());//使用當前線程的類載入器做為載入器,type為ConfigHandler介面    }    public T getExtension(String name) {        checkInit();//檢查是否初始化        if (name == null) {            return null;        }        try {            Spi spi = type.getAnnotation(Spi.class);            if (spi.scope() == Scope.SINGLETON) {                return getSingletonInstance(name);//返回唯一的對象            } else {                Class<T> clz = extensionClasses.get(name);                if (clz == null) {                    return null;                }                return clz.newInstance();//重新建立對象            }        } catch (Exception e) {            failThrows(type, "Error when getExtension " + name, e);        }        return null;    }    private synchronized void loadExtensionClasses() {        if (init) {            return;        }        extensionClasses = loadExtensionClasses(PREFIX);//載入相關的類        singletonInstances = new ConcurrentHashMap<String, T>();        init = true;    }    private ConcurrentMap<String, Class<T>> loadExtensionClasses(String prefix) {        String fullName = prefix + type.getName();//全名為:jar包名+\META-INF\services\com.weibo.api.motan.config.handler.ConfigHandler檔案裡的類        List<String> classNames = new ArrayList<String>();        try {            Enumeration<URL> urls;            if (classLoader == null) {                urls = ClassLoader.getSystemResources(fullName);            } else {                urls = classLoader.getResources(fullName);            }            if (urls == null || !urls.hasMoreElements()) {                return new ConcurrentHashMap<String, Class<T>>();            }            System.out.println("fullname:"+fullName);            while (urls.hasMoreElements()) {                URL url = urls.nextElement();                System.out.println("url:"+url.getFile());                parseUrl(type, url, classNames);            }        } catch (Exception e) {            throw new MotanFrameworkException(                    "ExtensionLoader loadExtensionClasses error, prefix: " + prefix + " type: " + type.getClass(), e);        }        for(String classN : classNames){            System.out.println("class:"+classN);        }        return loadClass(classNames);    }

 6.在parseUrl方法中進行檔案的內容讀取,並在loadClass中完成類的載入

    private void parseUrl(Class<T> type, URL url, List<String> classNames) throws ServiceConfigurationError {        InputStream inputStream = null;        BufferedReader reader = null;        try {            inputStream = url.openStream();            reader = new BufferedReader(new InputStreamReader(inputStream, MotanConstants.DEFAULT_CHARACTER));            String line = null;            int indexNumber = 0;            while ((line = reader.readLine()) != null) {                indexNumber++;                parseLine(type, url, line, indexNumber, classNames);//讀取到類的名稱:com.weibo.api.motan.config.handler.SimpleConfigHandler            }        } catch (Exception x) {            failLog(type, "Error reading spi configuration file", x);        } finally {            try {                if (reader != null) {                    reader.close();                }                if (inputStream != null) {                    inputStream.close();                }            } catch (IOException y) {                failLog(type, "Error closing spi configuration file", y);            }        }    }    private ConcurrentMap<String, Class<T>> loadClass(List<String> classNames) {        ConcurrentMap<String, Class<T>> map = new ConcurrentHashMap<String, Class<T>>();        for (String className : classNames) {            try {                Class<T> clz;                if (classLoader == null) {                    clz = (Class<T>) Class.forName(className);//裝載類:com.weibo.api.motan.config.handler.SimpleConfigHandler                } else {                    clz = (Class<T>) Class.forName(className, true, classLoader);                }                checkExtensionType(clz);                String spiName = getSpiName(clz);                if (map.containsKey(spiName)) {                    failThrows(clz, ":Error spiName already exist " + spiName);                } else {                    map.put(spiName, clz);                }            } catch (Exception e) {                failLog(type, "Error load spi class", e);            }        }        return map;    }

motan類載入的知識點總結:

1.使用jdk的spi規範,在\META-INF\services中添加實際的使用類描述,從而實作類別與類之間的完全解耦;

2.類載入器使用的是當前線程的類載入器;

3.motan的類載入器可以支援單例和多例兩種模式;

4.motan中大量使用了spi的類載入方式。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.