«1. Обзор

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

В этой статье мы фактически рассмотрим, как настроить удаленный вызов с использованием Spring Remoting JMS и Apache ActiveMQ в качестве промежуточного программного обеспечения для обмена сообщениями.

2. Запуск Apache ActiveMQ Broker

Apache ActiveMQ — это брокер сообщений с открытым исходным кодом, который позволяет приложениям обмениваться информацией асинхронно и полностью совместим с API службы сообщений Java.

Чтобы запустить наш эксперимент, нам сначала нужно настроить работающий экземпляр ActiveMQ. Мы можем выбрать один из нескольких способов: выполнить шаги, описанные в официальном руководстве, внедрить его в приложение Java или, проще говоря, запустить контейнер Docker с помощью следующей команды:

docker run -p 61616:61616 -p 8161:8161 rmohr/activemq:5.14.3

Это запустит контейнер ActiveMQ, который выставляется на порт 8081 — простой веб-интерфейс администрирования, с помощью которого мы можем проверять доступные очереди, подключенных клиентов и другую административную информацию. Вместо этого клиентам JMS потребуется использовать порт 61616 для подключения к брокеру и обмена сообщениями.

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

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

Как обычно, мы тщательно выбираем начальные зависимости Spring Boot, как описано здесь:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-activemq</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Мы явно исключили spring-boot-starter-tomcat, чтобы не иметь файлов .jar, связанных с Tomcat, в пути к классам.

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

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

4.1. Предоставление службы

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

Первый шаг — объявить bean-компонент, реализующий интерфейс сервиса, который мы хотим предоставить клиентам. Это bean-компонент, который будет выполнять бизнес-логику на сервере:

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

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

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

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

Для работы с JMS мы определяем JmsInvokerServiceExporter:

@Bean 
JmsInvokerServiceExporter exporter(CabBookingService implementation) {
    JmsInvokerServiceExporter exporter = new JmsInvokerServiceExporter();
    exporter.setServiceInterface(CabBookingService.class);
    exporter.setService(implementation);
    return exporter;
}

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

@Bean SimpleMessageListenerContainer listener(
  ConnectionFactory factory, 
  JmsInvokerServiceExporter exporter) {
 
    SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(factory);
    container.setDestinationName("remotingQueue");
    container.setConcurrentConsumers(1);
    container.setMessageListener(exporter);
    return container;
}

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

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

Значения различных параметров в основном зависят от способа установки ApacheMQ, и следующая конфигурация является разумной конфигурацией для нашего контейнера Docker, работающего на той же машине, где мы выполним следующие примеры:

spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.packages.trusted=org.springframework.remoting.support,java.lang,com.baeldung.api

Параметр spring.activemq.broker-url является ссылкой на порт AMQ. Вместо этого требуется более глубокое объяснение параметра spring.activemq.packages.trusted. Начиная с версии 5.12.2 ActiveMQ по умолчанию отклоняет любое сообщение типа

Начиная с версии 5.12.2 ActiveMQ по умолчанию отклоняет любое сообщение типа ObjectMessage, используемое для обмена сериализованным объектом Java, поскольку оно считается потенциальным вектором для атаки на безопасность в некоторые контексты.

«В любом случае можно указать AMQ принимать сериализованные объекты в указанных пакетах. org.springframework.remoting.support — это пакет, содержащий основные сообщения, представляющие собой вызов удаленного метода и его результат. Пакет

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

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

5.1. Вызов удаленной службы

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

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

Затем нам нужно настроить экспортер:

@Bean 
FactoryBean invoker(ConnectionFactory factory, Queue queue) {
    JmsInvokerProxyFactoryBean factoryBean = new JmsInvokerProxyFactoryBean();
    factoryBean.setConnectionFactory(factory);
    factoryBean.setServiceInterface(CabBookingService.class);
    factoryBean.setQueue(queue);
    return factoryBean;
}

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

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

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

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

Этого должно быть достаточно, чтобы продемонстрировать удаленный вызов через Apache AMQ. Итак, давайте сначала запустим ApacheMQ, затем серверное приложение и, наконец, клиентское приложение, которое будет вызывать удаленную службу.

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

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

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

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