private void hotReloadFilter()

in runner-starter/src/main/java/org/apache/apisix/plugin/runner/HotReloadProcess.java [103:178]


    private void hotReloadFilter() {
        if (!enableHotReload) {
            cancelHotReload("hotReloadFilter");
            return;
        }

        final BeanDefinitionRegistry registry = (BeanDefinitionRegistry) ctx.getAutowireCapableBeanFactory();
        String userDir = System.getProperty("user.dir");
        userDir = userDir.substring(0, userDir.lastIndexOf("apisix-java-plugin-runner") + 25);
        String workDir = userDir + loadPath;

        Path path = Paths.get(workDir);
        boolean exists = Files.exists(path);
        if (!exists) {
            logger.warn("The filter workdir for hot reload {} not exists", workDir);
            cancelHotReload("hotReloadFilter");
            return;
        }

        try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
            path.register(watchService, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
            Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                try {
                    watchService.close();
                } catch (IOException e) {
                    logger.error(e.getMessage());
                }
            }));

            while (true) {
                final WatchKey key = watchService.take();
                for (WatchEvent<?> watchEvent : key.pollEvents()) {
                    final WatchEvent.Kind<?> kind = watchEvent.kind();
                    final String filterFile = watchEvent.context().toString();

                    // ignore the file that is not java file
                    if (!filterFile.endsWith(".java")) {
                        continue;
                    }

                    String filterName = filterFile.substring(0, filterFile.length() - 5);
                    String filterBean = Character.toLowerCase(filterFile.charAt(0)) + filterName.substring(1);
                    final String filePath = workDir + filterFile;

                    if (kind == ENTRY_CREATE) {
                        logger.info("file create: {}", filePath);
                        BeanDefinitionBuilder builder = compile(userDir, filterName, filePath);
                        registry.registerBeanDefinition(filterBean, builder.getBeanDefinition());
                    } else if (kind == ENTRY_MODIFY) {
                        logger.info("file modify: {}", filePath);
                        registry.removeBeanDefinition(filterBean);
                        BeanDefinitionBuilder builder = compile(userDir, filterName, filePath);
                        registry.registerBeanDefinition(filterBean, builder.getBeanDefinition());
                    } else if (kind == ENTRY_DELETE) {
                        if (registry.containsBeanDefinition(filterBean)) {
                            logger.info("file delete: {}, and remove filter: {} ", filePath, filterBean);
                            registry.removeBeanDefinition(filterBean);
                            /*TODO: we need to remove the filter from the filter chain
                             * by remove the conf token in cache or other way
                             * */
                        }
                    } else {
                        logger.warn("unknown event: {}", kind);
                    }
                }

                boolean valid = key.reset();
                if (!valid) {
                    logger.warn("key is invalid");
                }
            }
        } catch (IOException | InterruptedException | ClassNotFoundException e) {
            logger.error("watch error", e);
            throw new RuntimeException(e);
        }
    }