This document is only for Spring Cloud Azure: 4.0.0. Please refer to Spring Versions Mapping to get more information about supported versions.

© 2016-2022 the original authors.

Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.

Spring is an open-source application framework developed by VMware that provides a simplified, modular approach for creating Java applications. Spring Cloud Azure is an open-source project that provides seamless Spring integration with Azure services.

1. Getting Help

If you have any questions about this document, please ask by creating GitHub issues. And Pull Request is welcome.

Table 1. GitHub repositories
GitHub repositories Description

Azure/azure-sdk-for-java

This repository used to hold the source code.

microsoft/spring-cloud-azure

This repository used to hold the document which is displaying in current page.

2. What Is New in 4.0 Since 3.10.x

This page covers changes made in 4.0 since 3.10. With this major release, we aim to bring better security, leaner dependencies, support for production readiness, and more.

To learn how to migrate to 4.0, please check the Appendix page.

2.1. Unified Development Experience

We constantly challenge ourselves on how we can make things more consistent and easier to understand, so our customers are not confronted with haphazard development choices. This is a long and self-evolving journey as consistency is relative and there will be things that are outside our control. We now humbly take another step in this direction to improve our developer experience by unifying project name, artifact ID and properties.

2.2. Simplified Dependency Management

Dependency management is one of the core value pillars that has helped Spring establish preeminence over to other Java frameworks. In that spirit, we have also been exploring ways to make dependency management easier for Spring developers on Azure. In this release, we have codified best practices and expertise from Spring experts and condensed all of our dependency BOMs into one, spring-cloud-azure-dependencies, which we believe will further bring down the learning curve and avoid ill-handling of dependencies.

2.3. Expanded Support Scope of Azure Support on start.spring.io

The Azure Support module in Spring Initializr provides auto-configuration of many Azure services.

In this release we have expanded the scope of Azure Support to cover the additional 4 more services:

  • Kafka

  • Event Hubs

  • Azure Cache for Redis

  • App Configuration

Our journey does end here and over time we will bring even more Azure services into the fold.

2.4. Untethered and Unrestrained

One feedback that we consistently hear is our Spring modules are unnecessarily stacked on top of too many layers of dependencies, which has prevented broader adoption. As an example, all of our early Spring modules rely on Spring Boot, and many of our customers are running Spring MVC apps in Tomcat, leveraging nothing but Spring Data, as an example, to communicate with data services. We now realize the flaw in our original design, and have rearchitected our Spring module dependencies from the ground up, untethered from layers of excess and entanglement.

2.5. More Control and Secure

At the heart of every real-world application, is identity and secret management. Support for managed identity has become an Azure fundamental that are getting mandated as a security baseline at individual services. We believe aligning on those guidelines will also benefit Spring developers at large, and have added Managed Identity support for App Configuration, Event Hub, Service Bus, Cosmos, Key Vault, Storage Blob, and Storage Queue. This enables building credential-free applications, which is a pattern that has picked up tremendous momentum both at Microsoft and in the community. In addition to Managed Identity, you can use any authentication methods supported in the underlying Azure SDK from our Spring libraries. For instance, you use SAS token and token credential to authenticate with Service Bus and Event Hubs. Credential chain is now enabled by default, allowing applications to obtain credentials from application properties, environment variables, managed identity, IDEs, etc. Lastly providing granular level access control at the resource level (i.e.: Service Bus queue), is often of paramount importance when it comes to meeting the needs of our enterprise customers. We’ve now unlocked these controls to our customers for better security governance and adherence to IT policies.

2.6. More Options Exposed in a Spring Idiomatic Way

Spring developers have long enjoyed the convenience of defining client options in application configuration files. We certainly do not want to take that privilege away and burden Spring developers with setting options via client objects. To that end, we’ve significantly improved autoconfiguration coverage of Azure SDK clients for both synchronous and asynchronous scenarios.

2.7. More Production Ready

Lastly all the above would be in vain if we do not have enough feature coverage to support our customers in production. Many things come to my mind to make an application production-ready, but observability often arrives at the top. We’ve added health indicators for App Configuration, Event Hubs, Cosmos, Key Vault, Storage Blob, Storage Queue, Storage File, as well as Spring Cloud Sleuth support for all HTTP-based Azure SDKs. As an example, you now can prob if storage blob is up or down via Spring Boot actuator endpoint, as well as track dependencies and latencies going from your application to Cosmos DB.

3. Migration Guide for 4.0

To learn how to migrate to 4.0, please check the Appendix page.

4. Getting Started

4.1. Setting up Dependencies

4.1.1. Bill of Material (BOM)

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.azure.spring</groupId>
      <artifactId>spring-cloud-azure-dependencies</artifactId>
      <version>version</version> (1)
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
1 The version for spring-cloud-azure-dependencies is 4.0.0.

4.1.2. Starter Dependencies

Spring Cloud Azure Starters are a set of convenient dependency descriptors to include in your application. Each starter includes all the dependencies and transitive dependencies needed to begin using its corresponding Spring Cloud Azure module. They boost your Spring Boot application development with Azure services.

For example, if you want to get started using Azure Cosmos DB for data persistence, include the spring-cloud-azure-starter-cosmos dependency in your project.

Spring Cloud Azure provides the following starters under the com.azure.spring group:

Table 2. Spring Cloud Azure starters
Name Description

spring-cloud-azure-starter

Core starter, including autoconfiguration support

spring-cloud-azure-starter-active-directory

Starter for using Azure Active Directory with Spring Security

spring-cloud-azure-starter-active-directory-b2c

Starter for using Azure Active Directory B2C with Spring Security

spring-cloud-azure-starter-appconfiguration

Starter for using Azure App Configuration

spring-cloud-azure-starter-cosmos

Starter for using Azure Cosmos DB

spring-cloud-azure-starter-eventhubs

Starter for using Azure Event Hubs

spring-cloud-azure-starter-keyvault-secrets

Starter for using Azure Key Vault Secrets

spring-cloud-azure-starter-servicebus

Starter for using Azure Service Bus

spring-cloud-azure-starter-servicebus-jms

Starter for using Azure Service Bus and JMS

spring-cloud-azure-starter-storage-blob

Starter for using Azure Storage Blob

spring-cloud-azure-starter-storage-file-share

Starter for using Azure Storage File Share

spring-cloud-azure-starter-storage-queue

Starter for using Azure Storage Queue

spring-cloud-azure-starter-actuator

Starter for using Spring Boot’s Actuator which provides production ready features

Below are starters for Spring Data support:

Table 3. Spring Data related starters
Name Description

spring-cloud-azure-starter-data-cosmos

Starter for using Azure Cosmos DB and Spring Data Cosmos DB

Below are starters for Spring Integration support:

Table 4. Spring Integration related starters
Name Description

spring-cloud-azure-starter-integration-eventhubs

Starter for using Azure Event Hubs and Spring Integration

spring-cloud-azure-starter-integration-servicebus

Starter for using Azure Service Bus and Spring Integration

spring-cloud-azure-starter-integration-storage-queue

Starter for using Azure Storage Queue and Spring Integration

Below are starters for Spring Cloud Stream support:

Table 5. Spring Cloud Stream related starters
Name Description

spring-cloud-azure-starter-stream-eventhubs

Starters for using Azure Event Hubs and Spring Cloud Stream Binder

spring-cloud-azure-starter-stream-servicebus

Starter for using Azure Service Bus and Spring Cloud Stream Binder

4.2. Learning Spring Cloud Azure

We prepared a full list of samples to show the usages, can be found at Spring Cloud Azure Samples.

5. Configuration

Most of Azure SDKs could be divided into two categories by transport type, HTTP-based and AMQP-based. There are properties that are common to all SDKs such as authentication principals and Azure environment settings. Or common to HTTP-based clients, such as logging level to log HTTP requests and responses. Spring Cloud Azure 4.0 provides five common categories of configuration properties, which could be specified to each Azure service.

Table 6. Service common properties
Property Description

spring.cloud.azure.<azure-service>.client

To configure the transport clients underneath one Azure service SDK.

spring.cloud.azure.<azure-service>.credential

To configure how to authenticate with Azure Active Directory for one Azure service SDK.

spring.cloud.azure.<azure-service>.profile

To configure the Azure cloud environment for one Azure service SDK.

spring.cloud.azure.<azure-service>.proxy

To configure the proxy options for one Azure service SDK.

spring.cloud.azure.<azure-service>.retry

To configure the retry options apply to one Azure service SDK. The retry options has supported part of the SDKs, there’s no spring.cloud.azure.cosmos.retry.

There are some properties that could be shared among different Azure services, for example using the same service principal to access Azure Cosmos DB and Azure Event Hubs. Spring Cloud Azure 4.0 allows application developers to specify properties that apply to all Azure SDKs with the prefix spring.cloud.azure.

Table 7. Global properties
Property Description

spring.cloud.azure.client

To configure the transport clients apply to all Azure SDKs by default.

spring.cloud.azure.credential

To configure how to authenticate with Azure Active Directory for all Azure SDKs by default.

spring.cloud.azure.profile

To configure the Azure cloud environment for all Azure SDKs by default.

spring.cloud.azure.proxy

To configure the proxy options apply to all Azure SDK clients by default.

spring.cloud.azure.retry

To configure the retry options apply to all Azure SDK clients by default.

Properties configured under each Azure service will override the global configurations.

Spring Cloud Azure unifies configuration properties' prefixes to spring.cloud.azure since 4.0, which will make configuration properties more consistent and more intuitive. Here’s a quick review of the serivce specific properties.

Table 8. Service specific properties
Azure Service Configuration Property Prefix Configuration Properties Link

Azure App Configuration

spring.cloud.azure.appconfiguration

App Configuration Properties

Azure Cosmos DB

spring.cloud.azure.cosmos

Cosmos Properties

Azure Event Hubs

spring.cloud.azure.eventhubs

Event Hubs Properties

Azure Key Vault Certificates

spring.cloud.azure.keyvault.certificate

Key Vault Certificates Properties

Azure Key Vault Secrets

spring.cloud.azure.keyvault.secret

Key Vault Secrets Properties

Azure Service Bus

spring.cloud.azure.servicebus

Service Bus Properties

Azure Storage Blob

spring.cloud.azure.storage.blob

Storage Blob Properties

Azure Storage File Share

spring.cloud.azure.storage.fileshare

Storage File Share Properties

Azure Storage Queue

spring.cloud.azure.storage.queue

Storage Queue Properties

6. Authentication

6.1. DefaultAzureCredential

The DefaultAzureCredential is appropriate for most scenarios where the application is intended to be run in the Azure Cloud. This is because the DefaultAzureCredential combines credentials commonly used to authenticate when deployed, with credentials used to authenticate in a development environment.

DefaultAzureCredential is intended to simplify getting started with the SDK by handling common scenarios with reasonable default behaviors. Developers who want more control or whose scenario isn’t served by the default settings should use other credential types.

The DefaultAzureCredential will attempt to authenticate via the following mechanisms in order.

DefaultAzureCredential
  • Environment - The DefaultAzureCredential will read account information specified via environment variables and use it to authenticate.

  • Managed Identity - If the application is deployed to an Azure host with Managed Identity enabled, the DefaultAzureCredential will authenticate with that account.

  • IntelliJ - If the developer has authenticated via Azure Toolkit for IntelliJ, the DefaultAzureCredential will authenticate with that account.

  • Visual Studio Code - If the developer has authenticated via the Visual Studio Code Azure Account plugin, the DefaultAzureCredential will authenticate with that account.

  • Azure CLI - If the developer has authenticated an account via the Azure CLI az login command, the DefaultAzureCredential will authenticate with that account.

Please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure resource.

6.2. Managed Identities

A common challenge for developers is the management of secrets and credentials used to secure communication between different components making up a solution. Managed identities eliminate the need for developers to manage credentials. Managed identities provide an identity for applications to use when connecting to resources that support Azure Active Directory (Azure AD) authentication. Applications may use the managed identity to obtain Azure AD tokens. For example, an application may use a managed identity to access resources like Azure Key Vault where developers can store credentials in a secure manner or to access storage accounts.

We encourage using managed identity instead of using connection string or key in your application for it’s more secure and will save the trouble of managing secrets and credentials. In this case, DefaultAzureCredential could better serve the scenario of developing locally using account information stored locally and deploying the application to Azure Cloud and using Managed Identity.

6.2.1. Managed Identity Types

There are two types of managed identities:

  • System-assigned Some Azure services allow you to enable a managed identity directly on a service instance. When you enable a system-assigned managed identity an identity is created in Azure AD that’s tied to the lifecycle of that service instance. So when the resource is deleted, Azure automatically deletes the identity for you. By design, only that Azure resource can use this identity to request tokens from Azure AD.

  • User-assigned You may also create a managed identity as a standalone Azure resource. You can create a user-assigned managed identity and assign it to one or more instances of an Azure service. In the case of user-assigned managed identities, the identity is managed separately from the resources that use it.

When using a user-assigned managed identity, you can specify the client ID by spring.cloud.azure.credential.client-id or spring.cloud.azure.<azure-service>.credential.client-id.
Please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure resource.
Please refer to What are managed identities for Azure resources? for more details about managed identity.

6.3. Other Credential Types

Developers who want more control or whose scenario isn’t served by the DefaultAzureCredential or whose scenario isn’t served by the default settings should use other credential types.

6.3.1. Authentication and Authorization with Azure Active Directory

With Azure AD, you can use Azure role-based access control (Azure RBAC) to grant permissions to a security principal, which may be a user or an application service principal. When a security principal (a user, or an application) attempts to access an Azure resource, for example, an Event Hubs resource, the request must be authorized. With Azure AD, access to a resource is a two-step process.

  1. First, the security principal’s identity is authenticated, and an OAuth 2.0 token is returned.

  2. Next, the token is passed as part of a request to the Azure service to authorize access to the specified resource.

Authenticate with Azure Active Directory

For applications want to connect to resources that support Azure AD authentication, below configurations could be set with prefix spring.cloud.azure.credential or spring.cloud.azure.<azure-service>.credential.

Table 9. Authentication properties
Property Description

client-id

Client id to use when performing service principal authentication with Azure.

client-secret

Client secret to use when performing service principal authentication with Azure.

client-certificate-path

Path of a PEM certificate file to use when performing service principal authentication with Azure.

client-certificate-password

Password of the certificate file.

username

Username to use when performing username/password authentication with Azure.

password

Password to use when performing username/password authentication with Azure.

managed-identity-enabled

Whether to enable managed identity.

To see the list of all Spring Cloud Azure related configuration properties please check the Appendix page.
Authorize Access with Azure Active Directory

The authorization step requires that one or more Azure roles be assigned to the security principal. The roles that are assigned to a security principal decide the permissions that the principal will have.

To see the list of all Azure built-in roles please check Azure built-in roles.

Following are the Azure built-in roles for authorizing access to Azure services supported in Spring Cloud Azure:

Table 10. Azure built-in roles
Role Description

App Configuration Data Owner

Allows full access to App Configuration data.

App Configuration Data Reader

Allows read access to App Configuration data.

Azure Event Hubs Data Owner

Allows for full access to Azure Event Hubs resources.

Azure Event Hubs Data Receiver

Allows receive access to Azure Event Hubs resources.

Azure Event Hubs Data Sender

Allows send access to Azure Event Hubs resources.

Azure Service Bus Data Owner

Allows for full access to Azure Service Bus resources.

Azure Service Bus Data Receiver

Allows for receive access to Azure Service Bus resources.

Azure Service Bus Data Sender

Allows for send access to Azure Service Bus resources.

Storage Blob Data Owner

Provides full access to Azure Storage blob containers and data, including assigning POSIX access control.

Storage Blob Data Reader

Read and list Azure Storage containers and blobs.

Storage Queue Data Reader

Read and list Azure Storage queues and queue messages.

Redis Cache Contributor

Manage Redis caches.

When using Spring Cloud Azure Resource Manager to get the connection strings of Event Hubs, Service Bus, and Storage Queue, or properties of Cache for Redis, assign the Azure built-in role Contributor. Azure Cache for Redis is special, and you can also assign the Redis Cache Contributor role to get the Redis properties.
A Key Vault access policy determines whether a given security principal, namely a user, application or user group, can perform different operations on Key Vault secrets, keys, and certificates. You can assign access policies using the Azure portal, the Azure CLI, or Azure PowerShell. Check here for more details.
Azure Cosmos DB exposes 2 built-in role definitions: Cosmos DB Built-in Data Reader and Cosmos DB Built-in Data Contributor. However, Azure portal support for role management isn’t available yet. Check here for more details about the permission model, role definitions, and role assignment.

6.3.2. SAS tokens

It’s also configurable for services support authenticating with Shared Access Signature (SAS). spring.cloud.azure.<azure-service>.sas-token is the property to configure. For example, using spring.cloud.azure.storage.blob.sas-token to authenticate to Storage Blob service.

6.3.3. Connection Strings

Connection strings are supported by some Azure services to provide connection information as well as credentials. To connect to those Azure services using a connection string, just configure spring.cloud.azure.<azure-service>.connection-string will do. For example, spring.cloud.azure.eventhubs.connection-string to connect to Event Hubs service.

7. Production Ready

Spring Cloud Azure 4.0 supports health indicators for App Configuration, Event Hubs, Cosmos, Key Vault Certificate, Key Vault Secret, Storage Blob, Storage Queue, and Storage File Share. It also provides integrations with Spring Cloud Sleuth for all HTTP-based Azure SDKs. As an example, you now can prob if storage blob is up or down via Spring Boot actuator endpoint, as well as track dependencies and latencies going from your application to Key Vault.

7.1. Enable Health Indicator

Add the Spring Cloud Azure Actuator Starter dependency. This dependency will also include the spring-boot-starter-actuator.

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter-actuator</artifactId>
</dependency>
Table 11. Configurable properties to enable or disable health indicators for each Azure service
Azure Service Property

App Configuration

management.health.azure-appconfiguration.enabled

Cosmos DB

management.health.azure-cosmos.enabled

Event Hubs

management.health.azure-eventhubs.enabled

Key Vault Certificate

management.health.azure-keyvault-certificate.enabled

Key Vault Secret

management.health.azure-keyvault-secret.enabled

Storage Blob

management.health.azure-storage-blob.enabled

Storage File Share

management.health.azure-storage-fileshare.enabled

Storage Queue

management.health.azure-storage-queue.enabled

Calling the health endpoint of Azure services may cause extra charge. For example, calling HOST_NAME:{port}/actuator/health/cosmos to get the Cosmos DB health info, it will calculate RUs.

7.2. Enable Sleuth

Add the Spring Cloud Azure Trace Sleuth dependency when you want to trace Azure SDK activities with using Spring Cloud Sleuth.

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-trace-sleuth</artifactId>
</dependency>
Only HTTP-based Azure SDK clients are supported now, for example, Eventhub and ServiceBus with AMQP transport are currently not supported, we recommend to use Azure Application Insights for such requirement.

8. Autoconfigure Azure SDK Clients

Spring Boot simplifies the Spring Cloud Azure development experience. Spring Cloud Azure starters are a set of convenient dependency descriptors to include in your application. They handle the object instantiation and configuration logic, so you don’t have to. Every starter depends on the spring-cloud-azure-starter to provide critical bits of configuration, like the Azure cloud environment and authentication information. You can configure these as properties in, for example, a yaml file:

spring:
  cloud:
    azure:
      profile:
        tenant-id: ${AZURE_TENANT_ID}
        cloud-type: Azure (1)
      credential:
        client-id: ${AZURE_CLIENT_ID}
1 cloud-type is optional for it has default value set to Azure.

These properties are optional and, if not specified, Spring Boot will try to automatically find them for you. For details on how Spring Boot finds these properties, refer to the documentation.

8.1. Dependency Setup

There are two ways to use Spring Cloud Azure starters. One is using Azure SDKs with this spring-cloud-azure-starter dependency. For example with Cosmos DB:

<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-cosmos</artifactId>
</dependency>
<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter</artifactId>
</dependency>

Or including the Spring Cloud Azure starter directly without adding Azure SDK dependencies. For example with Cosmos DB:

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter-cosmos</artifactId>
</dependency>
Please refer to Starter Dependencies for the list of starters Spring Cloud Azure supports.

8.2. Configuration

If you choose to use a security principal to authenticate and authorize with Azure Active Directory for accessing an Azure resource, please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure resource.

Configuration properties for each Azure service are under prefix spring.cloud.azure.<azure-service>.

To see the list of all Spring Cloud Azure related configuration properties please check the Appendix page.

8.3. Basic Usage

Adding below properties to your application.yaml will autoconfigure the Cosmos clients for you, both CosmosClient and CosmosAsyncClient are available in the context and could be autowired.

spring:
  cloud:
    azure:
      cosmos:
        database: ${AZURE_COSMOS_DATABASE_NAME}
        endpoint: ${AZURE_COSMOS_ENDPOINT}
        consistency-level: eventual
        connection-mode: direct
class Demo {
    @Autowired
    private CosmosClient cosmosClient;

    @Override
    public void run() {
        User item = User.randomUser();
        CosmosContainer container = cosmosClient.getDatabase(databaseName).getContainer(containerName);
        container.createItem(item);
    }
}

8.4. Samples

Please refer to azure-spring-boot-samples for more details.

9. Resource Handling

Spring project provides Spring Resources abstraction to access a number of low-level resources. It provides interfaces like Resource, ResourceLoader and ResourcePatternResolver. Spring Cloud Azure implements these interfaces for Azure Storage services which allows you to interact with Azure Storage Blob and File Share using Spring programming model. It provides spring-cloud-azure-starter-storage-blob and spring-cloud-azure-starter-storage-file-share to autoconfigure Azure Storage Blob and Azure Storage File Share.

Table 12. Azure Storage related libraries.
Starter Service Description

spring-cloud-azure-starter-storage-blob

Azure Storage Blob

Allows unstructured data to be stored and accessed at a massive scale in block blobs.

spring-cloud-azure-starter-storage-file-share

Azure Storage File Share

Offers fully managed cloud file shares that you can access from anywhere via the industry standard Server Message Block (SMB) protocol.

9.1. Dependency Setup

<dependencies>
    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-starter-storage-blob</artifactId> (1)
    </dependency>
    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-starter-storage-file-share</artifactId> (2)
    </dependency>
</dependencies>
1 Only required when you’re using Azure Storage Blob.
2 Only required when you’re using Azure Storage File Share.

9.2. Configuration

If you choose to use a security principal to authenticate and authorize with Azure Active Directory for accessing an Azure resource, please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure resource.
Table 13. Configurable properties of spring-cloud-azure-starter-storage-blob
Property Default Description

spring.cloud.azure.storage.blob.enabled

true

Whether to enable Azure Storage Blob.

spring.cloud.azure.storage.blob.endpoint

Endpoint for Azure Storage Blob service.

spring.cloud.azure.storage.blob.account-key

Private key to connect Azure Storage Blob.

spring.cloud.azure.storage.blob.account-name

Azure Storage Blob account name.

Table 14. Configurable properties of spring-cloud-azure-starter-storage-file-share
Property Default Description

spring.cloud.azure.storage.fileshare.enabled

true

Whether to enable Azure Storage File Share.

spring.cloud.azure.storage.fileshare.endpoint

Endpoint for Azure Storage File Share service.

spring.cloud.azure.storage.fileshare.account-key

Private key to connect Azure Storage File Share.

spring.cloud.azure.storage.fileshare.account-name

Azure Storage File Share account name.

9.3. Basic Usage

Provide the properties below in your configuration file.

spring:
  cloud:
    azure:
      storage:
        blob:
          account-name: ${STORAGE_ACCOUNT_NAME}
          account-key: ${STORAGE_ACCOUNT_KEY}
          endpoint: ${STORAGE_BLOB_ENDPOINT}
        fileshare:
          account-name: ${STORAGE_ACCOUNT_NAME}
          account-key: ${STORAGE_ACCOUNT_KEY}
          endpoint:  ${STORAGE_FILESHARE_ENDPOINT}

9.3.1. Get a Resource

Get a Resource with @Value

You can use the annotation of @Value("azure-blob://[your-container-name]/[your-blob-name]") to autowire a blob resource.

@Value("azure-blob://[your-container-name]/[your-blob-name]")
private Resource storageBlobResource;

You can use the annotation of @Value("azure-file://[your-fileshare-name]/[your-file-name]") to autowire a file resource.

@Value("azure-file://[your-fileshare-name]/[your-file-name]")
private Resource storageFileResource;
Get a Resource with ResourceLoader
@Autowired
private ResourceLoader resourceLoader;
...
// get a BlobResource
Resource storageBlobResource = resourceLoader.getResource("azure-blob://[your-container-name]/[your-blob-name]");
// get a FileResource
Resource storageFileResource = resourceLoader.getResource("azure-file://[your-fileshare-name]/[your-file-name]");
Get Resources by Searching Pattern

You can use implementation class of ResourcePatternResolver to search resources. Use AzureStorageBlobProtocolResolver to search blob resources, and AzureStorageFileProtocolResolver to search file resources.

  • Pattern search, the searchPattern should start with azure-blob:// or azure-file://. Such as azure-blob://**/**, it means list all blobs in all containers; azure-blob://demo-container/**, it means list all blobs in the demo-container container, including any sub-folders.

  • Location search, the searchLocation should start with azure-blob:// or azure-file://, the remaining file path should exist, otherwise an exception will be thrown.

@Autowired
private AzureStorageBlobProtocolResolver azureStorageBlobProtocolResolver;

@Autowired
private AzureStorageFileProtocolResolver azureStorageFileProtocolResolver;

// get all text blobs
Resource[] blobTextResources = azureStorageBlobProtocolResolver.getResources("azure-blob://[container-pattern]/*.txt");
// get all text files
Resource[] fileTextResources = azureStorageFileProtocolResolver.getResources("azure-file://[fileshare-pattern]/*.txt");

9.3.2. Handling with Resource

Download Data from Specific Resource

You can download a resource from Azure Stroage Blob or File Share with the getInputStream() method of Resource.

@Value("azure-blob://[your-container-name]/[your-blob-name]")
private Resource storageBlobResource;

@Value("azure-file://[your-fileshare-name]/[your-file-name]")
private Resource storageFileResource;

....

// download data as stream from blob resource
InputStream inputblobStream = storageBlobResource.getInputStream();
// download data as stream from file resource
InputStream inputfileStream = storageFileResource.getInputStream();
Upload Data to Specific Resource

You can upload to a resource to Azure Storage Blob or File Share by casting the Spring Resource to WritableResource.

@Value("azure-blob://[your-container-name]/[your-blob-name]")
private Resource storageBlobResource;

@Value("azure-file://[your-fileshare-name]/[your-file-name]")
private Resource storageFileResource;

String data = "sampledata";

// upload string data to blob
try (OutputStream blobos = ((WritableResource) this.storageBlobResource).getOutputStream()) {
  blobos.write(data.getBytes());
}
// upload string data to file
try (OutputStream fileos = ((WritableResource) this.storageFileResource).getOutputStream()) {
  fileos.write(data.getBytes());
}

9.3.3. Multipart Upload

Files larger than 4 MiB will be uploaded to Azure Storage in parallel.

9.4. Samples

Please refer to storage-blob-sample and storage-file-sample for more details.

10. Secret Management

Spring Cloud Azure construct PropertySource which holds secrets stored in Azure Key Vault Secrets.

10.1. Dependency Setup

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter-keyvault-secrets</artifactId>
</dependency>

10.2. Basic Usage

If you want to authenticate by client-id and client-secret, the following properties are required:

10.2.1. Configuration Properties

spring:
  cloud:
    azure:
      keyvault:
        secret:
          property-sources:
            - name: key-vault-property-souece-1
              endpoint: ${ENDPOINT_1}
            - name: key-vault-property-souece-2
              endpoint: ${ENDPOINT_2}

10.2.2. Java Code

@SpringBootApplication
public class SampleApplication implements CommandLineRunner {

    @Value("${sampleProperty1}")
    private String sampleProperty1;
    @Value("${sampleProperty2}")
    private String sampleProperty2;
    @Value("${samplePropertyInMultipleKeyVault}")
    private String samplePropertyInMultipleKeyVault;

    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }

    public void run(String[] args) {
        System.out.println("sampleProperty1: " + sampleProperty1);
        System.out.println("sampleProperty2: " + sampleProperty2);
        System.out.println("samplePropertyInMultipleKeyVault: " + samplePropertyInMultipleKeyVault);
    }

}

10.3. Advanced Usage

10.3.1. Special Characters in Property Name

Key Vault secret name only support characters in [0-9a-zA-Z-]. Refs: Vault-name and Object-name. If your property name contains other characters, you can use these workarounds:

  • Use - instead of . in secret name. . isn’t supported in secret name. If your application have property name which contains ., like spring.datasource.url, just replace . to - when save secret in Azure Key Vault. For example: Save spring-datasource-url in Azure Key Vault. In your application, you can still use spring.datasource.url to retrieve property value.

This method can not satisfy requirement like spring.datasource-url. When you save spring-datasource-url in Key Vault, only spring.datasource.url and spring-datasource-url is supported to retrieve property value, spring.datasource-url isn’t supported. To handle this case, please refer to the following option: Use property placeholders.
  • Use property placeholders. For example: setting this property in your application.properties: property.with.special.character_=${propertyWithoutSpecialCharacter}. The application will get propertyWithoutSpecialCharacter key name and assign its value to property.with.special.character_.

10.3.2. Case Sensitive

By default, the secret names are case-insensitive. To enable case-sensitive mode, just set the following property: spring.cloud.azure.keyvault.secret.property-sources[].case-sensitive=true.

10.3.3. Not Retrieve All Secrets In Key Vault

If you stored 1000 secrets in the Key Vault, and you just want to use 3 of them. You can list the 3 secret names by spring.cloud.azure.keyvault.secret.property-sources[].secret-keys.

10.3.4. Setting Refresh Interval

By default, the secrets in KeyVaultPropertySource will refresh every 30 minutes. You can configure the time by spring.cloud.azure.keyvault.secret.property-sources[].refresh-interval. For example: spring.cloud.azure.keyvault.secret.property-sources[].refresh-interval=60m means refresh every 60 minutes. Set to 0 to disable auto refresh.

10.3.5. PropertySource Priority

If key exists in multiple PropertySources, which will take effect is decided by the priority.

  • If there is no SystemEnvironmentPropertySource in PropertySource list, then KeyVaultPropertySource will take the highest priority.

  • If there is SystemEnvironmentPropertySource in PropertySource list, then SystemEnvironmentPropertySource have higher priority than KeyVaultPropertySource. Which means you can use environment variable to override the Key Vault secret value in your application.

  • If there are multiple KeyVaultPropertySource in PropertySource list, then the definition order is the priority order. Take above sample as example, key-vault-property-souece-1 has higher priority than key-vault-property-souece-2.

10.3.6. All Configurable Properties

Table 15. Configurable properties of Key Vault Secret PropertySource
Property Default value Description

spring.cloud.azure.keyvault.secret.property-source-enabled

true

Whether to enable the Key Vault property source.

spring.cloud.azure.keyvault.secret.property-sources[].name

Name of this property source.

spring.cloud.azure.keyvault.secret.property-sources[].endpoint

Azure Key Vault endpoint.

spring.cloud.azure.keyvault.secret.property-sources[].case-sensitive

false

Whether the secret keys are case-sensitive.

spring.cloud.azure.keyvault.secret.property-sources[].secret-keys

The secret keys supported for this property source. All keys be retrieved if this property is missing.

spring.cloud.azure.keyvault.secret.property-sources[].refresh-interval

30m

Time interval to refresh all Key Vault secrets.

spring.cloud.azure.keyvault.secret.property-sources[].service-version

Secret service version used when making API requests.

spring.cloud.azure.keyvault.secret.property-sources[].client

Client related properties.

spring.cloud.azure.keyvault.secret.property-sources[].credential

Credential related properties.

spring.cloud.azure.keyvault.secret.property-sources[].profile

Profile related properties.

spring.cloud.azure.keyvault.secret.property-sources[].proxy

Proxy related properties.

spring.cloud.azure.keyvault.secret.property-sources[].retry

Retry related properties.

  • Please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure Key Vault Secrets.

  • If common properties like client, credential, profile, proxy, retry aren’t configured in spring.cloud.azure.keyvault.secret.property-sources[].xxx, spring.cloud.azure.xxx will be used. Please refer to Configuration to get more information about these common properties.

  • Please refer to Configuration Properties to get more information about nested properties.

10.4. Samples

Sample project: property-source.

11. Spring Data Support

11.1. Spring Data CosmosDB Support

Azure Cosmos DB is a globally-distributed database service that allows developers to work with data using a variety of standard APIs, such as SQL, MongoDB, Graph, and Azure Table storage.

11.2. Dependency Setup

<dependency>
   <groupId>com.azure.spring</groupId>
   <artifactId>spring-cloud-azure-starter-data-cosmos</artifactId>
</dependency>

11.3. Configuration

If you choose to use a security principal to authenticate and authorize with Azure Active Directory for accessing an Azure resource, please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure resource.
Table 16. Configurable properties of spring-cloud-azure-starter-data-cosmos
Property Default Description

spring.cloud.azure.cosmos.enabled

true

Whether Azure Cosmos Service is enabled.

spring.cloud.azure.cosmos.database

The Cosmos DB database id.

spring.cloud.azure.cosmos.endpoint

Uri to connect Cosmos DB.

spring.cloud.azure.cosmos.key

Private key to connect Cosmos DB.

spring.cloud.azure.cosmos.credential.client-certificate-password

Password of the certificate file.

spring.cloud.azure.cosmos.credential.client-certificate-path

Path of a PEM certificate file to use when performing service principal authentication with Azure.

spring.cloud.azure.cosmos.credential.client-id

Client id to use when performing service principal authentication with Azure.

spring.cloud.azure.cosmos.credential.client-secret

Client secret to use when performing service principal authentication with Azure.

spring.cloud.azure.cosmos.credential.managed-identity-enabled

Whether to enable managed identity.

spring.cloud.azure.cosmos.credential.password

Password to use when performing username/password authentication with Azure.

spring.cloud.azure.cosmos.credential.username

Username to use when performing username/password authentication with Azure.

spring.cloud.azure.cosmos.populate-query-metrics

false

Populate Diagnostics Strings and Query metrics.

spring.cloud.azure.cosmos.consistency-level

Consistency levels in Azure Cosmos DB.

11.4. Key Concepts

  • Spring Data CrudRepository and ReactiveCrudRepository basic CRUD functionality

    • save

    • findAll

    • findOne by Id

    • deleteAll

    • delete by Id

    • delete entity

  • Spring Data @Id annotation. There’re 2 ways to map a field in domain class to id of Azure Cosmos DB document.

    • annotate a field in domain class with @Id, this field will be mapped to document id in Cosmos DB.

    • set name of this field to id, this field will be mapped to document id in Cosmos DB. [Note] if both way applied,

  • Custom collection Name. By default, collection name will be class name of user domain class. To customize it, add annotation @Document(collection="myCustomCollectionName") to your domain class, that’s all.

  • Supports Azure Cosmos DB partition. To specify a field of your domain class to be partition key field, just annotate it with @PartitionKey. When you do CRUD operation, please specify your partition value. For more sample on partition CRUD, please refer to test here

  • Supports Spring Data custom query find operation.

  • Supports spring-boot-starter-data-rest.

  • Supports List and nested type in domain class.

11.5. Basic Usage

11.5.1. Use Private Key to Access CosmosDB

The simplest way to connect CosmosDB with spring-cloud-azure-starter-data-cosmos is primary key, add below properties, and you are good to go.

spring:
  cloud:
    azure:
      cosmos:
        key: ${AZURE_COSMOS_KEY}
        endpoint: ${AZURE_COSMOS_ENDPOINT}
        database: ${AZURE_COSMOS_DATABASE}

11.5.2. Define an Entity

Define a simple entity as Document in Cosmos DB.

@Container(containerName = "mycollection")
public class User {
    @Id
    private String id;
    private String firstName;
    @PartitionKey
    private String lastName;
    private String address;

    public User() {
    }

    public User(String id, String firstName, String lastName, String address) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.address = address;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return String.format("%s %s, %s", firstName, lastName, address);
    }
}

id field will be used as document id in Azure Cosmos DB. Or you can annotate any field with @Id to map it to document id.

Annotation @Container(containerName = "mycollection") is used to specify the collection name of your document in Azure Cosmos DB.

11.5.3. Create Repositories

Extends ReactiveCosmosRepository interface, which provides Spring Data repository support.

@Repository
public interface UserRepository extends ReactiveCosmosRepository<User, String> {

    Flux<User> findByFirstName(String firstName);
}

So far ReactiveCosmosRepository provides basic save, delete and find operations. More operations will be supported later.

11.5.4. Create an Application Class

Here create an application class with all the components

@SpringBootApplication
public class CosmosSampleApplication implements CommandLineRunner {

   private static final Logger LOGGER = LoggerFactory.getLogger(CosmosSampleApplication.class);

    @Autowired
    private UserRepository repository;

    @Autowired
    private CosmosProperties properties;

    public static void main(String[] args) {
        SpringApplication.run(CosmosSampleApplication.class, args);
    }

    public void run(String... var1) {
        final User testUser = new User("testId", "testFirstName",
                "testLastName", "test address line one");

        // Save the User class to Azure Cosmos DB database.
        final Mono<User> saveUserMono = repository.save(testUser);

        final Flux<User> firstNameUserFlux = repository.findByFirstName("testFirstName");

        //  Nothing happens until we subscribe to these Monos.
        //  findById will not return the user as user is not present.
        final Mono<User> findByIdMono = repository.findById(testUser.getId());
        final User findByIdUser = findByIdMono.block();
        Assert.isNull(findByIdUser, "User must be null");

        final User savedUser = saveUserMono.block();
        Assert.state(savedUser != null, "Saved user must not be null");
        Assert.state(savedUser.getFirstName().equals(testUser.getFirstName()),
                "Saved user first name doesn't match");

        firstNameUserFlux.collectList().block();

        final Optional<User> optionalUserResult = repository.findById(testUser.getId()).blockOptional();
        Assert.isTrue(optionalUserResult.isPresent(), "Cannot find user.");

        final User result = optionalUserResult.get();
        Assert.state(result.getFirstName().equals(testUser.getFirstName()),
                "query result firstName doesn't match!");
        Assert.state(result.getLastName().equals(testUser.getLastName()),
                "query result lastName doesn't match!");
        LOGGER.info("findOne in User collection get result: {}", result.toString());

    }

    @PostConstruct
    public void setup() {
        // For this example, remove all of the existing records.
        this.repository.deleteAll().block();
    }
}

Autowired UserRepository interface, then can do save, delete and find operations.

11.6. Samples

Please refer to azure-spring-boot-samples for more details.

Apart from using the spring-cloud-azure-starter-data-cosmos library, you can directly use azure-spring-data-cosmos library for more complex scenarios. Please refer to Spring Data for Azure Cosmos DB for more details.

12. Spring Security Support

12.1. Spring Security With Azure Active Directory

When you are building a web application, identity and access management will always be foundational pieces.

Azure offers a great platform to democratize your application development journey, as it not only offers a cloud-base identity service, but also deep integration with the rest of the Azure ecosystem.

Spring Security has made it easy to secure your Spring based applications with powerful abstractions and extensible interfaces. However, as powerful as the Spring framework can be, it is not tailored to a specific identity provider.

The spring-cloud-azure-starter-active-directory (aad-starter for short) provides the most optimal way to connect your web application to an Azure Active Directory (AAD for short) tenant and protect resource server with AAD. It uses the Oauth 2.0 protocol to protect web applications and resource servers.

12.1.1. Accessing a Web Application

This scenario uses The OAuth 2.0 authorization code grant flow to log in a user with a Microsoft account.

Create Required Resources in Azure
  1. Read MS docs about register an application with the Microsoft identity platform.

  2. Create app registration. Get AZURE_TENANT_ID, AZURE_CLIENT_ID and AZURE_CLIENT_SECRET.

  3. Set redirect URI to APPLICATION_BASE_URI/login/oauth2/code/, for example localhost:8080/login/oauth2/code/. The tailing / is required.

Add Required Dependencies
<dependencies>
    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-starter-active-directory</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
</dependencies>
Add Required Properties
spring:
  cloud:
    azure:
      active-directory:
        profile:
          tenant-id: ${AZURE_TENANT_ID}
        credential:
          client-id: ${AZURE_CLIENT_ID}
          client-secret: ${AZURE_CLIENT_SECRET}

Now start you application and access your application by browser, then you will be redirected into Microsoft login page.

Advanced Usages
Add Extra Security Configurations
    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class AadOAuth2LoginSecurityConfig extends AadWebSecurityConfigurerAdapter {

        /**
         * Add configuration logic as needed.
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            super.configure(http);
            http.authorizeRequests()
                    .anyRequest().authenticated();
            // Do some custom configuration
        }
    }
Authorize Access by App Roles
If you want to use app role based access control, you can’t put group names in role claim . Refs: Configuring groups optional claims.
  • Step 2: Protect specific method.

class Demo {
    @GetMapping("Admin")
    @ResponseBody
    @PreAuthorize("hasAuthority('APPROLE_Admin')")
    public String admin() {
        return "Admin message";
    }
}
Authorize Access by Group Name Or Group ID
  • Step 1: Add related configuration properties.

spring:
  cloud:
    azure:
      active-directory:
        user-group:
          allowed-group-names: group1_name_1, group2_name_2
          # 1. If allowed-group-ids == all, then all group id will take effect.
          # 2. If "all" is used, we should not configure other group ids.
          # 3. "all" is only supported for allowed-group-ids, not supported for allowed-group-names.
          allowed-group-ids: group_id_1, group_id_2
  • Step 2: Protect specific method.

@Controller
public class RoleController {
    @GetMapping("group1")
    @ResponseBody
    @PreAuthorize("hasRole('ROLE_group1')")
    public String group1() {
        return "group1 message";
    }

    @GetMapping("group2")
    @ResponseBody
    @PreAuthorize("hasRole('ROLE_group2')")
    public String group2() {
        return "group2 message";
    }

    @GetMapping("group1Id")
    @ResponseBody
    @PreAuthorize("hasRole('ROLE_<group1-id>')")
    public String group1Id() {
        return "group1Id message";
    }

    @GetMapping("group2Id")
    @ResponseBody
    @PreAuthorize("hasRole('ROLE_<group2-id>')")
    public String group2Id() {
        return "group2Id message";
    }
}
Use National Azure Instead of Global Azure

Now except global Azure cloud, Azure Active Directory is deployed in the following national clouds:

  • Azure Government

  • Azure China 21Vianet

  • Azure Germany

Here is a sample of you want to use Azure China 21Vianet.

spring:
  cloud:
    azure:
      active-directory:
        base-uri: https://login.partner.microsoftonline.cn
        graph-base-uri: https://microsoftgraph.chinacloudapi.cn

You can refer to these MS doc to get more information from MS docs about National cloud deployments.

Configure Redirect URI Template

Developers can customize the redirect-uri.

redirect-uri

  • Step 1: Add redirect-uri-template properties in application.yml.

spring:
  cloud:
    azure:
      active-directory
        redirect-uri-template: ${REDIRECT-URI-TEMPLATE}
  • Step 2: Update redirect-uri in Azure portal.

web-application-config-redirect-uri

  • Step 3: Update WebSecurityConfigurerAdapter

After we set redirect-uri-template, we need to update WebSecurityConfigurerAdapter:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AadOAuth2LoginSecurityConfig extends AadWebSecurityConfigurerAdapter {
    /**
     * Add configuration logic as needed.
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.oauth2Login()
                .loginProcessingUrl("${REDIRECT-URI-TEMPLATE}")
                .and()
            .authorizeRequests()
                .anyRequest().authenticated();
    }
}
Samples

Sample project: aad-web-application.

12.1.2. Web Application Accessing Resource Servers

Create Required Resources in Azure
  1. Read MS docs about register an application with the Microsoft identity platform.

  2. Create app registration. Get AZURE_TENANT_ID, AZURE_CLIENT_ID and AZURE_CLIENT_SECRET.

  3. Set redirect URI to APPLICATION_BASE_URI/login/oauth2/code/, for example localhost:8080/login/oauth2/code/. The tailing / is required.

Add Required Dependencies
<dependencies>
    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-starter-active-directory</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
</dependencies>
Add Required Properties
spring:
  cloud:
    azure:
      active-directory:
        profile:
          tenant-id: ${AZURE_TENANT_ID}
        credential:
          client-id: ${AZURE_CLIENT_ID}
          client-secret: ${AZURE_CLIENT_SECRET}
        authorization-clients:
          graph:
            scopes: https://graph.microsoft.com/Analytics.Read, email

Here, graph is the name of OAuth2AuthorizedClient, scopes means the scopes need to consent when login.

Use OAuth2AuthorizedClient in Your Application
public class Demo {
    @GetMapping("/graph")
    @ResponseBody
    public String graph(
    @RegisteredOAuth2AuthorizedClient("graph") OAuth2AuthorizedClient graphClient) {
        // toJsonString() is just a demo.
        // oAuth2AuthorizedClient contains access_token. We can use this access_token to access resource server.
        return toJsonString(graphClient);
    }
}

Now start you application and access your application by browser, then you will be redirected into Microsoft login page.

Advanced Usages
Client Credential Flow

The default flow is authorization code flow, if you want to use client credentials flow, you can configure like this:

spring:
  cloud:
    azure:
      active-directory:
        profile:
          tenant-id: ${AZURE_TENANT_ID}
        credential:
          client-id: ${AZURE_CLIENT_ID}
          client-secret: ${AZURE_CLIENT_SECRET}
        authorization-clients:
          graph:
            authorization-grant-type: client_credentials # Change type to client_credentials
            scopes: https://graph.microsoft.com/Analytics.Read, email
Access Multiple Resource Servers

In one web application, you can access multiple resource server by configuring like this:

spring:
  cloud:
    azure:
      active-directory:
        profile:
          tenant-id: ${AZURE_TENANT_ID}
        credential:
          client-id: ${AZURE_CLIENT_ID}
          client-secret: ${AZURE_CLIENT_SECRET}
        authorization-clients:
          resource-server-1:
            scopes: # Scopes for resource-server-1
          resource-server-2:
            scopes: # Scopes for resource-server-2

Then you can use OAuth2AuthorizedClient in application like this

public class Demo {
    @GetMapping("/resource-server-1")
    @ResponseBody
    public String graph(
    @RegisteredOAuth2AuthorizedClient("resource-server-1") OAuth2AuthorizedClient client) {
        return callResourceServer1(client);
    }

    @GetMapping("/resource-server-2")
    @ResponseBody
    public String graph(
    @RegisteredOAuth2AuthorizedClient("resource-server-2") OAuth2AuthorizedClient client) {
        return callResourceServer2(client);
    }
}

In previous sample, all scopes will be consented when customer first login, no matter it’s belong to resource-server-1 or resource-server-2. If you don’t want to let customer consent all scopes, you can do like this:

spring:
  cloud:
    azure:
      active-directory:
        profile:
          tenant-id: ${AZURE_TENANT_ID}
        credential:
          client-id: ${AZURE_CLIENT_ID}
          client-secret: ${AZURE_CLIENT_SECRET}
        authorization-clients:
          resource-server-1:
            scopes: # Scopes for resource-server-1
          resource-server-2:
            on-demand: true  # means incremental consent
            scopes: # Scopes for resource-server-2
Samples

Sample project: aad-web-application.

12.1.3. Accessing a Resource Server

This scenario doesn’t support login, just protect the server by validating the access token. If the access token is valid, the server serves the request.

Add Required Dependencies
<dependencies>
    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-starter-active-directory</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>
</dependencies>
Add Required Properties
spring:
  cloud:
    azure:
      active-directory:
        credential:
          client-id: ${AZURE_CLIENT_ID}

Now start your application and access your application’s web api.

  1. You will get 401 without an access token.

  2. Access your application with an access token, the following claims in access token will be validated:

    • iss: The access token must be issued by Azure AD.

    • nbf: Current time can not before nbf.

    • exp: Current time can not after exp.

    • aud: If spring.cloud.azure.active-directory.credential.client-id or spring.cloud.azure.active-directory.credential.app-id-uri configured, the audience must equal to the configured client-id or app-id-uri. If the 2 properties are not configured, this claim will not be validated.

Refer to MS docs about Microsoft identity platform access tokens to get more information about access token.

Advanced Usages
Add Extra Security Configurations
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AadOAuth2ResourceServerSecurityConfig extends AadResourceServerWebSecurityConfigurerAdapter {
    /**
     * Add configuration logic as needed.
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http.authorizeRequests((requests) -> requests.anyRequest().authenticated());
    }
}
Validate Permission by Scopes
class Demo {
    @GetMapping("scope1")
    @ResponseBody
    @PreAuthorize("hasAuthority('SCOPE_Scope1')")
    public String scope1() {
        return "Congratulations, you can access `scope1` endpoint.";
    }
}

By doing this, when access /scope1 endpoint, the following claims in access token will be validated:

  • scp: The value must contains Scope1.

Validate Permission by App Roles
class Demo {
    @GetMapping("app-role1")
    @ResponseBody
    @PreAuthorize("hasAuthority('APPROLE_AppRole1')")
    public String appRole1() {
        return "Congratulations, you can access `app-role1` endpoint.";
    }
}

By doing this, when access /app-role1 endpoint, the following claims in access token will be validated:

  • roles: The value must contains AppRole1.

Samples

Sample project: aad-resource-server.

12.1.4. Resource Server Visiting Other Resource Servers

Create Required Resources in Azure
  1. Read MS docs about register an application with the Microsoft identity platform.

  2. Create app registration. Get AZURE_TENANT_ID, AZURE_CLIENT_ID and AZURE_CLIENT_SECRET.

Add Required Dependencies
<dependencies>
    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-starter-active-directory</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
</dependencies>
Add Required Properties
spring:
  cloud:
    azure:
      active-directory:
        profile:
          tenant-id: ${AZURE_TENANT_ID}
        credential:
          client-id: ${AZURE_CLIENT_ID}
          client-secret: ${AZURE_CLIENT_SECRET}
        authorization-clients:
          graph:
            scopes:
              - https://graph.microsoft.com/User.Read
Use OAuth2AuthorizedClient in Your Application
public class SampleController {
    @GetMapping("call-graph")
    public String callGraph(@RegisteredOAuth2AuthorizedClient("graph") OAuth2AuthorizedClient graph) {
        return callMicrosoftGraphMeEndpoint(graph);
    }
}
Samples

Sample project: aad-resource-server-obo.

12.1.5. Web Application and Resource Server in One Application

Create Required Resources in Azure
  1. Read MS docs about register an application with the Microsoft identity platform.

  2. Create app registration. Get AZURE_TENANT_ID, AZURE_CLIENT_ID and AZURE_CLIENT_SECRET.

Add Required Dependencies
<dependencies>
    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-starter-active-directory</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
</dependencies>
Add Required Properties

Set property spring.cloud.azure.active-directory.application-type to web_application_and_resource_server, and specify the authorization type for each authorization client.

spring:
  cloud:
    azure:
      active-directory:
        profile:
          tenant-id: ${AZURE_TENANT_ID}
        credential:
          client-id: ${AZURE_CLIENT_ID}
          client-secret: ${AZURE_CLIENT_SECRET}
        app-id-uri: ${WEB_API_ID_URI}
        application-type: web_application_and_resource_server  # This is required.
        authorization-clients:
          graph:
            authorizationGrantType: authorization_code # This is required.
            scopes:
              - https://graph.microsoft.com/User.Read
              - https://graph.microsoft.com/Directory.Read.All
Define SecurityConfigurationAdapter

Configure multiple HttpSecurity instances, AadWebApplicationAndResourceServerConfig contain two security configurations for resource server and web application.

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AadWebApplicationAndResourceServerConfig {

    @Order(1)
    @Configuration
    public static class ApiWebSecurityConfigurationAdapter extends AadResourceServerWebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity http) throws Exception {
            super.configure(http);
            // All the paths that match `/api/**`(configurable) work as `Resource Server`, other paths work as `Web application`.
            http.antMatcher("/api/**")
                .authorizeRequests().anyRequest().authenticated();
        }
    }

    @Configuration
    public static class HtmlWebSecurityConfigurerAdapter extends AadWebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            super.configure(http);
            // @formatter:off
            http.authorizeRequests()
                    .antMatchers("/login").permitAll()
                    .anyRequest().authenticated();
            // @formatter:on
        }
    }
}

12.1.6. Configuration

Table 17. Configurable properties of spring-cloud-azure-starter-active-directory
Name Default Description

spring.cloud.azure.active-directory.app-id-uri

App ID URI which might be used in the "aud" claim of an id_token.

spring.cloud.azure.active-directory.application-type

Type of the AAD application.

spring.cloud.azure.active-directory.authenticate-additional-parameters

Add additional parameters to the Authorization URL.

spring.cloud.azure.active-directory.authorization-clients

The OAuth2 authorization clients.

spring.cloud.azure.active-directory.credential.client-id

Client id to use when performing service principal authentication with Azure.

spring.cloud.azure.active-directory.credential.client-secret

Client secret to use when performing service principal authentication with Azure.

spring.cloud.azure.active-directory.jwk-set-cache-lifespan

5

The lifespan of the cached JWK set before it expires, default is 5 minutes.

spring.cloud.azure.active-directory.jwk-set-cache-refresh-time

5

The refresh time of the cached JWK set before it expires, default is 5 minutes.

spring.cloud.azure.active-directory.jwt-connect-timeout

Connection Timeout for the JWKSet Remote URL call.

spring.cloud.azure.active-directory.jwt-read-timeout

Read Timeout for the JWKSet Remote URL call.

spring.cloud.azure.active-directory.jwt-size-limit

Size limit in Bytes of the JWKSet Remote URL call.

spring.cloud.azure.active-directory.post-logout-redirect-uri

The redirect uri after logout.

spring.cloud.azure.active-directory.profile.cloud-type

Name of the Azure cloud to connect to. Supported types are: AZURE, AZURE_CHINA, AZURE_GERMANY, AZURE_US_GOVERNMENT, OTHER.

spring.cloud.azure.active-directory.profile.environment

Properties to Azure Active Directory endpoints.

spring.cloud.azure.active-directory.profile.tenant-id

Azure Tenant ID.

spring.cloud.azure.active-directory.redirect-uri-template

{baseUrl}/login/oauth2/code/

Redirection Endpoint: Used by the authorization server to return responses containing authorization credentials to the client via the resource owner user-agent.

spring.cloud.azure.active-directory.resource-server.claim-to-authority-prefix-map

Configure which claim will be used to build GrantedAuthority, and prefix of the GrantedAuthority’s string value. Default value is: "scp" → "SCOPE_", "roles" → "APPROLE_".

spring.cloud.azure.active-directory.resource-server.principal-claim-name

Configure which claim in access token be returned in AuthenticatedPrincipal#getName. Default value is "sub".

spring.cloud.azure.active-directory.session-stateless

false

If true activates the stateless auth filter AadAppRoleStatelessAuthenticationFilter. The default is false which activates AadAuthenticationFilter.

spring.cloud.azure.active-directory.user-group.allowed-group-ids

The group ids can be used to construct GrantedAuthority.

spring.cloud.azure.active-directory.user-group.allowed-group-names

The group names can be used to construct GrantedAuthority.

spring.cloud.azure.active-directory.user-group.use-transitive-members

false

If "true", use "v1.0/me/transitiveMemberOf" to get members. Otherwise, use "v1.0/me/memberOf".

spring.cloud.azure.active-directory.user-name-attribute

Decide which claim to be principal’s name.

Here are some examples about how to use these properties:

Application Type

THe application type can be inferred from the dependencies: spring-security-oauth2-client or spring-security-oauth2-resource-server. If the inferred value is not the value you want, you can specify the application type. Here is the table about valid values and inferred value:

Table 18. Application type of spring-cloud-azure-starter-active-directory
Has dependency: spring-security-oauth2-client Has dependency: spring-security-oauth2-resource-server Valid values of application type Inferred value

Yes

No

web_application

web_application

No

Yes

resource_server

resource_server

Yes

Yes

web_application, resource_server, resource_server_with_obo, web_application_and_resource_server

resource_server_with_obo

12.2. Spring Security With Azure Active Directory B2C

Azure Active Directory (Azure AD) B2C is an identity management service that enables you to customize and control how customers sign up, sign in, and manage their profiles when using your applications. Azure AD B2C enables these actions while protecting the identities of your customers at the same time.

12.2.1. Dependency Setup

<dependencies>
    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-starter-active-directory-b2c</artifactId>
    </dependency>
</dependencies>

12.2.2. Configuration

Table 19. Configurable properties of spring-cloud-azure-starter-active-directory-b2c
Name Default Description

spring.cloud.azure.active-directory.b2c.app-id-uri

App ID URI which might be used in the "aud" claim of a token.

spring.cloud.azure.active-directory.b2c.authenticate-additional-parameters

Additional parameters for authentication.

spring.cloud.azure.active-directory.b2c.authorization-clients

Specify client configuration.

spring.cloud.azure.active-directory.b2c.base-uri

AAD B2C endpoint base uri.

spring.cloud.azure.active-directory.b2c.credential

AAD B2C credential information.

spring.cloud.azure.active-directory.b2c.jwt-connect-timeout

Connection Timeout for the JWKSet Remote URL call.

spring.cloud.azure.active-directory.b2c.jwt-read-timeout

Read Timeout for the JWKSet Remote URL call.

spring.cloud.azure.active-directory.b2c.jwt-size-limit

Size limit in Bytes of the JWKSet Remote URL call.

spring.cloud.azure.active-directory.b2c.login-flow

sign-up-or-sign-in

Specify the primary sign-in flow key.

spring.cloud.azure.active-directory.b2c.logout-success-url

localhost:8080/login

Redirect url after logout.

spring.cloud.azure.active-directory.b2c.profile

AAD B2C profile information.

spring.cloud.azure.active-directory.b2c.reply-url

{baseUrl}/login/oauth2/code/

Reply url after get authorization code.

spring.cloud.azure.active-directory.b2c.user-flows

User flows.

spring.cloud.azure.active-directory.b2c.user-name-attribute-name

User name attribute name.

For full configurations, check the Appendix page.

12.2.3. Basic Usage

A web application is any web based application that allows user to login Azure AD, whereas a resource server will either accept or deny access after validating access_token obtained from Azure AD. We will cover 4 scenarios in this guide:

  1. Accessing a web application.

  2. Web application accessing resource servers.

  3. Accessing a resource server.

  4. Resource server accessing other resource servers.

B2C Web application & Web Api Overall

Usage 1: Accessing a Web Application

This scenario uses The OAuth 2.0 authorization code grant flow to log in a user with your Azure AD B2C user.

  • Step 1: Select Azure AD B2C from the portal menu, click Applications, and then click Add.

  • Step 2: Specify your application Name, we call it webapp, add localhost:8080/login/oauth2/code/ for the Reply URL, record the Application ID as your WEB_APP_AZURE_CLIENT_ID and then click Save.

  • Step 3: Select Keys from your application, click Generate key to generate WEB_APP_AZURE_CLIENT_SECRET and then Save.

  • Step 4: Select User flows on your left, and then Click New user flow.

  • Step 5: Choose Sign up or in, Profile editing and Password reset to create user flows respectively. Specify your user flow Name and User attributes and claims, click Create.

  • Step 6: Select API permissions > Add a permission > Microsoft APIs, select Microsoft Graph, select Delegated permissions, check offline_access and openid permissions, select Add permission to complete the process.

  • Step 7: Grant admin consent for Graph permissions. Add Graph permissions

  • Step 8: Add the following dependencies in your pom.xml.

<dependencies>
    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>azure-spring-boot-starter-active-directory-b2c</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity5</artifactId>
    </dependency>
</dependencies>
  • Step 9: Add properties in application.yml using the values you created earlier, for example:

spring:
  cloud:
    azure:
      active-directory:
        b2c:
          authenticate-additional-parameters:
            domain_hint: xxxxxxxxx         # optional
            login_hint: xxxxxxxxx          # optional
            prompt: [login,none,consent]   # optional
          base-uri: ${BASE_URI}
          credential:
            client-id: ${WEBAPP_AZURE_CLIENT_ID}
            client-secret: ${WEBAPP_AZURE_CLIENT_SECRET}
          login-flow: ${LOGIN_USER_FLOW_KEY}               # default to sign-up-or-sign-in, will look up the user-flows map with provided key.
          logout-success-url: ${LOGOUT_SUCCESS_URL}
          user-flows:
            ${YOUR_USER_FLOW_KEY}: ${USER_FLOW_NAME}
          user-name-attribute-name: ${USER_NAME_ATTRIBUTE_NAME}
  • Step 10: Write your Java code.

Controller code can refer to the following:

@Controller
public class WebController {

    private void initializeModel(Model model, OAuth2AuthenticationToken token) {
        if (token != null) {
            final OAuth2User user = token.getPrincipal();
            model.addAllAttributes(user.getAttributes());
            model.addAttribute("grant_type", user.getAuthorities());
            model.addAttribute("name", user.getName());
        }
    }

    @GetMapping(value = { "/", "/home" })
    public String index(Model model, OAuth2AuthenticationToken token) {
        initializeModel(model, token);
        return "home";
    }
}

Security configuration code can refer to the following:

@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final AadB2cOidcLoginConfigurer configurer;

    public WebSecurityConfiguration(AadB2cOidcLoginConfigurer configurer) {
        this.configurer == configurer;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .apply(configurer);
        // @formatter:off
    }
}

Copy the home.html from aad-b2c-web-application sample, and replace the PROFILE_EDIT_USER_FLOW and PASSWORD_RESET_USER_FLOW with your user flow name respectively that completed earlier.

  • Step 11: Build and test your app

Let Webapp run on port 8080.

  1. After your application is built and started by Maven, open localhost:8080/ in a web browser; you should be redirected to login page.

  2. Click link with the login user flow, you should be redirected Azure AD B2C to start the authentication process.

  3. After you have logged in successfully, you should see the sample home page from the browser.

Usage 2: Web Application Accessing Resource Servers

This scenario is based on Accessing a web application scenario to allow application to access other resources, that is [The OAuth 2.0 client credentials grant] flow.

  • Step 1: Select Azure AD B2C from the portal menu, click Applications, and then click Add.

  • Step 2: Specify your application Name, we call it webApiA, record the Application ID as your WEB_API_A_AZURE_CLIENT_ID and then click Save.

  • Step 3: Select Keys from your application, click Generate key to generate WEB_API_A_AZURE_CLIENT_SECRET and then Save.

  • Step 4: Select Expose an API on your left, and then Click the Set link, record the Application ID URI as your WEB_API_A_APP_ID_URL, then Save.

  • Step 5: Select Manifest on your left, and then paste the below json segment into appRoles array, record the Application ID URI as your WEB_API_A_APP_ID_URL, record the value of the app role as your WEB_API_A_ROLE_VALUE, then save.

{
  "allowedMemberTypes": [
    "Application"
  ],
  "description": "WebApiA.SampleScope",
  "displayName": "WebApiA.SampleScope",
  "id": "04989db0-3efe-4db6-b716-ae378517d2b7",
  "isEnabled": true,
  "value": "WebApiA.SampleScope"
}

Configure WebApiA appRoles

  • Step 6: Select API permissions > Add a permission > My APIs, select WebApiA application name, select Application Permissions, select WebApiA.SampleScope permission, select Add permission to complete the process.

  • Step 7: Grant admin consent for WebApiA permissions. Add WebApiA permission

  • Step 8: Add the following dependency on the basis of Accessing a web application scenario.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
  • Step 9: Add the following configuration on the basis of Accessing a web application scenario.

spring:
  cloud:
    azure:
      active-directory:
        b2c:
          base-uri: ${BASE_URI}             # Such as: https://xxxxb2c.b2clogin.com
          profile:
            tenant-id: ${AZURE_TENANT_ID}
          authorization-clients:
            ${RESOURCE_SERVER_A_NAME}:
              authorization-grant-type: client_credentials
              scopes: ${WEB_API_A_APP_ID_URL}/.default
  • Step 10: Write your Webapp Java code.

Controller code can refer to the following:

class Demo {
    /**
     * Access to protected data from Webapp to WebApiA through client credential flow. The access token is obtained by webclient, or
     * <p>@RegisteredOAuth2AuthorizedClient("webApiA")</p>. In the end, these two approaches will be executed to
     * DefaultOAuth2AuthorizedClientManager#authorize method, get the access token.
     *
     * @return Respond to protected data from WebApi A.
     */
    @GetMapping("/webapp/webApiA")
    public String callWebApiA() {
        String body = webClient
            .get()
            .uri(LOCAL_WEB_API_A_SAMPLE_ENDPOINT)
            .attributes(clientRegistrationId("webApiA"))
            .retrieve()
            .bodyToMono(String.class)
            .block();
        LOGGER.info("Call callWebApiA(), request '/webApiA/sample' returned: {}", body);
        return "Request '/webApiA/sample'(WebApi A) returned a " + (body != null ? "success." : "failure.");
    }
}

Security configuration code is the same with Accessing a web application scenario, another bean webClient is added as follows:

public class SampleConfiguration {
    @Bean
    public WebClient webClient(OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager) {
        ServletOAuth2AuthorizedClientExchangeFilterFunction function =
            new ServletOAuth2AuthorizedClientExchangeFilterFunction(oAuth2AuthorizedClientManager);
        return WebClient.builder()
                        .apply(function.oauth2Configuration())
                        .build();
    }
}
  • Step 11: Please refer to Accessing a resource server section to write your WebApiA Java code.

  • Step 12: Build and test your app

Let Webapp and WebApiA run on port 8080 and 8081 respectively. Start Webapp and WebApiA application, return to the home page after logging successfully, you can access localhost:8080/webapp/webApiA to get WebApiA resource response.

Usage 3: Accessing a Resource Server

This scenario not support login. Just protect the server by validating the access token, and if valid, serves the request.

<dependencies>
    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>azure-spring-boot-starter-active-directory-b2c</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
  • Step 4: Add the following configuration.

spring:
  cloud:
    azure:
      active-directory:
        b2c:
          base-uri: ${BASE_URI}             # Such as: https://xxxxb2c.b2clogin.com
          profile:
            tenant-id: ${AZURE_TENANT_ID}
          app-id-uri: ${APP_ID_URI}         # If you are using v1.0 token, please configure app-id-uri for `aud` verification
          credential:
            client-id: ${AZURE_CLIENT_ID}           # If you are using v2.0 token, please configure client-id for `aud` verification
  • Step 5: Write your Java code.

Controller code can refer to the following:

class Demo {
    /**
     * webApiA resource api for web app
     * @return test content
     */
    @PreAuthorize("hasAuthority('APPROLE_WebApiA.SampleScope')")
    @GetMapping("/webApiA/sample")
    public String webApiASample() {
        LOGGER.info("Call webApiASample()");
        return "Request '/webApiA/sample'(WebApi A) returned successfully.";
    }
}

Security configuration code can refer to the following:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests((requests) -> requests.anyRequest().authenticated())
            .oauth2ResourceServer()
            .jwt()
            .jwtAuthenticationConverter(new AadJwtBearerTokenAuthenticationConverter());
    }
}
  • Step 6: Build and test your app

Let WebApiA run on port 8081. Get the access token for webApiA resource and access localhost:8081/webApiA/sample as the Bearer authorization header.

Usage 4: Resource Server Accessing Other Resource Servers

This scenario is an upgrade of Accessing a resource server, supports access to other application resources, based on OAuth2 client credentials flow.

  • Step 1: Referring to the previous steps, we create a WebApiB application and expose an application permission WebApiB.SampleScope.

{
    "allowedMemberTypes": [
        "Application"
    ],
    "description": "WebApiB.SampleScope",
    "displayName": "WebApiB.SampleScope",
    "id": "04989db0-3efe-4db6-b716-ae378517d2b7",
    "isEnabled": true,
    "lang": null,
    "origin": "Application",
    "value": "WebApiB.SampleScope"
}

Configure WebApiB appRoles

  • Step 2: Grant admin consent for WebApiB permissions. Add WebApiB permission

  • Step 3: On the basis of Accessing a resource server, add a dependency in your pom.xml.

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
  • Step 4: Add the following configuration on the basis of Accessing a resource server scenario configuration.

spring:
  cloud:
    azure:
      active-directory:
        b2c:
          credential:
            client-secret: ${WEB_API_A_AZURE_CLIENT_SECRET}
          authorization-clients:
            ${RESOURCE_SERVER_B_NAME}:
              authorization-grant-type: client_credentials
              scopes: ${WEB_API_B_APP_ID_URL}/.default
  • Step 5: Write your Java code.

WebApiA controller code can refer to the following:

public class SampleController {
    /**
     * Access to protected data from WebApiA to WebApiB through client credential flow. The access token is obtained by webclient, or
     * <p>@RegisteredOAuth2AuthorizedClient("webApiA")</p>. In the end, these two approaches will be executed to
     * DefaultOAuth2AuthorizedClientManager#authorize method, get the access token.
     *
     * @return Respond to protected data from WebApi B.
     */
    @GetMapping("/webApiA/webApiB/sample")
    @PreAuthorize("hasAuthority('APPROLE_WebApiA.SampleScope')")
    public String callWebApiB() {
        String body = webClient
            .get()
            .uri(LOCAL_WEB_API_B_SAMPLE_ENDPOINT)
            .attributes(clientRegistrationId("webApiB"))
            .retrieve()
            .bodyToMono(String.class)
            .block();
        LOGGER.info("Call callWebApiB(), request '/webApiB/sample' returned: {}", body);
        return "Request 'webApiA/webApiB/sample'(WebApi A) returned a " + (body != null ? "success." : "failure.");
    }
}

WebApiB controller code can refer to the following:

public class SampleController {
    /**
     * webApiB resource api for other web application
     * @return test content
     */
    @PreAuthorize("hasAuthority('APPROLE_WebApiB.SampleScope')")
    @GetMapping("/webApiB/sample")
    public String webApiBSample() {
        LOGGER.info("Call webApiBSample()");
        return "Request '/webApiB/sample'(WebApi B) returned successfully.";
    }
}

Security configuration code is the same with Accessing a resource server scenario, another bean webClient is added as follows

public class SampleConfiguration {
    @Bean
    public WebClient webClient(OAuth2AuthorizedClientManager oAuth2AuthorizedClientManager) {
        ServletOAuth2AuthorizedClientExchangeFilterFunction function =
            new ServletOAuth2AuthorizedClientExchangeFilterFunction(oAuth2AuthorizedClientManager);
        return WebClient.builder()
                        .apply(function.oauth2Configuration())
                        .build();
    }
}
  • Step 6: Build and test your app

Let WebApiA and WebApiB run on port 8081 and 8082 respectively. Start WebApiA and WebApiB application, get the access token for webApiA resource and access localhost:8081/webApiA/webApiB/sample as the Bearer authorization header.

13. Spring Integration Support

Spring Integration Extension for Azure provides Spring Integration adapters for the various services provided by the Azure SDK for Java. We provide Spring Integration support for these Azure services: Event Hubs, Service Bus, Storage Queue. Below is a list of supported adapters:

  • spring-cloud-azure-starter-integration-eventhubs

  • spring-cloud-azure-starter-integration-servicebus

  • spring-cloud-azure-starter-integration-storage-queue

13.1. Spring Integration with Azure Event Hubs

13.1.1. Key Concepts

Azure Event Hubs is a big data streaming platform and event ingestion service. It can receive and process millions of events per second. Data sent to an event hub can be transformed and stored by using any real-time analytics provider or batching/storage adapters.

Spring Integration enables lightweight messaging within Spring-based applications and supports integration with external systems via declarative adapters. Those adapters provide a higher-level of abstraction over Spring’s support for remoting, messaging, and scheduling. The Spring Integration for Event Hubs extension project provides inbound and outbound channel adapters and gateways for Azure Event Hubs.

RxJava support APIs are dropped from version 4.0.0. Please refer to Javadoc for details.
Consumer Group

Event Hubs provides similar support of consumer group as Apache Kafka, but with slight different logic. While Kafka stores all committed offsets in the broker, you have to store offsets of Event Hubs messages being processed manually. Event Hubs SDK provides the function to store such offsets inside Azure Storage.

Partitioning Support

Event Hubs provides a similar concept of physical partition as Kafka. But unlike Kafka’s auto re-balancing between consumers and partitions, Event Hubs provides a kind of preemptive mode. The storage account acts as a lease to determine which partition is owned by which consumer. When a new consumer starts, it will try to steal some partitions from most heavy-loaded consumers to achieve the workload balancing.

To specify the load balancing strategy, developers can use EventHubsContainerProperties for the configuration. See the below section for an example of how to configure EventHubsContainerProperties.

Batch Consumer Support

The EventHubsInboundChannelAdapter supports the batch-consuming mode. To enable it, users can specify the listener mode as ListenerMode.BATCH when constructing an EventHubsInboundChannelAdapter instance. When enabled, an Message of which the payload is a list of batched events will be received and passed to the downstream channel. Each message header is also converted as a list, of which the content is the associated header value parsed from each event. For the communal headers of partition id, checkpointer and last enqueued properties, they are presented as a single value for the entire batch of events shares the same one. See Event Hubs Message Headers for more details.

The checkpoint header only exists when MANUAL checkpoint mode is used.

Checkpointing of batch consumer supports two modes: BATCH and MANUAL. BATCH mode is an auto checkpointing mode to checkpoint the entire batch of events together once they are received. MANUAL mode is to checkpoint the events by users. When used, the Checkpointer will be passed into the message header, and users could use it to do checkpointing.

The batch consuming policy can be specified by properties of max-size and max-wait-time, where max-size is a necessary property while max-wait-time is optional. To specify the batch consuming strategy, developers can use EventHubsContainerProperties for the configuration. See the below section for an example of how to configure EventHubsContainerProperties.

13.1.2. Dependency Setup

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter-integration-eventhubs</artifactId>
</dependency>

13.1.3. Configuration

This starter provides the following 3 parts of configuration options:

Connection Configuration Properties

This section contains the configuration options used for connecting to Azure Event Hubs.

If you choose to use a security principal to authenticate and authorize with Azure Active Directory for accessing an Azure resource, please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure resource.
Table 20. Connection configurable properties of spring-cloud-azure-starter-integration-eventhubs
Property Type Description

spring.cloud.azure.eventhubs.enabled

boolean

Whether an Azure Event Hubs is enabled.

spring.cloud.azure.eventhubs.connection-string

String

Event Hubs Namespace connection string value.

spring.cloud.azure.eventhubs.namespace

String

Event Hubs Namespace value, which is the prefix of the FQDN. A FQDN should be composed of <NamespaceName>.<DomainName>

spring.cloud.azure.eventhubs.domain-name

String

Domain name of an Azure Event Hubs Namespace value.

spring.cloud.azure.eventhubs.custom-endpoint-address

String

Custom Endpoint address.

spring.cloud.azure.eventhubs.shared-connection

Boolean

Whether the underlying EventProcessorClient and EventHubProducerAsyncClient use the same connection. By default, a new connection is constructed and used created for each Event Hub client created.

Checkpoint Configuration Properties

This section contains the configuration options for the Storage Blobs service, which is used for persisting partition ownership and checkpoint information.

From version 4.0.0, when the property of spring.cloud.azure.eventhubs.processor.checkpoint-store.create-container-if-not-exists is not enabled manually, no Storage container will be created automatically.
Table 21. Checkpointing configurable properties of spring-cloud-azure-starter-integration-eventhubs
Property Type Description

spring.cloud.azure.eventhubs.processor.checkpoint-store.create-container-if-not-exists

Boolean

Whether to allow creating containers if not exists.

spring.cloud.azure.eventhubs.processor.checkpoint-store.account-name

String

Name for the storage account.

spring.cloud.azure.eventhubs.processor.checkpoint-store.account-key

String

Storage account access key.

spring.cloud.azure.eventhubs.processor.checkpoint-store.container-name

String

Storage container name.

Common Azure Service SDK configuration options are configurable for Storage Blob checkpoint store as well. The supported configuration options are introduced in the Configuration page, and could be configured with either the unified prefix spring.cloud.azure. or the prefix of spring.cloud.azure.eventhubs.processor.checkpoint-store.

Event Hub Processor Configuration Properties

The EventHubsInboundChannelAdapter uses the EventProcessorClient to consume messages from an event hub, to configure the overall properties of an EventProcessorClient, developers can use EventHubsContainerProperties for the configuration. See the below section about how to work with EventHubsInboundChannelAdapter.

13.1.4. Basic Usage

Send messages to Azure Event Hubs

Step 1. Fill the credential configuration options.

  • For credentials as connection string, configure below properties in application.yml:

spring:
  cloud:
    azure:
      eventhubs:
        connection-string: ${AZURE_SERVICE_BUS_CONNECTION_STRING}
        processor:
          checkpoint-store:
            container-name: ${CHECKPOINT-CONTAINER}
            account-name: ${CHECKPOINT-STORAGE-ACCOUNT}
            account-key: ${CHECKPOINT-ACCESS-KEY}
  • For credentials as managed identities, configure below properties in application.yml:

spring:
  cloud:
    azure:
      credential:
        managed-identity-enabled: true
        client-id: ${AZURE_CLIENT_ID}
      eventhubs:
        namespace: ${AZURE_SERVICE_BUS_NAMESPACE}
        processor:
          checkpoint-store:
            container-name: ${CONTAINER_NAME}
            account-name: ${ACCOUNT_NAME}
  • For credentials as service principal, configure below properties in application.yml:

spring:
  cloud:
    azure:
      credential:
        client-id: ${AZURE_CLIENT_ID}
        client-secret: ${AZURE_CLIENT_SECRET}
      profile:
        tenant-id: ${AZURE_TENANT_ID}
      eventhubs:
        namespace: ${AZURE_SERVICE_BUS_NAMESPACE}
        processor:
          checkpoint-store:
            container-name: ${CONTAINER_NAME}
            account-name: ${ACCOUNT_NAME}

Step 2. Create DefaultMessageHandler with the bean of EventHubsTemplate to send messages to Event Hubs.

class Demo {
    private static final String OUTPUT_CHANNEL = "output";
    private static final String EVENTHUB_NAME = "eh1";

    @Bean
    @ServiceActivator(inputChannel = OUTPUT_CHANNEL)
    public MessageHandler messageSender(EventHubsTemplate eventHubsTemplate) {
        DefaultMessageHandler handler = new DefaultMessageHandler(EVENTHUB_NAME, eventHubsTemplate);
        handler.setSendCallback(new ListenableFutureCallback<Void>() {
            @Override
            public void onSuccess(Void result) {
                LOGGER.info("Message was sent successfully.");
            }
            @Override
            public void onFailure(Throwable ex) {
                LOGGER.error("There was an error sending the message.", ex);
            }
        });
        return handler;
    }
}

Step 3. Create a message gateway binding with the above message handler via a message channel.

class Demo {
    @Autowired
    EventHubOutboundGateway messagingGateway;

    @MessagingGateway(defaultRequestChannel = OUTPUT_CHANNEL)
    public interface EventHubOutboundGateway {
        void send(String text);
    }
}

Step 4. Send messages using the gateway.

class Demo {
    public void demo() {
        this.messagingGateway.send(message);
    }
}
Receive Messages from Azure Event Hubs

Step 1. Fill the credential configuration options.

Step 2. Create a bean of message channel as the input channel.

@Configuration
class Demo {
    @Bean
    public MessageChannel input() {
        return new DirectChannel();
    }
}

Step 3. Create EventHubsInboundChannelAdapter with the bean of EventHubsMessageListenerContainer to receive messages from Event Hubs.

@Configuration
class Demo {
    private static final String INPUT_CHANNEL = "input";
    private static final String EVENTHUB_NAME = "eh1";
    private static final String CONSUMER_GROUP = "$Default";

    @Bean
    public EventHubsInboundChannelAdapter messageChannelAdapter(
            @Qualifier(INPUT_CHANNEL) MessageChannel inputChannel,
            EventHubsMessageListenerContainer listenerContainer) {
        EventHubsInboundChannelAdapter adapter = new EventHubsInboundChannelAdapter(processorContainer);
        adapter.setOutputChannel(inputChannel);
        return adapter;
    }

    @Bean
    public EventHubsMessageListenerContainer messageListenerContainer(EventHubsProcessorFactory processorFactory) {
        EventHubsContainerProperties containerProperties = new EventHubsContainerProperties();
        containerProperties.setEventHubName(EVENTHUB_NAME);
        containerProperties.setConsumerGroup(CONSUMER_GROUP);
        containerProperties.setCheckpointConfig(new CheckpointConfig(CheckpointMode.MANUAL));
        return new EventHubsMessageListenerContainer(processorFactory, containerProperties);
    }
}

Step 4. Create a message receiver binding with EventHubsInboundChannelAdapter via the message channel created before.

class Demo {
    @ServiceActivator(inputChannel = INPUT_CHANNEL)
    public void messageReceiver(byte[] payload, @Header(AzureHeaders.CHECKPOINTER) Checkpointer checkpointer) {
        String message = new String(payload);
        LOGGER.info("New message received: '{}'", message);
        checkpointer.success()
                .doOnSuccess(s -> LOGGER.info("Message '{}' successfully checkpointed", message))
                .doOnError(e -> LOGGER.error("Error found", e))
                .block();
    }
}
Configure EventHubsMessageConverter to Customize ObjectMapper

EventHubsMessageConverter is made as a configurable bean to allow users to customize ObjectMapper.

Batch Consumer Support

To consume messages from Event Hubs in batches is similar with the above sample, besides users should set the batch-consuming related configuration options for EventHubsInboundChannelAdapter.

When create EventHubsInboundChannelAdapter, the listener mode should be set as BATCH. When create bean of EventHubsMessageListenerContainer, set the checkpoint mode as either MANUAL or BATCH, and the batch options can be configured as needed.

@Configuration
class Demo {
    private static final String INPUT_CHANNEL = "input";
    private static final String EVENTHUB_NAME = "eh1";
    private static final String CONSUMER_GROUP = "$Default";

    @Bean
    public EventHubsInboundChannelAdapter messageChannelAdapter(
            @Qualifier(INPUT_CHANNEL) MessageChannel inputChannel,
            EventHubsMessageListenerContainer listenerContainer) {
        EventHubsInboundChannelAdapter adapter = new EventHubsInboundChannelAdapter(processorContainer, ListenerMode.BATCH);
        adapter.setOutputChannel(inputChannel);
        return adapter;
    }

    @Bean
    public EventHubsMessageListenerContainer messageListenerContainer(EventHubsProcessorFactory processorFactory) {
        EventHubsContainerProperties containerProperties = new EventHubsContainerProperties();
        containerProperties.setEventHubName(EVENTHUB_NAME);
        containerProperties.setConsumerGroup(CONSUMER_GROUP);
        containerProperties.getBatch().setMaxSize(100);
        containerProperties.setCheckpointConfig(new CheckpointConfig(CheckpointMode.MANUAL));
        return new EventHubsMessageListenerContainer(processorFactory, containerProperties);
    }
}
Event Hubs Message Headers

The following table illustrates how Event Hubs message properties are mapped to Spring message headers. For Azure Event Hubs, message is called as event.

Table 22. Mapping between Event Hubs Message / Event Properties and Spring Message Headers in Record Listener Mode
Event Hubs Event Properties Spring Message Header Constants Type Description

Enqueued time

EventHubsHeaders#ENQUEUED_TIME

Instant

The instant, in UTC, of when the event was enqueued in the Event Hub partition.

Offset

EventHubsHeaders#OFFSET

Long

The offset of the event when it was received from the associated Event Hub partition.

Partition key

AzureHeaders#PARTITION_KEY

String

The partition hashing key if it was set when originally publishing the event.

Partition id

AzureHeaders#RAW_PARTITION_ID

String

The partition id of the Event Hub.

Sequence number

EventHubsHeaders#SEQUENCE_NUMBER

Long

The sequence number assigned to the event when it was enqueued in the associated Event Hub partition.

Last enqueued event properties

EventHubsHeaders#LAST_ENQUEUED_EVENT_PROPERTIES

LastEnqueuedEventProperties

The properties of the last enqueued event in this partition.

NA

AzureHeaders#CHECKPOINTER

Checkpointer

The header for checkpoint the specific message.

Users can parse the message headers for the related information of each event. To set a message header for the event, all customized headers will be put as an application property of an event, where the header is set as the property key. When events are received from Event Hubs, all application properties will be converted to the message header.

Message headers of partition key, enqueued time, offset and sequence number is not supported to be set manually.

When the batch-consumer mode is enabled, the specific headers of batched messages are listed as below, which contains a list of values from each single Event Hubs event.

Table 23. Mapping between Event Hubs Message / Event Properties and Spring Message Headers in Batch Listener Mode
Event Hubs Event Properties Spring Batch Message Header Constants Type Description

Enqueued time

EventHubsHeaders#ENQUEUED_TIME

List of Instant

List of the instant, in UTC, of when each event was enqueued in the Event Hub partition.

Offset

EventHubsHeaders#OFFSET

List of Long

List of the offset of each event when it was received from the associated Event Hub partition.

Partition key

AzureHeaders#PARTITION_KEY

List of String

List of the partition hashing key if it was set when originally publishing each event.

Sequence number

EventHubsHeaders#SEQUENCE_NUMBER

List of Long

List of the sequence number assigned to each event when it was enqueued in the associated Event Hub partition.

System properties

EventHubsHeaders#BATCH_CONVERTED_SYSTEM_PROPERTIES

List of Map

List of the system properties of each event.

Application properties

EventHubsHeaders#BATCH_CONVERTED_APPLICATION_PROPERTIES

List of Map

List of the application properties of each event, where all customized message headers or event properties are placed.

When publish messages, all the above batch headers will be removed from the messages if exist.

13.1.5. Samples

Please refer to azure-spring-boot-samples for more details.

13.2. Spring Integration with Azure Service Bus

13.2.1. Key Concepts

Spring Integration enables lightweight messaging within Spring-based applications and supports integration with external systems via declarative adapters.

The Spring Integration for Azure Service Bus extension project provides inbound and outbound channel adapters for Azure Service Bus.

CompletableFuture support APIs have been deprecated from version 2.10.0, and is replaced by Reactor Core from version 4.0.0. Please refer to Javadoc for details.

13.2.2. Dependency Setup

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter-integration-servicebus</artifactId>
</dependency>

13.2.3. Configuration

This starter provides the following 2 parts of configuration options:

Connection Configuration Properties

This section contains the configuration options used for connecting to Azure Service Bus.

If you choose to use a security principal to authenticate and authorize with Azure Active Directory for accessing an Azure resource, please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure resource.
Table 24. Connection configurable properties of spring-cloud-azure-starter-integration-servicebus
Property Type Description

spring.cloud.azure.servicebus.enabled

boolean

Whether an Azure Service Bus is enabled.

spring.cloud.azure.servicebus.connection-string

String

Service Bus Namespace connection string value.

spring.cloud.azure.servicebus.namespace

String

Service Bus Namespace value, which is the prefix of the FQDN. A FQDN should be composed of <NamespaceName>.<DomainName>

spring.cloud.azure.servicebus.domain-name

String

Domain name of an Azure Service Bus Namespace value.

Service Bus Processor Configuration Properties

The ServiceBusInboundChannelAdapter uses the ServiceBusProcessorClient to consume messages, to configure the overall properties of an ServiceBusProcessorClient, developers can use ServiceBusContainerProperties for the configuration. See the below section about how to work with ServiceBusInboundChannelAdapter.

13.2.4. Basic Usage

Send Messages to Azure Service Bus

Step 1. Fill the credential configuration options.

  • For credentials as connection string, configure below properties in application.yml:

spring:
  cloud:
    azure:
      servicebus:
        connection-string: ${AZURE_SERVICE_BUS_CONNECTION_STRING}
  • For credentials as managed identities, configure below properties in application.yml:

spring:
  cloud:
    azure:
      credential:
        managed-identity-enabled: true
        client-id: ${AZURE_CLIENT_ID}
      profile:
        tenant-id: ${AZURE_TENANT_ID}
      servicebus:
        namespace: ${AZURE_SERVICE_BUS_NAMESPACE}
  • For credentials as service principal, configure below properties in application.yml:

spring:
  cloud:
    azure:
      credential:
        client-id: ${AZURE_CLIENT_ID}
        client-secret: ${AZURE_CLIENT_SECRET}
      profile:
        tenant-id: ${AZURE_TENANT_ID}
      servicebus:
        namespace: ${AZURE_SERVICE_BUS_NAMESPACE}

Step 2. Create DefaultMessageHandler with the bean of ServiceBusTemplate to send messages to Service Bus, set the entity type for the ServiceBusTemplate. This sample takes Service Bus Queue as example.

class Demo {
    private static final String OUTPUT_CHANNEL = "queue.output";

    @Bean
    @ServiceActivator(inputChannel = OUTPUT_CHANNEL)
    public MessageHandler queueMessageSender(ServiceBusTemplate serviceBusTemplate) {
        serviceBusTemplate.setDefaultEntityType(ServiceBusEntityType.QUEUE);
        DefaultMessageHandler handler = new DefaultMessageHandler(QUEUE_NAME, serviceBusTemplate);
        handler.setSendCallback(new ListenableFutureCallback<Void>() {
            @Override
            public void onSuccess(Void result) {
                LOGGER.info("Message was sent successfully.");
            }

            @Override
            public void onFailure(Throwable ex) {
                LOGGER.info("There was an error sending the message.");
            }
        });

        return handler;
    }
}

Step 3. Create a message gateway binding with the above message handler via a message channel.

class Demo {
    @Autowired
    QueueOutboundGateway messagingGateway;

    @MessagingGateway(defaultRequestChannel = OUTPUT_CHANNEL)
    public interface QueueOutboundGateway {
        void send(String text);
    }
}

Step 4. Send messages using the gateway.

class Demo {
    public void demo() {
        this.messagingGateway.send(message);
    }
}
Receive Messages from Azure Service Bus

Step 1. Fill the credential configuration options.

Step 2. Create a bean of message channel as the input channel.

@Configuration
class Demo {
    private static final String INPUT_CHANNEL = "input";

    @Bean
    public MessageChannel input() {
        return new DirectChannel();
    }
}

Step 3. Create ServiceBusInboundChannelAdapter with the bean of ServiceBusMessageListenerContainer to receive messages to Service Bus. This sample takes Service Bus Queue as example.

@Configuration
class Demo {
    private static final String QUEUE_NAME = "queue1";

    @Bean
    public ServiceBusMessageListenerContainer messageListenerContainer(ServiceBusProcessorFactory processorFactory) {
        ServiceBusContainerProperties containerProperties = new ServiceBusContainerProperties();
        containerProperties.setEntityName(QUEUE_NAME);
        containerProperties.setAutoComplete(false);
        return new ServiceBusMessageListenerContainer(processorFactory, containerProperties);
    }

    @Bean
    public ServiceBusInboundChannelAdapter queueMessageChannelAdapter(
        @Qualifier(INPUT_CHANNEL) MessageChannel inputChannel,
        ServiceBusMessageListenerContainer listenerContainer) {
        ServiceBusInboundChannelAdapter adapter = new ServiceBusInboundChannelAdapter(listenerContainer);
        adapter.setOutputChannel(inputChannel);
        return adapter;
    }
}

Step 4. Create a message receiver binding with ServiceBusInboundChannelAdapter via the message channel we created before.

class Demo {
    @ServiceActivator(inputChannel = INPUT_CHANNEL)
    public void messageReceiver(byte[] payload, @Header(AzureHeaders.CHECKPOINTER) Checkpointer checkpointer) {
        String message = new String(payload);
        LOGGER.info("New message received: '{}'", message);
        checkpointer.success()
                .doOnSuccess(s -> LOGGER.info("Message '{}' successfully checkpointed", message))
                .doOnError(e -> LOGGER.error("Error found", e))
                .block();
    }
}
Configure ServiceBusMessageConverter to Customize ObjectMapper

ServiceBusMessageConverter is made as a configurable bean to allow users to customize ObjectMapper.

Service Bus Message Headers

For some Service Bus headers that can be mapped to multiple Spring header constants, the priority of different Spring headers is listed.

Table 25. Mapping between Service Bus Headers and Spring Headers
Service Bus Message Headers and Properties Spring Message Header Constants Type Configurable Description

Content type

MessageHeaders#CONTENT_TYPE

String

Yes

The RFC2045 Content-Type descriptor of the message.

Correlation id

ServiceBusMessageHeaders#CORRELATION_ID

String

Yes

The correlation id of the message

Message id

ServiceBusMessageHeaders#MESSAGE_ID

String

Yes

The message id of the message, this header has higher priority than MessageHeaders#ID.

Message id

MessageHeaders#ID

UUID

Yes

The message id of the message, this header has lower priority than ServiceBusMessageHeaders#MESSAGE_ID.

Partition key

ServiceBusMessageHeaders#PARTITION_KEY

String

Yes

The partition key for sending the message to a partitioned entity.

Reply to

MessageHeaders#REPLY_CHANNEL

String

Yes

The address of an entity to send replies to.

Reply to session id

ServiceBusMessageHeaders#REPLY_TO_SESSION_ID

String

Yes

The ReplyToGroupId property value of the message.

Scheduled enqueue time utc

ServiceBusMessageHeaders#SCHEDULED_ENQUEUE_TIME

OffsetDateTime

Yes

The datetime at which the message should be enqueued in Service Bus, this header has higher priority than AzureHeaders#SCHEDULED_ENQUEUE_MESSAGE.

Scheduled enqueue time utc

AzureHeaders#SCHEDULED_ENQUEUE_MESSAGE

Integer

Yes

The datetime at which the message should be enqueued in Service Bus, this header has lower priority than ServiceBusMessageHeaders#SCHEDULED_ENQUEUE_TIME.

Session id

ServiceBusMessageHeaders#SESSION_ID

String

Yes

The session identifier for a session-aware entity.

Time to live

ServiceBusMessageHeaders#TIME_TO_LIVE

Duration

Yes

The duration of time before this message expires.

To

ServiceBusMessageHeaders#TO

String

Yes

The "to" address of the message, reserved for future use in routing scenarios and presently ignored by the broker itself.

Subject

ServiceBusMessageHeaders#SUBJECT

String

Yes

The subject for the message.

Dead letter error description

ServiceBusMessageHeaders#DEAD_LETTER_ERROR_DESCRIPTION

String

No

The description for a message that has been dead-lettered.

Dead letter reason

ServiceBusMessageHeaders#DEAD_LETTER_REASON

String

No

The reason a message was dead-lettered.

Dead letter source

ServiceBusMessageHeaders#DEAD_LETTER_SOURCE

String

No

The entity in which the message was dead-lettered.

Delivery count

ServiceBusMessageHeaders#DELIVERY_COUNT

long

No

The number of the times this message was delivered to clients.

Enqueued sequence number

ServiceBusMessageHeaders#ENQUEUED_SEQUENCE_NUMBER

long

No

The enqueued sequence number assigned to a message by Service Bus.

Enqueued time

ServiceBusMessageHeaders#ENQUEUED_TIME

OffsetDateTime

No

The datetime at which this message was enqueued in Service Bus.

Expires at

ServiceBusMessageHeaders#EXPIRES_AT

OffsetDateTime

No

The datetime at which this message will expire.

Lock token

ServiceBusMessageHeaders#LOCK_TOKEN

String

No

The lock token for the current message.

Locked until

ServiceBusMessageHeaders#LOCKED_UNTIL

OffsetDateTime

No

The datetime at which the lock of this message expires.

Sequence number

ServiceBusMessageHeaders#SEQUENCE_NUMBER

long

No

The unique number assigned to a message by Service Bus.

State

ServiceBusMessageHeaders#STATE

ServiceBusMessageState

No

The state of the message, which can be Active, Deferred, or Scheduled.

Partition Key Support

This starter supports Service Bus partitioning by allowing setting partition key and session id in the message header. This section introduces how to set partition key for messages.

Recommended: Use ServiceBusMessageHeaders.PARTITION_KEY as the key of the header.

public class SampleController {
    @PostMapping("/messages")
    public ResponseEntity<String> sendMessage(@RequestParam String message) {
        LOGGER.info("Going to add message {} to Sinks.Many.", message);
        many.emitNext(MessageBuilder.withPayload(message)
                                    .setHeader(ServiceBusMessageHeaders.PARTITION_KEY, "Customize partition key")
                                    .build(), Sinks.EmitFailureHandler.FAIL_FAST);
        return ResponseEntity.ok("Sent!");
    }
}

Not recommended but currently supported: AzureHeaders.PARTITION_KEY as the key of the header.

public class SampleController {
    @PostMapping("/messages")
    public ResponseEntity<String> sendMessage(@RequestParam String message) {
        LOGGER.info("Going to add message {} to Sinks.Many.", message);
        many.emitNext(MessageBuilder.withPayload(message)
                                    .setHeader(AzureHeaders.PARTITION_KEY, "Customize partition key")
                                    .build(), Sinks.EmitFailureHandler.FAIL_FAST);
        return ResponseEntity.ok("Sent!");
    }
}
When both ServiceBusMessageHeaders.PARTITION_KEY and AzureHeaders.PARTITION_KEY are set in the message headers, ServiceBusMessageHeaders.PARTITION_KEY is preferred.
Session Support

This example demonstrates how to manually set the session id of a message in the application.

public class SampleController {
    @PostMapping("/messages")
    public ResponseEntity<String> sendMessage(@RequestParam String message) {
        LOGGER.info("Going to add message {} to Sinks.Many.", message);
        many.emitNext(MessageBuilder.withPayload(message)
                                    .setHeader(ServiceBusMessageHeaders.SESSION_ID, "Customize session id")
                                    .build(), Sinks.EmitFailureHandler.FAIL_FAST);
        return ResponseEntity.ok("Sent!");
    }
}
When the ServiceBusMessageHeaders.SESSION_ID is set in the message headers, and a different ServiceBusMessageHeaders.PARTITION_KEY (or AzureHeaders.PARTITION_KEY) header is also set, the value of the session id will eventually be used to overwrite the value of the partition key.

13.2.5. Samples

Please refer to azure-spring-boot-samples for more details.

13.3. Spring Integration with Azure Storage Queue

13.3.1. Key Concepts

Azure Queue Storage is a service for storing large numbers of messages. You access messages from anywhere in the world via authenticated calls using HTTP or HTTPS. A queue message can be up to 64 KB in size. A queue may contain millions of messages, up to the total capacity limit of a storage account. Queues are commonly used to create a backlog of work to process asynchronously.

13.3.2. Dependency Setup

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter-integration-storage-queue</artifactId>
</dependency>

13.3.3. Configuration

This starter provides the following configuration options:

Connection Configuration Properties

This section contains the configuration options used for connecting to Azure Storage Queue.

If you choose to use a security principal to authenticate and authorize with Azure Active Directory for accessing an Azure resource, please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure resource.
Table 26. Connection configurable properties of spring-cloud-azure-starter-integration-storage-queue
Property Type Description

spring.cloud.azure.storage.queue.enabled

boolean

Whether an Azure Storage Queue is enabled.

spring.cloud.azure.storage.queue.connection-string

String

Storage Queue Namespace connection string value.

spring.cloud.azure.storage.queue.accountName

String

Storage Queue account name.

spring.cloud.azure.storage.queue.accountKey

String

Storage Queue account key.

spring.cloud.azure.storage.queue.endpoint

String

Storage Queue service endpoint.

spring.cloud.azure.storage.queue.sasToken

String

Sas token credential

spring.cloud.azure.storage.queue.serviceVersion

QueueServiceVersion

QueueServiceVersion that is used when making API requests.

spring.cloud.azure.storage.queue.messageEncoding

String

Queue message encoding.

13.3.4. Basic Usage

Send messages to Azure Storage Queue

Step 1. Fill the credential configuration options.

  • For credentials as connection string, configure below properties in application.yml:

spring:
  cloud:
    azure:
      storage:
        queue:
          connection-string: ${AZURE_SERVICE_BUS_CONNECTION_STRING}
  • For credentials as managed identities, configure below properties in application.yml:

spring:
  cloud:
    azure:
      credential:
        managed-identity-enabled: true
        client-id: ${AZURE_CLIENT_ID}
      profile:
        tenant-id: ${AZURE_TENANT_ID}
      storage:
        queue:
          namespace: ${AZURE_SERVICE_BUS_NAMESPACE}
  • For credentials as service principal, configure below properties in application.yml:

spring:
  cloud:
    azure:
      credential:
        client-id: ${AZURE_CLIENT_ID}
        client-secret: ${AZURE_CLIENT_SECRET}
      profile:
        tenant-id: ${AZURE_TENANT_ID}
      storage:
        queue:
          namespace: ${AZURE_SERVICE_BUS_NAMESPACE}

Step 2. Create DefaultMessageHandler with the bean of StorageQueueTemplate to send messages to Storage Queue.

class Demo {
    private static final String STORAGE_QUEUE_NAME = "example";
    private static final String OUTPUT_CHANNEL = "output";

    @Bean
    @ServiceActivator(inputChannel = OUTPUT_CHANNEL)
    public MessageHandler messageSender(StorageQueueTemplate storageQueueTemplate) {
        DefaultMessageHandler handler = new DefaultMessageHandler(STORAGE_QUEUE_NAME, storageQueueTemplate);
        handler.setSendCallback(new ListenableFutureCallback<Void>() {
            @Override
            public void onSuccess(Void result) {
                LOGGER.info("Message was sent successfully.");
            }

            @Override
            public void onFailure(Throwable ex) {
                LOGGER.info("There was an error sending the message.");
            }
        });
        return handler;
    }
}

Step 3. Create a Message gateway binding with the above message handler via a message channel.

class Demo {
    @Autowired
    StorageQueueOutboundGateway storageQueueOutboundGateway;

    @MessagingGateway(defaultRequestChannel = OUTPUT_CHANNEL)
    public interface StorageQueueOutboundGateway {
        void send(String text);
    }
}

Step 4. Send messages using the gateway.

class Demo {
    public void demo() {
        this.storageQueueOutboundGateway.send(message);
    }
}
Receive Messages from Azure Storage Queue

Step 1. Fill the credential configuration options.

Step 2. Create a bean of message channel as the input channel.

class Demo {
    private static final String INPUT_CHANNEL = "input";

    @Bean
    public MessageChannel input() {
        return new DirectChannel();
    }
}

Step 3. Create StorageQueueMessageSource with the bean of StorageQueueTemplate to receive messages to Storage Queue.

class Demo {
    private static final String STORAGE_QUEUE_NAME = "example";

    @Bean
    @InboundChannelAdapter(channel = INPUT_CHANNEL, poller = @Poller(fixedDelay = "1000"))
    public StorageQueueMessageSource storageQueueMessageSource(StorageQueueTemplate storageQueueTemplate) {
        return new StorageQueueMessageSource(STORAGE_QUEUE_NAME, storageQueueTemplate);
    }
}

Step 4. Create a message receiver binding with StorageQueueMessageSource created in the last step via the message channel we created before.

class Demo {
    @ServiceActivator(inputChannel = INPUT_CHANNEL)
    public void messageReceiver(byte[] payload, @Header(AzureHeaders.CHECKPOINTER) Checkpointer checkpointer) {
        String message = new String(payload);
        LOGGER.info("New message received: '{}'", message);
        checkpointer.success()
            .doOnError(Throwable::printStackTrace)
            .doOnSuccess(t -> LOGGER.info("Message '{}' successfully checkpointed", message))
            .block();
    }
}

13.3.5. Samples

Please refer to azure-spring-boot-samples for more details.

14. Spring Cloud Stream Support

Spring Cloud Stream is a framework for building highly scalable event-driven microservices connected with shared messaging systems.

The framework provides a flexible programming model built on already established and familiar Spring idioms and best practices, including support for persistent pub/sub semantics, consumer groups, and stateful partitions.

Current binder implementations include:

  • spring-cloud-azure-stream-binder-eventhubs

  • spring-cloud-azure-stream-binder-servicebus

14.1. Spring Cloud Stream Binder for Azure Event Hubs

14.1.1. Key Concepts

The Spring Cloud Stream Binder for Azure Event Hubs provides the binding implementation for the Spring Cloud Stream framework. This implementation uses Spring Integration Event Hubs Channel Adapters at its foundation. From design’s perspective, Event Hubs is similar as Kafka. Also, Event Hubs could be accessed via Kafka API. If your project has tight dependency on Kafka API, you can try Events Hub with Kafka API Sample

Consumer Group

Event Hubs provides similar support of consumer group as Apache Kafka, but with slight different logic. While Kafka stores all committed offsets in the broker, you have to store offsets of Event Hubs messages being processed manually. Event Hubs SDK provides the function to store such offsets inside Azure Storage.

Partitioning Support

Event Hubs provides a similar concept of physical partition as Kafka. But unlike Kafka’s auto re-balancing between consumers and partitions, Event Hubs provides a kind of preemptive mode. The storage account acts as a lease to determine which partition is owned by which consumer. When a new consumer starts, it will try to steal some partitions from most heavy-loaded consumers to achieve the workload balancing.

To specify the load balancing strategy, properties of spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer.load-balancing.* are provided. See the consumer properties for more details.

Batch Consumer Support

Spring Cloud Azure Stream Event Hubs binder supports Spring Cloud Stream Batch Consumer feature.

To work with the batch-consumer mode, the property of spring.cloud.stream.bindings.<binding-name>.consumer.batch-mode should be set as true. When enabled, an Message of which the payload is a list of batched events will be received and passed to the Consumer function. Each message header is also converted as a list, of which the content is the associated header value parsed from each event. For the communal headers of partition id, checkpointer and last enqueued properties, they are presented as a single value for the entire batch of events shares the same one. See Event Hubs Message Headers for more details.

The checkpoint header only exists when MANUAL checkpoint mode is used.

Checkpointing of batch consumer supports two modes: BATCH and MANUAL. BATCH mode is an auto checkpointing mode to checkpoint the entire batch of events together once they are received by the binder. MANUAL mode is to checkpoint the events by users. When used, the Checkpointer will be passed into the message header, and users could use it to do checkpointing.

The batch size can be specified by properties of max-size and max-wait-time with prefix as spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer.batch., where max-size is a necessary property while max-wait-time is optional. See the consumer properties for more details.

14.1.2. Dependency Setup

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-stream-binder-eventhubs</artifactId>
</dependency>

Alternatively, you can also use the Spring Cloud Azure Stream Event Hubs Starter, as shown in the following example for Maven:

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter-stream-eventhubs</artifactId>
</dependency>

14.1.3. Configuration

The binder provides the following 3 parts of configuration options:

Connection Configuration Properties

This section contains the configuration options used for connecting to Azure Event Hubs.

If you choose to use a security principal to authenticate and authorize with Azure Active Directory for accessing an Azure resource, please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure resource.
Table 27. Connection configurable properties of spring-cloud-azure-stream-binder-eventhubs
Property Type Description

spring.cloud.azure.eventhubs.enabled

boolean

Whether an Azure Event Hubs is enabled.

spring.cloud.azure.eventhubs.connection-string

String

Event Hubs Namespace connection string value.

spring.cloud.azure.eventhubs.namespace

String

Event Hubs Namespace value, which is the prefix of the FQDN. A FQDN should be composed of <NamespaceName>.<DomainName>

spring.cloud.azure.eventhubs.domain-name

String

Domain name of an Azure Event Hubs Namespace value.

spring.cloud.azure.eventhubs.custom-endpoint-address

String

Custom Endpoint address.

Common Azure Service SDK configuration options are configurable for the Spring Cloud Azure Stream Event Hubs binder as well. The supported configuration options are introduced in the Configuration page, and could be configured with either the unified prefix spring.cloud.azure. or the prefix of spring.cloud.azure.eventhubs..

The binder also supports Spring Could Azure Resource Manager by default. To learn about how to retrieve the connection string with security principals that are not granted with Data related roles, please refer to the resource manager example for details.

Checkpoint Configuration Properties

This section contains the configuration options for the Storage Blobs service, which is used for persisting partition ownership and checkpoint information.

From version 4.0.0, when the property of spring.cloud.azure.eventhubs.processor.checkpoint-store.create-container-if-not-exists is not enabled manually, no Storage container will be created automatically with the name from spring.cloud.stream.bindings.<binding-name>.destination.
Table 28. Checkpointing configurable properties of spring-cloud-azure-stream-binder-eventhubs
Property Type Description

spring.cloud.azure.eventhubs.processor.checkpoint-store.create-container-if-not-exists

Boolean

Whether to allow creating containers if not exists.

spring.cloud.azure.eventhubs.processor.checkpoint-store.account-name

String

Name for the storage account.

spring.cloud.azure.eventhubs.processor.checkpoint-store.account-key

String

Storage account access key.

spring.cloud.azure.eventhubs.processor.checkpoint-store.container-name

String

Storage container name.

Common Azure Service SDK configuration options are configurable for Storage Blob checkpoint store as well. The supported configuration options are introduced in the Configuration page, and could be configured with either the unified prefix spring.cloud.azure. or the prefix of spring.cloud.azure.eventhubs.processor.checkpoint-store.
Azure Event Hubs Binding Configuration Properties

Below options are divided into four sections: Consumer Properties, Advanced Consumer Configurations, Producer Properties and Advanced Producer Configurations.

Consumer Properties

These properties are exposed via EventHubsConsumerProperties.

Table 29. Consumer configurable properties of spring-cloud-azure-stream-binder-eventhubs
Property Type Description

spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer.checkpoint.mode

CheckpointMode

Checkpoint mode used when consumer decide how to checkpoint message

spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer.checkpoint.count

Integer

Decides the amount of message for each partition to do one checkpoint. Will take effect only when PARTITION_COUNT checkpoint mode is used.

spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer.checkpoint.interval

Duration

Decides the time interval to do one checkpoint. Will take effect only when TIME checkpoint mode is used.

spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer.batch.max-size

Integer

The maximum number of events in a batch. Required for the batch-consumer mode.

spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer.batch.max-wait-time

Duration

The maximum time duration for batch consuming. Will take effect only when the batch-consumer mode is enabled and is optional.

spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer.load-balancing.update-interval

Duration

The interval time duration for updating.

spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer.load-balancing.strategy

LoadBalancingStrategy

The load balancing strategy.

spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer.load-balancing.partition-ownership-expiration-interval

Duration

The time duration after which the ownership of partition expires.

spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer.track-last-enqueued-event-properties

Boolean

Whether the event processor should request information on the last enqueued event on its associated partition, and track that information as events are received.

spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer.prefetch-count

Integer

The count used by the consumer to control the number of events the Event Hub consumer will actively receive and queue locally.

spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer.initial-partition-event-position

Map with the key as the partition id, and values of StartPositionProperties

The map containing the event position to use for each partition if a checkpoint for the partition does not exist in checkpoint store. This map is keyed off of the partition id.

The initial-partition-event-position configuration accepts a map to specify the initial position for each event hub. Thus, its key is the partition id, and the value is of StartPositionProperties which includes properties of offset, sequence number, enqueued date time and whether inclusive. For example, you can set it as
spring:
  cloud:
    stream:
      eventhubs:
        bindings:
          <binding-name>:
            consumer:
              initial-partition-event-position:
                0:
                  offset: earliest
                1:
                  sequence-number: 100
                2:
                  enqueued-date-time: 2022-01-12T13:32:47.650005Z
                4:
                  inclusive: false
Advanced Consumer Configuration

The above connection, checkpoint and common Azure SDK client configuration are supported to be customized for each binder consumer, which can be configured with the prefix spring.cloud.stream.eventhubs.bindings.<binding-name>.consumer..

Producer Properties

These properties are exposed via EventHubsProducerProperties.

Table 30. Producer configurable properties of spring-cloud-azure-stream-binder-eventhubs
Property Type Description

spring.cloud.stream.eventhubs.bindings.<binding-name>.producer.sync

boolean

The switch flag for sync of producer. If true, the producer will wait for a response after a send operation.

spring.cloud.stream.eventhubs.bindings.<binding-name>.producer.send-timeout

long

The amount of time to wait for a response after a send operation. Will take effect only when a sync producer is enabled.

Advanced Producer Configuration

The above connection and common Azure SDK client configuration are supported to be customized for each binder producer, which can be configured with the prefix spring.cloud.stream.eventhubs.bindings.<binding-name>.producer..

14.1.4. Basic Usage

Sending and Receiving Messages from/to Event Hubs

Step 1. Fill the configuration options with credential information.

  • For credentials as connection string, configure below properties in application.yml:

spring:
  cloud:
    azure:
      eventhubs:
        connection-string: ${EVENTHUB_NAMESPACE_CONNECTION_STRING}
        processor:
          checkpoint-store:
            container-name: ${CHECKPOINT_CONTAINER}
            account-name: ${CHECKPOINT_STORAGE_ACCOUNT}
            account-key: ${CHECKPOINT_ACCESS_KEY}
    stream:
      function:
        definition: consume;supply
      bindings:
        consume-in-0:
          destination: ${EVENTHUB_NAME}
          group: ${CONSUMER_GROUP}
        supply-out-0:
          destination: ${THE_SAME_EVENTHUB_NAME_AS_ABOVE}
      eventhubs:
        bindings:
          consume-in-0:
            consumer:
              checkpoint:
                mode: MANUAL
  • For credentials as service principal, configure below properties in application.yml:

spring:
  cloud:
    azure:
      credential:
        client-id: ${AZURE_CLIENT_ID}
        client-secret: ${AZURE_CLIENT_SECRET}
      profile:
        tenant-id: ${AZURE_TENANT_ID}
      eventhubs:
        namespace: ${EVENTHUB_NAMESPACE}
        processor:
          checkpoint-store:
            container-name: ${CONTAINER_NAME}
            account-name: ${ACCOUNT_NAME}
    stream:
      function:
        definition: consume;supply
      bindings:
        consume-in-0:
          destination: ${EVENTHUB_NAME}
          group: ${CONSUMER_GROUP}
        supply-out-0:
          destination: ${THE_SAME_EVENTHUB_NAME_AS_ABOVE}
      eventhubs:
        bindings:
          consume-in-0:
            consumer:
              checkpoint:
                mode: MANUAL
  • For credentials as managed identites, configure below properties in application.yml:

spring:
  cloud:
    azure:
      credential:
        managed-identity-enabled: true
        client-id: ${AZURE_MANAGED_IDENTITY_CLIENT_ID} # Only needed when using a user-assigned managed identity
      eventhubs:
        namespace: ${EVENTHUB_NAMESPACE}
        processor:
          checkpoint-store:
            container-name: ${CONTAINER_NAME}
            account-name: ${ACCOUNT_NAME}
    stream:
      function:
        definition: consume;supply
      bindings:
        consume-in-0:
          destination: ${EVENTHUB_NAME}
          group: ${CONSUMER_GROUP}
        supply-out-0:
          destination: ${THE_SAME_EVENTHUB_NAME_AS_ABOVE}

      eventhubs:
        bindings:
          consume-in-0:
            consumer:
              checkpoint:
                mode: MANUAL

Step2. Define supplier and consumer.

@Bean
public Consumer<Message<String>> consume() {
    return message -> {
        Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
        LOGGER.info("New message received: '{}', partition key: {}, sequence number: {}, offset: {}, enqueued time: {}",
                message.getPayload(),
                message.getHeaders().get(EventHubsHeaders.PARTITION_KEY),
                message.getHeaders().get(EventHubsHeaders.SEQUENCE_NUMBER),
                message.getHeaders().get(EventHubsHeaders.OFFSET),
                message.getHeaders().get(EventHubsHeaders.ENQUEUED_TIME)
        );

        checkpointer.success()
                .doOnSuccess(success -> LOGGER.info("Message '{}' successfully checkpointed", message.getPayload()))
                .doOnError(error -> LOGGER.error("Exception found", error))
                .block();
    };
}

@Bean
public Supplier<Message<String>> supply() {
    return () -> {
        LOGGER.info("Sending message, sequence " + i);
        return MessageBuilder.withPayload("Hello world, " + i++).build();
    };
}
Partitioning Support

A PartitionSupplier with user-provided partition information will be created to configure the partition information about the message to be sent, the following is the process of obtaining different priorities of the partition ID and key:

145347877 fa8afa90 ec28 4c0a 8277 63b9fdaa5d0f

Batch Consumer Support

Step 1. Fill the batch configuration options

spring:
  cloud:
    stream:
      function:
        definition: consume
      bindings:
        consume-in-0:
          destination: ${AZURE_EVENTHUB_NAME}
          group: ${AZURE_EVENTHUB_CONSUMER_GROUP}
          consumer:
            batch-mode: true
      eventhubs:
        bindings:
          consume-in-0:
            consumer:
              batch:
                max-batch-size: 10 # Required for batch-consumer mode
                max-wait-time: 1m # Optional, the default value is null
              checkpoint:
                mode: BATCH # or MANUAL as needed

Step2. Define supplier and consumer.

For checkpointing mode as BATCH, you can use below code to send messages and consume in batches.

@Bean
public Consumer<Message<List<String>>> consume() {
    return message -> {
            for (int i = 0; i < message.getPayload().size(); i++) {
                LOGGER.info("New message received: '{}', partition key: {}, sequence number: {}, offset: {}, enqueued time: {}",
                        message.getPayload().get(i),
                        ((List<Object>) message.getHeaders().get(EventHubsHeaders.BATCH_CONVERTED_PARTITION_KEY)).get(i),
                        ((List<Object>) message.getHeaders().get(EventHubsHeaders.BATCH_CONVERTED_SEQUENCE_NUMBER)).get(i),
                        ((List<Object>) message.getHeaders().get(EventHubsHeaders.BATCH_CONVERTED_OFFSET)).get(i),
                        ((List<Object>) message.getHeaders().get(EventHubsHeaders.BATCH_CONVERTED_ENQUEUED_TIME)).get(i));
            }

        };
}

@Bean
public Supplier<Message<String>> supply() {
    return () -> {
        LOGGER.info("Sending message, sequence " + i);
        return MessageBuilder.withPayload("\"test"+ i++ +"\"").build();
    };
}

For checkpointing mode as MANUAL, you can use below code to send messages and consume/checkpoint in batches.

@Bean
public Consumer<Message<List<String>>> consume() {
    return message -> {
        for (int i = 0; i < message.getPayload().size(); i++) {
            LOGGER.info("New message received: '{}', partition key: {}, sequence number: {}, offset: {}, enqueued time: {}",
                message.getPayload().get(i),
                ((List<Object>) message.getHeaders().get(EventHubHeaders.BATCH_CONVERTED_PARTITION_KEY)).get(i),
                ((List<Object>) message.getHeaders().get(EventHubHeaders.BATCH_CONVERTED_SEQUENCE_NUMBER)).get(i),
                ((List<Object>) message.getHeaders().get(EventHubHeaders.BATCH_CONVERTED_OFFSET)).get(i),
                ((List<Object>) message.getHeaders().get(EventHubHeaders.BATCH_CONVERTED_ENQUEUED_TIME)).get(i));
        }

        Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
        checkpointer.success()
                    .doOnSuccess(success -> LOGGER.info("Message '{}' successfully checkpointed", message.getPayload()))
                    .doOnError(error -> LOGGER.error("Exception found", error))
                    .block();
    };
}

@Bean
public Supplier<Message<String>> supply() {
    return () -> {
        LOGGER.info("Sending message, sequence " + i);
        return MessageBuilder.withPayload("\"test"+ i++ +"\"").build();
    };
}
In the batch-consuming mode, the default content type of Spring Cloud Stream binder is application/json, so make sure the message payload is aligned with the content type. For example, when using the default content type of application/json to receive messages with String payload, the payload should be JSON String, surrounded with double quotes for the original String text. While for text/plain content type, it can be a String object directly. For more details, please refer to the official doc of Spring Cloud Stream Content Type Negotiation.
Error Channels
  • Consumer error channel

This channel is open by default, you can handle the error message in this way:

// Replace destination with spring.cloud.stream.bindings.input.destination
// Replace group with spring.cloud.stream.bindings.input.group
@ServiceActivator(inputChannel = "{destination}.{group}.errors")
public void consumerError(Message<?> message) {
    LOGGER.error("Handling customer ERROR: " + message);
}
  • Producer error channel

This channel is not open by default. You need to add a configuration in your application.properties to enable it, like this:

spring.cloud.stream.default.producer.errorChannelEnabled=true

You can handle the error message in this way:

// Replace destination with spring.cloud.stream.bindings.output.destination
@ServiceActivator(inputChannel = "{destination}.errors")
public void producerError(Message<?> message) {
    LOGGER.error("Handling Producer ERROR: " + message);
}
  • Global default error channel

A global error channel called "errorChannel" is created by default Spring Integration, which allows users to subscribe many endpoints to it.

@ServiceActivator(inputChannel = "errorChannel")
public void producerError(Message<?> message) {
    LOGGER.error("Handling ERROR: " + message);
}
Event Hubs Message Headers

See the Event Hubs message headers for the basic message headers supported.

Multiple Binder Support

Connection to multiple Event Hubs namespaces is also supported by using multiple binders.This sample takes connection string as example. Credentials of service principals and managed identities are also supported, users can set related properties in each binder’s environment settings.

Step 1. To use multiple binders of EventHubs, we need to configure below properties in application.yml

spring:
  cloud:
    stream:
      function:
        definition: consume1;supply1;consume2;supply2
      bindings:
        consume1-in-0:
          destination: ${EVENTHUB_NAME_01}
          group: ${CONSUMER_GROUP_01}
        supply1-out-0:
          destination: ${THE_SAME_EVENTHUB_NAME_01_AS_ABOVE}
        consume2-in-0:
          binder: eventhub-2
          destination: ${EVENTHUB_NAME_02}
          group: ${CONSUMER_GROUP_02}
        supply2-out-0:
          binder: eventhub-2
          destination: ${THE_SAME_EVENTHUB_NAME_02_AS_ABOVE}
      binders:
        eventhub-1:
          type: eventhubs
          default-candidate: true
          environment:
            spring:
              cloud:
                azure:
                  eventhubs:
                    connection-string: ${EVENTHUB_NAMESPACE_01_CONNECTION_STRING}
                    processor:
                      checkpoint-store:
                        container-name: ${CHECKPOINT_CONTAINER_01}
                        account-name: ${CHECKPOINT_STORAGE_ACCOUNT}
                        account-key: ${CHECKPOINT_ACCESS_KEY}
        eventhub-2:
          type: eventhubs
          default-candidate: false
          environment:
            spring:
              cloud:
                azure:
                  eventhubs:
                    connection-string: ${EVENTHUB_NAMESPACE_02_CONNECTION_STRING}
                    processor:
                      checkpoint-store:
                        container-name: ${CHECKPOINT_CONTAINER_02}
                        account-name: ${CHECKPOINT_STORAGE_ACCOUNT}
                        account-key: ${CHECKPOINT_ACCESS_KEY}
      eventhubs:
        bindings:
          consume1-in-0:
            consumer:
              checkpoint:
                mode: MANUAL
          consume2-in-0:
            consumer:
              checkpoint:
                mode: MANUAL
      poller:
        initial-delay: 0
        fixed-delay: 1000

Step 2. we need define two suppliers and two consumers

@Bean
public Supplier<Message<String>> supply1() {
    return () -> {
        LOGGER.info("Sending message1, sequence1 " + i);
        return MessageBuilder.withPayload("Hello world1, " + i++).build();
    };
}

@Bean
public Supplier<Message<String>> supply2() {
    return () -> {
        LOGGER.info("Sending message2, sequence2 " + j);
        return MessageBuilder.withPayload("Hello world2, " + j++).build();
    };
}

@Bean
public Consumer<Message<String>> consume1() {
    return message -> {
        Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
        LOGGER.info("New message1 received: '{}'", message);
        checkpointer.success()
                .doOnSuccess(success -> LOGGER.info("Message1 '{}' successfully checkpointed", message))
                .doOnError(error -> LOGGER.error("Exception found", error))
                .block();
    };
}

@Bean
public Consumer<Message<String>> consume2() {
    return message -> {
        Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
        LOGGER.info("New message2 received: '{}'", message);
        checkpointer.success()
                .doOnSuccess(success -> LOGGER.info("Message2 '{}' successfully checkpointed", message))
                .doOnError(error -> LOGGER.error("Exception found", error))
                .block();
    };
}
Resource Provision

Event Hubs binder supports provisioning of event hub and consumer group, users could use below properties to enable provisioning.

spring:
  cloud:
    azure:
      credential:
        tenant-id: ${AZURE_TENANT_ID}
      profile:
        subscription-id: ${AZURE_SUBSCRIPTION_ID}
      eventhubs:
        resource:
          resource-group: ${AZURE_EVENTHUBS_RESOURECE_GROUP}

14.1.5. Samples

Please refer to azure-spring-boot-samples for more details.

14.2. Spring Cloud Stream Binder for Azure Service Bus

14.2.1. Key Concepts

The Spring Cloud Stream Binder for Azure Service Bus provides the binding implementation for the Spring Cloud Stream Framework. This implementation uses Spring Integration Service Bus Channel Adapters at its foundation.

Scheduled Message

This binder supports submitting messages to a topic for delayed processing. Users can send scheduled messages with header x-delay expressing in milliseconds a delay time for the message. The message will be delivered to the respective topics after x-delay milliseconds.

Consumer Group

Service Bus Topic provides similar support of consumer group as Apache Kafka, but with slight different logic. This binder relies on Subscription of a topic to act as a consumer group.

14.2.2. Dependency Setup

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-stream-binder-servicebus</artifactId>
</dependency>

Alternatively, you can also use the Spring Cloud Azure Stream Service Bus Starter, as shown in the following example for Maven:

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter-stream-servicebus</artifactId>
</dependency>

14.2.3. Configuration

The binder provides the following 2 parts of configuration options:

Connection Configuration Properties

This section contains the configuration options used for connecting to Azure Service Bus.

If you choose to use a security principal to authenticate and authorize with Azure Active Directory for accessing an Azure resource, please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure resource.
Table 31. Connection configurable properties of spring-cloud-azure-stream-binder-servicebus
Property Type Description

spring.cloud.azure.servicebus.enabled

boolean

Whether an Azure Service Bus is enabled.

spring.cloud.azure.servicebus.connection-string

String

Service Bus Namespace connection string value.

spring.cloud.azure.servicebus.namespace

String

Service Bus Namespace value, which is the prefix of the FQDN. A FQDN should be composed of <NamespaceName>.<DomainName>

spring.cloud.azure.servicebus.domain-name

String

Domain name of an Azure Service Bus Namespace value.

Common Azure Service SDK configuration options are configurable for the Spring Cloud Azure Stream Service Bus binder as well. The supported configuration options are introduced in the Configuration page, and could be configured with either the unified prefix spring.cloud.azure. or the prefix of spring.cloud.azure.servicebus..

The binder also supports Spring Could Azure Resource Manager by default. To learn about how to retrieve the connection string with security principals that are not granted with Data related roles, please refer to the resource manager example for details.

Azure Service Bus Binding Configuration Properties

Below options are divided into four sections: Consumer Properties, Advanced Consumer Configurations, Producer Properties and Advanced Producer Configurations.

Consumer Properties

These properties are exposed via ServiceBusConsumerProperties.

Table 32. Consumer configurable properties of spring-cloud-azure-stream-binder-servicebus
Property Type Default Description

spring.cloud.stream.servicebus.bindings.<binding-name>.consumer.requeue-rejected

boolean

false

If the failed messages are routed to the DLQ.

spring.cloud.stream.servicebus.bindings.<binding-name>.consumer.max-concurrent-calls

Integer

1

Max concurrent messages that the Service Bus processor client should process.

spring.cloud.stream.servicebus.bindings.<binding-name>.consumer.max-concurrent-sessions

Integer

null

Maximum number of concurrent sessions to process at any given time.

spring.cloud.stream.servicebus.bindings.<binding-name>.consumer.session-enabled

Boolean

null

Whether session is enabled.

spring.cloud.stream.servicebus.bindings.<binding-name>.consumer.prefetch-count

Integer

0

The prefetch count of the Service Bus processor client.

spring.cloud.stream.servicebus.bindings.<binding-name>.consumer.sub-queue

SubQueue

none

The type of the sub queue to connect to.

spring.cloud.stream.servicebus.bindings.<binding-name>.consumer.max-auto-lock-renew-duration

Duration

5m

The amount of time to continue auto-renewing the lock.

spring.cloud.stream.servicebus.bindings.<binding-name>.consumer.receive-mode

ServiceBusReceiveMode

peek_lock

The receive mode of the Service Bus processor client.

spring.cloud.stream.servicebus.bindings.<binding-name>.consumer.auto-complete

Boolean

true

Whether to settle messages automatically. If set as false, a message header of Checkpointer will be added to enable developers to settle messages manually.

Advanced Consumer Configuration

The above connection and common Azure SDK client configuration are supported to be customized for each binder consumer, which can be configured with the prefix spring.cloud.stream.servicebus.bindings.<binding-name>.consumer..

Producer Properties

These properties are exposed via ServiceBusProducerProperties.

Table 33. Producer configurable properties of spring-cloud-azure-stream-binder-servicebus
Property Type Default Description

spring.cloud.stream.servicebus.bindings.<binding-name>.producer.sync

boolean

false

Switch flag for sync of producer.

spring.cloud.stream.servicebus.bindings.<binding-name>.producer.send-timeout

long

10000

Timeout value for sending of producer.

spring.cloud.stream.servicebus.bindings.<binding-name>.producer.entity-type

ServiceBusEntityType

null

Service Bus entity type of the producer, required for the binding producer.

When using the binding producer, property of spring.cloud.stream.servicebus.bindings.<binding-name>.producer.entity-type is required to be configured.
Advanced Producer Configuration

The above connection and common Azure SDK client configuration are supported to be customized for each binder producer, which can be configured with the prefix spring.cloud.stream.servicebus.bindings.<binding-name>.producer..

14.2.4. Basic Usage

Sending and Receiving Messages from/to Service Bus

Step 1. Fill the configuration options with credential information.

  • For credentials as connection string, configure below properties in application.yml:

spring:
  cloud:
    azure:
      servicebus:
        connection-string: ${SERVICEBUS_NAMESPACE_CONNECTION_STRING}
    stream:
      function:
        definition: consume;supply
      bindings:
        consume-in-0:
          destination: ${SERVICEBUS_ENTITY_NAME}
          # If you use Service Bus Topic, please add below configuration
          # group: ${SUBSCRIPTION_NAME}
        supply-out-0:
          destination: ${SERVICEBUS_ENTITY_NAME_SAME_AS_ABOVE}
      servicebus:
        bindings:
          consume-in-0:
            consumer:
              auto-complete: false
          supply-out-0:
            producer:
              entity-type: queue # set as "topic" if you use Service Bus Topic
  • For credentials as service principal, configure below properties in application.yml:

spring:
  cloud:
    azure:
      credential:
        client-id: ${AZURE_CLIENT_ID}
        client-secret: ${AZURE_CLIENT_SECRET}
      profile:
        tenant-id: ${AZURE_TENANT_ID}
      servicebus:
        namespace: ${SERVICEBUS_NAMESPACE}
    stream:
      function:
        definition: consume;supply
      bindings:
        consume-in-0:
          destination: ${SERVICEBUS_ENTITY_NAME}
          # If you use Service Bus Topic, please add below configuration
          # group: ${SUBSCRIPTION_NAME}
        supply-out-0:
          destination: ${SERVICEBUS_ENTITY_NAME_SAME_AS_ABOVE}
      servicebus:
        bindings:
          consume-in-0:
            consumer:
              auto-complete: false
          supply-out-0:
            producer:
              entity-type: queue # set as "topic" if you use Service Bus Topic
  • For credentials as managed identities, configure below properties in application.yml:

spring:
  cloud:
    azure:
      credential:
        managed-identity-enabled: true
        client-id: ${MANAGED_IDENTITY_CLIENT_ID} # Only needed when using a user-assigned managed identity
      servicebus:
        namespace: ${SERVICEBUS_NAMESPACE}
    stream:
      function:
        definition: consume;supply
      bindings:
        consume-in-0:
          destination: ${SERVICEBUS_ENTITY_NAME}
          # If you use Service Bus Topic, please add below configuration
          # group: ${SUBSCRIPTION_NAME}
        supply-out-0:
          destination: ${SERVICEBUS_ENTITY_NAME_SAME_AS_ABOVE}
      servicebus:
        bindings:
          consume-in-0:
            consumer:
              auto-complete: false
          supply-out-0:
            producer:
              entity-type: queue # set as "topic" if you use Service Bus Topic

Step 2. Define supplier and consumer.

@Bean
public Consumer<Message<String>> consume() {
    return message -> {
        Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
        LOGGER.info("New message received: '{}', partition key: {}, sequence number: {}, offset: {}, enqueued time: {}",
                message.getPayload(),
                message.getHeaders().get(EventHubsHeaders.PARTITION_KEY),
                message.getHeaders().get(EventHubsHeaders.SEQUENCE_NUMBER),
                message.getHeaders().get(EventHubsHeaders.OFFSET),
                message.getHeaders().get(EventHubsHeaders.ENQUEUED_TIME)
        );

        checkpointer.success()
                .doOnSuccess(success -> LOGGER.info("Message '{}' successfully checkpointed", message.getPayload()))
                .doOnError(error -> LOGGER.error("Exception found", error))
                .block();
    };
}

@Bean
public Supplier<Message<String>> supply() {
    return () -> {
        LOGGER.info("Sending message, sequence " + i);
        return MessageBuilder.withPayload("Hello world, " + i++).build();
    };
}
Partition Key Support

The binder supports Service Bus partitioning by allowing setting partition key and session id in the message header. This section introduces how to set partition key for messages.

Spring Cloud Stream provides a partition key SpEL expression property spring.cloud.stream.bindings.<binding-name>.producer.partition-key-expression. For example, setting this property as "'partitionKey-' + headers[<message-header-key>]" and add a header called <message-header-key>. Spring Cloud Stream will use the value for this header when evaluating the above expression to assign a partition key. Here is an example producer code:

@Bean
public Supplier<Message<String>> generate() {
    return () -> {
        String value = “random payload”;
        return MessageBuilder.withPayload(value)
            .setHeader("<message-header-key>", value.length() % 4)
            .build();
    };
}
Session Support

The binder supports message sessions of Service Bus. Session id of a message could be set via the message header.

@Bean
public Supplier<Message<String>> generate() {
    return () -> {
        String value = “random payload”;
        return MessageBuilder.withPayload(value)
            .setHeader(ServiceBusMessageHeaders.SESSION_ID, "Customize session id")
            .build();
    };
}
According to Service Bus partitioning, session id has higher priority than partition key. So when both of ServiceBusMessageHeaders#SESSION_ID and ServiceBusMessageHeaders#PARTITION_KEY (or AzureHeaders#PARTITION_KEY) headers are set, the value of the session id will eventually be used to overwrite the value of the partition key.
Error Channels
  • Consumer error channel

This channel is open by default, and a default consumer error channel handler is used to send failed messages to the dead-letter queue when spring.cloud.stream.servicebus.bindings.<binding-name>.consumer.requeue-rejected is enabled, otherwise the failed messages will be abandoned.

To customize the consumer error channel handler, you can register you own error handler to the related consumer error channel in this way:

// Replace destination with spring.cloud.stream.bindings.input.destination
// Replace group with spring.cloud.stream.bindings.input.group
@ServiceActivator(inputChannel = "{destination}.{group}.errors")
public void consumerError(Message<?> message) {
    LOGGER.error("Handling customer ERROR: " + message);
}
  • Producer error channel

This channel is not open by default. You need to add a configuration in your application.properties to enable it, like this:

spring.cloud.stream.default.producer.errorChannelEnabled=true

You can handle the error message in this way:

// Replace destination with spring.cloud.stream.bindings.output.destination
@ServiceActivator(inputChannel = "{destination}.errors")
public void producerError(Message<?> message) {
    LOGGER.error("Handling Producer ERROR: " + message);
}
  • Global default error channel

A global error channel called "errorChannel" is created by default Spring Integration, which allows users to subscribe many endpoints to it.

@ServiceActivator(inputChannel = "errorChannel")
public void producerError(Message<?> message) {
    LOGGER.error("Handling ERROR: " + message);
}
Service Bus Message Headers

See the Service Bus message headers for the basic message headers supported.

When setting the partiton key, the priority of message header is higher than Spring Cloud Stream property. So spring.cloud.stream.bindings.<binding-name>.producer.partition-key-expression will take effect only when none of the headers of ServiceBusMessageHeaders#SESSION_ID, ServiceBusMessageHeaders#PARTITION_KEY, AzureHeaders#PARTITION_KEY is configured.
Multiple Binder Support

Connection to multiple Service Bus namespaces is also supported by using multiple binders. This sample takes connection string as example. Credentials of service principals and managed identities are also supported, users can set related properties in each binder’s environment settings.

Step 1. To use multiple binders of ServiceBus, we need to configure below properties in application.yml

spring:
  cloud:
    stream:
      function:
        definition: consume1;supply1;consume2;supply2
      bindings:
        consume1-in-0:
          destination: ${SERVICEBUS_TOPIC_NAME}
          group: ${SUBSCRIPTION_NAME}
        supply1-out-0:
          destination: ${SERVICEBUS_TOPIC_NAME_SAME_AS_ABOVE}
        consume2-in-0:
          binder: servicebus-2
          destination: ${SERVICEBUS_QUEUE_NAME}
        supply2-out-0:
          binder: servicebus-2
          destination: ${SERVICEBUS_QUEUE_NAME_SAME_AS_ABOVE}
      binders:
        servicebus-1:
          type: servicebus
          default-candidate: true
          environment:
            spring:
              cloud:
                azure:
                  servicebus:
                    connection-string: ${SERVICEBUS_NAMESPACE_01_CONNECTION_STRING}
        servicebus-2:
          type: servicebus
          default-candidate: false
          environment:
            spring:
              cloud:
                azure:
                  servicebus:
                    connection-string: ${SERVICEBUS_NAMESPACE_02_CONNECTION_STRING}
      servicebus:
        bindings:
          consume1-in-0:
            consumer:
              auto-complete: false
          supply1-out-0:
            producer:
              entity-type: topic
          consume2-in-0:
            consumer:
              auto-complete: false
          supply2-out-0:
            producer:
              entity-type: queue
      poller:
        initial-delay: 0
        fixed-delay: 1000

Step 2. we need define two suppliers and two consumers

@Bean
public Supplier<Message<String>> supply1() {
    return () -> {
        LOGGER.info("Sending message1, sequence1 " + i);
        return MessageBuilder.withPayload("Hello world1, " + i++).build();
    };
}

@Bean
public Supplier<Message<String>> supply2() {
    return () -> {
        LOGGER.info("Sending message2, sequence2 " + j);
        return MessageBuilder.withPayload("Hello world2, " + j++).build();
    };
}

@Bean
public Consumer<Message<String>> consume1() {
    return message -> {
        Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
        LOGGER.info("New message1 received: '{}'", message);
        checkpointer.success()
                .doOnSuccess(s -> LOGGER.info("Message '{}' successfully checkpointed", message.getPayload()))
                .doOnError(e -> LOGGER.error("Error found", e))
                .block();
    };
}

@Bean
public Consumer<Message<String>> consume2() {
    return message -> {
        Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
        LOGGER.info("New message2 received: '{}'", message);
        checkpointer.success()
                .doOnSuccess(s -> LOGGER.info("Message '{}' successfully checkpointed", message.getPayload()))
                .doOnError(e -> LOGGER.error("Error found", e))
                .block();
    };

}
Resource Provision

Service bus binder supports provisioning of queue, topic and subscription, users could use below properties to enable provisioning.

spring:
  cloud:
    azure:
      credential:
        tenant-id: ${AZURE_TENANT_ID}
      profile:
        subscription-id: ${AZURE_SUBSCRIPTION_ID}
      servicebus:
        resource:
          resource-group: ${AZURE_SERVICEBUS_RESOURECE_GROUP}
    stream:
      servicebus:
        bindings:
          <binding-name>:
            consumer:
              entity-type: ${SERVICEBUS_CONSUMER_ENTITY_TYPE}

14.2.5. Samples

Please refer to azure-spring-boot-samples for more details.

15. Spring JMS Support

To use Azure Service Bus by the JMS API integrated into the Spring JMS framework. Azure Service Bus connection string have to be provided which is to be parsed into the login username, password and remote URI for the AMQP broker.

15.1. Dependency Setup

Adding below dependencies if you want to migrate your Spring JMS application to use Azure Service Bus.

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter-servicebus-jms</artifactId>
</dependency>

15.2. Configuration

Table 34. Configurable properties when using Spring JMS support
Property Description

spring.jms.servicebus.connection-string

Azure Service Bus connection string. Should be provided when want to provide the connection string directly.

spring.jms.servicebus.topic-client-id

JMS clientID. Only works for the bean of topicJmsListenerContainerFactory.

spring.jms.servicebus.idle-timeout

The duration for idle.

spring.jms.servicebus.pricing-tier

The Azure Service Bus Price Tier.

spring.jms.servicebus.listener.reply-pub-sub-domain

Whether the reply destination type is topic.

spring.jms.servicebus.listener.phase

Specify the phase in which this container should be started and stopped.

spring.jms.servicebus.listener.reply-qos-settings

Configure the QosSettings to use when sending a reply.

spring.jms.servicebus.listener.subscription-durable

Whether to make the subscription durable. Only works for the bean of topicJmsListenerContainerFactory.

spring.jms.servicebus.listener.subscription-shared

Whether to make the subscription shared. Only works for the bean of topicJmsListenerContainerFactory.

spring.jms.servicebus.password

Login password of the AMQP broker

spring.jms.servicebus.pool.block-if-full

Whether to block when a connection is requested and the pool is full.

spring.jms.servicebus.pool.block-if-full-timeout

Blocking period before throwing an exception if the pool is still full.

spring.jms.servicebus.pool.enabled

Whether a JmsPoolConnectionFactory should be created, instead of a regularConnectionFactory.

spring.jms.servicebus.pool.idle-timeout

Connection idle timeout.

spring.jms.servicebus.pool.max-connections

Maximum number of pooled connections.

spring.jms.servicebus.pool.max-sessions-per-connection

Maximum number of pooled sessions per connection in the pool.

spring.jms.servicebus.pool.time-between-expiration-check

Time to sleep between runs of the idle connection eviction thread.

spring.jms.servicebus.pool.use-anonymous-producers

Whether to use only one anonymous "MessageProducer" instance.

spring.jms.servicebus.prefetch-policy.all

Fallback value for prefetch option in this Service Bus namespace.

spring.jms.servicebus.prefetch-policy.durable-topic-prefetch

The number of prefetch for durable topic.

spring.jms.servicebus.prefetch-policy.queue-browser-prefetch

The number of prefetch for queue browser.

spring.jms.servicebus.prefetch-policy.queue-prefetch

The number of prefetch for queue.

spring.jms.servicebus.prefetch-policy.topic-prefetch

The number of prefetch for topic.

spring.jms.servicebus.remote-url

URL of the AMQP broker.

spring.jms.servicebus.username

Login user of the AMQP broker.

Spring JMS general configuration is omited for short. Please refer to Spring JMS Document for more details.

15.3. Basic Usage

15.3.1. Use Service Bus Connection String

The simplest way to connect to Service Bus for Spring JMS application is with the connection string.

Add below properties and you are good to go.

spring:
  jms:
    servicebus:
      connection-string: ${AZURE_SERVICEBUS_CONNECTION_STRING}
      pricing-tier: ${PRICING_TIER}
The default enabled ConnectionFactory is the CachingConnectionFactory which adds Session caching as well MessageProducer caching. If you want to activate the connection pooling featured one of JmsPoolConnectionFactory, the property of spring.jms.servicebus.pool.enabled should be specified true. You can find other pooling configuration options (properties with prefix spring.jms.servicebus.pool.) from the above Configuration section.

15.4. Samples

Please refer to azure-spring-boot-samples for more details.

16. Kafka Support

Connect to Azure Event Hubs (Basic pricing tier is not supported) using Spring Kafka libraries. There are two approaches to connect to Azure Event Hubs for Kafka, the first one is to provide the Azure Event Hubs connection string directly, the other is to use Azure Resource Manager to retrieve the connection string.

16.1. Dependency Setup

Adding below dependencies if you want to migrate your Apache Kafka application to use Azure Event Hubs for Kafka.

<dependency>
  <groupId>com.azure.spring</groupId>
  <artifactId>spring-cloud-azure-starter</artifactId>
</dependency>

If you want to retrieve the connection string using Azure Resource Manager, please also add below dependency

<dependency>
  <groupId>com.azure.spring</groupId>
  <artifactId>spring-cloud-azure-resourcemanager</artifactId>
</dependency>

16.2. Configuration

If you choose to use a security principal to authenticate and authorize with Azure Active Directory for accessing an Azure resource, please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure resource.
Table 35. Configurable properties when using Kafka support
Property Description

spring.cloud.azure.eventhubs.kafka.enabled

Whether to enable the Azure Event Hubs Kafka support, default to true.

spring.cloud.azure.eventhubs.connection-string

Azure Event Hubs connection string. Should be provided when want to provide the connection string directly.

spring.cloud.azure.eventhubs.namespace

Azure Event Hubs namespace. Should be provided when want to retrieve the connection information through Azure Resource Manager.

spring.cloud.azure.eventhubs.resource.resource-group

The resource group of Azure Event Hubs namespace. Should be provided when want to retrieve the connection information through Azure Resource Manager.

spring.cloud.azure.profile.subscription-id

The subscription id. Should be provided when want to retrieve the connection information through Azure Resource Manager.

Authentication information is also required for authenticating for Azure Resource Manager. The credential related configurations of Resource Manager should be configured under prefix spring.cloud.azure. Please refer to Authentication for more details.

16.3. Basic Usage

16.3.1. Use Event Hubs Connection String

The simplest way to connect to Event Hubs for Kafka is with the connection string.

Add below properties and you are good to go.

spring:
  cloud:
    azure:
      eventhubs:
        connection-string: ${AZURE_EVENTHUBS_CONNECTION_STRING}

16.3.2. Use Azure Resource Manager to Retrieve Connection String

If you don’t want to configure connection string in your application, it’s also possible to use Azure Resource Manager to retrieve the connection string. And you could use credentials stored in Azure CLI or other local development tool, like Visual Studio Code or Intellij IDEA to authenticate with Azure Resource Manager. Or Managed Identity if your application is deployed to Azure Cloud. Just make sure the principal have sufficient permission to read resource metadata.

Add below properties and you are good to go.

spring:
  cloud:
    azure:
      profile:
        subscription-id: ${AZURE_SUBSCRIPTION_ID}
      eventhubs:
        namespace: ${AZURE_EVENTHUBS_NAMESPACE}
        resource:
          resource-group: ${AZURE_EVENTHUBS_RESOURCE_GROUP}

16.4. Samples

Please refer to azure-spring-boot-samples for more details.

17. Redis Support

Connect to Azure Cache for Redis using Spring Redis libraries. With adding spring-cloud-azure-starter and spring-cloud-azure-resourcemanager to your application, it’s possible to read the Azure Cache for Redis connection information through Azure Resource Manager and auto-configure the Redis properties.

17.1. Dependency Setup

Adding below dependencies if you want to use the Spring Cloud Azure Redis support to your Spring Boot application using Redis.

<dependencies>
    <dependency>
      <groupId>com.azure.spring</groupId>
      <artifactId>spring-cloud-azure-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>com.azure.spring</groupId>
      <artifactId>spring-cloud-azure-resourcemanager</artifactId>
    </dependency>
</dependencies>

17.2. Configuration

If you choose to use a security principal to authenticate and authorize with Azure Active Directory for accessing an Azure resource, please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure resource.
Table 36. Configurable properties when using Redis support
Property Description Default Value Required

spring.cloud.azure.redis.enabled

Azure Cache for Redis instance name.

true

No

spring.cloud.azure.redis.name

Azure Cache for Redis instance name.

Yes

spring.cloud.azure.redis.resource.resource-group

The resource group of Azure Cache for Redis.

Yes

spring.cloud.azure.profile.subscription-id

The subscription id.

Yes

Authentication information is also required for authenticating for Azure Resource Manager. The credential related configurations of Resource Manager should be configured under prefix spring.cloud.azure. Please refer to Authentication for more details.

17.3. Basic Usage

Add below properties and you are good to go.

spring.cloud.azure.redis.name=${AZURE_CACHE_REDIS_NAME}
spring.cloud.azure.redis.resource.resource-group=${AZURE_CACHE_REDIS_RESOURCE_GROUP}

17.4. Samples

Please refer to azure-spring-boot-samples for more details.

18. Resource Manager

Azure Resource Manager (ARM) is the deployment and management service for Azure. It provides a management layer that enables you to create, update, and delete resources in your Azure account. Spring Cloud Azure Resourcemanger can help provision resources or retrieve resource metadata.

18.1. Dependency Setup

<dependency>
  <groupId>com.azure.spring</groupId>
  <artifactId>spring-cloud-azure-resourcemanager</artifactId>
</dependency>

18.2. Configuration

If you choose to use a security principal to authenticate and authorize with Azure Active Directory for accessing an Azure resource, please refer to Authorize access with Azure AD to make sure the security principal has been granted the sufficient permission to access the Azure resource.
Table 37. Configurable properties of spring-cloud-azure-resourcemanager
Property Description

spring.cloud.azure.resource-manager.enabled

Whether the Resource Manager is enabled. Default is true.

spring.cloud.azure.credential.client-id

Client id to use when performing service principal authentication with Azure.

spring.cloud.azure.credential.client-secret

Client secret to use when performing service principal authentication with Azure.

spring.cloud.azure.credential.client-certificate-path

Path of a PEM certificate file to use when performing service principal authentication with Azure.

spring.cloud.azure.credential.client-certificate-password

Password of the certificate file.

spring.cloud.azure.credential.username

Username to use when performing username/password authentication with Azure.

spring.cloud.azure.credential.password

Password to use when performing username/password authentication.

spring.cloud.azure.credential.managed-identity-enabled

Whether to enable managed identity.

spring.cloud.azure.profile.cloud-type

Name of the Azure cloud to connect to.

spring.cloud.azure.profile.environment.active-directory-endpoint

The Azure Active Directory endpoint to connect to for authentication.

spring.cloud.azure.profile.subscription-id

Subscription id to use when connecting to Azure resources.

spring.cloud.azure.profile.tenant-id

Tenant id for Azure resources.

spring.cloud.azure.<azure-service>.namespace

The namespace of the Azure service to provision resources with.

spring.cloud.azure.<azure-service>.resource.resource-group

The resource group holding an Azure service resource.

18.3. Basic Usage

Spring Cloud Azure Resource Manager can work together with specific Spring Cloud Azure starters to retrieve connection information, such as connection strings, to connect to Azure services. It can also together with spring-cloud-azure-starter and third-party libraries to retrieve metadata like username/password, to complete authentication, such as: Kafka Support, Redis Support.

For example, to retrieve the connection string of an Azure Service, developers can use a service principal as the credential to authenticate and retrieve the connection string. The configuration is listed as below. The provided service principal should be assigned a role of Contributor of the associated namespace at least. Please refer to Authorize access with Azure AD to make sure the principal has been granted the sufficient permission to access the Azure resource.

spring:
  cloud:
    azure:
      credential:
        client-id: ${AZURE_CLIENT_ID}
        client-secret: ${AZURE_CLIENT_SECRET}
      profile:
        tenant-id: ${AZURE_TENANT_ID}
        subscription-id: ${AZURE_SUBSCRIPTION_ID}
      <azure-service>:
        namespace: ${SERVICEBUS_NAMESPACE}
        resource:
          resource-group: ${RESOURCE_GROUP}

18.4. Samples

Please refer to azure-spring-boot-samples for more details.

19. Configuration Properties

To see the list of all Spring Cloud Azure related configuration properties please check the Appendix page.

20. Appendix