對於我們自己封裝的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<Path> watchEventPath = (WatchEvent<Path>) 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 <U>
* @return
*/
public static <U extends ProviderFactory> List<U> getProviderFactory(Class<U> clazz) {
List<U> list = new ArrayList<>();
for (ClassLoader classLoader : dynamicClassLoaders) {
ServiceLoader<U> load = ServiceLoader.load(clazz, classLoader);
List<String> 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<String> result = new ArrayList<>();
for (ProviderFactory u : SpiFactory.getProviderFactory(ProviderFactory.class)) {
result.add(u.create().login());
}
return ResponseEntity.ok(result);
}
結果