Java SPI 机制
Java About 3,278 words示例代码
接口
package com.example.service;
public interface HelloService {
void sayHello();
}
实现类
package com.example.impl;
import com.example.service.HelloService;
public class HelloServiceImpl implements HelloService {
@Override
public void sayHello() {
System.out.println("hello from impl");
}
}
配置文件
在META-INF
文件夹下新建以接口全限定名为名称的文件,文件内容是具体实现类的全限定名。
└─src
├─com
│ └─example
│ │ Test.java
│ │
│ ├─impl
│ │ HelloServiceImpl.java
│ │ HelloServiceImpl2.java
│ │
│ └─service
│ HelloService.java
│
└─META-INF
└─services
com.example.service.HelloService
示例文件内容:
com.example.impl.HelloServiceImpl
com.example.impl.HelloServiceImpl2
SPI
public class Test {
public static void main(String[] args) {
ServiceLoader<HelloService> serviceLoader = ServiceLoader.load(HelloService.class);
// 增强 for 循环编译成字节码后就是迭代器
// for (HelloService service : serviceLoader) {
// service.sayHello();
// }
Iterator<HelloService> iterator = serviceLoader.iterator();
while (iterator.hasNext()) {
HelloService helloService = iterator.next();
helloService.sayHello();
}
}
}
输出:
hello from impl
hello from impl2
原理
LazyIterator
中的hasNextService
判断fullName
,nextService
中使用Class.forName()
加载。
public final class ServiceLoader<S> implements Iterable<S> {
private static final String PREFIX = "META-INF/services/";
public Iterator<S> iterator() {
return new Iterator<S>() {
public S next() {
if (knownProviders.hasNext())
return knownProviders.next().getValue();
return lookupIterator.next();
}
};
}
private class LazyIterator implements Iterator<S> {
private boolean hasNextService() {
if (nextName != null) {
return true;
}
if (configs == null) {
String fullName = PREFIX + service.getName();
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
configs = loader.getResources(fullName);
}
while ((pending == null) || !pending.hasNext()) {
if (!configs.hasMoreElements()) {
return false;
}
pending = parse(service, configs.nextElement());
}
nextName = pending.next();
return true;
}
private S nextService() {
if (!hasNextService())
throw new NoSuchElementException();
String cn = nextName;
nextName = null;
Class<?> c = null;
c = Class.forName(cn, false, loader);
S p = service.cast(c.newInstance());
providers.put(cn, p);
return p;
throw new Error(); // This cannot happen
}
public boolean hasNext() {
return hasNextService();
}
public S next() {
return nextService();
}
}
}
Views: 1,301 · Posted: 2022-04-09
————        END        ————
Give me a Star, Thanks:)
https://github.com/fendoudebb/LiteNote扫描下方二维码关注公众号和小程序↓↓↓
Loading...