Spring AOP结合Java WatchService仅执行一次问题求助
排查Spring AOP配合WatchService仅触发首个文件日志的问题
我之前在做文件监听+AOP日志的时候也踩过几乎一模一样的坑,咱们从最常见的问题开始排查:
1. 最可能的原因:WatchKey未重置
WatchService的核心机制是每次处理完事件后必须调用key.reset(),否则这个WatchKey会进入无效状态,后续的文件事件根本不会被捕获。看你的代码片段里只写了while (key.isValid()),但没看到重置的逻辑——这大概率就是第一个文件能触发,后面没反应的原因。
修改后的监听代码应该加上重置逻辑:
public void monitor() { try { while (true) { // 用take()阻塞等待事件,比直接用key.pollEvents()更稳定 WatchKey key = watchService.take(); for (WatchEvent<?> event : key.pollEvents()) { WatchEvent.Kind<?> kind = event.kind(); // 先处理溢出事件,避免丢失后续事件 if (StandardWatchEventKinds.OVERFLOW == kind) { continue; } // 转换为路径事件,处理新增文件 WatchEvent<Path> pathEvent = (WatchEvent<Path>) event; Path fileName = pathEvent.context(); Path fullFilePath = yourWatchedDir.resolve(fileName); // 这里调用你的业务方法,确保被AOP拦截 handleNewFile(fullFilePath); } // 关键步骤:重置WatchKey,否则后续事件无法被接收 boolean isKeyValid = key.reset(); if (!isKeyValid) { // 如果key失效,说明监听的目录可能被删除了,退出循环并重新注册 break; } } } catch (InterruptedException e) { // 中断线程时处理,避免资源泄漏 Thread.currentThread().interrupt(); } }
2. AOP代理的内部调用问题
虽然你说第一个文件触发了日志,但还是要确认:你的日志切面是不是拦截了handleNewFile()这类业务方法?如果monitor()和handleNewFile()在同一个类里,直接用this.handleNewFile()调用是不会触发AOP的——因为Spring AOP是基于动态代理的,内部调用绕过了代理对象。
解决办法有两种:
- 把
handleNewFile()抽成单独的Spring Bean,在监听类里注入这个Bean来调用 - 用
AopContext.currentProxy()获取自身的代理对象来调用:
// 注意:需要在启动类加上@EnableAspectJAutoProxy(exposeProxy = true) ((YourListenerBean) AopContext.currentProxy()).handleNewFile(fullFilePath);
3. FTP上传的特殊情况
有些FTP客户端上传文件时,会先创建一个临时文件(比如带.tmp后缀),上传完成后再重命名为目标文件。这时候你可能只监听了ENTRY_CREATE事件,但实际的有效文件是通过ENTRY_RENAME事件出现的。可以同时监听这两种事件:
// 注册监听时加上ENTRY_RENAME yourWatchedDir.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_RENAME);
最后总结
先优先检查WatchKey的重置逻辑,这是90%以上此类问题的根源;然后确认AOP的调用方式是否正确;最后再考虑FTP上传的特殊事件类型。
内容的提问来源于stack exchange,提问作者user8126531
相关产品推荐
相关产品推荐

