java spi(service provider interface)示例与原理解析
目的提供服务注册与发现,让功能的使用方和提供方解耦
示例
1.提供接口package com.yemin.service;
public interface Animals {
public void run();
public void eat();
}
2.实现接口接口1package 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");
}
}接口2package 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 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
}