Send messages to and receive messages from Azure Service Bus queues (Java)

In this quickstart, you create a Java app to send messages to and receive messages from an Azure Service Bus queue.

Note

This quick start provides step-by-step instructions for a simple scenario of sending messages to a Service Bus queue and receiving them. You can find pre-built Java samples for Azure Service Bus in the Azure SDK for Java repository on GitHub.

Tip

If you're working with Azure Service Bus resources in a Spring application, we recommend that you consider Spring Cloud Azure as an alternative. Spring Cloud Azure is an open-source project that provides seamless Spring integration with Azure services. To learn more about Spring Cloud Azure, and to see an example using Service Bus, see Spring Cloud Stream with Azure Service Bus.

Prerequisites

Create a namespace in the Azure portal

To begin using Service Bus messaging entities in Azure, you must first create a namespace with a name that is unique across Azure. A namespace provides a scoping container for Service Bus resources (queues, topics, etc.) within your application.

To create a namespace:

  1. Sign in to the Azure portal.

  2. Navigate to the All services page.

  3. On the left navigation bar, select Integration from the list of categories, hover the mouse over Service Bus, and then select + button on the Service Bus tile.

    Image showing selection of Create a resource, Integration, and then Service Bus in the menu.

  4. In the Basics tag of the Create namespace page, follow these steps:

    1. For Subscription, choose an Azure subscription in which to create the namespace.

    2. For Resource group, choose an existing resource group, or create a new one.

    3. Enter a name for the namespace. The namespace name should adhere to the following naming conventions:

      • The name must be unique across Azure. The system immediately checks to see if the name is available.
      • The name length is at least 6 and at most 50 characters.
      • The name can contain only letters, numbers, hyphens -.
      • The name must start with a letter and end with a letter or number.
      • The name doesn't end with -sb or -mgmt.
    4. For Location, choose the region in which your namespace should be hosted.

    5. For Pricing tier, select the pricing tier (Basic, Standard, or Premium) for the namespace. For this quickstart, select Standard.

    6. If you select Premium tier, select whether you can enable geo-replication for the namespace. The Geo-Replication feature ensures that the metadata and data of a namespace are continuously replicated from a primary region to one or more secondary regions.

      Important

      If you want to use topics and subscriptions, choose either Standard or Premium. Topics/subscriptions aren't supported in the Basic pricing tier.

      If you selected the Premium pricing tier, specify the number of messaging units. The premium tier provides resource isolation at the CPU and memory level so that each workload runs in isolation. This resource container is called a messaging unit. A premium namespace has at least one messaging unit. You can select 1, 2, 4, 8 or 16 messaging units for each Service Bus Premium namespace. For more information, see Service Bus Premium Messaging.

    7. Select Review + create at the bottom of the page.

      Image showing the Create a namespace page

    8. On the Review + create page, review settings, and select Create.

  5. Once the deployment of the resource is successful, select Go to resource on the deployment page.

    Image showing the deployment succeeded page with the Go to resource link.

  6. You see the home page for your service bus namespace.

    Image showing the home page of the Service Bus namespace created.

Create a queue in the Azure portal

  1. On the Service Bus Namespace page, expand Entities on the navigational menu to the left, and select Queues.

  2. On the Queues page, select + Queue on the toolbar.

  3. Enter a name for the queue, and leave the other values with their defaults.

  4. Now, select Create.

    Screenshot that shows the Create queue page.

Authenticate the app to Azure

This quick start shows you two ways of connecting to Azure Service Bus: passwordless and connection string.

The first option shows you how to use your security principal in Microsoft Entra ID and role-based access control (RBAC) to connect to a Service Bus namespace. You don't need to worry about having hard-coded connection string in your code or in a configuration file or in a secure storage like Azure Key Vault.

The second option shows you how to use a connection string to connect to a Service Bus namespace. If you are new to Azure, you may find the connection string option easier to follow. We recommend using the passwordless option in real-world applications and production environments. For more information, see Authentication and authorization. You can also read more about passwordless authentication on the overview page.

Assign roles to your Microsoft Entra user

When developing locally, make sure that the user account that connects to Azure Service Bus has the correct permissions. You'll need the Azure Service Bus Data Owner role in order to send and receive messages. To assign yourself this role, you'll need the User Access Administrator role, or another role that includes the Microsoft.Authorization/roleAssignments/write action. You can assign Azure RBAC roles to a user using the Azure portal, Azure CLI, or Azure PowerShell. Learn more about the available scopes for role assignments on the scope overview page.

The following example assigns the Azure Service Bus Data Owner role to your user account, which provides full access to Azure Service Bus resources. In a real scenario, follow the Principle of Least Privilege to give users only the minimum permissions needed for a more secure production environment.

Azure built-in roles for Azure Service Bus

For Azure Service Bus, the management of namespaces and all related resources through the Azure portal and the Azure resource management API is already protected using the Azure RBAC model. Azure provides the below Azure built-in roles for authorizing access to a Service Bus namespace:

  • Azure Service Bus Data Owner: Enables data access to Service Bus namespace and its entities (queues, topics, subscriptions, and filters). A member of this role can send and receive messages from queues or topics/subscriptions.
  • Azure Service Bus Data Sender: Use this role to give the send access to Service Bus namespace and its entities.
  • Azure Service Bus Data Receiver: Use this role to give the receive access to Service Bus namespace and its entities.

If you want to create a custom role, see Rights required for Service Bus operations.

Add Microsoft Entra user to Azure Service Bus Owner role

Add your Microsoft Entra user name to the Azure Service Bus Data Owner role at the Service Bus namespace level. It will allow an app running in the context of your user account to send messages to a queue or a topic, and receive messages from a queue or a topic's subscription.

Important

In most cases, it will take a minute or two for the role assignment to propagate in Azure. In rare cases, it may take up to eight minutes. If you receive authentication errors when you first run your code, wait a few moments and try again.

  1. If you don't have the Service Bus Namespace page open in the Azure portal, locate your Service Bus namespace using the main search bar or left navigation.

  2. On the overview page, select Access control (IAM) from the left-hand menu.

  3. On the Access control (IAM) page, select the Role assignments tab.

  4. Select + Add from the top menu and then Add role assignment from the resulting drop-down menu.

    A screenshot showing how to assign a role.

  5. Use the search box to filter the results to the desired role. For this example, search for Azure Service Bus Data Owner and select the matching result. Then choose Next.

  6. Under Assign access to, select User, group, or service principal, and then choose + Select members.

  7. In the dialog, search for your Microsoft Entra username (usually your user@domain email address) and then choose Select at the bottom of the dialog.

  8. Select Review + assign to go to the final page, and then Review + assign again to complete the process.

Send messages to a queue

In this section, you'll create a Java console project, and add code to send messages to the queue that you created earlier.

Create a Java console project

Create a Java project using Eclipse or a tool of your choice.

Configure your application to use Service Bus

Add references to Azure Core and Azure Service Bus libraries.

If you're using Eclipse and created a Java console application, convert your Java project to a Maven: right-click the project in the Package Explorer window, select Configure -> Convert to Maven project. Then, add dependencies to these two libraries as shown in the following example.

Update the pom.xml file to add dependencies to Azure Service Bus and Azure Identity packages.

    <dependencies>
        <dependency>
            <groupId>com.azure</groupId>
            <artifactId>azure-messaging-servicebus</artifactId>
            <version>7.13.3</version>
        </dependency>
        <dependency>
            <groupId>com.azure</groupId>
            <artifactId>azure-identity</artifactId>
            <version>1.8.0</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

Add code to send messages to the queue

  1. Add the following import statements at the topic of the Java file.

    import com.azure.messaging.servicebus.*;
    import com.azure.identity.*;
    
    import java.util.concurrent.TimeUnit;
    import java.util.Arrays;
    import java.util.List;
    
  2. In the class, define variables to hold connection string and queue name.

    static String queueName = "<QUEUE NAME>";
    

    Important

    Replace <QUEUE NAME> with the name of the queue.

  3. Add a method named sendMessage in the class to send one message to the queue.

    Important

    Replace NAMESPACENAME with the name of your Service Bus namespace.

    static void sendMessage()
    {
        // create a token using the default Azure credential
        DefaultAzureCredential credential = new DefaultAzureCredentialBuilder()
                .build();
    
        ServiceBusSenderClient senderClient = new ServiceBusClientBuilder()
                .fullyQualifiedNamespace("NAMESPACENAME.servicebus.windows.net")
                .credential(credential)
                .sender()
                .queueName(queueName)
                .buildClient();
    
        // send one message to the queue
        senderClient.sendMessage(new ServiceBusMessage("Hello, World!"));
        System.out.println("Sent a single message to the queue: " + queueName);
    }
    
    
  4. Add a method named createMessages in the class to create a list of messages. Typically, you get these messages from different parts of your application. Here, we create a list of sample messages.

    static List<ServiceBusMessage> createMessages()
    {
        // create a list of messages and return it to the caller
        ServiceBusMessage[] messages = {
                new ServiceBusMessage("First message"),
                new ServiceBusMessage("Second message"),
                new ServiceBusMessage("Third message")
        };
        return Arrays.asList(messages);
    }
    
  5. Add a method named sendMessageBatch method to send messages to the queue you created. This method creates a ServiceBusSenderClient for the queue, invokes the createMessages method to get the list of messages, prepares one or more batches, and sends the batches to the queue.

    Important

    Replace NAMESPACENAME with the name of your Service Bus namespace.

    static void sendMessageBatch()
    {
        // create a token using the default Azure credential
        DefaultAzureCredential credential = new DefaultAzureCredentialBuilder()
                .build();
    
        ServiceBusSenderClient senderClient = new ServiceBusClientBuilder()
                .fullyQualifiedNamespace("NAMESPACENAME.servicebus.windows.net")
                .credential(credential)
                .sender()
                .queueName(queueName)
                .buildClient();
    
        // Creates an ServiceBusMessageBatch where the ServiceBus.
        ServiceBusMessageBatch messageBatch = senderClient.createMessageBatch();
    
        // create a list of messages
        List<ServiceBusMessage> listOfMessages = createMessages();
    
        // We try to add as many messages as a batch can fit based on the maximum size and send to Service Bus when
        // the batch can hold no more messages. Create a new batch for next set of messages and repeat until all
        // messages are sent.
        for (ServiceBusMessage message : listOfMessages) {
            if (messageBatch.tryAddMessage(message)) {
                continue;
            }
    
            // The batch is full, so we create a new batch and send the batch.
            senderClient.sendMessages(messageBatch);
            System.out.println("Sent a batch of messages to the queue: " + queueName);
    
            // create a new batch
            messageBatch = senderClient.createMessageBatch();
    
            // Add that message that we couldn't before.
            if (!messageBatch.tryAddMessage(message)) {
                System.err.printf("Message is too large for an empty batch. Skipping. Max size: %s.", messageBatch.getMaxSizeInBytes());
            }
        }
    
        if (messageBatch.getCount() > 0) {
            senderClient.sendMessages(messageBatch);
            System.out.println("Sent a batch of messages to the queue: " + queueName);
        }
    
        //close the client
        senderClient.close();
    }
    

Receive messages from a queue

In this section, you add code to retrieve messages from the queue.

  1. Add a method named receiveMessages to receive messages from the queue. This method creates a ServiceBusProcessorClient for the queue by specifying a handler for processing messages and another one for handling errors. Then, it starts the processor, waits for few seconds, prints the messages that are received, and then stops and closes the processor.

    Important

    • Replace NAMESPACENAME with the name of your Service Bus namespace.
    • Replace QueueTest in QueueTest::processMessage in the code with the name of your class.
    // handles received messages
    static void receiveMessages() throws InterruptedException
    {
        DefaultAzureCredential credential = new DefaultAzureCredentialBuilder()
                .build();
    
        ServiceBusProcessorClient processorClient = new ServiceBusClientBuilder()
                .fullyQualifiedNamespace("NAMESPACENAME.servicebus.windows.net")
                .credential(credential)
                .processor()
                .queueName(queueName)
                .processMessage(context -> processMessage(context))
                .processError(context -> processError(context))
                .buildProcessorClient();
    
        System.out.println("Starting the processor");
        processorClient.start();
    
        TimeUnit.SECONDS.sleep(10);
        System.out.println("Stopping and closing the processor");
        processorClient.close();
    }
    
  2. Add the processMessage method to process a message received from the Service Bus subscription.

    private static void processMessage(ServiceBusReceivedMessageContext context) {
        ServiceBusReceivedMessage message = context.getMessage();
        System.out.printf("Processing message. Session: %s, Sequence #: %s. Contents: %s%n", message.getMessageId(),
            message.getSequenceNumber(), message.getBody());
    }
    
  3. Add the processError method to handle error messages.

    private static void processError(ServiceBusErrorContext context) {
        System.out.printf("Error when receiving messages from namespace: '%s'. Entity: '%s'%n",
            context.getFullyQualifiedNamespace(), context.getEntityPath());
    
        if (!(context.getException() instanceof ServiceBusException)) {
            System.out.printf("Non-ServiceBusException occurred: %s%n", context.getException());
            return;
        }
    
        ServiceBusException exception = (ServiceBusException) context.getException();
        ServiceBusFailureReason reason = exception.getReason();
    
        if (reason == ServiceBusFailureReason.MESSAGING_ENTITY_DISABLED
            || reason == ServiceBusFailureReason.MESSAGING_ENTITY_NOT_FOUND
            || reason == ServiceBusFailureReason.UNAUTHORIZED) {
            System.out.printf("An unrecoverable error occurred. Stopping processing with reason %s: %s%n",
                reason, exception.getMessage());
        } else if (reason == ServiceBusFailureReason.MESSAGE_LOCK_LOST) {
            System.out.printf("Message lock lost for message: %s%n", context.getException());
        } else if (reason == ServiceBusFailureReason.SERVICE_BUSY) {
            try {
                // Choosing an arbitrary amount of time to wait until trying again.
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                System.err.println("Unable to sleep for period of time");
            }
        } else {
            System.out.printf("Error source %s, reason %s, message: %s%n", context.getErrorSource(),
                reason, context.getException());
        }
    }
    
  4. Update the main method to invoke sendMessage, sendMessageBatch, and receiveMessages methods and to throw InterruptedException.

    public static void main(String[] args) throws InterruptedException {
        sendMessage();
        sendMessageBatch();
        receiveMessages();
    }
    

Run the app

  1. If you're using Eclipse, right-click the project, select Export, expand Java, select Runnable JAR file, and follow the steps to create a runnable JAR file.

  2. If you're signed into the machine using a user account that's different from the user account added to the Azure Service Bus Data Owner role, follow these steps. Otherwise, skip this step and move on to run the Jar file in the next step.

    1. Install Azure CLI on your machine.

    2. Run the following CLI command to sign in to Azure. Use the same user account that you added to the Azure Service Bus Data Owner role.

      az login
      
  3. Run the Jar file using the following command.

    java -jar <JAR FILE NAME>
    
  4. You see the following output in the console window.

    Sent a single message to the queue: myqueue
    Sent a batch of messages to the queue: myqueue
    Starting the processor
    Processing message. Session: 88d961dd801f449e9c3e0f8a5393a527, Sequence #: 1. Contents: Hello, World!
    Processing message. Session: e90c8d9039ce403bbe1d0ec7038033a0, Sequence #: 2. Contents: First message
    Processing message. Session: 311a216a560c47d184f9831984e6ac1d, Sequence #: 3. Contents: Second message
    Processing message. Session: f9a871be07414baf9505f2c3d466c4ab, Sequence #: 4. Contents: Third message
    Stopping and closing the processor
    

On the Overview page for the Service Bus namespace in the Azure portal, you can see incoming and outgoing message count. Wait for a minute or so and then refresh the page to see the latest values.

Incoming and outgoing message count

Select the queue on this Overview page to navigate to the Service Bus Queue page. You see the incoming and outgoing message count on this page too. You also see other information such as the current size of the queue, maximum size, active message count, and so on.

Queue details

Next Steps

See the following documentation and samples: