Java SPI 机制
Java 大约 3278 字示例代码
接口
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();
}
}
}
阅读 565 · 发布于 2022-04-09
————        END        ————
Give me a Star, Thanks:)
https://github.com/fendoudebb扫描下方二维码关注公众号和小程序↓↓↓

昵称:
随便看看
换一批
-
Android 使用 Intent 实现花式跳转阅读 4020
-
Docker 同步宿主机时区阅读 136
-
软考-系统架构设计师:电子商务阅读 1157
-
Windows Terminal 添加 Git Bash阅读 394
-
Node.js 模块阅读 118
-
Ubuntu 修改 apt 镜像阅读 2787
-
Windows 子系统 WslRegisterDistribution failed with error: 0xc03a001a阅读 689
-
minikube Pod 无法解析 Service 主机名阅读 268
-
Spring Boot 无法写出 Cookie阅读 2404
-
Linux 之 CentOS yum 更换镜像阅读 2421