Статьи

Настройте приложение Spring JMS с поддержкой Spring Boot и аннотациями

1. Введение

В предыдущих статьях мы узнали, как настроить проект с помощью Spring JMS. Если вы ознакомитесь со статьей Введение в обмен сообщениями с Spring JMS , вы заметите, что он настроен с использованием XML. В этой статье будут использованы преимущества, представленные в версии Spring 4.1, и сконфигурирован проект JMS с использованием только конфигурации Java.

В этом примере мы также увидим, как легко можно настроить проект с помощью Spring Boot .

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

Смотрите пример проекта на github .

Разделы:

  1. Введение.
  2. Пример приложения.
  3. Настройка проекта.
  4. Простой пример со слушателем JMS.
  5. Отправка ответа в другую очередь с помощью @SendTo.
  6. Вывод.

2. Пример приложения

Приложение использует клиентскую службу для отправки заказов в очередь JMS, где JMS-слушатель будет зарегистрирован и обработать эти заказы. После получения слушатель сохранит заказ через сервис Store:

jms_diagram

Мы будем использовать класс Order для создания заказов:

01
02
03
04
05
06
07
08
09
10
11
12
13
public class Order implements Serializable {
    private static final long serialVersionUID = -797586847427389162L;
     
    private final String id;
     
    public Order(String id) {
        this.id = id;
    }
     
    public String getId() {
        return id;
    }
}

Прежде чем перейти к первому примеру, мы сначала рассмотрим, как строится структура проекта.

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

3.1 Настройка pom.xml

Первое, что нужно сделать, это определить артефакт spring-boot-starter-parent как наш родительский pom.

1
2
3
4
5
6
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

Этот родительский элемент в основном устанавливает несколько значений по умолчанию Maven и обеспечивает управление зависимостями для основных зависимостей, которые мы будем использовать, например версию Spring (которая является 4.1.6).

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

Следующим шагом является установка основных зависимостей для Spring Boot:

1
2
3
4
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

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

Наконец, мы добавим зависимость Spring JMS и брокер сообщений ActiveMQ, оставив весь файл pom.xml следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<groupId>xpadro.spring</groupId>
<artifactId>jms-boot-javaconfig</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>JMS Spring Boot Javaconfig</name>
  
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.3.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
  
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <start-class>xpadro.spring.jms.JmsJavaconfigApplication</start-class>
    <java.version>1.8</java.version>
    <amq.version>5.4.2</amq.version>
</properties>
  
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jms</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-core</artifactId>
        <version>${amq.version}</version>
    </dependency>
</dependencies>
  
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

3.2 Настройка Spring с помощью Java Config

Классу конфигурации просто нужно настроить встроенный брокер сообщений. Остальное автоматически настраивается Spring Boot:

01
02
03
04
05
06
07
08
09
10
11
12
13
@SpringBootApplication
public class JmsJavaconfigApplication {
    private static final String JMS_BROKER_URL = "vm://embedded?broker.persistent=false,useShutdownHook=false";
     
    @Bean
    public ConnectionFactory connectionFactory() {
        return new ActiveMQConnectionFactory(JMS_BROKER_URL);
    }
     
    public static void main(String[] args) {
        SpringApplication.run(JmsJavaconfigApplication.class, args);
    }
}

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

1
2
3
4
5
6
7
8
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Configuration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {

Теперь все готово. Мы увидим, как настроить JMS-слушатель в примере в следующем разделе, так как он настроен с аннотацией.

4. Простой пример со слушателем JMS

4.1 Отправка заказа в очередь JMS

Класс ClientService отвечает за отправку нового заказа в очередь JMS. Для этого он использует JmsTemplate:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
@Service
public class ClientServiceImpl implements ClientService {
    private static final String SIMPLE_QUEUE = "simple.queue";
     
    private final JmsTemplate jmsTemplate;
     
    @Autowired
    public ClientServiceImpl(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }
     
    @Override
    public void addOrder(Order order) {
        jmsTemplate.convertAndSend(SIMPLE_QUEUE, order);
    }
}

Здесь мы используем JmsTemplate для преобразования нашего экземпляра Order и отправки его в очередь JMS. Если вы предпочитаете отправлять сообщение напрямую через отправленное сообщение, вместо этого вы можете использовать новый JmsMessagingTemplate . Это предпочтительнее, поскольку в нем используется более стандартизированный класс Message .

4.2 Получение заказа, отправленного в очередь JMS

Зарегистрировать JMS-слушатель в контейнере JMS-слушателя так же просто, как добавить аннотацию @JmsListener к методу, который мы хотим использовать. Это создаст контейнер слушателя JMS под крышками, который будет принимать сообщения, отправленные в указанную очередь, и делегировать их нашему классу слушателя:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
@Component
public class SimpleListener {
    private final StoreService storeService;
     
    @Autowired
    public SimpleListener(StoreService storeService) {
        this.storeService = storeService;
    }
     
    @JmsListener(destination = "simple.queue")
    public void receiveOrder(Order order) {
        storeService.registerOrder(order);
    }
}

StoreService получает заказ и сохраняет его в списке полученных заказов:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
@Service
public class StoreServiceImpl implements StoreService {
    private final List<Order> receivedOrders = new ArrayList<>();
     
    @Override
    public void registerOrder(Order order) {
        this.receivedOrders.add(order);
    }
     
    @Override
    public Optional<Order> getReceivedOrder(String id) {
        return receivedOrders.stream().filter(o -> o.getId().equals(id)).findFirst();
    }
}

4.3 Тестирование приложения

Теперь давайте добавим тест, чтобы проверить, все ли мы сделали правильно:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = JmsJavaconfigApplication.class)
public class SimpleListenerTest {
     
    @Autowired
    private ClientService clientService;
     
    @Autowired
    private StoreService storeService;
     
    @Test
    public void sendSimpleMessage() {
        clientService.addOrder(new Order("order1"));
         
        Optional<Order> storedOrder = storeService.getReceivedOrder("order1");
        Assert.assertTrue(storedOrder.isPresent());
        Assert.assertEquals("order1", storedOrder.get().getId());
    }
}

5. Отправка ответа в другую очередь с помощью @SendTo

Еще одно дополнение к Spring JMS — аннотация @SendTo. Эта аннотация позволяет слушателю отправить сообщение в другую очередь. Например, следующий слушатель получает заказ из «in.queue» и после сохранения заказа отправляет подтверждение в «out.queue».

1
2
3
4
5
6
@JmsListener(destination = "in.queue")
@SendTo("out.queue")
public String receiveOrder(Order order) {
    storeService.registerOrder(order);
    return order.getId();
}

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

1
2
3
4
@JmsListener(destination = "out.queue")
public void receiveOrder(String orderId) {
    registerService.registerOrderId(orderId);
}

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

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