对于我们自己封装的spi来说,我们可能希望他实现类似于插件的功能,例如你有一个汽车工厂,你目前有提供小汽车,如果你希望他动态支持卡车,公交车,那么spi可以帮你实现这个功能,对于我实现这个SPI功能主要由以下几个步骤组成。
对文件夹目录的监控
对文件夹里jar也的装载,动态类加载器机制实现
通过类型名称,返回实现类的列表
具体实现
目录监控
/**
* 目录监控.
*
* @param path
*/
public static void watchDir(String path) {
initClassLoader(path);
try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
//给path路径加上文件观察服务
Paths.get(path).register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE);
while (true) {
final WatchKey key = watchService.take();
for (WatchEvent> watchEvent : key.pollEvents()) {
final WatchEvent.Kind> kind = watchEvent.kind();
if (kind == StandardWatchEventKinds.OVERFLOW) {
continue;
}
final WatchEvent watchEventPath = (WatchEvent) watchEvent;
final Path filename = watchEventPath.context();
System.out.println(kind + " -> " + filename);
initClassLoader(path);
}
boolean valid = key.reset();
if (!valid) {
break;
}
}
} catch (IOException | InterruptedException ex) {
System.err.println(ex);
}
}
目录下动态类加载器添加到当前系统加载器里
static void initClassLoader(String path) {
for (File file : FileUtil.loopFiles(path)) {
System.out.println("load jar:" + file.getName());
URL url = file.toURI().toURL();
DynamicClassLoader dynamicClassLoader = new DynamicClassLoader(new URL[]{url}, ClassLoader.getSystemClassLoader());
dynamicClassLoaders.add(dynamicClassLoader);
}
}
通过类型返回类型的实现
/**
* 返回所有具体的providerFactory工厂,使用dynamicClassLoaders加载器
*
* @param clazz
* @param
* @return
*/
public static List getProviderFactory(Class clazz) {
List list = new ArrayList<>();
for (ClassLoader classLoader : dynamicClassLoaders) {
ServiceLoader load = ServiceLoader.load(clazz, classLoader);
List idList = list.stream().map(o -> o.getId()).collect(Collectors.toList());
for (U providerFactory : load) {
if (!idList.contains(providerFactory.getId())) {
list.add(providerFactory);
}
}
}
return list;
}
程序调用
@SneakyThrows
@GetMapping("hello")
public ResponseEntity hello() {
List result = new ArrayList<>();
for (ProviderFactory u : SpiFactory.getProviderFactory(ProviderFactory.class)) {
result.add(u.create().login());
}
return ResponseEntity.ok(result);
}
结果