Java进阶—SPI

SPI 简介

SPI 全称为 Service Provider Interface,是JDK内置的一种服务提供发现机制。

作用

  • 为接口自动寻找实现类

实现方式

  1. 标准制定者制定接口
  2. META-INF/services/目录中创建以接口全限定名命名的文件,该文件内容为接口具体实现类的全限定名,文件编码必须为UTF-8。如果该Service有多个服务实现,则每一行写一个服务实现(#后面的内容为注释)。
  3. 如SPI的实现类为jar,则需要将其放在当前程序的classpath下。
  4. 接口的具体实现类必须有一个无参构造方法。
  5. 使用ServiceLoader.load(Class clazz); 自动寻找接口的实现类。

基于这样一个方式就能很好的找到服务接口的实现类,而不需要再代码里制定。

jdk提供服务实现查找的一个工具类:java.util.ServiceLoader。

示例

项目结构:

定义一个接口:HelloService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.lzumetal.javalean.spi.service;

/**
* <p>Description: </p>
*
* @author liaosi
* @date 2018-07-31
*/
public interface HelloService {

String sayHello(String name);

}

接口实现类

本示例中 HelloService 有两个实现类,分别为:EnglishDemoServiceImplChineseDemoServiceImpl,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.lzumetal.javalean.spi.service.impl;

import com.lzumetal.javalean.spi.service.HelloService;

/**
* <p>Description: </p>
*
* @author liaosi
* @date 2018-07-31
*/
public class ChineseHelloServiceImpl implements HelloService {

@Override
public String sayHello(String name) {
return "你好," + name;
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.lzumetal.javalean.spi.service.impl;

import com.lzumetal.javalean.spi.service.HelloService;

/**
* <p>Description: </p>
*
* @author liaosi
* @date 2018-07-31
*/
public class EnglishHelloServiceImpl implements HelloService{

@Override
public String sayHello(String name) {
return "hello," + name;
}

}

META-INF/services/ 目录配置

src/main/resources下创建META-INF/services/目录,并新建com.lzumetal.javalean.spi.service.HelloService 文件,内容如下:

1
2
3
4
5
#English implementation
com.lzumetal.javalean.spi.service.impl.EnglishHelloServiceImpl

#Chinese implementation
com.lzumetal.javalean.spi.service.impl.ChineseHelloServiceImpl

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.lzumetal.javalean.spi.test;

import com.lzumetal.javalean.spi.service.HelloService;

import java.util.Iterator;
import java.util.ServiceLoader;

/**
* <p>Description: </p>
*
* @author liaosi
* @date 2018-07-31
*/
public class SpiTest {

public static void main(String[] args) {
ServiceLoader<HelloService> serviceLoader = ServiceLoader.load(HelloService.class);
Iterator<HelloService> serviceIterator = serviceLoader.iterator();
while (serviceIterator != null && serviceIterator.hasNext()) {
HelloService helloService = serviceIterator.next();
System.out.println("calss:" + helloService.getClass().getName() +
"|sayHello method:" + helloService.sayHello("world"));
}
}
}

运行结果

1
2
calss:com.lzumetal.javalean.spi.service.impl.EnglishHelloServiceImpl|sayHello method:hello,world
calss:com.lzumetal.javalean.spi.service.impl.ChineseHelloServiceImpl|sayHello method:你好,world
------ 本文完 ------