2019独角兽企业重金招聘Python工程师标准>>>

自定义ServicesLoader来实现根据配置使用不通的SPI实现从而实现项目扩展

一 、  都知道Java中的SPI技术,也是dubbo中实验的,

通过这个案例可以快速的了解spi是什么?https://my.oschina.net/lenglingx/blog/879292

这个案例就是直接简单使用的spi,都说dubbo是也是使用spi来做扩展的,去看了一下dubbo的介绍,了解到了:ExtensionLoader.java

且dubbo使用是通过配置来的,如注册协议有,redis,和zookeeper。

这里我们就介绍如何实现通过配置来和spi结合实现dubbo这样的。

二、  这个项目介绍,log-parent,为整体项目,内部有4个项目。

log为api的接口项目

alog为ALog实现

blog为BLog实现

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();// 由于一个接口的实现类可能存在多个jar包中的META-INF目录下,所以下面使用getResources返回一个URL数组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实现:

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  这个文件。

内容为

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  这个文件。

内容为

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文件,内容如下:

logType=blog

可以是alog或者blog。配置不同,将调用不同的实现。

运行如下:

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的实现。基本实现了读配置来觉得调不通的SPI的实现

就像使用dubbo注册时你配置的是的redis就使用了redis注册中心,zookeeper就使用了zookeeper注册中心,我们这是配置alog就使用了ALogger实现,配置blog就使用了BLogger实现一样。

这个例子的地址:https://git.oschina.net/lenglingx-163/log-parent.git

转载于:https://my.oschina.net/lenglingx/blog/1505958

自定义ServicesLoader来实现根据配置使用不通的SPI实现从而实现项目扩展相关推荐

  1. 微信小程序生态13-微信公众号自定义菜单、个性化菜单配置

    文章导航 微信小程序生态1-初识小程序 微信小程序生态2-创建一个微信小程序 微信小程序生态3-微信小程序登录流程设计 微信小程序生态4-扫普通二维码进入小程序.打开短链接进入小程序 微信小程序生态5 ...

  2. 自定义spring boot的自动配置

    文章目录 添加Maven依赖 创建自定义 Auto-Configuration 添加Class Conditions 添加 bean Conditions Property Conditions Re ...

  3. SpringCloud 服务网关 Zuul 自定义路由和排除路由配置

    前言 首先需要说明的是该文是 [带你入门SpringCloud 之 服务网关 Zuul ]的拓展篇,如果还未阅读 [带你入门SpringCloud 之 服务网关 Zuul ]请先阅读完毕后在阅读该文. ...

  4. 20.番外篇——Vue如何自定义组件并且进行全局配置

    20.番外篇--如何自定义组件并且进行全局配置 前言 1.创建自定义组件 2.导出自定义组件 3.main.js中引入自定义的公共组件并挂在到Vue 4.使用自定义的公共组件 前言 通过之前的系列文章 ...

  5. matplotlib自定义设置plt.colorbar函数配置颜色条的刻度数实战:自定义设置颜色条刻度、并为刻度值进行命名和标签化

    matplotlib自定义设置plt.colorbar函数配置颜色条的刻度数实战:自定义设置颜色条刻度.并为刻度值进行命名和标签化 目录

  6. Docker下Prometheus和Grafana三部曲之三:自定义监控项开发和配置

    本文是<Docker下Prometheus和Grafana三部曲>的终篇,前面的文章中,我们体验了快速搭建监控环境,也揭示了如何编排Docker容器来简化环境搭建过程,在监控系统中有个业务 ...

  7. 通过velocity自定义模板字符串实现可配置的外部调用查询接口

    背景公司的系统被其他很多行内系统调用,查询某一个实体信息但是由于安全管控,每个系统调用我们系统获得的字段是不一样的.目前有两种方案可以实施: 1.利用行内的数仓系统,将表备份,然后通过数据交换平台sf ...

  8. 使用Vue @media print在JavaScript中插入不同尺寸的打印页面,可自定义尺寸大小和打印机配置

    本文介绍了如何在Vue项目中使用@media print和JavaScript来插入不同尺寸的打印页面,并提供了代码编写.使用教程.注意事项和避坑点,最后进行了总结. 一.介绍 在开发Web应用程序时 ...

  9. tomcat中实现特定路径下的图片的url访问Tomcat配置图片保存路径,图片不保存在项目路径下...

    使用Tomcat作为服务器的时候,如果不配置图片保存路径,将图片保存在项目路径下,那么再次打war包发布项目可能会造成图片的丢失,每次重启前将图片先保存再copy到服务器明显不方便,这时可以配置图片保 ...

最新文章

  1. 一篇非常好的transformer年度总结
  2. 二十七、二叉树--删除结点
  3. swift为UIView添加extension扩展frame
  4. Java 技术篇-IntelliJ IDEA 导入数据库驱动jar包实例演示
  5. leetcode98. 验证二叉搜索树
  6. matlab main函数_Python 和MATLAB 制作Gif 图像
  7. 漫步线性代数十三——线性变换
  8. IDEA 中git使用非默认ssh客户端进行登录
  9. MacBook Air 过热降温技巧
  10. Java基础算法--排序
  11. 线程安全的几种单例模式
  12. 怎样将OFD转成PDF并保留电子签章
  13. 图形学中常用计算几何总结
  14. MacOSx打包dmg文件(带背景图片)
  15. Flutter 3更新详解
  16. 2020年ubuntu安装QQ和微信和迅雷的正确姿势
  17. 【软考 系统架构设计师】嵌入式系统⑤ 嵌入式系统开发与设计
  18. Wordpress模板主题中functions.php常用功能代码与常用插件[ 后台篇](持续收集整理)
  19. 揭晓计算机的神秘面纱——计算机是如何工作的(一)
  20. 6-18位包含数字字母,大小写,特殊字符,正则表达式

热门文章

  1. CC2530的串口实验
  2. python五:运算符
  3. @GetMapping和@PostMapping接收参数的格式
  4. [转][linux]简单的linux下的tcp/udp
  5. 通过重建Hosting系统理解HTTP请求在ASP.NET Core管道中的处理流程[上]:采用管道处理请求...
  6. Scala学习之映射(Map)
  7. C语言 将文件内容转换成Dump文件数据格式
  8. Python 公众号 小程序抓包分析
  9. PDF批量替换文字器免费版
  10. zend studio for Eclipse注册码及汉化