programing

봄에 폴더/디렉토리를 어떻게 모니터링합니까?

skycolor 2023. 7. 31. 21:14
반응형

봄에 폴더/디렉토리를 어떻게 모니터링합니까?

저는 봄에 윈도우의 모니터링 디렉토리가 될 스프링 부트 애플리케이션을 작성하고 싶지 않습니다. 그리고 제가 서브 폴더를 변경하거나 새로운 폴더를 추가하거나 기존 폴더를 삭제할 때 그것에 대한 정보를 얻고 싶습니다.

내가 어떻게 그럴 수 있을까?저는 이것을 읽었습니다: 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-ftpSpring 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

반응형