I am trying to execute "WatchService" with spring but it is looking impossible because when I am trying to run this service at the time of application context but loading of spring context becoming stop when control come at
key = watcher.take();
due to this loading of application context is not happening.
below is the full code
@Component
public class DirectoryWatchDemo {
@PostConstruct
public static void test(){
try {
WatchService watcher = FileSystems.getDefault().newWatchService();
Path dir = Paths.get("C:/test");
dir.register(watcher, ENTRY_CREATE);
System.out.println("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();
System.out.println(kind.name() + ": " + fileName);
if (kind == ENTRY_MODIFY &&
fileName.toString().equals("DirectoryWatchDemo.java")) {
System.out.println("My source file has changed!!!");
}
}
boolean valid = key.reset();
if (!valid) {
break;
}
}
} catch (IOException ex) {
System.err.println(ex);
}
}
}
I am doing in this way because I do not want to execute "WatchService" manually.
It is because you have an endless loop, and therefore the method invocation of @PostConstruct never return.
(it seams strange to me, that @PostConstruct works with static methods, but maybe this works)
So the solution is that you start an new thread for your watcher. You could do this in different ways:
@Async to that method (I do not know if this works for @PostConstruct methods) (the major drawback is, that this starts BEFOR the complete application context is initialize)@Scheduler annotation: @Scheduled(fixedDelay = Long.MAX_VALUE) - (the advantage over @PostConstruct+@Async is: that it works for sure and it starts just AFTER the complete context is initialized)WatchService.take waits for the next watch key: "Retrieves and removes next watch key, waiting if none are yet present."
PostConstruct - which is a Java annotation, versus a Spring annotation - "is used on a method that needs to be executed after dependency injection is done to perform any initialization. This method MUST be invoked before the class is put into service." Based on this documentation it seems PostConstruct must return before the bean can be put into service ("MUST be invoked before the class is put into service").
But your PostConstruct method does not return; so PostConstruct is not what you need.
You might consider implementing the Spring InitializingBean interface, which provides a callback method afterPropertiesSet. It should allow you to start this type of service method.
Otherwise you could look at the Apache VFS2 virtual file system, which includes a folder watcher. That is what my project uses; it was pretty easy to start the watcher at system start time; and also, it watches for file delete, update, and create events (unlike the Camel file watcher).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With