Перезапуск службы с использованием Guava
В настоящее время я разрабатываю приложение, в котором мне нужно управлять состоянием нескольких служб и останавливать/запускать их на основе некоторых событий. Проблема заключается в том, что, как указано в документах, служба Guava является однонаправленной, то есть после ее остановки ее нельзя запустить снова.
Так как мне нужно как-то обойти эту проблему, я столкнулся с несколькими альтернативами, которые я бы хотел вынести на рассмотрение (тем более, что могут быть недостатки для каждого из них, о которых я не знаю сейчас).
Первым очевидным решением этой проблемы является создание новой службы, когда мне нужно "перезапустить" ее. Это работает, но в моей нынешней архитектуре это немного усложнит ситуацию: в настоящее время я устанавливаю все службы и основываюсь на событиях из EventBus, запуская или останавливая их, если это необходимо. Класс, который вызывает методы start и stop, сохраняет только ссылку на карту сервисов и вызывает правильный метод в этих экземплярах на основании полученного события. Если мне нужно создать экземпляр нового объекта в ответ на Событие, мне придется отказаться от некоторой де-связи, которая у меня есть (возможно, сохраняя класс каждого типа Сервиса и вызывая конструктор с использованием отражения).
Другая возможность - реализовать интерфейс службы как RestartableThreadedService (или что-то в этом роде). Если бы я взял этот маршрут, мой метод start() мог бы создать другой поток, как если бы это был первый раз, и reset состояния.
Есть ли какой-либо явный недостаток для второго подхода? Я боюсь, что у меня может возникнуть некоторый очевидный недостаток (помимо того, что нужно что-то немного усложнять), особенно в отношении управления потоками.
Ответы
Ответ 1
Я бы рекомендовал ваш первый подход, но есть лучшие способы сделать это, чем размышления. Использование инъекции зависимостей или, возможно, передача объектов Supplier<Service>
вместо использования serviceClass.newInstance()
, вероятно, путь сюда.
Ответ 2
Рассмотрим использование областей Guice.
Ответ 3
Эта же проблема отслеживается в этом github: https://github.com/google/guava/issues/418
У меня есть предлагаемое изменение здесь: https://github.com/okigan/guava/commit/8f51b155f9ce5c60236b9a9bfdc6ca5f8bf5e51d
суть состоит в том, чтобы добавить reset() в AbstractService
что позволяет перейти от TERMINATED обратно в NEW:
public final void reset() {
lock.lock();
try {
switch (snapshot.state) {
case TERMINATED:
case FAILED:
snapshot = new StateSnapshot(State.NEW);
break;
default:
throw new AssertionError("Unexpected state: " + snapshot.state);
}
} catch (Throwable resetFailure) {
notifyFailed(resetFailure);
} finally {
lock.unlock();
executeListeners();
}
}