在企業級應用開發中,經常需要監控特定目錄下的文件變化(新增、刪除、修改),並自動觸發相應的業務邏輯。本文將詳細介紹如何基於 Spring 框架與 Apache Commons IO 組件,構建一套完整、可配置的文件監控系統。
整個監控體系由四大核心組件組成,各司其職:
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 文件監測器:每 10 秒掃描一次 -->
<bean id="monitor" class="com.interfaces.file.monitor.FileMonitorImpl">
<constructor-arg index="0" value="10000"/>
<constructor-arg index="1" ref="observer"/>
</bean>
<!-- 文件觀察器:監聽 D:\UploadDir,只處理 .xml 文件 -->
<bean id="observer" class="com.interfaces.file.monitor.FileObserverImpl">
<constructor-arg index="0" value="D:\\UploadDir"/>
<constructor-arg index="1" ref="filter"/>
<constructor-arg index="2" ref="listener"/>
</bean>
<!-- 文件監聽器 -->
<bean id="listener" class="com.interfaces.file.monitor.FileListener"/>
<!-- 文件過濾器:支援多副檔名,逗號分隔 -->
<bean id="filter" class="com.interfaces.file.monitor.FileFilterImpl">
<constructor-arg index="0" value="xml,txt,bak"/>
</bean>
</beans>
通過繼承 ContextLoaderListener,在 Spring 容器啟動時自動啟動監控器,關閉時優雅停止:
public class SpringContextLoaderListener extends ContextLoaderListener {
@Override
public void contextInitialized(ServletContextEvent event) {
super.contextInitialized(event);
getScanner().start(); // 啟動目錄掃描器
}
@Override
public void contextDestroyed(ServletContextEvent event) {
getScanner().stop(); // 停止掃描器
super.contextDestroyed(event);
}
private FileMonitor getScanner() {
return getCurrentWebApplicationContext().getBean(FileMonitor.class);
}
}
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application.xml</param-value>
</context-param>
<listener>
<listener-class>com.web.SpringContextLoaderListener</listener-class>
</listener>
</web-app>
封裝 FileAlterationMonitor,提供觀察器註冊、啟停控制:
public class FileMonitorImpl implements FileMonitor {
private final FileAlterationMonitor monitor;
private static final String THREAD_NAME = "File-MONITOR-Daemon";
public FileMonitorImpl(int interval, FileAlterationObserver observer) {
this(interval, observer, new BasicThreadFactory.Builder()
.namingPattern(THREAD_NAME).daemon(false).build());
}
// 委託給 Commons IO 實現核心邏輯
@Override public void start() { try { monitor.start(); } catch (Exception e) { e.printStackTrace(); } }
@Override public void stop() { try { monitor.stop(); } catch (Exception e) { e.printStackTrace(); } }
// ... 其他委託方法
}
繼承 FileAlterationObserver,在構造時自動創建不存在的目錄,並註冊監聽器與過濾器:
public class FileObserverImpl extends FileAlterationObserver implements FileObserver {
private final FileFilter filter;
public FileObserverImpl(String dir, FileFilter filter, FileAlterationListener listener) {
super(dir, filter, (IOCase) null);
addListener(listener);
this.filter = filter;
// 確保目錄存在
File directory = new File(dir);
if (!directory.exists()) FileUtils.forceMkdir(directory);
else if (directory.isFile()) { FileUtils.forceDelete(directory); FileUtils.forceMkdir(directory); }
}
// ... 接口方法委託給父類
}
繼承 FileAlterationListenerAdaptor,只需覆寫關心的事件:
public final class FileListener extends FileAlterationListenerAdaptor {
@Override public void onFileCreate(File file) { /* 業務邏輯:新文件到達 */ }
@Override public void onFileDelete(File file) { /* 業務邏輯:文件被刪除 */ }
@Override public void onFileChange(File file) { /* 業務邏輯:文件內容變更 */ }
@Override public void onStart(FileAlterationObserver o) { /* 掃描開始 */ }
@Override public void onStop(FileAlterationObserver o) { /* 掃描結束 */ }
}
基於 FilenameUtils.isExtension 實現多副檔名匹配:
public class FileFilterImpl implements FileFilter {
private final String[] extensions;
public FileFilterImpl(String... extensions) { this.extensions = extensions; }
@Override public boolean accept(File pathname) {
return FilenameUtils.isExtension(pathname.getName(), extensions);
}
@Override public String[] getExtensions() { return extensions; }
}
本方案充分利用 Spring 的依賴注入與生命周期管理,結合 Apache Commons IO 成熟的文件監控 API,實現了配置靈活、代碼清晰、生產可用的文件變更監控系統。開發者只需關注 FileListener 中的具體業務邏輯,即可快速接入各類文件驅動的業務場景。