Статьи

Apache TomEE + JMS.

Я помню старые времена J2EE (1.3 и 1.4), когда было невероятно сложно начать проект с использованием JMS . Вам нужно было установить JMS- брокер , создать темы или очереди и, наконец, начать собственную битву с файлами конфигурации сервера и JNDI .

Благодаря JavaEE 6 и более поздним версиям использование JMS действительно легко и просто. Но с Apache TomEE начать работу еще проще. В этом посте мы увидим, как создать и протестировать простое приложение, которое отправляет и получает сообщение в / из очереди JMS с помощью Apache TomEE .

Apache TomEE использует Apache Active MQ в качестве JMS- провайдера. В этих примерах вам не нужно ничего скачивать или устанавливать, потому что все элементы будут предоставлены как зависимости Maven , но если вы планируете (и должны) использовать сервер Apache TomEE, вам необходимо загрузить Apache TomEE plus или Apache TomEE plume. Вы можете прочитать больше о версиях Apache TomEE в http://tomee.apache.org/comparison.html .

зависимости

Первое, что нужно сделать, это добавить javaee-api в качестве предоставленной зависимости, а junit и openejb-core в качестве тестовой зависимости. Обратите внимание, что зависимость openejb-core добавлена, чтобы иметь время выполнения для выполнения тестов, мы рассмотрим это подробно в разделе тестов.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<dependencies>
  <dependency>
    <groupId>org.apache.openejb</groupId>
    <artifactId>javaee-api</artifactId>
    <version>6.0-6</version>
    <scope>provided</scope>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.apache.openejb</groupId>
    <artifactId>openejb-core</artifactId>
    <version>4.7.1</version>
    <scope>test</scope>
  </dependency>
</dependencies>

Бизнес код

Следующим шагом является создание бизнес-кода, отвечающего за отправку сообщений и получение сообщений из очереди JMS . Также он содержит метод для получения сообщений из очереди . Для этого примера мы будем использовать EJB без сохранения состояния .

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
 
@Stateless
public class Messages {
 
  //Standard @Resource annotation is used to inject the ConnectionFactory.
  //If no name is provided using lookup or name attribute,
  //the fully qualified name of the class with an slash (/) and the name of the attribute is used.
  //In this example: java:comp/env/org.superbiz.jms.Messages/connectionFactory.
  @Resource
  private ConnectionFactory connectionFactory;
 
  //Standard @Resource annotation is used to inject the Queue.
  //If no name is provided using lookup or name attribute,
  //the fully qualified name of the class with an slash (/) and the name of the attribute is used.
  //In this example: java:comp/env/org.superbiz.injection.jms.Messages/chatQueue.
  @Resource
  private Queue chatQueue;
 
 
  public void sendMessage(String text) throws JMSException {
 
      Connection connection = null;
      Session session = null;
 
      try {
          connection = connectionFactory.createConnection();
          //Connection is get from ConnectionFactory instance and it is started.
          connection.start();
 
          //Creates a session to created connection.
          session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
 
          //Creates a MessageProducer from Session to the Queue.
          MessageProducer producer = session.createProducer(chatQueue);
          producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
 
          TextMessage message = session.createTextMessage(text);
 
          //Tells the producer to send the message
          producer.send(message);
      } finally {
          if (session != null) session.close();
          if (connection != null) connection.close();
      }
  }
 
  public String receiveMessage() throws JMSException {
 
      Connection connection = null;
      Session session = null;
      MessageConsumer consumer = null;
 
      try {
          connection = connectionFactory.createConnection();
          connection.start();
 
          session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
 
          consumer = session.createConsumer(chatQueue);
 
          //Waits for a message with timeout. Note that because a TextMessage is sent, the receive method expects a TextMessage too.
          TextMessage message = (TextMessage) consumer.receive(1000);
 
          return message.getText();
      } finally {
          if (consumer != null) consumer.close();
          if (session != null) session.close();
          if (connection != null) connection.close();
      }
  }
}

Самая важная часть класса Messages — это заметить, как легко внедрить ConnectionFactory и
Очереди в коде. Вам нужно всего лишь использовать аннотацию @Resource, а контейнер сделает все остальное за вас. В заключение отметим, что поскольку мы не использовали атрибуты name или lookup для установки имени, имя поля используется в качестве имени ресурса.

Тест

И, наконец, мы можем написать тест, который утверждает, что сообщения отправляются и принимаются с использованием очереди JMS . Мы могли бы использовать, например, Arquilian для написания теста, но для этого случая и из-за простоты мы собираемся использовать встроенный экземпляр OpenEJB для развертывания примера JMS и запуска тестов.

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
public class MessagesTest {
 
  //Messages EJB is injected.
  @EJB
  private Messages messages;
 
  @Before
  public void setUp() throws Exception {
    Properties p = new Properties();
    //Embedded OpenEJB container is started.
    //And current test added inside created container
    //So we can use javaee annotations inside
    EJBContainer.createEJBContainer(p).getContext().bind("inject", this);
  }
 
  @Test
  public void shouldSendAndReceiveMessages() throws Exception {
 
    //Three messages are sent.
    messages.sendMessage("Hello World!");
    messages.sendMessage("How are you?");
    messages.sendMessage("Still spinning?");
 
    //Three messages are received.
    assertThat(messages.receiveMessage(), is("Hello World!"));
    assertThat(messages.receiveMessage(), is("How are you?"));
    assertThat(messages.receiveMessage(), is("Still spinning?"));
  }
 
}

Обратите внимание, что этот тест действительно прост и лаконичен, вам нужно всего лишь программно запустить контейнер EJB и связать текущий тест внутри него, чтобы мы могли использовать аннотации JavaEE внутри теста. Остальное — простой тест JUnit .

И если вы запустите тест, вы получите зеленую пулю. Но подождите, возможно, вам интересно, где находится JMS- брокер и его конфигурация? Где находится определение ConnectionFactory и очереди JMS ? И здесь вступает в игру OpenEJBApache TomEE ).

В этом случае OpenEJBApache TomEE ) будут использовать Apache Active MQ во встроенном режиме, поэтому вам не нужно устанавливать Apache Active MQ на компьютер для запуска тестов. Более того, Apache TomEE создаст для вас все необходимые ресурсы. Например, он создаст для вас ConnectionFactory и очередь с параметрами по умолчанию и ожидаемыми именами ( org.superbiz.Messages / connectionFactory для ConnectionFactory и org.superbiz.Messages / chatQueue для очереди ), поэтому вам не нужно беспокоиться о настроить JMS на этапе тестирования. Apache TomEE достаточно умен, чтобы создавать и настраивать их для вас.

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
Jan 10, 2015 10:32:48 AM org.apache.openejb.config.AutoConfig processResourceRef
INFO: Auto-linking resource-ref 'java:comp/env/org.superbiz.Messages/connectionFactory' in bean Messages to Resource(id=Default JMS Connection Factory)
Jan 10, 2015 10:32:48 AM org.apache.openejb.config.ConfigurationFactory configureService
INFO: Configuring Service(id=org.superbiz.Messages/chatQueue, type=Resource, provider-id=Default Queue)
Jan 10, 2015 10:32:48 AM org.apache.openejb.config.AutoConfig logAutoCreateResource
INFO: Auto-creating a Resource with id 'org.superbiz.Messages/chatQueue' of type 'javax.jms.Queue for 'Messages'.
Jan 10, 2015 10:32:48 AM org.apache.openejb.assembler.classic.Assembler createRecipe
INFO: Creating Resource(id=org.superbiz.Messages/chatQueue)
Jan 10, 2015 10:32:48 AM org.apache.openejb.config.AutoConfig processResourceEnvRef
INFO: Auto-linking resource-env-ref 'java:comp/env/org.superbiz.Messages/chatQueue' in bean Messages to Resource(id=org.superbiz.Messages/chatQueue)
Jan 10, 2015 10:32:48 AM org.apache.openejb.config.ConfigurationFactory configureService
INFO: Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container)
Jan 10, 2015 10:32:48 AM org.apache.openejb.config.AutoConfig createContainer
INFO: Auto-creating a container for bean javaee.MessagesTest: Container(type=MANAGED, id=Default Managed Container)

И все, очень просто и легко начать работу с JMS благодаря Java EE и TomEE . В следующем посте мы увидим, как сделать то же самое, но с помощью Message Driven Beans (MDB).