zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    记录idea run dashboard设置 (微服务项目多服务启动)
    记录Java8中的字符串转数组再通过指定符号拼接
    Java 调用底层接口的几种方法
    工作两个月以后的感想
    几种开源工作流引擎的简单比较
    labin编译的另一种方式
    最近参加一个团队创业项目的感触
    gof设计模式——生成器c++实现
    gof设计模式——抽象工厂 c++实现
    几种开源网络爬虫的简单比较
  • 原文地址:https://www.cnblogs.com/lori/p/14410788.html
Copyright © 2011-2022 走看看