java spi(service provider interface)示例与原理解析
目的
提供服务注册与发现,让功能的使用方和提供方解耦
示例
1.提供接口
package com.yemin.service;
public interface Animals {
public void run();
public void eat();
}
2.实现接口
接口1
package com.yemin.serviceImpl;
import com.yemin.service.Animals;
public class Cat implements Animals {
static {
System.out.println("hello world cat");
}
@Override
public void run() {
System.out.println("cat is running");
}
@Override
public void eat() {
System.out.println("cat is eating");
}
}
接口2
package com.yemin.serviceImpl;
import com.yemin.service.Animals;
public class Dog implements Animals {
static {
System.out.println("hello world dog");
}
@Override
public void run() {
System.out.println("dog is running");
}
@Override
public void eat() {
System.out.println("dog is eating");
}
}
3.注册接口与实现
创建要注册接口的目录文件
resourcesMETA-INFservicescom.yemin.service.Animals
文件内放入具体实现,选择需要的实现
com.yemin.serviceImpl.Cat
com.yemin.serviceImpl.Dog
4.使用服务
在其他模块引用该模块依赖,或者打成jar包给其他项目使用
public static void main(String[] args) {
ServiceLoader<Animals> animalsIterator = ServiceLoader.load(Animals.class);
for (Animals a:animalsIterator){
System.out.println(a);
}
}
原理
- ServiceLoader.load(Animals.class)
- new ServiceLoader<>(service, loader)
- reload()
- lookupIterator = new LazyIterator(service, loader);
ServiceLoader寻找"META-INF/services/"
下的接口实例
private static final String PREFIX = "META-INF/services/";
LazyIterator 每次获取下一个元素的时候,加载并实例化对象
private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
String cn = nextName;
nextName = null;
Class<?> c = null;
try {
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service,
"Provider " + cn + " not found");
}
if (!service.isAssignableFrom(c)) {
fail(service,
"Provider " + cn + " not a subtype");
}
try {
S p = service.cast(c.newInstance());
providers.put(cn, p);
return p;
} catch (Throwable x) {
fail(service,
"Provider " + cn + " could not be instantiated",
x);
}
throw new Error(); // This cannot happen
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。