code: private void watchPath() {
  		for (;;) {
  			//監視キーの送信を待機
  			WatchKey key;
  			try {
  				key = watcher.take();
  			} catch (InterruptedException ex) {
  				log.debug("WatchService catched InterruptedException.");
  				break;
  			} catch (Throwable ex) {
  				log.error("Unexpected exception occured.", ex);
  				break;
  			}
  
  			for (WatchEvent<?> event : key.pollEvents()) {
  				WatchEvent.Kind<?> kind = event.kind();
  
  				if (kind == OVERFLOW) {
  					continue;
  				}
  
  				//ファイル名はイベントのコンテキストです。
  				@SuppressWarnings("unchecked")
  				WatchEvent<Path> evt = (WatchEvent<Path>) event;
  				Path dir = watchDirs.get(key);
  				Path path = dir.resolve(evt.context());
  
  				log.trace("file changed.({}). path={}", kind.name(), path);
  				boolean isSqlFile = path.toString().endsWith(fileExtension);
  				if (Files.isDirectory(path) || !isSqlFile) {
  					// ENTRY_DELETEの時はFiles.isDirectory()がfalseになるので拡張子での判定も行う
  					if (kind == ENTRY_CREATE) {
  						traverse(path, true, false);
  					} else if (kind == ENTRY_DELETE) {
  						key.cancel();
  						watchDirs.remove(key);
  						continue;
  					}
  				} else if (isSqlFile) {
  					if (kind == ENTRY_CREATE) {
  						traverse(path, true, false);
  					} else if (kind == ENTRY_MODIFY || kind == ENTRY_DELETE) {
  						String sqlName = getSqlName(path);
  						sqlInfos.computeIfPresent(sqlName, (k, v) -> {
  							return v.computePath(path, kind == ENTRY_DELETE);
  						});
  					}
  				}
  			}
  			key.reset();
  		}
  		try {
  			watcher.close();
  		} catch (IOException e) {
  			// do nothing
  		}
  	}
docs: Pathの監視