自定义ServicesLoader来实现根据配置使用不通的SPI实现从而实现项目扩展
2019獨角獸企業(yè)重金招聘Python工程師標準>>>
自定義ServicesLoader來實現(xiàn)根據(jù)配置使用不通的SPI實現(xiàn)從而實現(xiàn)項目擴展
?
一 、 ?都知道Java中的SPI技術(shù),也是dubbo中實驗的,
通過這個案例可以快速的了解spi是什么?https://my.oschina.net/lenglingx/blog/879292
這個案例就是直接簡單使用的spi,都說dubbo是也是使用spi來做擴展的,去看了一下dubbo的介紹,了解到了:ExtensionLoader.java
且dubbo使用是通過配置來的,如注冊協(xié)議有,redis,和zookeeper。
這里我們就介紹如何實現(xiàn)通過配置來和spi結(jié)合實現(xiàn)dubbo這樣的。
?
二、 ?這個項目介紹,log-parent,為整體項目,內(nèi)部有4個項目。
log為api的接口項目
alog為ALog實現(xiàn)
blog為BLog實現(xiàn)
logTest為這個 log的測試項目
log項目的Log接口
package com.tspi.log;public interface Logger {public void debug(String logger);public void info(String logger);public void warn(String logger);public void error(String logger);}CustomServiceLoader自定義serviceLoader
package com.tspi.log;import java.net.URL; import java.util.Enumeration; import java.util.HashMap; import java.util.Map;import org.apache.commons.io.IOUtils;public class CustomServiceLoader {public static final String MAPPING_CONFIG_PREFIX = "META-INF/services";public static Map mservices;public static <S> Map<String, Class<S>> loade(Class<S> service) throws Exception {String mappingConfigFile = MAPPING_CONFIG_PREFIX + "/log/" + service.getName();// 由于一個接口的實現(xiàn)類可能存在多個jar包中的META-INF目錄下,所以下面使用getResources返回一個URL數(shù)組System.out.println("configFile:" + mappingConfigFile);Enumeration<URL> configFileUrls = CustomServiceLoader.class.getClassLoader().getResources(mappingConfigFile);if (configFileUrls == null) {return null;}//List<S> services = new LinkedList<S>();mservices = new HashMap<String, Class<S>>();while (configFileUrls.hasMoreElements()) {URL configFileUrl = configFileUrls.nextElement();String configContent = IOUtils.toString(configFileUrl.openStream());System.out.println("configContent:");System.out.println(configContent);System.out.println("configContent --end");String[] serviceNames = configContent.split("\n");for (String serviceName : serviceNames) {System.out.println("serviceName: " + serviceName);String[] tempServiceName = serviceName.split("=");System.out.println("tmpServiceName:" + tempServiceName[0] + "," +tempServiceName[1]);ClassLoader classLoader = CustomServiceLoader.class.getClassLoader();System.out.println("classloader:" + classLoader);Class class1 = classLoader.loadClass(tempServiceName[1]);System.out.println("class1" + class1);Object serviceInstance = class1.newInstance();Logger log = (Logger)serviceInstance;log.warn("TEST!!!");//services.add((S) serviceInstance);mservices.put(tempServiceName[0], serviceInstance);}}System.out.println("-----");System.out.println("mservices:" + mservices.toString());return mservices;}public static Object getType(String type) {System.out.println("type:" + type);System.out.println("-----");System.out.println("mservices:" + mservices.toString());return mservices.get(type);}}?
alog項目:
ALogger實現(xiàn):
package com.tspi.alog;import com.tspi.log.Logger;public class ALogger implements Logger{public ALogger() {}public void debug(String logger) {System.out.println("ALogger-->debug: " + logger);}public void info(String logger) {System.out.println("ALogger-->info: " + logger); }public void warn(String logger) {System.out.println("ALogger-->warn: " + logger);}public void error(String logger) {System.out.println("ALogger-->error: " + logger);}}同時在resources目錄下添加
META-INF/services/log/com.tspi.log.Logger ?這個文件。
內(nèi)容為
alog=com.tspi.alog.ALogger?
blog項目同alog 項目已樣:
package com.tspi.blog;import com.tspi.log.Logger;public class BLogger implements Logger{public BLogger() {}public void debug(String logger) {System.out.println("BLogger-->debug: " + logger);}public void info(String logger) {System.out.println("BLogger-->info: " + logger); }public void warn(String logger) {System.out.println("BLogger-->warn: " + logger);}public void error(String logger) {System.out.println("BLogger-->error: " + logger);} }同樣在resources目錄下添加
META-INF/services/log/com.tspi.log.Logger ?這個文件。
內(nèi)容為
blog=com.tspi.blog.BLogger?
logTest項目:
App.java
package com.tspi.logtest;import java.util.ResourceBundle;import com.tspi.log.CustomServiceLoader; import com.tspi.log.Logger;/*** Hello world!**/ public class App {public static void main(String[] args) {System.out.println("Hello World!");ResourceBundle log = ResourceBundle.getBundle("log");String logString = log.getString("logType");System.out.println("logType:" + logString);CustomServiceLoader customServiceLoader = new CustomServiceLoader();try {customServiceLoader.loade(Logger.class);} catch (Exception e) {e.printStackTrace();}System.out.println("logString:" + logString);Logger logger = (Logger) customServiceLoader.getType(logString);logger.info("我愛你。。。");} }這個項目依賴著前面三個項目,在這個項目的resources這個目錄下新建log.properties文件,內(nèi)容如下:
logType=blog可以是alog或者blog。配置不同,將調(diào)用不同的實現(xiàn)。
運行如下:
Hello World! logType:blog configFile:META-INF/services/log/com.tspi.log.Logger configContent: alog=com.tspi.alog.ALogger configContent --end serviceName: alog=com.tspi.alog.ALogger tmpServiceName:alog,com.tspi.alog.ALogger classloader:sun.misc.Launcher$AppClassLoader@73d16e93 class1class com.tspi.alog.ALogger ALogger-->warn: TEST!!! configContent: blog=com.tspi.blog.BLogger configContent --end serviceName: blog=com.tspi.blog.BLogger tmpServiceName:blog,com.tspi.blog.BLogger classloader:sun.misc.Launcher$AppClassLoader@73d16e93 class1class com.tspi.blog.BLogger BLogger-->warn: TEST!!! ----- mservices:{blog=com.tspi.blog.BLogger@14ae5a5, alog=com.tspi.alog.ALogger@7f31245a} logString:blog type:blog ----- mservices:{blog=com.tspi.blog.BLogger@14ae5a5, alog=com.tspi.alog.ALogger@7f31245a} BLogger-->info: 我愛你。。。?
如果配置的是alog,
最后打印將會是ALogger-->info: 我愛你。。。
?
三、 ?后記
這基本就是一個很簡單的自定義servicesLoader的實現(xiàn)。基本實現(xiàn)了讀配置來覺得調(diào)不通的SPI的實現(xiàn)
就像使用dubbo注冊時你配置的是的redis就使用了redis注冊中心,zookeeper就使用了zookeeper注冊中心,我們這是配置alog就使用了ALogger實現(xiàn),配置blog就使用了BLogger實現(xiàn)一樣。
這個例子的地址:https://git.oschina.net/lenglingx-163/log-parent.git
?
?
?
轉(zhuǎn)載于:https://my.oschina.net/lenglingx/blog/1505958
總結(jié)
以上是生活随笔為你收集整理的自定义ServicesLoader来实现根据配置使用不通的SPI实现从而实现项目扩展的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Docker 常见问题 (FAQ)-20
- 下一篇: 解决查看框架源码时 class file