Теперь давайте посмотрим, как работает push-модель, объявив JMS-слушатель.
ОБЪЯВЛЕНИЕ ЛИСТЕНЕРА СООБЩЕНИЙ
В отличие от модели извлечения (pull), где для получения сообщения требовался явный вызов метода receive() или receiveAndConvert(), листенер сообщений является пассивным компонентом, который простаивает до получения сообщения.
Чтобы создать листенер сообщений, который реагирует на сообщения JMS, вы просто должны аннотировать метод в компоненте с помощью @JmsListener. В следующем листинге показан новый компонент OrderListener, который пассивно прослушивает сообщения, а не активно запрашивает их.
Листинг 8.4. Компонент OrderListener, который прослушивает заказы
package tacos.kitchen.messaging.jms.listener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
@Component
public class OrderListener {
private KitchenUI ui;
@Autowired
public OrderListener(KitchenUI ui) {
this.ui = ui;
}
@JmsListener(destination = "tacocloud.order.queue")
public void receiveOrder(Order order) {
ui.displayOrder(order);
}
}
Метод receiveOrder () аннотирован JmsListener для «прослушивания» сообщений в месте назначения tacocloud.order.queue. Он не имеет отношения к JmsTemplate и не вызывается явно кодом вашего приложения. Вместо этого, каркасный код в Spring ожидает поступления сообщений в указанный пункт назначения, и когда они приходят, метод receiveOrder() вызывается автоматически с полезной нагрузкой Order в качестве параметра.
Во многих отношениях аннотация @JmsListener похожа на одну из аннотаций сопоставления запросов Spring MVC, например, @GetMapping или @PostMapping. В Spring MVC методы, аннотированные одним из методов отображения запросов, реагируют на запросы по указанному пути. Точно так же методы, аннотированные @JmsListener, реагируют на сообщения, поступающие в пункт назначения.
Слушатели сообщений часто советуются как лучший выбор, потому что они не блокируют и могут быстро обрабатывать несколько сообщений. Однако в контексте приложения Taco Cloud они, возможно, не лучший выбор. Повара являются существенным узким местом в системе и могут не иметь возможности готовить тако так быстро, как поступают заказы. Повар может наполовину выполнить заказ, когда на экране отображается новый заказ. Пользовательский интерфейс кухни должен был бы буферизовать заказы по мере их поступления, чтобы не перегружать кухонный персонал.
Нельзя сказать, что слушатели сообщений плохие. Напротив, они идеально подходят для быстрой обработки сообщений. Но когда обработчики сообщений должны иметь возможность запрашивать бОльшую часть сообщений в свое время, модель извлечения, предлагаемая JmsTemplate, кажется более подходящей.
Поскольку JMS определяется стандартной спецификацией Java и поддерживается многими реализациями брокера сообщений, это обычный выбор для обмена сообщениями в Java. Но у JMS есть несколько недостатков, не последним из которых является то, что в качестве спецификации Java его использование ограничено приложениями Java. Новые опции обмена сообщениями, такие как RabbitMQ и Kafka, устраняют эти недостатки и доступны для других языков и платформ, помимо JVM. Давайте отложим JMS и посмотрим, как вы могли бы реализовать обмен сообщениями о заказах тако с RabbitMQ.
8.2 Работа с RabbitMQ и AMQP
Как, возможно, самая известная реализация AMQP, RabbitMQ предлагает более продвинутую стратегию маршрутизации сообщений, чем JMS. Принимая во внимание, что сообщения JMS адресуются с именем пункта назначения, из которого получатель получит их, сообщения AMQP адресуются с именем обмена и ключом маршрутизации, которые отделены от очереди, которую прослушивает получатель. Эта связь между обменом и очередями показана на рисунке 8.1.
Рис. 8.1. Сообщения, отправляемые на обмен RabbitMQ, направляются в одну или несколько очередей на основе ключей маршрутизации и привязок.
Когда сообщение приходит к брокеру RabbitMQ, оно отправляется на тот обмен (exchange), для которого оно было адресовано. Exchange отвечает за маршрутизацию сообщения в одну или несколько очередей в зависимости от типа exchange, привязки между exchange и очередями (queue) и значения ключа маршрутизации сообщения.
Существует несколько видов обмена, включая следующие:
Default — обмен, который автоматически создается брокером. Он направляет сообщения в очереди, чье имя совпадает с ключом маршрутизации сообщения. Все очереди по умолчанию привязаны к default exchange.