sentinel中利用spi机制构建子类示例
这里需要构建YunProcessorSlot接口下面的所有子类
并addLast方法构建链路
即用Spi机制实例化子类
public class DefaultYunSlotChainBuilder implements YunSlotChainBuilder {
@Override
public ProcessSlotChain build() {
ProcessSlotChain processorSlotChain = new YunDefaultProcessorSlotChain();
List<YunProcessorSlot> yunProcessorSlots =
SpiLoader.of(YunProcessorSlot.class).loadInstanceList();
for (YunProcessorSlot yunProcessorSlot : yunProcessorSlots){
processorSlotChain.addLast((YunAbstractLinkedProcessorSlot<?>) yunProcessorSlot);
}
return processorSlotChain;
}
}
先加载classLoader
public static <T> SpiLoader<T> of(Class<T> service) {
String className = service.getName();
SpiLoader<T> spiLoader = SPI_LOADER_MAP.get(className);
if (spiLoader == null) {
synchronized (SpiLoader.class) {
spiLoader = SPI_LOADER_MAP.get(className);
if (spiLoader == null) {
//这里new SpiLoader<>(service)放入到缓存之中
SPI_LOADER_MAP.putIfAbsent(className, new SpiLoader<>(service));
spiLoader = SPI_LOADER_MAP.get(className);
}
}
}
return spiLoader;
}
接着是load方法,load主要是实现读取文件的每一行,然后class.forName将class对象加载的容器之中
public List<S> loadInstanceList() {
load();
return createInstanceList(classList);
}
public void load() {
if (!loaded.compareAndSet(false, true)) {
return;
}
String fullFileName = SPI_FILE_PREFIX + service.getName();
ClassLoader classLoader;
if (SentinelConfig.shouldUseContextClassloader()) {
classLoader = Thread.currentThread().getContextClassLoader();
} else {
classLoader = service.getClassLoader();
}
if (classLoader == null) {
classLoader = ClassLoader.getSystemClassLoader();
}
Enumeration<URL> urls = null;
try {
urls = classLoader.getResources(fullFileName);
} catch (IOException e) {
fail("Error locating SPI configuration file, filename=" + fullFileName + ", classloader=" + classLoader, e);
}
if (urls == null || !urls.hasMoreElements()) {
RecordLog.warn("No SPI configuration file, filename=" + fullFileName + ", classloader=" + classLoader);
return;
}
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
InputStream in = null;
BufferedReader br = null;
try {
in = url.openStream();
br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
String line;
while ((line = br.readLine()) != null) {
if (StringUtil.isBlank(line)) {
// Skip blank line
continue;
}
line = line.trim();
int commentIndex = line.indexOf("#");
if (commentIndex == 0) {
// Skip comment line
continue;
}
if (commentIndex > 0) {
line = line.substring(0, commentIndex);
}
line = line.trim();
Class<S> clazz = null;
try {
clazz = (Class<S>) Class.forName(line, false, classLoader);
} catch (ClassNotFoundException e) {
fail("class " + line + " not found", e);
}
if (!service.isAssignableFrom(clazz)) {
fail("class " + clazz.getName() + "is not subtype of " + service.getName() + ",SPI configuration file=" + fullFileName);
}
classList.add(clazz);
Spi spi = clazz.getAnnotation(Spi.class);
String aliasName = spi == null || "".equals(spi.value()) ? clazz.getName() : spi.value();
if (classMap.containsKey(aliasName)) {
Class<? extends S> existClass = classMap.get(aliasName);
fail("Found repeat alias name for " + clazz.getName() + " and "
+ existClass.getName() + ",SPI configuration file=" + fullFileName);
}
classMap.put(aliasName, clazz);
if (spi != null && spi.isDefault()) {
if (defaultClass != null) {
fail("Found more than one default Provider, SPI configuration file=" + fullFileName);
}
defaultClass = clazz;
}
RecordLog.info("[SpiLoader] Found SPI implementation for SPI {}, provider={}, aliasName={}"
+ ", isSingleton={}, isDefault={}, order={}",
service.getName(), line, aliasName
, spi == null ? true : spi.isSingleton()
, spi == null ? false : spi.isDefault()
, spi == null ? 0 : spi.order());
}
} catch (IOException e) {
fail("error reading SPI configuration file", e);
} finally {
closeResources(in, br);
}
}
sortedClassList.addAll(classList);
Collections.sort(sortedClassList, new Comparator<Class<? extends S>>() {
@Override
public int compare(Class<? extends S> o1, Class<? extends S> o2) {
Spi spi1 = o1.getAnnotation(Spi.class);
int order1 = spi1 == null ? 0 : spi1.order();
Spi spi2 = o2.getAnnotation(Spi.class);
int order2 = spi2 == null ? 0 : spi2.order();
return Integer.compare(order1, order2);
}
});
}