Jdk1.7本地文件监控

Jdk实现本地文件监听

监听实现: ConfigDirWatchContext

package com.jinko.apollo;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import de.schlichtherle.io.File;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import static java.nio.file.StandardWatchEventKinds.*;

/**
 * @author xxx
 */
public class ConfigDirWatchContext {
    private static final Logger logger = LoggerFactory.getLogger(ConfigDirWatchContext.class);
    private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(10, 10, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), new ThreadFactoryBuilder().setNameFormat("ConfigDirWatchContextPool -%d").build(), new ThreadPoolExecutor.AbortPolicy());
    private static WatchService WATCHER = null;
    private static final String SUFFIX = ".properties";
    private static final Map<String, Properties> CONFIGS = new ConcurrentHashMap<>();
    private static final List<String> FAIL_PATH = new ArrayList<>(0);
    private static final Path ROOT_PATH = Paths.get("/app/ecology/filesystem/config/");
    private static final ConfigDirWatchContext SINGLE_INSTANCE = new ConfigDirWatchContext();


    public static ConfigDirWatchContext newInstance() {
        return SINGLE_INSTANCE;
    }


    public Map<String, Properties> getConfigs() {
        return Collections.unmodifiableMap(CONFIGS);
    }

    public List<String> getFailList() {
        return Collections.unmodifiableList(FAIL_PATH);
    }

    private ConfigDirWatchContext() {
        recursiveRegister(ROOT_PATH);
        this.watchStart();
    }

    private synchronized WatchService buildWatcher() {
        if (Objects.nonNull(WATCHER)) {
            return WATCHER;
        }
        try {
            return WATCHER = FileSystems.getDefault().newWatchService();
        } catch (Throwable e) {
            logger.info("ConfigDirWatchService Throwable", e);
        }
        throw new RuntimeException("");
    }

    @SneakyThrows
    private void recursiveRegister(Path path) {
        // 这里的监听必须是目录
        if (!path.toFile().exists() && !path.toFile().mkdirs()) {
            logger.info("ConfigDirWatchService mkdir error {}", path.toAbsolutePath());
            FAIL_PATH.add(path.toAbsolutePath().toString());
            return;
        }
        // 创建WatchService,它是对操作系统的文件监视器的封装,相对之前,不需要遍历文件目录,效率要高很多
        WatchService watcher = buildWatcher();
        // 注册指定目录使用的监听器,监视目录下文件的变化;
        // PS:Path必须是目录,不能是文件;
        // StandardWatchEventKinds.ENTRY_MODIFY,表示监视文件的修改事件
        path.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY, ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE);
        Files.list(path).forEach(child -> {
            if (Files.exists(child)) {
                if (Files.isDirectory(child)) {
                    recursiveRegister(child);
                } else if (child.toString().endsWith(SUFFIX)) {
                    CONFIGS.put(getKey(child), read(child));
                }
            }
        });
    }

    private String getKey(Path path) {
        return ROOT_PATH.relativize(path).toString().replace(File.separator, ".");
    }

    private ConfigDirWatchContext watchStart() {
        EXECUTOR.submit(() -> {
            try {
                // 创建一个线程,等待目录下的文件发生变化
                logger.info("watchStart ... ");
                while (true) {
                    // 获取目录的变化:
                    // take()是一个阻塞方法,会等待监视器发出的信号才返回。
                    // 还可以使用watcher.poll()方法,非阻塞方法,会立即返回当时监视器中是否有信号。
                    // 返回结果WatchKey,是一个单例对象,与前面的register方法返回的实例是同一个;
                    WatchKey key = buildWatcher().take();
                    // 处理文件变化事件:
                    // key.pollEvents()用于获取文件变化事件,只能获取一次,不能重复获取,类似队列的形式。
                    for (WatchEvent<?> event : key.pollEvents()) {
                        // event.kind():事件类型
                        if (event.kind() == StandardWatchEventKinds.OVERFLOW) {
                            //事件可能lost or discarded
                            continue;
                        }
                        Watchable watchable = key.watchable();
                        // 返回触发事件的文件或目录的路径(相对路径)
                        Path fullPath = Paths.get(watchable.toString(), event.context().toString());
                        logger.info("path={} , type={}", fullPath, event.kind());
                        handler(fullPath, event);
                    }
                    // 每次调用WatchService的take()或poll()方法时需要通过本方法重置
                    if (!key.reset()) {
                        break;
                    }
                }
            } catch (Throwable e) {
                logger.info("ConfigDirWatchService Throwable", e);
            }
        });
        return this;
    }

    private void handler(Path changePath, WatchEvent event) {
        if (Objects.isNull(event) || Objects.isNull(changePath)) {
            logger.info("hander error {} {} ", changePath, event);
            return;
        }
        if (!Files.isDirectory(changePath)) {
            handlerFile(changePath, event);
            return;
        }
        if (ENTRY_CREATE.name().equals(event.kind().name())) {
            /*  添加新的监听目录 */
            recursiveRegister(changePath);
        } else {
            logger.info("not handler Directory {} {}", changePath, event.kind());
        }
    }

    private void handlerFile(Path changePath, WatchEvent event) {
        if (Objects.isNull(event) || Objects.isNull(changePath) || !changePath.toString().endsWith(SUFFIX)) {
            logger.info("hander error {} {} ", changePath, event);
            return;
        }
        if (ENTRY_CREATE.name().equals(event.kind().name()) || ENTRY_MODIFY.name().equals(event.kind().name())) {
            CONFIGS.put(getKey(changePath), read(changePath));
        } else if (ENTRY_DELETE.name().equals(event.kind().name())) {
            CONFIGS.remove(getKey(changePath));
        } else {
            logger.info("handler {} {}", changePath, event.kind());
        }
    }

    @SneakyThrows
    private Properties read(Path path) {
        Properties properties = new Properties();
        properties.load(Files.newInputStream(path));
        return properties;
    }

    @SneakyThrows
    public static void main(String[] args) throws IOException {
        Map<String, Properties> configs = new ConfigDirWatchContext()
                .watchStart().getConfigs();
//        Thread.sleep(100000000);
    }
}

工具类: ConfigUtils

package com.jinko.apollo;

import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @author xxx
 */
public class ConfigUtils {

    private final ConfigDirWatchContext CONTEXT = ConfigDirWatchContext.newInstance();
    private static final String SUFFIX = ".properties";
    private final Map<String, Properties> CONFIGS = CONTEXT.getConfigs();

    public static ConfigUtils newInstance() {
        return new ConfigUtils();
    }

    public String get(String path, String key) {
        return get(path, key, null);
    }

    public String get(String path, String key, String defaultValue) {
        String realKey = String.format("%s%s", path, SUFFIX);
        if (StringUtils.isBlank(path) || !CONFIGS.containsKey(realKey)) {
            return defaultValue;
        }
        return CONFIGS.get(realKey).getProperty(key, defaultValue);
    }

    public Map<String, Properties> getConfigs() {
        return CONFIGS;
    }

    public List<String> getFailPathList() {
        return CONTEXT.getFailList();
    }


    @SneakyThrows
    public static void main(String[] args) {
        ConfigUtils configUtils = newInstance();
        Map<String, Properties> configs = configUtils.getConfigs();
        String key = configUtils.get("bestsign.config", "key");
        String key1 = configUtils.get("", "key");
        String key2 = configUtils.get(null, "key");
        System.out.println(key);
        Thread.sleep(100000);
    }


}
package com.jinko.apollo;

import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @author xuyuansheng
 */
public class ConfigUtils {

    private final ConfigDirWatchContext CONTEXT = ConfigDirWatchContext.newInstance();
    private static final String SUFFIX = ".properties";
    private final Map<String, Properties> CONFIGS = CONTEXT.getConfigs();

    public static ConfigUtils newInstance() {
        return new ConfigUtils();
    }

    public String get(String path, String key) {
        return get(path, key, null);
    }

    public String get(String path, String key, String defaultValue) {
        String realKey = String.format("%s%s", path, SUFFIX);
        if (StringUtils.isBlank(path) || !CONFIGS.containsKey(realKey)) {
            return defaultValue;
        }
        return CONFIGS.get(realKey).getProperty(key, defaultValue);
    }

    public Map<String, Properties> getConfigs() {
        return CONFIGS;
    }

    public List<String> getFailPathList() {
        return CONTEXT.getFailList();
    }


    @SneakyThrows
    public static void main(String[] args) {
        ConfigUtils configUtils = newInstance();
        Map<String, Properties> configs = configUtils.getConfigs();
        String key = configUtils.get("bestsign.config", "key");
        String key1 = configUtils.get("", "key");
        String key2 = configUtils.get(null, "key");
        System.out.println(key);
        Thread.sleep(100000);
    }


}
package com.jinko.apollo;

import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @author xuyuansheng
 */
public class ConfigUtils {

    private final ConfigDirWatchContext CONTEXT = ConfigDirWatchContext.newInstance();
    private static final String SUFFIX = ".properties";
    private final Map<String, Properties> CONFIGS = CONTEXT.getConfigs();

    public static ConfigUtils newInstance() {
        return new ConfigUtils();
    }

    public String get(String path, String key) {
        return get(path, key, null);
    }

    public String get(String path, String key, String defaultValue) {
        String realKey = String.format("%s%s", path, SUFFIX);
        if (StringUtils.isBlank(path) || !CONFIGS.containsKey(realKey)) {
            return defaultValue;
        }
        return CONFIGS.get(realKey).getProperty(key, defaultValue);
    }

    public Map<String, Properties> getConfigs() {
        return CONFIGS;
    }

    public List<String> getFailPathList() {
        return CONTEXT.getFailList();
    }


    @SneakyThrows
    public static void main(String[] args) {
        ConfigUtils configUtils = newInstance();
        Map<String, Properties> configs = configUtils.getConfigs();
        String key = configUtils.get("bestsign.config", "key");
        String key1 = configUtils.get("", "key");
        String key2 = configUtils.get(null, "key");
        System.out.println(key);
        Thread.sleep(100000);
    }


}

posted @ 2023-02-12 20:26  菜阿  阅读(13)  评论(0编辑  收藏  举报