Подробное объяснение компонентов Spring JMS

Java Spring

Github

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

JmsTemplate

Используется для отправки и получения сообщений (получение синхронно и будет заблокировано). каждыйJmsTemplateЭкземпляры имеют свою собственную конфигурацию, такую ​​как:connectionFactory,sessionTransacted,sessionAcknowledgeMode,deliveryMode,timeToLiveи так далее, поэтому необходимо предоставлять разные конфигурации в соответствии с разными сценариями.JmsTemplateBean вместо Singleton Bean берет на себя все операции JMS.

Ниже приведена диаграмма классов (включены только некоторые ключевые свойства):

ConnectionFactory

Весна дает дваjavax.jms.ConnectionFactoryРеализация:SingleConnectionFactoryа такжеCachingConnectionFactory. На самом деле они являются разновидностью Wrapper, используемой для кэширования таких вещей, как:Connection,Session,MessageProducer,MessageConsumer.

ФактическиJavadoc для JmsTemplateупомянул:

NOTE: The ConnectionFactory used with this template should return pooled Connections (or a single shared Connection) as well as pooled Sessions and MessageProducers. Otherwise, performance of ad-hoc JMS operations is going to suffer.

в документации Spring JMSCaching Messaging ResourcesВ нем также упоминается необходимость оптимизации использования ресурсов для повышения производительности:

The standard API involves creating many intermediate objects. To send a message the following 'API' walk is performed
ConnectionFactory->Connection->Session->MessageProducer->send
Between the ConnectionFactory and the Send operation there are three intermediate objects that are created and destroyed. To optimise the resource usage and increase performance two implementations of ConnectionFactory are provided.

Ниже приведена диаграмма классов (включены только некоторые ключевые свойства):

SingleConnectionFactory

SingleConnectionFactoryКак следует из названия, независимо от того, сколько раз вы звонитеcreateConnection(..)оба возвращают одно и то жеConnectionпример. но не кешируетSession, то есть вызов один разcreateSession(...)Будет создан новый экземпляр.

в состоянии пройтиSingleConnectionFactoryTestУзнать больше.

Поэтому в большинстве случаев не рекомендуется использоватьSingleConnectionFactory.

CachingConnectionFactory

CachingConnectionFactoryунаследовано отSingleConnectionFactory, за исключением того, что кеш остается прежнимConnectionПомимо характеристик экземпляра, он также добавляетSession,MessageProducer,MessageConsumerкеш.

CachingConnectionFactoryОн поддерживаетAcknowledge Mode -> List<Session>Карта, sessionCacheSize фактически относится кList<Session>размер, поэтому будет максимум 4 * sessionCacheSizeSessionКэшируется (поскольку JMS определяет четыре режима подтверждения).
а такжеCachingConnectionFactoryЕго сущность не является Объектом Пул, поэтому он не будет блокироваться или возвращать значение null, поскольку фактическое количество запросов сеанса превышает sessionCacheSize, вы можете использовать его с уверенностью.

CachingConnectionFactoryкаждый вернулсяSessionиметь внутриConsumerCacheKey -> MessageConsumerтак же какDestinationCacheKey -> MessageProducerКарта, используемая для кэшированияMessageProducerа такжеMessageConsumer.

в состоянии пройтиCachingConnectionFactoryУзнать больше.

MessageListenerContainer

В Spring JMS есть функцияMessageListenerContainer, согласно официальной документации:

A message listener container is used to receive messages from a JMS message queue and drive the MessageListener that is injected into it.

упомянутый вышеMessageListenerто естьjavax.jms.MessageListener, в первый раз, когда я увидел эту штуку, я почувствовал себя немного странно, потому чтоMessageListenerФормальное использование должно бытьMessageConsumer.setMessageListener()Вот и все.

потому чтоMessageListenerContainerунаследовано отSmartLifeCycle, поэтому он обеспечивает функцию открытия соединения и сеанса при запуске программы и закрытия сеанса и соединения при закрытии программы, так что вам не нужно беспокоиться о восстановлении ресурсов.

Две реализации описаны нижеSimpleMessageListenerContainerа такжеDefaultMessageListenerContainer.

Ниже приведена диаграмма классов (включены только некоторые ключевые свойства):

SimpleMessageListenerContainer

SimpleMessageListenerContainerиспользоватьMessageConsumer.setMessageListener()Для прослушивания сообщений он не поддерживает участие во внешних транзакциях (таких как PlatformTransactionManager).

Можно держать несколькоMessageConsumerпример. код показывает, как показано ниже:

// ...

private int concurrentConsumers = 1;
private Set<Session> sessions;
private Set<MessageConsumer> consumers;

// ...
protected void initializeConsumers() throws JMSException {
  // Register Sessions and MessageConsumers.
  synchronized (this.consumersMonitor) {
    if (this.consumers == null) {
      this.sessions = new HashSet<Session>(this.concurrentConsumers);
      this.consumers = new HashSet<MessageConsumer>(this.concurrentConsumers);
      Connection con = getSharedConnection();
      for (int i = 0; i < this.concurrentConsumers; i++) {
        Session session = createSession(con);
        MessageConsumer consumer = createListenerConsumer(session);
        this.sessions.add(session);
        this.consumers.add(consumer);
      }
    }
  }
}

Существует два способа обработки сообщений: 1) традиционныйMessageConsumer.setMessageListener();2) использоватьExecutor.

if (this.taskExecutor != null) {
  consumer.setMessageListener(new MessageListener() {
    @Override
    public void onMessage(final Message message) {
      taskExecutor.execute(new Runnable() {
        @Override
        public void run() {
          processMessage(message, session);
        }
      });
    }
  });
}
else {
  consumer.setMessageListener(new MessageListener() {
    @Override
    public void onMessage(Message message) {
      processMessage(message, session);
    }
  });
}

DefaultMessageListenerContainer

DefaultMessageListenerContainerа такжеSimpleMessageListenerContainerРазличный, он используетMessageConsumer.receive()для обработки сообщений и поддержки XA сделка.

потому чтоreceive()это синхронный, блокирующий метод, производительность которого неsetMessageListener()Хорошо, так что это очень зависит от многопоточности (TaskExecutor), что также дает преимущества динамического масштабирования.

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

Получать сообщения асинхронно

Способы получения сообщений синхронно:JmsTemplate.receive*()а такжеMessageConsumer.receive*(), я не буду здесь много говорить, а сосредоточусь на нескольких способах асинхронного получения сообщений.

MessageListener & MessageListenerContainer

ПучокMessageListenerупакован вMessageListenerContainerПолучать сообщения, примеры смотрите в официальной документацииAsynchronous Reception - Message-Driven POJOs

SessionAwareMessageListener

SessionAwareMessageListenerпредоставляется Spring иMessageListenerпохожий интерфейс,MessageListenerContainerЭтот интерфейс поддерживается, использование иMessageListenerТакой же.

MessageListenerAdapter

MessageListenerAdapter— это еще один способ асинхронного получения сообщений, предоставляемый Spring.MessageListenerа такжеSessionAwareMessageListenerБолее гибкий, потому что он использует отражение для передачи сообщений вашим методам, которые получают сообщения.

См. официальную документацию по использованиюthe SessionAwareMessageListener interface.

@JmsListener

@JmsListenerэто еще один способ получения сообщений, как им пользоваться можно посмотреть в официальной документацииAnnotation-driven listener endpoints.

@JmsListenerа такжеMessageListener,SessionAwareMessageListener,MessageListenerAdapterНапример, также нужен контейнер, пользователи могут@JmsListener.containerFactoryатрибут для указанияJmsListenerContainerFactory.

Spring предоставляет две реализации JmsListenerContainerFactory:

  1. DefaultJmsListenerContainerFactory, используемый для создания DefaultMessageListenerContainer, предоставляемого Spring BootDefaultJmsListenerContainerFactoryConfigurerкак инструмент настройки
  2. SimpleJmsListenerContainerFactory, используемый для создания SimpleMessageListenerContainer

Итак, используя@JmsListenerТщательный выбор правильногоJmsListenerContainerFactory, а не принимать одну конфигурацию глобально.

Суммировать

При использовании Spring JMS следует помнить о трех вещах:

  1. В соответствии с реальной ситуацией настройте соответствующий компонент ConnectionFactory, при необходимости может быть несколько компонентов ConnectionFactory.
  2. JmsTemplate, MessageListenerContainer, JmsListenerContainerFactory необходимо настроить разные bean-компоненты в соответствии с реальной ситуацией, чтобы избежать глобального использования одного набора.
  3. JmsTemplate, MessageListenerContainer, JmsListenerContainerFactory выбирают соответствующий ConnectionFactory.
  4. Установите соответствующий размер пула исполнителей/потоков, чтобы избежать большого количества блоков потоков.

Ниже приведена диаграмма взаимосвязи между различными компонентами.

использованная литература