spi~動態監控目錄的jar實現熱加載

對於咱們本身封裝的spi來講,咱們可能但願他實現相似於插件的功能,例如你有一個汽車工廠,你目前有提供小汽車,若是你但願他動態支持卡車,公交車,那麼spi能夠幫你實現這個功能,對於我實現這個SPI功能主要由如下幾個步驟組成。app

  1. 對文件夾目錄的監控
  2. 對文件夾裏jar也的裝載,動態類加載器機制實現
  3. 經過類型名稱,返回實現類的列表

具體實現

目錄監控

/**
     * 目錄監控.
     *
     * @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;
    }

程序調用

1

@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);
    }

結果
2ide

相關文章
相關標籤/搜索