运行时读取类路径下修改的TXT文件无法获取新数据问题
问题核心
本质是classpath资源的缓存机制导致的:
- 开发环境中,Spring的
ClassPathResource默认会缓存资源内容,即使修改外部源文件,读取的依然是缓存的旧数据。 - 生产环境里,classpath文件打包在jar包内,修改jar外的源文件不会影响JVM已加载的资源,读取的始终是jar内的旧文件。
解决办法
1. 开发环境:绕开ClassPathResource缓存
直接读取项目源码目录下的实际文件,不依赖Spring缓存的Resource对象:
public void readFile() throws IOException { try { List<ClientValue> clients = new ArrayList<>(); Path actualPath; // 判断是否为classpath资源 if (filePath instanceof ClassPathResource) { // 直接指向src/main/resources下的真实文件路径 String resourcePath = ((ClassPathResource) filePath).getPath(); actualPath = Paths.get("src/main/resources", resourcePath); } else { actualPath = Paths.get(filePath.getURI()); } // 后续读取逻辑不变 Files.readAllLines(actualPath).stream() .skip(1) .map(line -> line.split(";")) .map(this::createClientValue) .forEach(clients::add); this.clients = clients; log.debug("Client values: {}", this.clients); } catch (IOException e) { log.error("无法读取clients.txt文件", e); throw new IllegalStateException(); } }
2. 生产环境:将文件移出classpath
生产环境不建议依赖classpath文件的动态更新,更可靠的方案是:
- 将
clients.txt放到应用外部固定目录,比如/opt/app/config/clients.txt - 修改配置文件中的
filePath为外部路径,例如file:/opt/app/config/clients.txt - 代码直接读取该外部路径,彻底避开classpath缓存问题
3. 强制刷新Resource缓存(不推荐生产用)
如果必须使用classpath资源,每次读取时创建新的Resource实例并禁用缓存:
public void readFile() throws IOException { try { List<ClientValue> clients = new ArrayList<>(); // 每次创建新的ClassPathResource实例,禁用缓存 ClassPathResource freshResource = new ClassPathResource("clients.txt"); freshResource.setUseCaches(false); Path actualPath = Paths.get(freshResource.getURI()); Files.readAllLines(actualPath).stream() .skip(1) .map(line -> line.split(";")) .map(this::createClientValue) .forEach(clients::add); this.clients = clients; log.debug("Client values: {}", this.clients); } catch (IOException e) { log.error("无法读取clients.txt文件", e); throw new IllegalStateException(); } }
额外提醒
- 确认
FileChangeListener监听的是实际被修改的文件路径,而非classpath的缓存路径,否则触发监听也无法读取新内容。 - 你实现的
isLocked文件锁判断逻辑可以保留,能避免读取正在写入的不完整文件。
内容的提问来源于stack exchange,提问作者Dmitry-Dsafgi-Bachinin
相关产品推荐
相关产品推荐

