点击上方 "程序员小乐"关注, 星标或置顶一起成长
每天凌晨00点00分, 第一时间与你相约
每日英文
If you concentrate on the ONE thing in your life that makes you truly happy... everything else in your life will fall into place.
如果人只关注着真正带给自己快乐的事,那其余一切,就都清晰明了了。
每日掏心****话
年轻时候,以为坚持是永不动摇;到这个年纪,明白了,坚持就是犹疑着退缩着心猿意马着一步三停着,还在往前走。
来自:sigangjun | 责编:乐乐
链接:blog.csdn.net/sigangjun/article/details/79071850
程序员小乐(ID:study_tech)第 816 次推文 图片来自百度
往日回顾:马化腾动怒!微信数据“被共享”,山寨微信团伙被判一年!
正文
SPI的全名为:Service Provider Interface,大多数开发人员可能不熟悉,因为这个是针对厂商或者插件的。在java.util.ServiceLoader的文档里有比较详细的介绍。
简单的总结下 Java SPI 机制的思想。我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志模块的方案,xml解析模块、jdbc模块的方案等。面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。
一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。为了实现在模块装配的时候能不在程序里动态指明,这就需要一种服务发现机制。
Java SPI 就是提供这样的一个机制:为某个接口寻找服务实现的机制。有点类似IOC的思想,就是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要。
Java SPI 的具体约定为:当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。
而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。
基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。jdk提供服务实现查找的一个工具类:java.util.ServiceLoader。
1.common-logging
apache最早提供的日志的门面接口。只有接口,没有实现。具体方案由各提供商实现, 发现日志提供商是通过扫描 META-INF/services/org.apache.commons.logging.LogFactory配置文件,通过读取该文件的内容找到日志提工商实现类。
只要我们的日志实现里包含了这个文件,并在文件里制定 LogFactory工厂接口的实现类即可。
2.jdbc
jdbc4.0以前, 开发人员还需要基于Class.forName("xxx")的方式来装载驱动,jdbc4也基于spi的机制来发现驱动提供商了,可以通过META-INF/services/java.sql.Driver文件里指定实现类的方式来暴露驱动提供者。
一个内容管理系统有一个搜索模块。是基于接口编程的。搜索的实现可能是基于文件系统的搜索,也可能是基于数据库的搜索
接口定义如下:
package my.xyz.spi; import java.util.List; public interface Search { public List serch(String keyword); }
A公司采用文件系统搜索的方式实现了 Search接口,B公司采用了数据库系统的方式实现了Search接口。
A公司实现的类:com.A.spi.impl.FileSearch
B公司实现的类:com.B.spi.impl.DatabaseSearch
那么A公司发布 实现jar包时,则要在jar包中META-INF/services/my.xyz.spi.Search文件中写下如下内容:
com.A.spi.impl.FileSearch
那么B公司发布 实现jar包时,则要在jar包中META-INF/services/my.xyz.spi.Search文件中写下如下内容:
com.B.spi.impl.DatabaseSearch
下面是 SPI 测试代码:
package com.xyz.factory; import java.util.Iterator; import java.util.ServiceLoader; import my.xyz.spi.Search; public class SearchFactory { private SearchFactory() { } public static Search newSearch() { Search search = null; ServiceLoader<Search> serviceLoader = ServiceLoader.load(Search.class); Iterator<Search> searchs = serviceLoader.iterator(); if (searchs.hasNext()) { search = searchs.next(); } return search; } }
欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,学习能力的提升上有新的认识,欢迎转发分享给更多人。
欢迎各位读者加入订阅号程序员小乐技术群,在后台回复“加群”或者“学习”即可。
猜你还想看
在SpringBoot中使用Spring Session解决分布式会话共享问题
关注订阅号「程序员小乐」,收看更多精彩内容
嘿,你在看吗?************************
本文分享自微信公众号 - 程序员小乐(study_tech)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。