Guia do desenvolvedor de JMS 2.0 do Barramento de Serviço do Azure

Este guia fornece informações detalhadas para ajudá-lo a se comunicar com Barramento de Serviço do Azure usando a API do JMS (Serviço de Mensagens Java) 2.0.

Como desenvolvedor Java, se você for novo no Barramento de Serviço do Azure, considere ler os artigos a seguir.

Como começar Conceitos

modelo de programação do JMS (Serviço de Mensagem Java)

O modelo de programação da API do Serviço de Mensagem Java é descrito nas seguintes seções:

Observação

A camada Premium do Barramento de Serviço do Azure dá suporte ao JMS 1.1 e ao JMS 2.0.

Barramento de Serviço do Azure – A camada Standard dá suporte à funcionalidade limitada do JMS 1.1. Para obter mais detalhes, consulte esta documentação.

JMS – Blocos de construção

Use os blocos de construção a seguir para se comunicar com o aplicativo JMS.

Observação

Este guia é adaptado do tutorial Oracle Java EE 6 para o JMS (Serviço de Mensagens Java).

Para obter uma melhor compreensão do JMS (Serviço de Mensagens do Java), consulte este tutorial.

Fábrica de conexões

Observação

A azure-servicebus-jms biblioteca está disponível em duas variantes: com.azure:azure-servicebus-jms (versão 2.0.0+) para Jakarta EE (jakarta.jms.*) e com.microsoft.azure:azure-servicebus-jms (versão 1.0.x) para Java EE (javax.jms.*). Para obter diretrizes sobre como escolher o artefato certo, consulte Suporte a Jakarta EE e javax.

O cliente usa o objeto de fábrica de conexões para se conectar ao provedor JMS. A fábrica de conexões encapsula um conjunto de parâmetros de configuração de conexão que o administrador define.

Cada fábrica de conexões é uma instância do ConnectionFactory, QueueConnectionFactoryou TopicConnectionFactory interface.

Para simplificar a conexão com Barramento de Serviço do Azure, essas interfaces são implementadas por meio de ServiceBusJmsConnectionFactory, ServiceBusJmsQueueConnectionFactory ou ServiceBusJmsTopicConnectionFactory, respectivamente.

Importante

Aplicativos Java que usam a API JMS 2.0 podem se conectar ao Barramento de Serviço do Azure usando a cadeia de conexão ou usando um TokenCredential para aproveitar a autenticação com suporte do Microsoft Entra. Ao usar autenticação com suporte do Microsoft Entra, certifique-se de atribuir funções e permissões à identidade como necessário.

Crie uma identidade gerenciada atribuída pelo sistema no Azure e use essa identidade para criar uma TokenCredential.

TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build();

Você pode criar uma instância da fábrica de conexões com os seguintes parâmetros:

  • Credencial de token – representa uma credencial capaz de fornecer um token OAuth.
  • Host – o nome do host do namespace da camada Barramento de Serviço do Azure Premium.
  • Conjunto de propriedades ServiceBusJmsConnectionFactorySettings, que contém:
    • connectionIdleTimeoutMS - tempo limite ocioso de conexão em milissegundos.
    • traceFrames - sinalizador booliano para coletar quadros de rastreamento AMQP para depuração.
    • Outros parâmetros de configuração.

Crie a fábrica, conforme mostrado no exemplo a seguir. A credencial de token e o host são parâmetros necessários, mas as outras propriedades são opcionais.

String host = "<YourNamespaceName>.servicebus.windows.net";
ConnectionFactory factory = new ServiceBusJmsConnectionFactory(tokenCredential, host, null); 

Destino do JMS

Um destino é o objeto que um cliente usa para especificar o destino das mensagens que ele produz e a origem das mensagens que ele consome.

Os destinos são mapeados para entidades no Barramento de Serviço do Azure – filas (em cenários ponto a ponto) e tópicos (em cenários pub-sub).

Conexões

Uma conexão encapsula uma conexão virtual com um provedor JMS. Com o Barramento de Serviço do Azure, isso representa uma conexão com estado entre o aplicativo e o Barramento de Serviço do Azure através do AMQP.

Crie uma conexão a partir da fábrica de conexões, conforme mostrado no exemplo a seguir:

Connection connection = factory.createConnection();

Sessões

Uma sessão é um contexto de thread único para produzir e consumir mensagens. Use-o para criar mensagens, produtores de mensagens e consumidores. Ele também fornece um contexto transacional para agrupar envios e recebimentos em uma unidade atômica de trabalho.

Crie uma sessão do objeto de conexão, conforme mostrado no exemplo a seguir:

Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);

Observação

A API do JMS não dá suporte ao recebimento de mensagens de filas ou tópicos do barramento de serviço com sessões de mensagens habilitadas.

Modos de sessão

Crie uma sessão com qualquer um dos modos a seguir.

Modos de sessão Comportamento
Session.AUTO_ACKNOWLEDGE A sessão reconhece automaticamente o recebimento de uma mensagem por um cliente quando a sessão retorna com êxito de uma chamada para receber ou quando o ouvinte da mensagem a sessão chama para processar a mensagem retorna com êxito.
Session.CLIENT_ACKNOWLEDGE O cliente reconhece uma mensagem consumida chamando o método de reconhecimento da mensagem.
Session.DUPS_OK_ACKNOWLEDGE Esse modo de confirmação instrui a sessão a reconhecer de forma preguiçosa a entrega de mensagens.
Session.SESSION_TRANSACTED Passe esse valor como o argumento para o método createSession(int sessionMode) no objeto Connection para especificar que a sessão deve usar uma transação local.

Se você não especificar o modo de sessão, o padrão será Session.AUTO_ACKNOWLEDGE.

JMSContext

Observação

JMSContext é definido como parte da especificação JMS 2.0.

O JMSContext combina a funcionalidade fornecida pelo objeto de conexão e sessão. Você o cria a partir do objeto de fábrica de conexões.

JMSContext context = connectionFactory.createContext();

Modos de JMSContext

Assim como o objeto Session , você pode criar o JMSContext com os mesmos modos de reconhecimento mencionados nos modos de sessão.

JMSContext context = connectionFactory.createContext(JMSContext.AUTO_ACKNOWLEDGE);

Se você não especificar um modo, o padrão será JMSContext.AUTO_ACKNOWLEDGE.

Produtores de mensagens do JMS

Um produtor de mensagens é um objeto que você cria usando um JMSContext ou uma Sessão. Use-o para enviar mensagens para um destino.

Você pode criá-lo como um objeto autônomo, conforme mostrado no exemplo a seguir:

JMSProducer producer = context.createProducer();

Ou você pode criá-lo em runtime quando precisar enviar uma mensagem.

context.createProducer().send(destination, message);

Consumidores de mensagem JMS

Um consumidor de mensagem é um objeto que um JMSContext ou uma Sessão cria. Use-o para receber mensagens enviadas para um destino. Crie-o conforme mostrado no exemplo a seguir:

JMSConsumer consumer = context.createConsumer(dest);

Recebimentos síncronos por meio do método receive()

O consumidor da mensagem fornece uma maneira síncrona de receber mensagens do destino por meio do receive() método.

Se você não especificar argumentos ou tempo limite, ou se especificar um tempo limite de 0, o consumidor bloqueará indefinidamente, a menos que a mensagem chegue ou a conexão for interrompida (o que ocorrer primeiro).

Message m = consumer.receive();
Message m = consumer.receive(0);

Quando você fornece um argumento positivo diferente de zero, o consumidor bloqueia até que esse temporizador expire.

Message m = consumer.receive(1000); // time out after one second.

Recebimentos assíncronos com ouvintes de mensagem JMS

Um ouvinte de mensagens é um objeto que você usa para tratamento assíncrono de mensagens em um destino. Ele implementa a interface MessageListener, que contém o método onMessage, onde a lógica de negócios específica deve estar.

Você deve criar uma instância de um objeto de ouvinte de mensagens e registrá-lo em um consumidor de mensagem específico usando o método setMessageListener.

Listener myListener = new Listener();
consumer.setMessageListener(myListener);

Consumo de tópicos

Você cria consumidores de mensagens JMS em um destino, que pode ser uma fila ou um tópico.

Os consumidores em filas são simplesmente objetos do lado do cliente que residem no contexto da Sessão (e conexão) entre o aplicativo cliente e o Barramento de Serviço do Azure.

Os consumidores, no entanto, têm duas partes em tópicos -

  • Um objeto do lado do cliente que reside no contexto da sessão (ou JMSContext) e
  • Uma assinatura que é uma entidade no Barramento de Serviço do Azure.

As assinaturas estão documentadas aqui e podem ser um dos seguintes tipos:

  • Assinaturas duráveis compartilhadas
  • Assinaturas não duráveis compartilhadas
  • Assinaturas duráveis não compartilhadas
  • Assinaturas não duráveis não compartilhadas

Navegadores de fila JMS

A API do JMS fornece um QueueBrowser objeto que o aplicativo pode usar para navegar pelas mensagens na fila e exibir os valores de cabeçalho para cada mensagem.

Você pode criar um Navegador de Filas usando o JMSContext, conforme mostrado no exemplo a seguir:

QueueBrowser browser = context.createBrowser(queue);

Observação

A API do JMS não fornece uma API para procurar um tópico.

Essa limitação existe porque o tópico em si não armazena as mensagens. Assim que a mensagem é enviada para o tópico, ela é encaminhada para as assinaturas apropriadas.

Seletores de mensagens JMS

Aplicativos receptores podem usar seletores de mensagens para filtrar as mensagens que recebem. Usando seletores de mensagem, o aplicativo receptor descarrega o trabalho de filtragem de mensagens para o provedor JMS (nesse caso, Barramento de Serviço do Azure) em vez de assumir essa própria responsabilidade.

Você pode usar seletores ao criar qualquer um dos seguintes consumidores:

  • Assinatura durável compartilhada
  • Assinatura durável não compartilhada
  • Assinatura não durável compartilhada
  • Assinatura não durável não compartilhada
  • Consumidor da fila
  • Navegador de filas

Observação

Barramento de Serviço seletores não dão suporte a palavras-chave sql LIKE e BETWEEN.

Mensagens agendadas (atraso de entrega)

O JMS 2.0 dá suporte ao agendamento de uma mensagem para entrega futura usando o setDeliveryDelay método em um MessageProducer ou JMSProducer. Quando você define essa propriedade, Barramento de Serviço aceita a mensagem, mas só a torna visível para os consumidores após o período de atraso decorrido.

MessageProducer producer = session.createProducer(queue);

// Schedule a message for delivery 30 seconds from now
producer.setDeliveryDelay(30000);
producer.send(session.createTextMessage("Scheduled message"));

Para obter um exemplo de trabalho completo, consulte QueueScheduledSend.java no repositório azure-servicebus-jms-samples.

Seleção e resiliência da fábrica de conexão

Quando você usa ServiceBusJmsConnectionFactory no Spring Boot ou em outras estruturas que gerenciam conexões JMS, escolha o wrapper de fábrica de conexões correto para remetentes e ouvintes para garantir a operação confiável.

Role Fábrica de conexões Por que
Remetentes (JmsTemplate) CachingConnectionFactory Encapsulamento ServiceBusJmsConnectionFactory JmsTemplate cria e fecha uma conexão por envio por padrão. CachingConnectionFactory mantém uma única conexão AMQP e armazena sessões em cache, evitando a instabilidade de conexão que pode esgotar os recursos do corretor sob carga.
Ouvintes (@JmsListener, DefaultMessageListenerContainer) Bruto ServiceBusJmsConnectionFactory (desembrulhado) Cada contêiner de ouvinte obtém sua própria conexão AMQP com ciclo de vida independente. Se uma conexão falhar (expiração do token, atualização de gateway, blip de rede), somente esse ouvinte será afetado e o Spring recriará a conexão automaticamente.

O que os ouvintes devem evitar

Aviso

Nunca use SingleConnectionFactory com contêineres de ouvinte. Isso força todos os ouvintes a compartilhar uma única conexão JMS. Se essa conexão for interrompida por qualquer motivo, todos os ouvintes perderão a conectividade simultaneamente e não poderão se recuperar de forma independente. Use o bruto ServiceBusJmsConnectionFactory para que cada contêiner de ouvinte gerencie sua própria conexão.

CachingConnectionFactory em contêineres de ouvinte também podem causar problemas porque sessões armazenadas em cache podem fazer referência a uma conexão subjacente obsoleta. Para o ouvinte, a fábrica primária garante que cada contêiner possa criar uma nova conexão de forma independente.

Padrões padrão do Spring Cloud Azure

Se você usar spring-cloud-azure-starter-servicebus-jms (versão 6.2.0+), o starter aplicará essa separação padronizada por padrão:

spring.jms.servicebus.pool.enabled spring.jms.cache.enabled Fábrica de remetente Fábrica de ouvintes
(não definido) (não definido) CachingConnectionFactory ServiceBusJmsConnectionFactory
(não definido) true CachingConnectionFactory CachingConnectionFactory
(não definido) false ServiceBusJmsConnectionFactory ServiceBusJmsConnectionFactory
true (não definido) JmsPoolConnectionFactory JmsPoolConnectionFactory

Em versões mais antigas (pré-6.2.0), os remetentes e ouvintes usam ServiceBusJmsConnectionFactory por padrão, o que faz com que os remetentes criem uma nova conexão por envio.

Adicionando um ouvinte de exceção

Sem um ouvinte de exceção, as quedas de conexão são completamente silenciosas. Adicione um jakarta.jms.ExceptionListener às fábricas de remetentes e ouvintes para observabilidade.

connection.setExceptionListener(exception -> {
    log.error("JMS connection error: {}", exception.getMessage(), exception);
});

No Spring Boot, defina o ouvinte de exceção no CachingConnectionFactory (para remetentes) e no DefaultJmsListenerContainerFactory (para ouvintes).

Para obter um exemplo de trabalho completo mostrando todos esses padrões, consulte o Spring Boot JMS Resilience sample no repositório azure-servicebus-jms-samples.

Filas de mensagens não entregues

Cada assinatura de fila e tópico no Barramento de Serviço do Azure tem uma dead letter queue (DLQ) associada. O sistema move automaticamente mensagens que não pode entregar nem processar para o DLQ. Por exemplo, o sistema move uma mensagem para o DLQ quando a mensagem excede a contagem máxima de entrega ou seu TTL (vida útil) expira.

Importante

Para mover mensagens expiradas de TTL para o DLQ, habilite o envio de mensagens mortas na expiração da mensagem para a fila ou assinatura. Sem essa configuração, o sistema descarta silenciosamente mensagens expiradas. Para obter as etapas de configuração, consulte Habilitar letras mortas para uma fila ou assinatura.

No JMS, você acessa o DLQ como um destino separado construindo o caminho completo e criando um JmsQueue com ele. Nenhuma API especial é necessária.

Formato do caminho da fila DLQ:

<queue-name>/$deadletterqueue

Formato de caminho DLQ da assinatura do tópico:

<topic-name>/Subscriptions/<subscription-name>/$deadletterqueue

Exemplo – consumindo da fila de mensagens mortas:

import org.apache.qpid.jms.JmsQueue;

// Construct the DLQ path for a queue named "orders"
String dlqPath = "orders/$deadletterqueue";
JmsQueue dlqDestination = new JmsQueue(dlqPath);

// Create a consumer on the DLQ and receive messages
MessageConsumer dlqConsumer = session.createConsumer(dlqDestination);
Message message = dlqConsumer.receive(5000);

Mensagens com mensagens mortas incluem propriedades de metadados que descrevem por que a mensagem foi morta:

Property Description
DeadLetterReason O motivo pelo qual a mensagem foi escrita em letras mortas (por exemplo, TTLExpiredException ou MaxDeliveryCountExceeded).
DeadLetterErrorDescription Uma descrição legível para humanos da razão da mensagem não entregue.

Leia estas propriedades usando message.getStringProperty():

String reason = message.getStringProperty("DeadLetterReason");
String description = message.getStringProperty("DeadLetterErrorDescription");

Para obter um exemplo de trabalho completo, consulte QueueDeadLetterReceive.java no repositório azure-servicebus-jms-samples.

Disposição do Advanced Message Queuing Protocol e mapeamento da operação de Barramento de Serviço

Veja como uma disposição AMQP é convertida em uma operação do Barramento de Serviço:

ACCEPTED = 1; -> Complete()
REJECTED = 2; -> DeadLetter()
RELEASED = 3; (just unlock the message in service bus, will then get redelivered)
MODIFIED_FAILED = 4; -> Abandon() which increases delivery count
MODIFIED_FAILED_UNDELIVERABLE = 5; -> Defer()

Resumo

Este guia do desenvolvedor mostra como Java aplicativos cliente que usam o JMS (Serviço de Mensagens Java) podem se conectar a Barramento de Serviço do Azure.

Próximas etapas

Para obter mais informações sobre Barramento de Serviço do Azure e detalhes sobre entidades do JMS (Serviço de Mensagens Java), consulte os seguintes artigos: