最近有这么个需求,用户期望可以通过修改配置文件,并将数据文件丢到服务器上面,立即读取数据并绘制。由于这个数据我们不能直接拿来就用,需要转一遍格式,而且转换的速度又不是非常快,所以 和师兄们商量着想了个替代方案,异步化处理数据,不是用户点击之后才进行数据的转换,而是先转好,这个数据放内存也不靠谱,肯定要放数据库做持久化的,反正先整着试试。
1、引依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
</dependency>
2、两大核心类(监听事件类和监控器类)
监听事件类:
@Slf4j
@Component
public class FileListener implements FileAlterationListener {
@Override
public void onStart(FileAlterationObserver fileAlterationObserver) {
File directory = fileAlterationObserver.getDirectory();
log.info("开始监听..." + directory);
}
@Override
public void onDirectoryCreate(File file) {
log.info("目录被创建了...");
}
@Override
public void onDirectoryChange(File file) {
log.info("目录被修改了...");
}
@Override
public void onDirectoryDelete(File file) {
log.info("目录被删除了...");
}
@Override
public void onFileCreate(File file) {
log.info("文件被创建了...");
}
@Override
public void onFileChange(File file) {
log.info("文件被修改了...");
}
@Override
public void onFileDelete(File file) {
log.info("文件被删除了...");
}
@Override
public void onStop(FileAlterationObserver fileAlterationObserver) {
File directory = fileAlterationObserver.getDirectory();
log.info("结束监听..." + directory);
}
}
监控器类:
public class FileMonitor {
private FileListener fileListener; //监听事件
private String path; //监听的文件路径
private FileAlterationMonitor monitor;
private long defaultInterval = 10000L; //默认监听的时间间隔
public FileMonitor() {
}
public FileMonitor(String path) {
this.path = path;
this.monitor = new FileAlterationMonitor(defaultInterval);
}
public FileMonitor(String path, long interval) {
this.path = path;
this.monitor = new FileAlterationMonitor(interval);
}
public void setFileListener(FileListener fileListener) {
this.fileListener = fileListener;
}
public void start() {
if (monitor == null) {
throw new IllegalStateException("Listener must not be null");
}
if (path == null) {
throw new IllegalStateException("Listen path must not be null");
}
FileAlterationObserver observer = new FileAlterationObserver(path);
observer.addListener(fileListener);
monitor.addObserver(observer);
try {
monitor.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3、监听Spring容器初始化
启动类:
@SpringBootApplication
public class StartApplication {
public static void main(String[] args) {
SpringApplication.run(StartApplication.class, args);
}
@Bean
public FileMonitor fileMonitor() {
return new FileMonitor("./");
}
}
监听容器启动的类:
@Slf4j
@Component
public class ContextFileListener implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
private FileMonitor fileMonitor;
@Autowired
private FileListener fileListener;
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
if (contextRefreshedEvent.getApplicationContext().getParent() == null) {
fileMonitor.setFileListener(fileListener);
fileMonitor.start();
}
}
}
4、底层
可以看到,底层还是开一个线程在哪里不停地跑,只不过是线程会歇息interval的时间。
这里有一点注意下,这个demo实现的path参数是目录名,也就是说,被观察的对象是该目录下的所有文件,当有文件发生变动的时候,就会触发监听事件。