spi~动态监控目录的jar实现热加载

对于我们自己封装的spi来说,我们可能希望他实现类似于插件的功能,例如你有一个汽车工厂,你目前有提供小汽车,如果你希望他动态支持卡车,公交车,那么spi可以帮你实现这个功能,对于我实现这个SPI功能主要由以下几个步骤组成。

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

结果
2

原文地址:https://www.cnblogs.com/lori/p/14410788.html