Java отследить изменение файла

Как Java может отслеживать изменения файлов

Если логбэк используется в качестве компонента вывода журнала в приложении, большинство из них будет настроено logback.xml Этот файл и в производственной среде напрямую изменяют уровень журнала в файле logback.xml, он может вступить в силу без перезапуска приложения.

Итак, как реализована эта функция?

I. Описание и анализ проблемы

В ответ на вышеуказанную проблему сначала выложите практический кейс на моем личном сайтеZ+В, все гаджеты динамически добавляются и скрываются с помощью файлов конфигурации. Поскольку существует только один сервер, файлы конфигурации упрощаются и помещаются непосредственно в каталог сервера.

Текущая проблема заключается в том, что при изменении содержимого этого файла приложение может обнаружить это изменение, перезагрузить содержимое файла и обновить внутренний кеш приложения.

Один из самых простых способов придумать, это опрос, чтобы определить, был ли файл изменен. Если он был изменен, перезагрузите и обновите память, поэтому основные проблемы, о которых следует беспокоиться, заключаются в следующем:

  • Как опросить?
  • Как определить, модифицирован ли файл?
  • Если конфигурация ненормальная, служба будет недоступна? (То есть отказоустойчивость, к этой теме это не относится, но важнее . )

II. Разработка и реализация

После абстрагирования проблемы соответствующее решение станет более ясным.

  • Как опросить? — «Таймер, ScheduledExecutorService может быть реализован
  • Как судить о модификации файла? —«В соответствии с java.io.File#lastModified Получите время последней модификации файла и сравните его

Тогда проще очень простая реализация:

public class FileUpTest < private long lastTime; @Test public void testFileUpdate() < File file = new File("/tmp/alarmConfig"); // Во-первых, отметка времени последней модификации файла lastTime = file.lastModified(); // Задание по времени, каждую секунду, чтобы определить, изменился ли файл, то есть изменился ли lastModified ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); scheduledExecutorService.scheduleAtFixedRate(new Runnable() < @Override public void run() < if (file.lastModified() > lastTime) < System.out.println("file update! time : " + file.lastModified()); lastTime = file.lastModified(); > > >,0, 1, TimeUnit.SECONDS); try < Thread.sleep(1000 * 60); > catch (InterruptedException e) < e.printStackTrace(); >> > Скопировать код

Вышеупомянутая очень простая, очень простая реализация, которая в основном может удовлетворить наши потребности, так в чем проблема с этой реализацией?

Читайте также:  Java thread wait exception

Что произойдет, если во время выполнения запланированной задачи возникнет исключение?

Внесите небольшие изменения в приведенный выше код

public class FileUpTest < private long lastTime; private void ttt() < throw new NullPointerException(); > @Test public void testFileUpdate() < File file = new File("/tmp/alarmConfig"); lastTime = file.lastModified(); ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); scheduledExecutorService.scheduleAtFixedRate(new Runnable() < @Override public void run() < if (file.lastModified() > lastTime) < System.out.println("file update! time : " + file.lastModified()); lastTime = file.lastModified(); ttt(); > > >, 0, 1, TimeUnit.SECONDS); try < Thread.sleep(1000 * 60 * 10); > catch (InterruptedException e) < e.printStackTrace(); >> > Скопировать код

При фактическом тестировании было обнаружено, что приведенный выше код запускался только тогда, когда он был изменен в первый раз, но вторая модификация не имеет никакого эффекта. То есть, когда генерируется исключение, задача синхронизации больше не будет продолжаться. Основная причина этой проблемы — ScheduledExecutorService Причина

Непосредственно просматривать описание аннотации исходного кода ScheduledExecutorService

Если при любом выполнении задачи возникает исключение, последующие выполнения подавляются. В противном случае задача будет завершена только через отмену или завершение работы исполнителя. Исключение, следующие задачи больше не будут выполняться.

Поэтому при использовании этой позы вы должны убедиться, что ваша задача не генерирует исключение, иначе вы не сможете играть позже.

Соответствующее решение относительно простое, просто поймите все

III. Расширенное издание

Предыдущая версия представляет собой базовую реализацию. Конечно, в круге java в основном можно найти множество общих требований в соответствующих инструментах с открытым исходным кодом для использования. Конечно, это не исключение, и это должна быть серия apache, в которой все сравнивают атрибуты.

Во-первых, maven зависит от

dependency> groupId>commons-io groupId> artifactId>commons-io artifactId> version>2.6 version> dependency> Скопировать код

В основном с помощью этого инструмента FileAlterationObserver , FileAlterationListener , FileAlterationMonitor Эти три класса используются для реализации связанных сценариев спроса. Конечно, он очень прост в использовании, поэтому непонятно, как это объяснить. Просто посмотрите на код, скопированный из одного из моих проектов с открытым исходным кодом quick-alarm.

public class PropertiesConfListenerHelper < public static boolean registerConfChangeListener(File file, Function> func) < try < // Интервал опроса 5 секунд long interval = TimeUnit.SECONDS.toMillis(5); // Поскольку мониторинг осуществляется в модуле каталога, здесь находится непосредственно корневой каталог файла File dir = file.getParentFile(); // Создаем файловый обозреватель для фильтрации FileAlterationObserver observer = new FileAlterationObserver(dir, FileFilterUtils.and(FileFilterUtils.fileFileFilter(), FileFilterUtils.nameFileFilter(file.getName()))); // Настраиваем прослушиватель изменений файла observer.addListener(new MyFileListener(func)); FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer); monitor.start(); return true; > catch (Exception e) < log.error("register properties change listener error! e:<>", e); return false; > > static final class MyFileListener extends FileAlterationListenerAdaptor < private Function> func; public MyFileListener(Function> func) < this.func = func; > @Override public void onFileChange(File file)  < Mapans = func.apply(file); // Если загрузка не удалась, распечатываем журнал log.warn("PropertiesConfig changed! reload ans: <>", ans); > > > Скопировать код

В связи с приведенной выше реализацией кратко объясните несколько моментов:

  • Этот мониторинг файлов основан на корневом каталоге, а затем могут быть установлены фильтры для отслеживания соответствующих изменений файлов.
  • Как указано выше registerConfChangeListener Метод, входящий файл представляет собой конкретный файл конфигурации, поэтому при построении параметров извлекается каталог, а имя файла извлекается как фильтр.
  • Второй параметр — это синтаксис jdk8, который представляет собой конкретное содержимое файла конфигурации чтения и отображается на соответствующий объект сущности.

Возникает вопрос: что произойдет, если при выполнении метода func возникнет исключение?

Фактические результаты тестирования такие же, как указано выше. После создания исключения вы все равно становитесь на колени, поэтому вам все равно нужно следить за тем, чтобы исключение не запускалось.

Так что просто взгляните на приведенную выше логику реализации и напрямую вычтите основной модуль

public void run() < while(true) < if(this.running) < Iterator var1 = this.observers.iterator(); while(var1.hasNext()) < FileAlterationObserver observer = (FileAlterationObserver)var1.next(); observer.checkAndNotify(); >if(this.running) < try < Thread.sleep(this.interval); > catch (InterruptedException var3) < ; >continue; > > return; > > Скопировать код

Это в основном ясно из вышеизложенного. Вся логика реализации отличается от нашего первого метода задачи синхронизации. Здесь потоки используются напрямую, бесконечный цикл, а спящий режим используется внутри для приостановки. Поэтому, когда возникает исключение, это эквивалентно Просто выбрось, и эта нить встанет на колени

Версия JDK

jdk1.7, предоставляет WatchService , Его также можно использовать для отслеживания изменений файлов. Я не обращался к нему раньше. Я видел инструкции и искал связанные с использованием. Это было довольно просто. Также дана простая демонстрация.

@Test public void testFileUpWather() throws IOException < // Объясняем, что слушатель здесь также должен быть каталогом Path path = Paths.get("/tmp"); WatchService watcher = FileSystems.getDefault().newWatchService(); path.register(watcher, ENTRY_MODIFY); new Thread(() -> < try < while (true) < WatchKey key = watcher.take(); for (WatchEvent event : key.pollEvents()) < if (event.kind() == OVERFLOW) < // Событие может быть потеряно или отменено continue; > Path fileName = (Path) event.context(); System.out.println("Обновление файла:" + fileName); > if (!key.reset()) < // сбросить WatchKey break; > > > catch (Exception e) < e.printStackTrace(); >>).start(); try < Thread.sleep(1000 * 60 * 10); > catch (InterruptedException e) < e.printStackTrace(); >> Скопировать код

IV. Резюме

Использование Java для отслеживания изменений файла конфигурации в основном включает два момента.

  • Как опросить: таймер (Timer, ScheduledExecutorService), бесконечный цикл потока + сон
  • Модификация файла: File # lastModified

В целом, эта реализация относительно проста. Независимо от того, является ли это индивидуальной реализацией или полагается на commos-io, она не требует больших технических затрат, но следует отметить одну вещь:

  • Не создавайте исключений в методах обратного вызова для заданий по времени или при изменении файлов! ! !

Чтобы избежать вышеупомянутой ситуации, реализация, которая может быть выполнена, заключается в использовании уведомления об асинхронном сообщении EventBus. Когда файл изменяется, отправьте сообщение, а затем добавьте его к конкретному методу перезагрузки содержимого файла. @Subscribe Достаточно аннотации, которая не только обеспечивает разделение, но и позволяет избежать исключений службы, вызванных исключениями (если вас интересует эта реализация, вы можете прокомментировать и объяснить)

V. Прочее

Справочный проект

заявление

Это не так хорошо, как написано письмо. Уже упомянутое содержание является чисто семейным заявлением. Из-за моих средних способностей и неполного мнения, если у вас есть какие-либо вопросы, вы можете критиковать и исправлять

Источник

Оцените статью