`
iamzhongyong
  • 浏览: 797419 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

SPI初步接触和简单例子

    博客分类:
  • java
 
阅读更多

     偶然间看到SPI这个名词,之前知道API,但是SPI还没怎么接触过,打算找些资料看看。

    API和SPI的区别是啥?

     API全称是Application Programming Interface,应用程序接口,我们在写java代码的时候,定义接口,是非常常见的事情。SPI的全称是Service Provider Interface,作为普通的开发人员大都不怎么熟悉,因为SPI主要针对厂商或者插件来搞的。

    框架提供API及其实现,框架在实现过程中提供SPI回调机制。SPI是框架的扩展点,如果使用方要扩展框架,可以自己实现SPI并注入框架,于是框架使用方其实也是一个服务提供商。

    简单描述,就是API是给使用者用的,而SPI是给扩展者用的。

    ​API是针对功能的抽象描述,SPI是针对变化的。

    我们在设计系统的时候,会抽象出不同模块,例如日志模块、数据库连接模块,在面向对象的设计中,一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。为了实现在模块装配的时候能在程序里动态指明,就需要一种服务发现机制,有点类似IOC的思想,将装配的控制权移到程序之外。

    框架如何发现SPI?

    通过java中的ServiceLoader类来发现SPI,此类负责加载Service,

    介绍地址如下:http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html

    应用或者第三方如何注入SPI的实现?

    在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件,这个文件中就是实现该服务接口的具体实现类的完全限定名,而当框架调用ServiceLoader.load方法时,就能通过jar中的文件找到具体的实现类名,并装载实例化,完成SPI的注入。

    ​构建SPI的步骤是啥?

1、在jar中的META-INF/services目录中,放置文件,然后jar包放在classpath下面;

2、文件名为要扩展的接口包路径全名。文件内部为接口实现类,格式为utf-8;

3、使用JDK标准载入类,ServiceLoader来加载;

-----------------------------------------------------------------------------------------

    ​一个实例

1、定义接口People,接口中有一个方法

People.java

1
2
3
4
package com.iamzhongyong;
public interface People {
    public void printMyName();
}

2、搞两个实现类,这里SPI的实现是框架自己

APeopleImpl.java

1
2
3
4
5
6
7
8
package com.spi.impl;
import com.iamzhongyong.People;
public class APeopleImpl implements People {
    @Override
    public void printMyName() {
        System.out.println("i am A people...");
    }
}

BPeopleImpl.java

1
2
3
4
5
6
7
8
package com.spi.impl;
import com.iamzhongyong.People;
public class BPeopleImpl implements People {
    @Override
    public void printMyName() {
        System.out.println("i am B people...");
    }
}

3、src目录下,构建META-INF/services目录,然后文件名为”com.iamzhongyong.People“

文件内容为此接口的两个实现类

1
2
com.spi.impl.APeopleImpl
com.spi.impl.BPeopleImpl

4、构建main函数,用ServiceLoader来加载实现类

1
2
3
4
5
6
7
8
9
10
import java.util.ServiceLoader;
import com.iamzhongyong.People;
public class MainSPI {
    public static void main(String[] args) {
        ServiceLoader<People> loaders = ServiceLoader.load(People.class);
        for(People p : loaders){
            p.printMyName();
        }
    }
}

代码结构如下:

-------------------------------------------------------------------------------------------------------

debug代码

    ​框架自己扩展关系图

    ​

    ​第三方提供的SPI

    ​

 

参考文章:

http://docs.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html 

http://stan001140.iteye.com/blog/1743874

 

 

1
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics