2016-09-07 2 views
1

У меня есть три guava Service s, которые начинаются с guava ServiceManager асинхронно.Зависимости от Guice

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

Какой здесь образец?

Я могу ввести службу базы данных в другие службы и вызвать метод awaitRunning() при запуске службы, но тогда я буду испытывать такую ​​же проблему, когда ServiceManager выключается.

ответ

0

Я считаю, что у гуса не существует готового механизма для этого. Весна, например. имеет атрибут зависимости, который может определять некоторый порядок. Существуют рамки, которые также дают вам это с помощью guice (например, dropwizard guicey реализует аннотацию заказа). Это, однако, довольно просто решить.

Подходом является использование многострочных элементов для определения менеджера для всех классов зависимостей. Это я буду называть Managed (принято с причала). Интерфейс будет выполнять заказ. Затем мы используем диспетчер, который запускает все службы один за другим в четко определенном порядке (также может использоваться для выключения, если требуется).

Смотрите мой пример кода здесь:

public class ExecutionOrder { 

    public static void main(String[] args) { 

     Injector createInjector = Guice.createInjector(new AbstractModule() { 
      @Override 
      protected void configure() { 
       Multibinder<Managed> multiBinder = Multibinder.newSetBinder(binder(), Managed.class); 
       multiBinder.addBinding().to(Service1.class); 
       multiBinder.addBinding().to(Service2.class); 

       bind(ManagedManager.class).in(Singleton.class); 
      } 
     }); 

     createInjector.getInstance(ManagedManager.class); // start it 
    } 

    public interface Managed extends Comparable<Managed> { 

     public default void start() {} 
     public default int getOrder() { return 0;} 

     @Override 
     default int compareTo(Managed o) { 
      return Integer.compare(getOrder(), o.getOrder()); 
     } 
    } 

    public static class ManagedManager { 
     @Inject 
     public ManagedManager(final Set<Managed> managed) { 
      managed.stream().sorted().forEach(Managed::start); 
     } 

    } 

    public static class Service1 implements Managed { 

     @Override 
     public void start() { 
      System.out.println("Started Service 1"); 
     } 

     @Override 
     public int getOrder() { 
      return 1; 
     } 
    } 

    public static class Service2 implements Managed { 

     @Override 
     public void start() { 
      System.out.println("Started Service 2"); 
     } 

     @Override 
     public int getOrder() { 
      return 2; 
     } 
    } 
} 

My - правда, глупо назвали - ManagedManager впрыскивается Guice со всеми управляемыми интерфейсами, используя multibindings Guice (см модуль I инициализировать). Затем я сортирую и запускаю вызов.

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

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

Я надеюсь, что это помогает,

Артур