Java知识分享
热爱技术,分享技术

Event Bus实战之监控目录变化

JDK自1.7版本后提供了WatchService类,该类可以基于事件通知的方式监控文件或者目录的任何变化,文件的改变相当于每个事件( Event)的发生,针对不同的时间执行不同的动作,结合NIO2.0中提供的WatchService 和我们实现的Event Bus实现文件目录的监控的功能。

1. DirectoryMonitor

package cn.hackcloud.concurrency.filebus;

import cn.hackcloud.concurrency.bus.EventBus;

import java.nio.file.*;

public class DirectoryMonitor {
private WatchService watchService;
private final EventBus eventBus;
private final Path path;
private volatile boolean start = false;

public DirectoryMonitor(final EventBus eventBus, final String targetPath) {
this(eventBus, targetPath, "");
}

//构造Monitor的时候需要传入EventBus以及需要监控的目最
public DirectoryMonitor(final EventBus eventBus, final String targetPath, final String... morePaths) {
this.eventBus = eventBus;
this.path = Paths.get(targetPath, morePaths);
}


public void startMonitor() throws Exception {
this.watchService = FileSystems.getDefault().newWatchService();
//为路径注册感兴趣的事件
this.path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_CREATE);
System.out.printf("The directory [8s] is monitoring... \n", path);
this.start = true;
while (start) {
WatchKey watchKey = null;
try {
//当有事件发生时会返回对应的WatchKey
watchKey = watchService.take();
watchKey.pollEvents().forEach(event ->
{
WatchEvent.Kind<?> kind = event.kind();
Path path = (Path) event.context();
Path child = DirectoryMonitor.this.path.resolve(path);
//提交FileChangeEvent到EventBus
eventBus.post(new FileChangeEvent(child, kind));
});
} catch (Exception e) {
this.start = false;
} finally {
if (watchKey != null)
watchKey.reset();
}
}
}

public void stopMonitor() throws Exception {
System.out.printf("The directory [%s] monitor will be stop...\n", path);
Thread.currentThread().interrupt();
this.start = false;
this.watchService.close();
System.out.printf("The directory [%s] monitor will be stop done. \n", path);

}
}

在创建WatchService之后将文件的修改、删除、创建等注册给了WatchService,在指定目录下发生诸如此类的事件之后便会收到通知,我们将事件类型和发生变化的文件Path封装成FileChangeEvent提交给Event Bus。

2. FileChangeEvent

FileChangeEvent比较简单,就是对WatchEvent.Kind和Path的包装,一旦目录发生任何改变,都会提交FileChangeEvent事件

public class FileChangeEvent {
private final Path path;
private final WatchEvent.Kind<?> kind;

public FileChangeEvent(Path path, WatchEvent.Kind<?> kind) {
this.path = path;
this.kind = kind;
}

public Path getPath() {
return path;
}

public WatchEvent.Kind<?> getKind() {
return kind;
}
}

3. 监控目录变化

目录监控的程序我们已经实现了,下面就来写一个接受文件目录变化Subscriber,也就是当目录发生变化时用来接受事件的方法。

package cn.hackcloud.concurrency.filebus;
import cn.hackcloud.concurrency.bus.Subscribe;
public class FileChangeListener {
    @Subscribe
    public void onChange(FileChangeEvent event) {
        System.out.printf("%s-%s\n", event.getPath(), event.getKind());
    }
}

onChange方法由@Subscribe 标记,但没有指定topic,当有事件发送到了默认的topic上之后,该方法将被调用执行,接下来我们将FileChangeListener的实例注册给Event Bus并且启动Monitor程序,代码如下:

public static void main(String[] args) throws Exception {
    ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.
            newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
    final EventBus eventBus = new AsyncEventBus(executor);
    //注册
    eventBus.register(new FileChangeListener());
    DirectoryMonitor monitor = new DirectoryMonitor(eventBus, "G:\\hackcloud");
    monitor.startMonitor();
}
Event Bus实战之监控目录变化插图

4. 总结

在本章中,实现了一个EventBus模式的小框架,EventBus 有点类似于GOF设
计模式中的监听者模式,但是EventBus提供的功能更加强大,使用起来也更加灵活,EventBus中的Subscriber不需要继承任何类或者实现任何接口,在使用EventBus时只需要持有Bus的引用即可。


在EventBus的设计中有三个非常重要的角色( Bus、Registry 和Dispatcher), Bus 主要提供给外部使用的操作方法,Registry注册表用来整理记录所有注册在EventBus上的Subscriber, Dispatcher 主要负责对Subscriber消息进行推送(用反射的方式执行方法),但是考虑到程序的灵活性,Dispatcher 方法中又提供了Executor 的多态方式。

打赏
本站所有资源均来源于网络,仅供学习使用,请支持正版!Java技术开源 » Event Bus实战之监控目录变化

评论 抢沙发

评论前必须登录!

 

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续提供更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫

登录

找回密码

注册