java 如何在spring中监控文件夹/目录?

wj8zmpe1  于 2023-01-19  发布在  Java
关注(0)|答案(8)|浏览(486)

我不想在Spring写Spring Boot 应用程序,这将是在Windows中的监控目录,当我改变子文件夹或添加新的或删除现有的一个,我想得到有关的信息。
我怎么能这么做呢?我读过这篇文章:http://docs.spring.io/spring-integration/reference/html/files.html和每个结果下的'Spring文件观察员'在谷歌,但我找不到解决方案...
你有这样的好文章或例子吗?我不希望它像这样:

@SpringBootApplication
@EnableIntegration
public class SpringApp{

    public static void main(String[] args) {
        SpringApplication.run(SpringApp.class, args);
    }

    @Bean
    public WatchService watcherService() {
        ...//define WatchService here
    }
}

问候

wlsrxk51

wlsrxk511#

spring-boot-devtools具有FileSystemWatcher

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>

文件监视器配置

@Configuration
public class FileWatcherConfig {
    @Bean
    public FileSystemWatcher fileSystemWatcher() {
        FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(true, Duration.ofMillis(5000L), Duration.ofMillis(3000L));
        fileSystemWatcher.addSourceFolder(new File("/path/to/folder"));
        fileSystemWatcher.addListener(new MyFileChangeListener());
        fileSystemWatcher.start();
        System.out.println("started fileSystemWatcher");
        return fileSystemWatcher;
    }

    @PreDestroy
    public void onDestroy() throws Exception {
        fileSystemWatcher().stop();
    }
}

我的文件更改监听器

@Component
public class MyFileChangeListener implements FileChangeListener {

    @Override
    public void onChange(Set<ChangedFiles> changeSet) {
        for(ChangedFiles cfiles : changeSet) {
            for(ChangedFile cfile: cfiles.getFiles()) {
                if( /* (cfile.getType().equals(Type.MODIFY) 
                     || cfile.getType().equals(Type.ADD)  
                     || cfile.getType().equals(Type.DELETE) ) && */ !isLocked(cfile.getFile().toPath())) {
                    System.out.println("Operation: " + cfile.getType() 
                      + " On file: "+ cfile.getFile().getName() + " is done");
                }
            }
        }
    }
    
    private boolean isLocked(Path path) {
        try (FileChannel ch = FileChannel.open(path, StandardOpenOption.WRITE); FileLock lock = ch.tryLock()) {
            return lock == null;
        } catch (IOException e) {
            return true;
        }
    }

}
yeotifhr

yeotifhr2#

从Java 7开始,WatchService将是最好的解决方案。
Spring配置可能如下所示:

@Slf4j
@Configuration
public class MonitoringConfig {

    @Value("${monitoring-folder}")
    private String folderPath;

    @Bean
    public WatchService watchService() {
        log.debug("MONITORING_FOLDER: {}", folderPath);
        WatchService watchService = null;
        try {
            watchService = FileSystems.getDefault().newWatchService();
            Path path = Paths.get(folderPath);

            if (!Files.isDirectory(path)) {
                throw new RuntimeException("incorrect monitoring folder: " + path);
            }

            path.register(
                    watchService,
                    StandardWatchEventKinds.ENTRY_DELETE,
                    StandardWatchEventKinds.ENTRY_MODIFY,
                    StandardWatchEventKinds.ENTRY_CREATE
            );
        } catch (IOException e) {
            log.error("exception for watch service creation:", e);
        }
        return watchService;
    }
}

以及用于启动监控自身的Bean:

@Slf4j
@Service
@AllArgsConstructor
public class MonitoringServiceImpl {

    private final WatchService watchService;

    @Async
    @PostConstruct
    public void launchMonitoring() {
        log.info("START_MONITORING");
        try {
            WatchKey key;
            while ((key = watchService.take()) != null) {
                for (WatchEvent<?> event : key.pollEvents()) {
                    log.debug("Event kind: {}; File affected: {}", event.kind(), event.context());
                }
                key.reset();
            }
        } catch (InterruptedException e) {
            log.warn("interrupted exception for monitoring service");
        }
    }

    @PreDestroy
    public void stopMonitoring() {
        log.info("STOP_MONITORING");

        if (watchService != null) {
            try {
                watchService.close();
            } catch (IOException e) {
                log.error("exception while closing the monitoring service");
            }
        }
    }
}

此外,您必须为应用程序类设置@EnableAsync(it配置)。
并从application.yml中截取:
监控文件夹:C:\用户\目录
使用 Spring Boot 2.3.1进行测试。
还使用了异步池的配置:

@Slf4j
@EnableAsync
@Configuration
@AllArgsConstructor
@EnableConfigurationProperties(AsyncProperties.class)
public class AsyncConfiguration implements AsyncConfigurer {

    private final AsyncProperties properties;

    @Override
    @Bean(name = "taskExecutor")
    public Executor getAsyncExecutor() {
        log.debug("Creating Async Task Executor");
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(properties.getCorePoolSize());
        taskExecutor.setMaxPoolSize(properties.getMaxPoolSize());
        taskExecutor.setQueueCapacity(properties.getQueueCapacity());
        taskExecutor.setThreadNamePrefix(properties.getThreadName());
        taskExecutor.initialize();
        return taskExecutor;
    }

    @Bean
    public TaskScheduler taskScheduler() {
        return new ConcurrentTaskScheduler();
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new CustomAsyncExceptionHandler();
    }
}

其中,自定义异步异常处理程序为:

@Slf4j
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

    @Override
    public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
        log.error("Exception for Async execution: ", throwable);
        log.error("Method name - {}", method.getName());
        for (Object param : objects) {
            log.error("Parameter value - {}", param);
        }
    }
}

属性文件中的配置:

async-monitoring:
  core-pool-size: 10
  max-pool-size: 20
  queue-capacity: 1024
  thread-name: 'async-ex-'

其中AsyncProperties

@Getter
@Setter
@ConfigurationProperties("async-monitoring")
public class AsyncProperties {
    @NonNull
    private Integer corePoolSize;
    @NonNull
    private Integer maxPoolSize;
    @NonNull
    private Integer queueCapacity;
    @NonNull
    private String threadName;
}

为了使用异步执行,我正在处理如下事件:

validatorService.processRecord(recordANPR, zipFullPath);

其中验证程序服务的外观如下所示:

@Async
public void processRecord(EvidentialRecordANPR record, String fullFileName) {

主要思想是配置异步配置-〉从MonitoringService调用它-〉将@Async注解放在您调用的另一个服务的方法上(它应该是另一个bean的方法-初始化通过代理)。

xtupzzrd

xtupzzrd4#

参见Spring Integration Samples Repo,在“基本”下有一个文件示例。
在应用程序file-split-ftp下有一个更新和更复杂的示例-它使用Sping Boot 和Java配置,而不是旧示例中使用的xml。

cwdobuhd

cwdobuhd5#

找到了一个变通方法,可以按@Scheduled(fixedDelay = Long.MAX_VALUE)注解任务
你可以检查代码:

@Scheduled(fixedDelay = Long.MAX_VALUE)
public void watchTask() {
                this.loadOnStartup();
                try {
                    WatchService watcher = FileSystems.getDefault().newWatchService();
                    Path file = Paths.get(propertyFile);
                    Path dir = Paths.get(file.getParent().toUri());
                    dir.register(watcher, ENTRY_MODIFY);
                    logger.info("Watch Service registered for dir: " + dir.getFileName());
    
                    while (true) {
                        WatchKey key;
                        try {
                            key = watcher.take();
                        } catch (InterruptedException ex) {
                            return;
                        }
    
                        for (WatchEvent<?> event : key.pollEvents()) {
                            WatchEvent.Kind<?> kind = event.kind();
    
                            @SuppressWarnings("unchecked")
                            WatchEvent<Path> ev = (WatchEvent<Path>) event;
                            Path fileName = ev.context();
                            logger.debug(kind.name() + ": " + fileName);
                            if (kind == ENTRY_MODIFY &&
                                    fileName.toString().equals(file.getFileName().toString())) {
                                    //publish event here
                            }
                        }
                        boolean valid = key.reset();
                        if (!valid) {
                            break;
                        }
                    }
                } catch (Exception ex) {
                    logger.error(ex.getMessage(), ex);
                }
            }
        }
of1yzvn4

of1yzvn46#

这里没有给出细节,一些可能会帮助您解决问题的提示。
你可以从Sławomir Czaja的回答中得到目录WatchService的代码:
您可以使用纯java实现此功能,而不需要spring https://docs.oracle.com/javase/tutorial/essential/io/notification.html
并将该代码 Package 成一个可运行的任务。该任务可以使用SimpMessagingTemplate通知您的客户端目录更改,如下所述:Web套接字STOMP句柄发送
然后,您可以创建如下所述的调度程序:处理任务的开始和重复的调度。
别忘了在mvc-config中配置调度和websocket支持,以及在客户端配置STOMP支持(进一步阅读:STOMP over Websocket

v9tzhpje

v9tzhpje7#

Apache commons-io是另一个监视文件/目录更改的好方法。
您可以在下面的答案中看到使用它的利弊概述:https://stackoverflow.com/a/41013350/16470819

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>
lfapxunr

lfapxunr8#

以防万一,如果有人正在寻找递归子文件夹监视器,这个链接可能会有帮助:How to watch a folder and subfolders for changes

相关问题