February 17th, 2025

Spring Cloud Azure updates and troubleshooting tips for Java on AKS

Moary Chen
Software Engineer

In this post, we explore the newest features, improvements, and bug fixes in Spring Cloud Azure and Java on Azure. We cover versions 5.16.0 to 5.19.0 of Spring Cloud Azure and provide troubleshooting tips for Java processes on Azure Kubernetes Service (AKS). This comprehensive overview shows you what’s new and how it can benefit your projects.

Fresh capabilities to explore

Discover the latest features and enhancements in Spring Cloud Azure, designed to address common user scenarios and improve your development experience.

Full support for Spring Boot 3.4

Spring Cloud Azure 5.19.0 now fully supports Spring Boot 3.4.0 and later versions. This means you can apply the latest Spring Boot features in your applications. For more information, see the release notes.

Enhanced configuration of authentication mechanism

Spring Cloud Azure offers flexible configuration properties, prefixed with spring.cloud.azure.credential., to manage several types of credentials, such as service principals and managed identities. With the latest enhancement, you can now use spring.cloud.azure.credential.token-credential-bean-name to further customize your authentication beans, providing even greater control over your application’s security.

First, define a TokenCredential bean in your application:

@Bean
TokenCredential myTokenCredential() {
    // Your concrete TokenCredential instance
}

Next, add one property entry for it:

spring:
  cloud:
    azure:
      credential:
        token-credential-bean-name: myTokenCredential

Configuration for Azure SDK clients

Not only can the token-credential-bean-name property be configured at the spring.cloud.azure level, but it can also be configured for each service client. For example, you could configure it for the Azure Storage blob client:

spring:
  cloud:
    azure:
      storage:
        blob:
          account-name: <your-azure-storage-account-name>
          container-name: <your-blob-container-name>
          credential:
            token-credential-bean-name: myTokenCredential

Configuration for passwordless connections

Apart from configuring the token credential for Azure SDK clients, you could also configure it for other Azure services like Azure Database for MySQL – Flexible Server, Azure Database for PostgreSQL – Flexible Server, Azure Cache for Redis, and Service Bus. The following configuration is an example for the Redis passwordless connection:

spring:
  data:
    redis:
      host: <your-azure-redis-name>.redis.cache.windows.net
      port: 6380
      ssl:
        enabled: true
      azure:
        passwordless-enabled: true
        credential:
          token-credential-bean-name: myTokenCredential

And the following configuration is an example for a Service Bus JMS passwordless connection:

spring:
  jms:
    servicebus:
      pricing-tier: <your-service-bus-pricing-tier>
      namespace: <your-service-bus-namespace>
      topic-client-id: <topic-client-id>
      passwordless-enabled: true
      credential:
        token-credential-bean-name: myTokenCredential

Configuration for Key Vault property source

Since the Key Vault property source authenticates at an earlier initialization stage, the token-credential-bean-name property doesn’t take effect on it. But you can still configure a customized TokenCredential for it. For example, before the Spring Boot application runs, register a token credential object for authentication to Key Vault:

public static void main(String[] args) {
    SpringApplication application = new SpringApplication(YourSpringApplication.class);
    application.addBootstrapRegistryInitializer(registry -> 
        registry.register(TokenCredential.class, context -> {
            // Your concrete TokenCredential instance 
        }));
    application.run(args);
}

New Java Diagnostic Tool on AKS

The Java Diagnostic Tool (diag4j) is a lightweight, nonintrusive monitoring and diagnostic solution for Java applications running on AKS.

Key features of the tool include:

  • Lightweight and noninvasive: By using Spring Boot Admin (SBA) and the Java Attach Agent, the tool is resource-efficient and doesn’t require extensive modifications to applications.
  • Automatic Kubernetes Integration: The tool automatically discovers pods with exposed actuator endpoints, listing them on the SBA dashboard.
  • Real-time metrics and diagnostics: The tool displays real-time application metrics, garbage collection (GC) status, and environment variables. You can also adjust log levels dynamically for deeper insights into specific issues.
  • Advanced diagnostics: The tool offers enhanced diagnostic features. These features include:
    • Inspection of stack traces
    • Viewing of local variables
    • Generation of heap and thread dumps
    • Injection of logs dynamically for troubleshooting
  • IDE compatibility: The tool integrates with JetBrains IntelliJ to enable debugging without needing to rebuild or redeploy the application, enabling streamlined troubleshooting.

For a detailed guide on getting started with diag4j, see Get started with Java Diagnostic Tool. Here’s a video about using diag4j.

You can provide feedback or create an issue in this GitHub repository.

Common scenarios

In the following sections, we iterate through several common scenarios.

Dead-lettering a message using Service Bus JMS

Service Bus JMS provides a way to consume Dead Letter Queue (DLQ) messages from a Service Bus queue in the same way as consuming a queue using the @JmsListener annotation.

First, use the following configuration:

spring:
  jms:
    listener:
      session:
        acknowledge-mode: CLIENT
        transacted: false
    servicebus:
      pricing-tier: <your-service-bus-pricing-tier>
      namespace: <your-service-bus-namespace>
      passwordless-enabled: true

Use the following sample code to consume messages from the Service Bus queue. If the message is invalid, move it to the DLQ of the queue:

@Component
public class QueueReceiveService {
    private final Logger LOGGER = LoggerFactory.getLogger(QueueReceiveService.class);
    private static final String QUEUE_NAME = "<your-queue-name>";

    @JmsListener(destination = QUEUE_NAME, containerFactory = "jmsListenerContainerFactory")
    public void receiveMessage(JmsObjectMessage message) throws JMSException {
        User user = (User) message.getObject();
        LOGGER.info("Received message from queue: {}.", user);
        if (user.getName().toLowerCase().contains("invalid")) {
            message.setIntProperty(JmsMessageSupport.JMS_AMQP_ACK_TYPE, REJECTED);
            message.acknowledge();
            LOGGER.info("Move message into dead letter queue: {}.", user);
        }
    }
}

Use the following sample code to consume DLQ messages from the Service Bus queue:

@Component
public class DeadLetterQueueReceiveService {
    private final Logger LOGGER = LoggerFactory.getLogger(DeadLetterQueueReceiveService.class);
    private static final String QUEUE_NAME = "<your-queue-name>";
    private static final String DEAD_LETTER_QUEUE_NAME_SUFFIX = "/$deadletterqueue";
    private static final String DEAD_LETTER_QUEUE_NAME = QUEUE_NAME + DEAD_LETTER_QUEUE_NAME_SUFFIX;

    @JmsListener(destination = DEAD_LETTER_QUEUE_NAME, containerFactory = "jmsListenerContainerFactory")
    public void receiveDeadLetterMessage(JmsObjectMessage message) throws JMSException {
        User user = (User) message.getObject();
        LOGGER.info("Received message from dead letter queue: {}.", user);
    }
}

Refresh Key Vault property sources

Key Vault property sources support automatic refresh. For example, use the following configuration to refresh the secret keys. Then each property source can use a different refresh internal:

spring:
  cloud:
    azure:
      keyvault:
        secret:
          property-source-enabled: true
          property-sources:
            - endpoint: ${KEY_VAULT_ENDPOINT_1}
              name: KeyVault1
              refresh-interval: 10s
              secret-keys:
                - one-minutes-available-username
                - one-minutes-available-password
            - endpoint: ${KEY_VAULT_ENDPOINT_2}
              name: KeyVault2
              refresh-interval: 30s
              secret-keys: game-rules

Configure passwordless connections with multiple data sources

Spring Data supports registering multiple data sources. As of Spring Cloud Azure JDBC Starter 5.18.0, it also supports multiple data sources with passwordless connections. For example, use the following configuration to define two database sources for different operation permissions. One source is for read operations and the other is for write operations:

spring:
  datasource:
    read:
      url: <your-azure-database-jdbc-url>
      username: <your-database-user-name-for-read>
      azure:
        passwordless-enabled: true
    write:
      url: <your-azure-database-jdbc-url>
      username: <your-database-user-name-for-write>
      azure:
        passwordless-enabled: true
        credential:
          token-credential-bean-name: myTokenCredential

This configuration uses different authentication methods for each data source. The first data source uses the Azure Identity library’s DefaultAzureCredential to authenticate with Microsoft Entra ID. The second data source uses the customized token credential bean.

Protect your applications with efficiency

Enhance your app’s security and performance with the latest updates in Key Vault JCA and Azure Identity Extensions. These updates include support for intermediate certificates and caching TokenCredential instances.

Key Vault JCA supports loading of intermediate certificates

Since version 2.10.0, the Key Vault Java Cryptography Architecture (JCA) can read intermediate certificates in certificate chains. With the new version of azure-security-keyvault-jca, such kinds of certificates can be used too:

  1. Enable HTTPS in Spring Boot application.
  2. Sign and verify jar files.
  3. Use Azure Key Vault to deliver TLS/SSL certificates to the Java Virtual Machine.
  4. Use Azure Key Vault to deliver TLS/SSL certificates to Apache Tomcat.

Azure Identity Extensions now supports caching of token credential instances

As of Azure Identity Extensions version 1.2.0, the library supports caching of TokenCredential objects across multiple authentication invocations by default via the property azure.tokenCredentialCacheEnabled. This capability reduces the number of Microsoft Entra access token requests. For example, when using the Azure Identity library’s WorkloadIdentityCredential, more pressure is placed on the internal authorization server for access token acquisition if the token credential caching disabled. To disable token credential caching and to customize the access token acquisition timeout, use the following code:

Properties properties = new Properties();
properties.setProperty("user", "<your-database-username>");
properties.setProperty("authenticationPluginClassName", 
                           "com.azure.identity.extensions.jdbc.postgresql.AzurePostgresqlAuthenticationPlugin");
properties.setProperty("azure.tokenCredentialCacheEnabled", "false");
String url = "<your-database-jdbc-url>";
Connection connection = DriverManager.getConnection(url, properties);
// use connection to execute SQL

Known issues

In the following section, note the known issues to be resolved as soon as possible after upgrading the newer version.

Use global managed identity credential

As of Spring Cloud Azure version 5.18.0, a defect in merging the global credential properties bean to each SDK properties bean is fixed. If you upgrade from version 5.18.0 to 5.19.0 and use global managed identity credential, you should encounter regression test failures. For more information, see the following GitHub issues:

Feedback

Your feedback and contributions are always welcome on StackOverflow or GitHub.

Resources

To learn more about Spring Cloud Azure, we invite you to visit the following links:

Author

Moary Chen
Software Engineer

0 comments