dubbo2.6.x原始碼-03 SPI動態擴充套件機制
阿新 • • 發佈:2022-05-19
簡介
- jdk spi
- dubbo spi
jdk 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
介面
public interface JdkSpiService {
String sayHello(String s);
}
實現
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; } }
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
呼叫
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); } } }
原始碼分析
ServiceLoader#load()
public static <S> ServiceLoader<S> load(Class<S> service) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
return ServiceLoader.load(service, cl);
}
ServiceLoader#load()
public static <S> ServiceLoader<S> load(Class<S> service, ClassLoader loader)
{
return new ServiceLoader<>(service, loader);
}
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)
- 動態實現類似策略模式需要自行設計一定的機制