Dubbo源码-03-Java SPI
一 Demo
.
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── alibaba
│ │ │ └── dubbo
│ │ │ └── demo
│ │ │ └── spi
│ │ │ └── jdk
│ │ │ ├── JdkSpiClient.java // 如何使用接口的实现
│ │ │ └── service
│ │ │ ├── JdkSpiService.java // 接口抽象
│ │ │ └── impl
│ │ │ ├── JdkSpiServiceImplA.java // 具体实现
│ │ │ └── JdkSpiServiceImplB.java // 具体实现
│ │ └── resources
│ │ └── META-INF
│ │ └── services
│ │ └── com.alibaba.dubbo.demo.spi.jdk.service.JdkSpiService // 配置文件
└── tree.txt
1 接口声明
public interface JdkSpiService {
String sayHello(String s);
}
2 实现定义
public class JdkSpiServiceImplA implements JdkSpiService {
@Override
public String sayHello(String s) {
return "this is A, hello " + s;
}
}
public class JdkSpiServiceImplB implements JdkSpiService {
@Override
public String sayHello(String s) {
return "this is B, hello " + s;
}
}
3 classpath配置(META-INF/services/com.alibaba.dubbo.demo.spi.jdk.service.JdkSpiService)
com.alibaba.dubbo.demo.spi.jdk.service.impl.JdkSpiServiceImplA
com.alibaba.dubbo.demo.spi.jdk.service.impl.JdkSpiServiceImplB
4 调用
public class JdkSpiClient {
public static void main(String[] args) {
ServiceLoader<JdkSpiService> services = ServiceLoader.load(JdkSpiService.class);
/**
* jdk内置工具类扫描出指定文件配置的所有实现
* 扫描过程中将所有的实现都通过反射的技术实现实例化缓存起来
*/
for (JdkSpiService s : services) {
String ret = s.sayHello("world");
System.out.println(ret);
}
}
}
二 源码分析
1 ServiceLoader#load()
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
2 ServiceLoader#load()
public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader)
{
return new ServiceLoader<>(service, loader);
}
3 ServiceLoader
public final class ServiceLoader<S> implements Iterable<S>{
public Iterator<S> iterator() {
return new Iterator<S>() {
Iterator<Map.Entry<String,S>> knownProviders
= providers.entrySet().iterator();
public boolean hasNext() {
if (knownProviders.hasNext())
return true;
return lookupIterator.hasNext();
}
public S next() {
if (knownProviders.hasNext())
return knownProviders.next().getValue();
return lookupIterator.next();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
private class LazyIterator
implements Iterator<S>
{
Class<S> service;
ClassLoader loader;
Enumeration<URL> configs = null;
Iterator<String> pending = null;
String nextName = null;
private LazyIterator(Class<S> service, ClassLoader loader) {
this.service = service;
this.loader = loader;
}
private boolean hasNextService() {
if (nextName != null) {
return true;
}
if (configs == null) {
try {
String fullName = PREFIX + service.getName();
if (loader == null)
configs = ClassLoader.getSystemResources(fullName);
else
configs = loader.getResources(fullName);
} catch (IOException x) {
fail(service, "Error locating configuration files", x);
}
}
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;
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
}
public boolean hasNext() {
if (acc == null) {
return hasNextService();
} else {
PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
public Boolean run() { return hasNextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
public S next() {
if (acc == null) {
return nextService();
} else {
PrivilegedAction<S> action = new PrivilegedAction<S>() {
public S run() { return nextService(); }
};
return AccessController.doPrivileged(action, acc);
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}
该类实现了Iterable也就是说支持增强for循环 通过内部类的方式实现了对迭代器的支持
轮询的时候触发对指定路径的classpath文件扫描META-INF/services/ 然后通过反射的方式创建实例
三 总结
- 实现简单 jdk内置的工具类
- 扫描过程中将所有的实现都功过反射方式实例化
- 遍历的方式是通过迭代器 时间复杂度是O(N)
- 动态实现类似策略模式需要自行设计一定的机制
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?