봄에 폴더/디렉토리를 어떻게 모니터링합니까?
저는 봄에 윈도우의 모니터링 디렉토리가 될 스프링 부트 애플리케이션을 작성하고 싶지 않습니다. 그리고 제가 서브 폴더를 변경하거나 새로운 폴더를 추가하거나 기존 폴더를 삭제할 때 그것에 대한 정보를 얻고 싶습니다.
내가 어떻게 그럴 수 있을까?저는 이것을 읽었습니다: http://docs.spring.io/spring-integration/reference/html/files.html 과 구글의 'spring file watcher' 아래에 있는 각각의 결과를 읽었지만, 해결책을 찾을 수 없습니다.
이런 것에 대한 좋은 기사나 예문이 있습니까?이런 식으로 하고 싶지 않아요.
@SpringBootApplication
@EnableIntegration
public class SpringApp{
public static void main(String[] args) {
SpringApplication.run(SpringApp.class, args);
}
@Bean
public WatchService watcherService() {
...//define WatchService here
}
}
안부 전해요
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;
}
}
}
Java 7부터는 WatchService가 제공됩니다. 이것이 최고의 솔루션이 될 것입니다.
스프링 구성은 다음과 같습니다.
@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:\Users\nazar_art
스프링 부트로 테스트됨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
-> put@Async
호출한 다른 서비스에서 위의 방법에 대한 주석(다른 빈의 방법이어야 함 - 초기화는 프록시를 통해 수행됨).
봄이 없어도 순수한 자바를 사용할 수 있습니다. https://docs.oracle.com/javase/tutorial/essential/io/notification.html
스프링 통합 샘플 레포를 참조하십시오. 파일 샘플은 'basic' 아래에 있습니다.
더 최근이고 더 정교한 샘플이 애플리케이션에 있습니다.file-split-ftp
Spring Boot 및 Java 구성 대 이전 샘플에 사용된 xml을 사용합니다.
작업에 주석을 달 수 있는 해결 방법을 찾았습니다.@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);
}
}
}
여기에 도움이 될 수 있는 몇 가지 조언은 제공하지 않고 있습니다.
당신은 그 디렉토리를 가져갈 수 있습니다.WatchService
스와보미르 카자의 대답에서 나온 코드:
봄이 없어도 순수한 자바를 사용할 수 있습니다. https://docs.oracle.com/javase/tutorial/essential/io/notification.html
실행 가능한 작업에 코드를 래핑합니다.에게 이작은클게다사디변렉알리수있다릴습니경을 사용하여 수 .SimpMessagingTemplate
여기에 설명된 대로: 웹 소켓 STOMP 핸들 전송
그런 다음 작업의 시작 및 재확증을 처리하는 스케줄링에 대해 설명하는 것과 같은 스케줄러를 만들 수 있습니다.
mvc-config에서 스케줄링 및 웹 소켓 지원을 구성하고 클라이언트 측에서 STOMP 지원을 구성하는 것을 잊지 마십시오(자세한 내용은 여기: STOMP over Websocket).
Apache commons-io는 파일/디렉토리의 변경사항을 볼 수 있는 또 다른 좋은 대안입니다.
다음 답변에서 사용에 대한 장단점의 개요를 확인할 수 있습니다. https://stackoverflow.com/a/41013350/16470819
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
만약 누군가가 재귀적 하위 폴더 감시자를 찾고 있다면, 이 링크는 다음과 같은 도움이 될 수 있습니다.폴더 및 하위 폴더의 변경 사항을 감시하는 방법
언급URL : https://stackoverflow.com/questions/40020999/how-to-monitor-folder-directory-in-spring
'programing' 카테고리의 다른 글
Spring 속성 자리 표시자를 확인할 수 없습니다. (0) | 2023.07.31 |
---|---|
Swift의 지수 연산자 (0) | 2023.07.31 |
나중에 사용할 주피터(IPython) 노트북 세션을 피클 또는 저장하는 방법 (0) | 2023.07.26 |
스프링 기본 스코프가 싱글톤입니까? (0) | 2023.07.26 |
파워셸을 사용하여 프로젝트에서 선 수 찾기 (0) | 2023.07.26 |