Учебные материалы

Обмен сообщениями с RabbitMQ

Этот урок освещает процесс настройки RabbitMQ AMQP сервера, который публикует и подписывается на сообщения.

Что вы создадите

Вы создадите приложение, которое публикует сообщение с использованием Spring AMQP RabbitTemplate и подписывается на POJO сообщение через MessageListenerAdapter.

Что вам потребуется

  • Примерно 15 минут свободного времени
  • Любимый текстовый редактор или IDE
  • JDK 6 и выше
  • Gradle 1.11+ или Maven 3.0+
  • Вы также можете импортировать код этого урока, а также просматривать web-страницы прямо из Spring Tool Suite (STS), собственно как и работать дальше из него.
  • RabbitMQ сервер (инструкция по установке см. ниже)

Как проходить этот урок

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

Чтобы начать с нуля, перейдите в Настройка проекта.

Чтобы пропустить базовые шаги, выполните следующее:

Когда вы закончите, можете сравнить получившийся результат с образцом в gs-messaging-rabbitmq/complete.

Настройка проекта

Для начала вам необходимо настроить базовый скрипт сборки. Вы можете использовать любую систему сборки, которая вам нравится для сборки проетов Spring, но в этом уроке рассмотрим код для работы с Gradle и Maven. Если вы не знакомы ни с одним из них, ознакомьтесь с соответсвующими уроками Сборка Java-проекта с использованием Gradle или Сборка Java-проекта с использованием Maven.

Создание структуры каталогов

В выбранном вами каталоге проекта создайте следующую структуру каталогов; к примеру, командой mkdir -p src/main/java/hello для *nix систем:

└── src
    └── main
        └── java
            └── hello

Создание файла сборки Gradle

Ниже представлен начальный файл сборки Gradle. Файл pom.xml находится здесь. Если вы используете Spring Tool Suite (STS), то можете импортировать урок прямо из него.

Если вы посмотрите на pom.xml, вы найдете, что указана версия для maven-compiler-plugin. В общем, это не рекомендуется делать. В данном случае он предназначен для решения проблем с нашей CI системы, которая по умолчанию имеет старую(до Java 5) версию этого плагина.

build.gradle

buildscript {
    repositories {
        maven { url "http://repo.spring.io/libs-release" }
        mavenLocal()
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.8.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot'

jar {
    baseName = 'gs-messaging-rabbitmq'
    version =  '0.1.0'
}

repositories {
    mavenLocal()
    mavenCentral()
    maven { url "http://repo.spring.io/libs-release" }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-amqp")
    testCompile("junit:junit")
}

task wrapper(type: Wrapper) {
    gradleVersion = '1.11'
}

Spring Boot gradle plugin предоставляет множество удобных возможностей:

  • Он собирает все jar'ы в classpath и собирает единое, исполняемое "über-jar", что делает более удобным выполнение и доставку вашего сервиса
  • Он ищет public static void main() метод, как признак исполняемого класса
  • Он предоставляет встроенное разрешение зависимостей, с определенными номерами версий для соответсвующих Spring Boot зависимостей. Вы можете переопределить на любые версии, какие захотите, но он будет по умолчанию для Boot выбранным набором версий

Создание получателя сообщения RabbitMQ

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

src/main/java/hello/Receiver.java

package hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Receiver {

	@Autowired
	AnnotationConfigApplicationContext context;

	public void receiveMessage(String message) {
        System.out.println("Received <" + message + ">");
        this.context.close();
    }
}

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

Для удобства, этот POJO подключает AnnotationConfigApplicationContext. Это позволяет ему завершать приложение после получения сообщения. Однако это не желательно делать в рабочих приложениях.

Регистрация обработчика и отправка сообщения

Spring AMQP RabbitTemplate предоставляет вам все необходимое для отправки и получения соoбщений через RabbitMQ. В частности, вам необходимо настроить:

  • Контейнер обработчика сообщения
  • Описать очередь, систему обмена и взаимодействие между ними
Sprin Boot автоматически создает фабрику соединения и RabbitTemplate, уменьшая количество кода, написанного вами.

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

src/main/java/hello/Application.java

package hello;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableAutoConfiguration
public class Application implements CommandLineRunner {

	final static String queueName = "spring-boot";

	@Autowired
	RabbitTemplate rabbitTemplate;

	@Bean
	Queue queue() {
		return new Queue(queueName, false);
	}

	@Bean
	TopicExchange exchange() {
		return new TopicExchange("spring-boot-exchange");
	}

	@Bean
	Binding binding(Queue queue, TopicExchange exchange) {
		return BindingBuilder.bind(queue).to(exchange).with(queueName);
	}

	@Bean
	SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) {
		SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
		container.setConnectionFactory(connectionFactory);
		container.setQueueNames(queueName);
		container.setMessageListener(listenerAdapter);
		return container;
	}

    @Bean
    Receiver receiver() {
        return new Receiver();
    }

	@Bean
	MessageListenerAdapter listenerAdapter(Receiver receiver) {
		return new MessageListenerAdapter(receiver, "receiveMessage");
	}

    public static void main(String[] args) throws InterruptedException {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println("Waiting five seconds...");
        Thread.sleep(5000);
        System.out.println("Sending message...");
        rabbitTemplate.convertAndSend(queueName, "Hello from RabbitMQ!");
    }
}

Бин, определенный в методе listenerAdapter(), зарегистрирован как обработчик сообщения в контейнере, определенном в container(). Он будет обрабатывать сообщения в очереди "chat". Т.к. Receiver класс является POJO, его необходимо упаковать в адаптер MessageListenerAdapter бработчика сообщения, в котором вы укажете вызов метода receiveMessage().

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

Бины контейнера обработчика сообщения и получателя - это все, что вам необходимо для обработки сообщений. Для отправки сообщения, вам необходим Rabbit шаблон.

Метод queue() создает AMQP очередь. Метод exchange() создает список обмена. Метод binding() связывает их между собой, определяя их поведение при публикации RabbitTemplate для обмена.

Spring AMQP требует, чтобы Queue, TopicExchange и Binding были определены как высокоуровневые Spring бины в правильном порядке их организации.

Метод main() начинает свою работу с создания контекста приложения Spring. Затем контекст приложения инициализирует контейнер обработчика сообщения, который в свою очередь запускает прослушку сообщений. Далее он получает RabbitTemplate из контекста приложени, ждет пять секунд и отправляет сообщение "Hello from RabbitMQ!" очередь "chat". В заключении, он закрывает контекст приложения Spring и приложение завершает работу.

Сборка исполняемого JAR

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

./gradlew build

Затем вы можете запустить JAR-файл:

java -jar build/libs/gs-messaging-rabbitmq-0.1.0.jar

Если вы используете Maven, вы можете запустить приложение, используя mvn spring-boot:run, либо вы можете собрать приложение с mvn clean package и запустить JAR примерно так:

java -jar target/gs-messaging-rabbitmq-0.1.0.jar
Процедура, описанная выше, создает исполняемый JAR. Вы также можете вместо него собрать классический WAR-файл.

Запуск сервиса

Если вы используете Gradle, вы можете запустить ваш сервис из командной строки:

./gradlew clean build && java -jar build/libs/gs-messaging-rabbitmq-0.1.0.jar
Если вы используете Maven, то можете запустить ваш сервис таким образом: mvn clean package && java -jar target/gs-messaging-rabbitmq-0.1.0.jar.

Как вариант, вы можете запустить ваш сервис напрямую из Gradle примерно так:

./gradlew bootRun
С mvn - mvn spring-boot:run.

Вы должны увидеть следующее:

Sending message...
Received <Hello from RabbitMQ!>

Итог

Поздравляем! Вы только что разработали простой приложение для публикации и подписки, используя Spring и RabbitMQ. Здесь вы можете сделать большее, чем описано в данном уроке, но он рассчитан стать хорошим стартом для вас.

С оригинальным текстом урока вы можете ознакомиться на spring.io.

comments powered by Disqus