Рубрики
Без рубрики

Пружинное дистанционное управление с помощью AMQP

Краткое практическое руководство, объясняющее, как использовать Spring Remoting с AMQP для выполнения синхронных удаленных вызовов процедур через асинхронный носитель.

Автор оригинала: baeldung.

1. Обзор

Мы видели в предыдущих частях серии, как мы можем использовать Spring Remoting и связанные с этим технологии для включения синхронных Удаленных вызовов процедур поверх HTTP-канала между сервером и клиентом.

В этой статье мы исследуем Spring Remoting поверх AMQP , что позволяет выполнять синхронный RPC при использовании среды , которая по своей сути асинхронна .

2. Установка RabbitMQ

Существуют различные системы обмена сообщениями, совместимые с AMQP , которые мы могли бы использовать, и мы выбираем RabbitMQ , потому что это проверенная платформа и она полностью поддерживается в Spring – оба продукта управляются одной и той же компанией (Pivotal).

Если вы не знакомы с AMQP или RabbitMQ , вы можете прочитать наше краткое введение .

Итак, первый шаг-установить и запустить RabbitMQ . Существуют различные способы его установки – просто выберите предпочтительный метод, следуя инструкциям, указанным в официальном руководстве .

3. Зависимости Maven

Мы собираемся настроить сервер и клиент Spring Boot приложения, чтобы показать, как работает AMQP Remoting . Как это часто бывает с Spring Boot , нам просто нужно выбрать и импортировать правильные стартовые зависимости, как описано здесь :


    org.springframework.boot
    spring-boot-starter-amqp
    
        
            org.springframework.boot
            spring-boot-starter-tomcat
        
    

Мы явно исключили spring-boot-starter-tomcat , потому что нам не нужен встроенный HTTP сервер – он будет автоматически запущен, если мы разрешим Maven импортировать все транзитивные зависимости в пути к классу.

4. Серверное приложение

4.1. Предоставление Услуг

Как мы показали в предыдущих статьях, будет представлена Служба бронирования такси , которая имитирует вероятную удаленную службу.

Давайте начнем с объявления компонента, который реализует интерфейс службы, которую мы хотим сделать удаленно вызываемой. Это компонент, который фактически выполнит вызов службы на стороне сервера:

@Bean 
CabBookingService bookingService() {
    return new CabBookingServiceImpl();
}

Затем давайте определим очередь, из которой сервер будет извлекать вызовы. В этом случае достаточно указать для него имя, предоставив его в конструкторе:

@Bean 
Queue queue() {
    return new Queue("remotingQueue");
}

Как мы уже знаем из предыдущих статей, одной из основных концепций Spring Remoting является Экспортер услуг , компонент, который на самом деле собирает запросы на вызов из некоторого источника ─ в данном случае RabbitMQ очередь ─ и вызывает нужный метод реализации службы .

В этом случае мы определяем AmqpInvokerServiceExporter , который, как вы можете видеть, нуждается в ссылке на AmqpTemplate . Класс AmqpTemplate предоставляется Spring Framework и облегчает обработку AMQP- совместимых систем обмена сообщениями так же, как JdbcTemplate облегчает работу с базами данных.

Мы не будем явно определять такой AmqpTemplate bean, потому что он будет автоматически предоставлен модулем автоматической настройки Spring Boot :

@Bean AmqpInvokerServiceExporter exporter(
  CabBookingService implementation, AmqpTemplate template) {
 
    AmqpInvokerServiceExporter exporter = new AmqpInvokerServiceExporter();
    exporter.setServiceInterface(CabBookingService.class);
    exporter.setService(implementation);
    exporter.setAmqpTemplate(template);
    return exporter;
}

Наконец, нам нужно определить контейнер , который несет ответственность за получение сообщений из очереди и пересылку их какому-либо указанному слушателю .

Затем мы подключим этот контейнер к экспортеру услуг, который мы создали на предыдущем шаге, чтобы позволить ему получать сообщения в очереди . Здесь ConnectionFactory автоматически предоставляется Spring Boot так же, как AmqpTemplate :

@Bean 
SimpleMessageListenerContainer listener(
  ConnectionFactory facotry, 
  AmqpInvokerServiceExporter exporter, 
  Queue queue) {
 
    SimpleMessageListenerContainer container
     = new SimpleMessageListenerContainer(facotry);
    container.setMessageListener(exporter);
    container.setQueueNames(queue.getName());
    return container;
}

4.2. Конфигурация

Давайте не забудем настроить файл application.properties , чтобы разрешить Spring Boot настраивать основные объекты. Очевидно, что значения параметров также будут зависеть от способа установки RabbitMQ .

Например, следующая конфигурация может быть разумной, когда RabbitMQ запускает ее на той же машине, на которой работает этот пример:

spring.rabbitmq.dynamic=true
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.host=localhost

5. Клиентское приложение

5.1. Вызовите Удаленную службу

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

@Bean 
Queue queue() {
    return new Queue("remotingQueue");
}

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

@Bean 
Exchange directExchange(Queue someQueue) {
    DirectExchange exchange = new DirectExchange("remoting.exchange");
    BindingBuilder
      .bind(someQueue)
      .to(exchange)
      .with("remoting.binding");
    return exchange;
}

Хорошее введение в основные понятия RabbitMQ как Обмены и Привязки доступно здесь .

Поскольку Spring Boot не выполняет автоматическую настройку AmqpTemplate , мы должны настроить его сами, указав ключ маршрутизации r /. При этом нам нужно дважды проверить, что ключ маршрутизации и exchange совпадают с тем, который использовался для определения Exchange на предыдущем шаге:

@Bean RabbitTemplate amqpTemplate(ConnectionFactory factory) {
    RabbitTemplate template = new RabbitTemplate(factory);
    template.setRoutingKey("remoting.binding");
    template.setExchange("remoting.exchange");
    return template;
}

Затем, как и в случае с другими реализациями Spring Remoting , мы определяем FactoryBean , который будет создавать локальные прокси-серверы удаленно предоставляемой службы . Здесь нет ничего особенного, нам просто нужно предоставить интерфейс удаленного сервиса:

@Bean AmqpProxyFactoryBean amqpFactoryBean(AmqpTemplate amqpTemplate) {
    AmqpProxyFactoryBean factoryBean = new AmqpProxyFactoryBean();
    factoryBean.setServiceInterface(CabBookingService.class);
    factoryBean.setAmqpTemplate(amqpTemplate);
    return factoryBean;
}

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

CabBookingService service = context.getBean(CabBookingService.class);
out.println(service.bookRide("13 Seagate Blvd, Key Largo, FL 33037"));

5.2. Настройка

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

5.3. Запустите пример

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

Что происходит за кулисами, так это то, что Amqp ProxyFactoryBean создаст прокси-сервер, реализующий CabBookingService .

Когда метод вызывается на этом прокси-сервере, он помещает сообщение в очередь на RabbitMQ , указывая в нем все параметры вызова и имя очереди, которая будет использоваться для отправки результата.

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

Amqp ProxyFactoryBean получает обратно результат и, наконец, возвращает значение, первоначально созданное на стороне сервера.

6. Заключение

В этой статье мы рассмотрели, как мы можем использовать Spring Remoting для предоставления RPC поверх системы обмена сообщениями.

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

Как обычно, вы найдете источники на на GitHub .