Spring Integration带NioFileLocker的入站通道在只读文件系统触发异常
你遇到的报错是NioFileLocker的固有特性导致的:该类底层会以读写模式打开目标文件获取文件通道,再申请独占锁,而只读网络文件系统不允许任何写入操作,无法以读写模式打开文件,因此直接抛出文件不存在的异常,和你的判断完全一致。
针对只读文件系统下仍要避免文件重复处理的需求,有以下几种可行方案:
单节点部署场景
直接使用内存级的已处理文件过滤器即可,不需要依赖文件锁:
- 自定义
FileListFilter实现类,内部通过ConcurrentHashMap或Guava Cache存储已处理文件的唯一标识(可选择「文件名+最后修改时间+文件大小」的组合,文件更新频率高的话可以补充计算文件哈希),扫描到文件时先判断标识是否已存在,不存在才放行处理。 - 也可以直接使用Spring Integration自带的
AcceptOnceFileListFilter,开箱即用,默认基于内存存储已处理文件元数据。
多节点部署场景
需要分布式的状态存储来保证多节点不会重复处理同一文件,可选方案:
- 使用持久化的AcceptOnce过滤器
Spring Integration提供了FileSystemPersistentAcceptOnceFileListFilter,可以自定义元数据存储的目录,你只需将存储路径配置到本地可写磁盘或者其他可写的共享存储,无需修改现有业务逻辑,即可替代NioFileLocker实现防重复处理的能力,是改造成本最低的方案。 - 外置标记文件
每处理完一个文件,在本地可写目录或其他可写共享存储中创建一个和原文件同名的空标记文件(比如原文件名为a.txt,标记文件名为a.txt.processed),处理文件前先判断对应的标记文件是否存在,不存在才执行处理逻辑。 - 分布式锁/分布式缓存
引入Redis等分布式组件,两种用法可选:
- 用分布式缓存存储已处理文件的唯一标识,设置合理的过期时间避免缓存无限膨胀,过滤器查询缓存判断是否放行
- 用分布式锁实现和原有NioFileLocker一致的逻辑,锁的key设置为文件的唯一标识,拿到锁的节点才可以处理文件,处理完成后释放锁
注意事项
如果你的网络盘文件存在同文件名覆盖更新的场景,不要仅用文件名作为唯一判定标识,需要补充最后修改时间、文件大小、内容哈希等维度,避免更新后的文件被判定为已处理而漏掉。
内容的提问来源于stack exchange,提问作者Kode Charlie
相关产品推荐
相关产品推荐

