转自:http://singleant.iteye.com/blog/1497259

最近看到公司的一些框架和之前看到的开源的一些框架的一些服务发现和接入都采用了java的spi机制。

所以简单的总结下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文件里指定实现类的方式来暴露驱动提供者。

3.自己编写简单例子

假设有一个内容搜索系统,分为展示和搜索两个模块。展示和搜索基于接口编程。搜索的实现可能是基于文件系统的搜索,也可能是基于数据库的搜索。实例代码如下

Search.java: 搜索接口

Java代码  
  1. package search;
  2. import java.util.List;
  3. import definition.Doc;
  4. public interface Search {
  5. List<Doc> search(String keyword);
  6. }

FileSearch.java:文件系统的搜索实现

Java代码  
  1. package search;
  2. import java.util.List;
  3. import definition.Doc;
  4. public class FileSearch implements Search {
  5. @Override
  6. public List<Doc> search(String keyword) {
  7. System.out.println("now use file system search. keyword:" + keyword);
  8. return null;
  9. }
  10. }

DatabaseSearch.java

Java代码  
  1. package search;
  2. import java.util.List;
  3. import definition.Doc;
  4. public class DatabaseSearch implements Search {
  5. @Override
  6. public List<Doc> search(String keyword) {
  7. System.out.println("now use database search. keyword:" + keyword);
  8. return null;
  9. }
  10. }

SearchTest.java

Java代码  
  1. package search;
  2. import java.util.Iterator;
  3. import java.util.ServiceLoader;
  4. public class SearchTest {
  5. public static void main(String[] args) {
  6. ServiceLoader<Search> s = ServiceLoader.load(Search.class);
  7. Iterator<Search> searchs = s.iterator();
  8. if (searchs.hasNext()) {
  9. Search curSearch = searchs.next();
  10. curSearch.search("test");
  11. }
  12. }
  13. }

最后创建在META-INF/searvices/search.Search文件。

当search.Search文件内容是"search.FileSearch"时,程序输出是:

now use file system search. keyword:test

当search.Search文件内容是"search.DatabaseSearch"时,程序输出是:

now use database search. keyword:test 
可以看出SearchTest里没有任何和具体实现有关的代码,而是基于spi的机制去查找服务的实现。

最新文章

  1. [.net 面向对象程序设计进阶] (1) 开篇
  2. MySQL之存储引擎MyISAM/InnoDB高并发优化经验
  3. session的工作原理
  4. ElasticSearch + Kibana
  5. hihocoder #1179 : 永恒游戏 暴力
  6. python中struct模块及packet和unpacket
  7. JVM OOM处理
  8. mi家前端面经
  9. 可视化n次贝塞尔曲线及过程动画演示--大宝剑
  10. JMeter—断言(十一)
  11. Codeforces 15E Triangles - 组合数学
  12. Codeforces787D(SummerTrainingDay06-D 线段树+最短路)
  13. Java 权限框架 Shiro 实战二:与spring集成、filter机制
  14. Kd-tree的学习
  15. bzoj 4372 烁烁的游戏——动态点分治+树状数组
  16. windows下 git+tortoiseGit的使用【转】
  17. 记录一次使用terminal进行git管理与提交到Github的过程
  18. bash高级
  19. ubuntu被delete的文件位置
  20. $.ajaxComplete()

热门文章

  1. IIS 安装问题
  2. C#读取RSS源,并利用Solr索引
  3. 封装CSS动画
  4. kindeditor异步加载 无法初始化
  5. Larazrus 快捷键 总结。
  6. Java网络编程一
  7. POJ 2031 Building a Space Station【最小生成树+简单计算几何】
  8. 2018 ACM-ICPC 青岛网络赛
  9. 洛谷——P1476 休息中的小呆
  10. Python开发基础-Day19继承组合应用、对象序列化和反序列化,选课系统综合示例