Azure Service Bus JMS 2.0 개발자 가이드

이 가이드에서는 JMS(Java Message Service) 2.0 API를 사용하여 Azure Service Bus 통신하는 데 도움이 되는 자세한 정보를 제공합니다.

Java 개발자로서 Azure Service Bus를 접하는 경우 다음 문서를 읽어 보세요.

시작하기 개념들

Java 메시지 서비스(JMS) 프로그래밍 모델

Java Message Service API 프로그래밍 모델은 다음 섹션에서 설명합니다.

비고

Azure Service Bus 프리미엄 계층 은 JMS 1.1 및 JMS 2.0을 지원합니다.

Azure Service Bus - 표준 계층은 제한된 JMS 1.1 기능을 지원합니다. 자세한 내용은 이 설명서를 참조하세요.

JMS - 구성 요소

다음 구성 요소를 사용하여 JMS 애플리케이션과 통신합니다.

비고

이 가이드는 Oracle Java EE 6 Java Message Service(JMS) 튜토리얼에서 차용한 것입니다.

JMS(Java Message Service)에 대한 자세한 내용은 이 자습서를 참조하세요.

연결 팩터리

비고

라이브러리는 두 가지 변형으로 제공됩니다: azure-servicebus-jms의 경우 com.azure:azure-servicebus-jms ()용과, jakarta.jms.*의 경우 com.microsoft.azure:azure-servicebus-jms ()용. 올바른 아티팩트 선택에 대한 지침은 Jakarta EE 및 javax 지원을 참조하세요.

클라이언트는 연결 팩터리 개체를 사용하여 JMS 공급자에 연결합니다. 연결 팩터리는 관리자가 정의하는 연결 구성 매개 변수 집합을 캡슐화합니다.

각 연결 팩터리는 , ConnectionFactory또는 QueueConnectionFactory 인터페이스의 TopicConnectionFactory인스턴스입니다.

Azure Service Bus 연결을 간소화하기 위해 이러한 인터페이스는 각각 ServiceBusJmsConnectionFactory, ServiceBusJmsQueueConnectionFactory 또는 ServiceBusJmsTopicConnectionFactory 통해 구현됩니다.

중요합니다

JMS 2.0 API를 사용하는 Java 애플리케이션은 연결 문자열 사용하거나 TokenCredential 사용하여 Microsoft Entra 백업된 인증을 활용하여 Azure Service Bus 연결할 수 있습니다. Microsoft Entra 백업 인증을 사용하는 경우 필요에 따라 id에 역할 및 권한 할당해야 합니다.

Azure에서 시스템에 할당된 관리 ID를 만들고, 이 ID를 사용하여 TokenCredential를 생성하세요.

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

다음 매개 변수를 사용하여 연결 팩터리를 인스턴스화할 수 있습니다.

  • 토큰 자격 증명 - OAuth 토큰을 제공할 수 있는 자격 증명을 나타냅니다.
  • 호스트 - Azure Service Bus 프리미엄 계층 네임스페이스의 호스트 이름입니다.
  • 다음을 포함하는 ServiceBusJmsConnectionFactorySettings 속성 모음:
    • connectionIdleTimeoutMS - 유휴 연결 시간 제한(밀리초)입니다.
    • traceFrames - 디버깅을 위해 AMQP 추적 프레임을 수집하는 부울 플래그입니다.
    • 기타 구성 매개 변수입니다.

다음 예제와 같이 팩터리를 만듭니다. 토큰 자격 증명 및 호스트는 필수 매개 변수이지만 다른 속성은 선택 사항입니다.

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

JMS 대상

대상은 클라이언트가 생성하는 메시지의 대상과 클라이언트가 사용하는 메시지의 원본을 지정하는 데 사용하는 개체입니다.

대상은 Azure Service Bus - 큐(지점 간 시나리오) 및 토픽(게시-구독 시나리오)의 엔터티에 매핑됩니다.

관계망

연결은 JMS 공급자와의 가상 연결을 캡슐화합니다. Azure Service Bus를 사용하면 애플리케이션과 Azure Service Bus 간에 AMQP를 통해 상태를 저장하는 연결이 생성됩니다.

다음 예제와 같이 연결 팩터리에서 연결을 만듭니다.

Connection connection = factory.createConnection();

세션

세션은 메시지를 생성하고 사용하는 단일 스레드 컨텍스트입니다. 이를 활용하여 메시지, 메시지 생산자 및 메시지 소비자를 생성합니다. 또한 송신 및 수신을 원자성 작업 단위로 그룹화하기 위한 트랜잭션 컨텍스트를 제공합니다.

다음 예제와 같이 연결 개체에서 세션을 만듭니다.

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

비고

JMS API는 메시징 세션을 사용하도록 설정된 Service Bus 큐 또는 토픽에서 메시지 수신을 지원하지 않습니다.

세션 모드

다음 모드를 사용하여 세션을 만듭니다.

세션 모드 행동
Session.AUTO_ACKNOWLEDGE (세션 자동 인식) 세션은 메시지를 수신하기 위한 호출이 성공적으로 반환되거나, 세션이 메시지를 처리하기 위해 호출한 메시지 수신기가 성공적으로 반환될 때, 클라이언트의 메시지 수신을 자동으로 승인합니다.
Session.CLIENT_ACKNOWLEDGE 클라이언트는 메시지의 승인 메서드를 호출하여 사용된 메시지를 승인합니다.
Session.DUPS_OK_ACKNOWLEDGE 이 승인 모드는 메시지 배달을 지연적으로 승인하도록 세션에 지시합니다.
Session.SESSION_TRANSACTED 이 값을 Connection 개체의 메서드 createSession(int sessionMode) 에 인수로 전달하여 세션에서 로컬 트랜잭션을 사용하도록 지정합니다.

세션 모드를 지정하지 않으면 기본값은 Session.AUTO_ACKNOWLEDGE.

JMSContext

비고

JMSContext는 JMS 2.0 사양의 일부로 정의됩니다.

JMSContext는 연결 및 세션 개체에서 제공하는 기능을 결합합니다. 당신은 연결 팩토리 개체에서 그것을 만듭니다.

JMSContext context = connectionFactory.createContext();

JMSContext 모드

Session 개체와 마찬가지로 세션 모드에서 설명한 것과 동일한 승인 모드로 JMSContext를 만들 수 있습니다.

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

모드를 지정하지 않으면 기본값은 JMSContext.AUTO_ACKNOWLEDGE.

JMS 메시지 생산자

메시지 생산자는 JMSContext 또는 Session을 사용하여 만드는 개체입니다. 대상에 메시지를 보내는 데 사용합니다.

다음 예제와 같이 독립 실행형 개체로 만들 수 있습니다.

JMSProducer producer = context.createProducer();

또는 메시지를 보내야 할 때 런타임에 만들 수 있습니다.

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

JMS 메시지 수신자

메시지 소비자는 JMSContext 또는 세션이 만드는 개체입니다. 대상에 전송된 메시지를 수신하는 데 사용합니다. 다음 예제와 같이 만듭니다.

JMSConsumer consumer = context.createConsumer(dest);

receive() 메서드를 통해 동기 수신

메시지 소비자는 receive() 메서드를 통해 대상에서 메시지를 수신하는 동기 방법을 제공합니다.

인수 또는 시간 제한을 지정하지 않거나 시간 제한을 0지정하는 경우 메시지가 도착하거나 연결이 끊어지지 않는 한 소비자는 무기한 차단됩니다(이전 중 어느 것이든지).

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

0이 아닌 양수 인수를 제공하면 소비자는 해당 타이머가 만료될 때까지 차단합니다.

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

JMS 메시지 수신기를 사용하여 비동기 수신

메시지 수신기는 대상에서 메시지를 비동기식으로 처리하는 데 사용하는 개체입니다. MessageListener 인터페이스를 구현하며, 이 인터페이스는 특정 비즈니스 논리가 있어야 하는 onMessage 메서드를 포함합니다.

메서드를 사용하여 setMessageListener 메시지 수신기 개체를 인스턴스화하고 특정 메시지 소비자에 등록해야 합니다.

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

토픽에서 소비

메시지를 수신하려면 큐 또는 토픽과 같은 목적지를 지정하여 JMS 메시지 컨슈머 를 생성해야 합니다.

큐의 소비자는 클라이언트 애플리케이션과 Azure Service Bus 간의 세션(및 연결) 컨텍스트에 있는 클라이언트 쪽 개체일 뿐입니다.

그러나 주제에 대한 소비자는 두 부분으로 구성됩니다.

  • 세션(또는 JMSContext)의 컨텍스트에 있는 클라이언트 쪽 개체
  • Azure Service Bus의 엔터티인 구독.

구독은 여기에 설명되어 있으며 다음 유형 중 하나일 수 있습니다.

  • 공유되는 지속형 구독
  • 공유되는 비지속형 구독
  • 공유되지 않는 지속형 구독
  • 공유되지 않는 비지속형 구독

JMS 큐 브라우저

JMS API는 애플리케이션이 큐의 메시지를 찾아보고 각 메시지에 대한 헤더 값을 표시하는 데 사용할 수 있는 개체를 제공합니다 QueueBrowser .

다음 예제와 같이 JMSContext를 사용하여 큐 브라우저를 만들 수 있습니다.

QueueBrowser browser = context.createBrowser(queue);

비고

JMS API는 토픽을 찾아보는 API를 제공하지 않습니다.

이 제한은 토픽 자체가 메시지를 저장하지 않기 때문에 존재합니다. 메시지가 토픽으로 전송되는 즉시 적절한 구독으로 전달됩니다.

JMS 메시지 선택기

애플리케이션을 수신하면 메시지 선택기를 사용하여 수신하는 메시지를 필터링할 수 있습니다. 수신 애플리케이션은 메시지 선택기를 사용하여 메시지를 필터링하는 작업을 해당 책임 자체를 취하는 대신 JMS 공급자(이 경우 Azure Service Bus)로 오프로드합니다.

다음 소비자를 만들 때 선택기를 사용할 수 있습니다.

  • 공유되는 지속형 구독
  • 공유되지 않는 지속성 구독
  • 공유되는 비지속형 구독
  • 공유되지 않는 비지속성 구독
  • 큐 소비자
  • 큐 브라우저

비고

Service Bus 선택기는 LIKEBETWEEN SQL 키워드를 지원하지 않습니다.

예약된 메시지(배달 지연)

JMS 2.0은 `setDeliveryDelay` 메서드를 사용하여 `MessageProducer` 또는 `JMSProducer`에서 향후 배달을 위한 메시지 예약을 지원합니다. 이 속성을 설정하면 Service Bus 메시지를 수락하지만 지연 기간이 경과한 후에만 소비자에게 표시됩니다.

MessageProducer producer = session.createProducer(queue);

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

전체 작업 샘플은 azure-servicebus-jms-samples 리포지토리의 QueueScheduledSend.java 참조하세요.

연결 팩토리 선택 및 탄력성

Spring Boot 또는 JMS 연결을 관리하는 다른 프레임워크에서 사용하는 ServiceBusJmsConnectionFactory 경우 발신자수신기 에 적합한 연결 팩터리 래퍼를 선택하여 안정적인 작업을 보장합니다.

Role 연결 팩터리 이유
보낸 사람 (JmsTemplate) CachingConnectionFactory 포장 ServiceBusJmsConnectionFactory JmsTemplate 는 기본적으로 전송당 연결을 만들고 닫습니다. CachingConnectionFactory 는 단일 AMQP 연결을 유지하고 세션을 캐시하므로 로드 중인 Broker 리소스를 소진할 수 있는 연결 변동을 방지합니다.
수신기 (@JmsListener, DefaultMessageListenerContainer) 원본 ServiceBusJmsConnectionFactory (언랩된) 각 수신기 컨테이너는 AMQP 연결을 사용하며 독립적인 수명 주기를 가집니다. 연결이 실패하면(토큰 만료, 게이트웨이 업그레이드, 네트워크 블립), 해당 수신기만 영향을 받으며 Spring은 자동으로 연결을 다시 만듭니다.

수신기에 대해 피해야 할 사항

경고

수신기 컨테이너에는 SingleConnectionFactory를 절대 사용하지 마십시오. 모든 수신기가 단일 JMS 연결을 공유하도록 합니다. 어떤 이유로든 연결이 중단되면 모든 수신기가 동시에 연결을 끊고 독립적으로 복구할 수 없습니다. 각 수신기 컨테이너가 자체 연결을 관리하게 되도록 원시 ServiceBusJmsConnectionFactory 를 사용합니다.

CachingConnectionFactory 캐시된 세션이 부실한 기본 연결을 참조할 수 있으므로 수신기 컨테이너에서 문제가 발생할 수도 있습니다. 리스너의 경우, 원시 팩토리는 각 컨테이너가 독립적으로 새로운 네트워크 연결을 생성할 수 있도록 보장합니다.

Spring Cloud Azure 기본값

(버전 6.2.0 이상)을 사용하는 spring-cloud-azure-starter-servicebus-jms 경우 시작은 기본적으로 이 팩터리 분리를 적용합니다.

spring.jms.servicebus.pool.enabled spring.jms.cache.enabled 발신자 팩토리 수신기 팩터리
(설정되지 않음) (설정되지 않음) CachingConnectionFactory ServiceBusJmsConnectionFactory
(설정되지 않음) true CachingConnectionFactory CachingConnectionFactory
(설정되지 않음) false ServiceBusJmsConnectionFactory ServiceBusJmsConnectionFactory
true (설정되지 않음) JmsPoolConnectionFactory JmsPoolConnectionFactory

이전 버전(6.2.0 이전)에서 보낸 사람과 수신기는 기본적으로 사용 ServiceBusJmsConnectionFactory 하므로 보낸 사람이 전송당 새 연결을 만듭니다.

예외 수신기 추가

예외 수신기가 없으면 연결이 아무런 알림 없이 조용히 끊어집니다. 관찰 가능성을 위해 송신자 및 수신자 팩토리 모두에 jakarta.jms.ExceptionListener 을 추가하세요:

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

Spring Boot에서 CachingConnectionFactory (발신자의 경우) 및 DefaultJmsListenerContainerFactory (수신자의 경우)에 예외 수신기를 설정합니다.

이러한 모든 패턴을 보여 주는 전체 작업 샘플은 azure-servicebus-jms-samples 리포지토리의 Spring Boot JMS 복원력 샘플을 참조하세요.

배달 못한 편지 큐

Azure Service Bus의 모든 큐와 토픽 구독에는 각각 연결된 죽은 편지 큐(DLQ)가 있습니다. 시스템은 배달하거나 처리할 수 없는 메시지를 DLQ로 자동으로 이동합니다. 예를 들어 메시지가 최대 배달 횟수를 초과하거나 TTL(Time to Live)이 만료되면 시스템이 메시지를 DLQ로 이동합니다.

중요합니다

TTL이 만료된 메시지를 DLQ로 보내려면, 큐 또는 구독에서 메시지 만료 시 죽은 편지 기능을 활성화하세요. 이 설정이 없으면 시스템에서 만료된 메시지를 자동으로 삭제합니다. 구성 단계는 큐 또는 구독에 대해 죽은 편지 기능 사용 설정을 참조하세요.

JMS에서는 전체 경로를 구성하고 그것을 사용하여 JmsQueue을 생성함으로써 DLQ에 별도의 대상으로 액세스합니다. 특별한 API는 필요하지 않습니다.

큐 DLQ 경로 형식:

<queue-name>/$deadletterqueue

토픽 구독 DLQ 경로 형식:

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

예제 - 큐의 데드 레터 큐에서 메시지 소비:

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);

처리되지 않은 메시지에는 메시지가 처리되지 않은 이유를 설명하는 메타데이터 속성이 포함됩니다.

재산 Description
DeadLetterReason 메시지가 데드 레터 처리된 이유입니다(예: TTLExpiredException 또는 MaxDeliveryCountExceeded).
DeadLetterErrorDescription 배달 못한 편지 이유에 대한 사람이 읽을 수 있는 설명입니다.

이러한 속성을 message.getStringProperty()을 이용하여 읽습니다.

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

전체 작업 샘플은 azure-servicebus-jms-samples 리포지토리의 QueueDeadLetterReceive.java 참조하세요.

AMQP 처리 및 Service Bus 작업 매핑

AMQP 처리가 Service Bus 작업으로 변환되는 방법은 다음과 같습니다.

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()

요약

이 개발자 가이드에서는 Java 메시지 서비스(JMS)를 사용하는 클라이언트 애플리케이션을 Java Azure Service Bus 연결할 수 있는 방법을 보여 줍니다.

다음 단계

Azure Service Bus 대한 자세한 내용 및 JMS(Java Message Service) 엔터티에 대한 자세한 내용은 다음 문서를 참조하세요.