Skip to content

Commit

Permalink
Merge pull request #197 from jamebal/develop
Browse files Browse the repository at this point in the history
perf: 文件监控使用性能更好的watchService
  • Loading branch information
jamebal authored Dec 5, 2024
2 parents ef5eaa0 + ba6dac6 commit b4f84fe
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 220 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,11 @@
<artifactId>commons-io</artifactId>
<version>2.16.1</version>
</dependency>
<dependency>
<groupId>io.methvin</groupId>
<artifactId>directory-watcher</artifactId>
<version>0.18.0</version>
</dependency>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.doc.free</artifactId>
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/jmal/clouddisk/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.jmal.clouddisk.config;

import com.jmal.clouddisk.exception.BrokenPipeFilter;
import com.jmal.clouddisk.interceptor.AuthInterceptor;
import com.jmal.clouddisk.interceptor.FileInterceptor;
import com.jmal.clouddisk.interceptor.HeaderLocaleChangeInterceptor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
Expand Down Expand Up @@ -88,4 +90,12 @@ public HeaderLocaleChangeInterceptor localeChangeInterceptor() {
return new HeaderLocaleChangeInterceptor();
}

@Bean
public FilterRegistrationBean<BrokenPipeFilter> brokenPipeFilter() {
FilterRegistrationBean<BrokenPipeFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new BrokenPipeFilter());
registrationBean.addUrlPatterns("/*");
return registrationBean;
}

}
28 changes: 28 additions & 0 deletions src/main/java/com/jmal/clouddisk/exception/BrokenPipeFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.jmal.clouddisk.exception;

import jakarta.servlet.*;

import java.io.IOException;

public class BrokenPipeFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) {}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (IOException e) {
if (e.getMessage().contains("Broken pipe")) {
// 忽略 Broken pipe 错误
return;
}
throw e;
}
}

@Override
public void destroy() {}
}
143 changes: 76 additions & 67 deletions src/main/java/com/jmal/clouddisk/listener/FileListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,76 @@
import cn.hutool.core.text.CharSequenceUtil;
import com.jmal.clouddisk.config.FileProperties;
import com.jmal.clouddisk.service.IFileService;
import com.jmal.clouddisk.util.CaffeineUtil;
import io.methvin.watcher.DirectoryChangeEvent;
import io.methvin.watcher.DirectoryChangeListener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

/**
* 文件变化监听器
* <p>
* 在Apache的Commons-IO中有关于文件的监控功能的代码. 文件监控的原理如下:
* 由文件监控类FileAlterationMonitor中的线程不停的扫描文件观察器FileAlterationObserver,
* 如果有文件的变化,则根据相关的文件比较器,判断文件时新增,还是删除,还是更改。(默认为1000毫秒执行一次扫描)
*
* @author jmal
*/
@Slf4j
@Service
public class FileListener extends FileAlterationListenerAdaptor {
@RequiredArgsConstructor
public class FileListener implements DirectoryChangeListener {

@Autowired
FileProperties fileProperties;
private final FileProperties fileProperties;

@Autowired
IFileService fileService;
private final IFileService fileService;

/**
* 文件创建执行
* 续要过滤掉的目录列表
*/
private final Set<Path> FILTER_DIR_SET = new CopyOnWriteArraySet<>();

public void addFilterDir(Path path) {
FILTER_DIR_SET.add(path);
}

public Set<Path> getFilterDirSet() {
return FILTER_DIR_SET;
}

public void removeFilterDir(Path path) {
FILTER_DIR_SET.remove(path);
}

public boolean containsFilterDir(Path path) {
return FILTER_DIR_SET.contains(path);
}

@Override
public void onEvent(DirectoryChangeEvent directoryChangeEvent) {
Path eventPath = directoryChangeEvent.path();
DirectoryChangeEvent.EventType eventType = directoryChangeEvent.eventType();
// 检查是否为忽略路径
if (FILTER_DIR_SET.stream().anyMatch(eventPath::startsWith)) {
log.debug("Ignore Event: {}, Path: {}", eventType, eventPath);
return;
}
log.debug("DirectoryChangeEvent: {}, Path: {}", eventType, eventPath);
switch (eventType) {
case CREATE:
onFileCreate(eventPath.toFile());
break;
case MODIFY:
onFileChange(eventPath.toFile());
break;
case DELETE:
onFileDelete(eventPath.toFile());
break;
}
}

/**
* 文件创建执行
* @param file 文件
*/
public void onFileCreate(File file) {
try {
// 判断文件名是否在monitorIgnoreFilePrefix中
Expand All @@ -46,23 +85,25 @@ public void onFileCreate(File file) {
return;
}
fileService.createFile(username, file);
CaffeineUtil.setLastAccessTimeCache();
log.info("用户:{},新建文件:{}", username, file.getAbsolutePath());
} catch (Exception e) {
log.error("新建文件后续操作失败, " + file.getAbsolutePath(), e);
log.error("新建文件后续操作失败, {}", file.getAbsolutePath(), e);
}
}

/**
* 文件创建修改
* @param file 文件
*/
@Override
public void onFileChange(File file) {
try {
String username = ownerOfChangeFile(file);
if (CharSequenceUtil.isBlank(username)) {
return;
}
fileService.updateFile(username, file);
CaffeineUtil.setLastAccessTimeCache();
log.info("用户:{},修改文件:{}", username, file.getAbsolutePath());
} catch (Exception e) {
log.error("修改文件后续操作失败", e);
Expand All @@ -71,69 +112,23 @@ public void onFileChange(File file) {

/**
* 文件删除
* @param file 文件
*/
@Override
public void onFileDelete(File file) {
try {
String username = ownerOfChangeFile(file);
if (CharSequenceUtil.isBlank(username)) {
return;
}
fileService.deleteFile(username, file);
CaffeineUtil.setLastAccessTimeCache();
log.info("用户:{},删除文件:{}", username, file.getAbsolutePath());
} catch (Exception e) {
log.error("删除文件后续操作失败", e);
}
}

/**
* 目录创建
*/
@Override
public void onDirectoryCreate(File directory) {
try {
String username = ownerOfChangeFile(directory);
if (CharSequenceUtil.isBlank(username)) {
return;
}
fileService.createFile(username, directory);
log.info("用户:{},新建目录:{}", username, directory.getAbsolutePath());
} catch (Exception e) {
log.error("新建目录后续操作失败", e);
}
}

/**
* 目录修改
*/
@Override
public void onDirectoryChange(File directory) {
try {
String username = ownerOfChangeFile(directory);
log.info("用户:{},修改目录:{}", username, directory.getAbsolutePath());
} catch (Exception e) {
log.error("修改目录后续操作失败", e);
}
}

/**
* 目录删除
*/
@Override
public void onDirectoryDelete(File directory) {
try {
String username = ownerOfChangeFile(directory);
if (CharSequenceUtil.isBlank(username)) {
return;
}
fileService.deleteFile(username, directory);
log.info("用户:{},删除目录:{}", username, directory.getAbsolutePath());
} catch (Exception e) {
log.error("删除目录后续操作失败", e);
}
}

/***
* 判断变化的文件属于哪个用户
* @return username
*/
Expand All @@ -151,4 +146,18 @@ private String ownerOfChangeFile(File file) {
return username;
}

@Override
public boolean isWatching() {
return DirectoryChangeListener.super.isWatching();
}

@Override
public void onIdle(int i) {
DirectoryChangeListener.super.onIdle(i);
}

@Override
public void onException(Exception e) {
DirectoryChangeListener.super.onException(e);
}
}
Loading

0 comments on commit b4f84fe

Please sign in to comment.