Moary Chen explores the latest advancements in Spring Cloud Azure with a special focus on Java applications deployed in Azure Kubernetes Service (AKS), offering comprehensive updates and troubleshooting tips.

Spring Cloud Azure: Latest Updates and Troubleshooting Tips for Java on AKS

By Moary Chen

This post explores the newest features, improvements, and bug fixes introduced in Spring Cloud Azure for Java developers, specifically covering versions 5.16.0 to 5.19.0. It also provides troubleshooting guidance for Java processes running on Azure Kubernetes Service (AKS) and highlights practical features such as advanced authentication, diagnostics tooling, passwordless connections, and known issues to be mindful of after upgrades.


Fresh Capabilities to Explore

Full Support for Spring Boot 3.4

Spring Cloud Azure 5.19.0 now fully supports Spring Boot 3.4.0 and later. Developers can adopt the newest Spring Boot features within their Azure-connected applications.

See the release notes for details.

Enhanced Configuration of Authentication Mechanism

Spring Cloud Azure lets you flexibly configure authentication properties, using the spring.cloud.azure.credential. prefix for credentials like service principals and managed identities. The new spring.cloud.azure.credential.token-credential-bean-name property allows further customization and control over authentication beans, improving the security of your applications.

Example: Custom TokenCredential Bean

Java Bean:

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

YAML Property:

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

Client-specific Configuration

You may configure the token-credential-bean-name for individual Azure SDK clients, such as Blob Storage:

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

Passwordless Connections

Configure the token credential for various Azure services, e.g., Azure Database for MySQL, PostgreSQL, Redis, and Service Bus.

Azure Redis Example:

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

Service Bus JMS Example:

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

Key Vault Property Source Authentication

For Key Vault property sources, token-credential-bean-name does not apply as authentication occurs earlier. Instead, a custom TokenCredential can be set during application bootstrap:

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

New Java Diagnostic Tool on AKS

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

Key features:

  • Lightweight Integration: Utilizes Spring Boot Admin and Java Attach Agent for minimal resource impact.
  • Automatic Kubernetes Integration: Detects pods with actuator endpoints and lists them in the SBA dashboard.
  • Real-time Metrics & Diagnostics: Presents live app metrics, GC status, environment variables, and allows dynamic log level adjustments.
  • Advanced Diagnostics: View stack traces, local variables, perform heap/thread dumps, dynamically inject logs.
  • IDE Compatibility: Integrates with JetBrains IntelliJ for streamlined, live debugging.

  • Get started with Java Diagnostic Tool
  • YouTube video: Diag4j in action
  • GitHub repository for feedback/issues

Common Scenarios

Dead-lettering a Message Using Service Bus JMS

Consume from the Service Bus Dead Letter Queue (DLQ) like any standard queue using @JmsListener.

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

Standard Queue Listener:

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

DLQ Listener:

@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 can now auto-refresh at configurable intervals for each source and property.

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 can now manage multiple data sources using passwordless authentication. From version 5.18.0, Spring Cloud Azure JDBC Starter supports this scenario:

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
  • The read data source uses DefaultAzureCredential (e.g., Microsoft Entra ID)
  • The write data source uses a custom token credential bean

Protecting Applications with Efficiency

Key Vault JCA Support for Intermediate Certificates

From version 2.10.0, Key Vault Java Cryptography Architecture (JCA) can read intermediate certificates in certificate chains:

Azure Identity Extensions: TokenCredential Caching

From version 1.2.0, Azure Identity Extensions supports caching of TokenCredential objects across authentication attempts. This reduces Microsoft Entra access token request load.

Disable Caching Example:

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 as needed

Known Issues

A defect regarding merging of global credential properties with each SDK properties bean was fixed in version 5.18.0. Upgrading to 5.19.0 may result in regression test failures for users of global managed identity credentials. Relevant issues:


Resources

Feedback and contributions welcome on Stack Overflow and GitHub.

This post appeared first on “Microsoft DevBlog”. Read the entire article here