{"id":3331,"date":"2025-02-17T09:05:08","date_gmt":"2025-02-17T17:05:08","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/azure-sdk\/?p=3331"},"modified":"2025-02-17T09:05:08","modified_gmt":"2025-02-17T17:05:08","slug":"spring-cloud-azure-updates-and-troubleshooting-tips-for-java-on-aks","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/azure-sdk\/spring-cloud-azure-updates-and-troubleshooting-tips-for-java-on-aks\/","title":{"rendered":"Spring Cloud Azure updates and troubleshooting tips for Java on AKS"},"content":{"rendered":"<p>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&#8217;s new and how it can benefit your projects.<\/p>\n<h2>Fresh capabilities to explore<\/h2>\n<p>Discover the latest features and enhancements in Spring Cloud Azure, designed to address common user scenarios and improve your development experience.<\/p>\n<h3>Full support for Spring Boot 3.4<\/h3>\n<p>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 <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-java\/blob\/main\/sdk\/spring\/CHANGELOG.md\">release notes<\/a>.<\/p>\n<h3>Enhanced configuration of authentication mechanism<\/h3>\n<p>Spring Cloud Azure offers flexible configuration properties, prefixed with <code>spring.cloud.azure.credential.<\/code>, to manage several types of credentials, such as service principals and managed identities. With the latest enhancement, you can now use <code>spring.cloud.azure.credential.token-credential-bean-name<\/code> to further customize your authentication beans, providing even greater control over your application&#8217;s security.<\/p>\n<p>First, define a <code>TokenCredential<\/code> bean in your application:<\/p>\n<pre><code class=\"language-java\">@Bean\r\nTokenCredential myTokenCredential() {\r\n    \/\/ Your concrete TokenCredential instance\r\n}<\/code><\/pre>\n<p>Next, add one property entry for it:<\/p>\n<pre><code class=\"language-yaml\">spring:\r\n  cloud:\r\n    azure:\r\n      credential:\r\n        token-credential-bean-name: myTokenCredential<\/code><\/pre>\n<h4>Configuration for Azure SDK clients<\/h4>\n<p>Not only can the <code>token-credential-bean-name<\/code> property be configured at the <code>spring.cloud.azure<\/code> level, but it can also be configured for each service client. For example, you could configure it for the Azure Storage blob client:<\/p>\n<pre><code class=\"language-yaml\">spring:\r\n  cloud:\r\n    azure:\r\n      storage:\r\n        blob:\r\n          account-name: &lt;your-azure-storage-account-name&gt;\r\n          container-name: &lt;your-blob-container-name&gt;\r\n          credential:\r\n            token-credential-bean-name: myTokenCredential<\/code><\/pre>\n<h4>Configuration for passwordless connections<\/h4>\n<p>Apart from configuring the token credential for Azure SDK clients, you could also configure it for other Azure services like Azure Database for MySQL &#8211; Flexible Server, Azure Database for PostgreSQL &#8211; Flexible Server, Azure Cache for Redis, and Service Bus. The following configuration is an example for the Redis passwordless connection:<\/p>\n<pre><code class=\"language-yaml\">spring:\r\n  data:\r\n    redis:\r\n      host: &lt;your-azure-redis-name&gt;.redis.cache.windows.net\r\n      port: 6380\r\n      ssl:\r\n        enabled: true\r\n      azure:\r\n        passwordless-enabled: true\r\n        credential:\r\n          token-credential-bean-name: myTokenCredential<\/code><\/pre>\n<p>And the following configuration is an example for a Service Bus JMS passwordless connection:<\/p>\n<pre><code class=\"language-yaml\">spring:\r\n  jms:\r\n    servicebus:\r\n      pricing-tier: &lt;your-service-bus-pricing-tier&gt;\r\n      namespace: &lt;your-service-bus-namespace&gt;\r\n      topic-client-id: &lt;topic-client-id&gt;\r\n      passwordless-enabled: true\r\n      credential:\r\n        token-credential-bean-name: myTokenCredential<\/code><\/pre>\n<h4>Configuration for Key Vault property source<\/h4>\n<p>Since the Key Vault property source authenticates at an earlier initialization stage, the <code>token-credential-bean-name<\/code> property doesn&#8217;t take effect on it. But you can still configure a customized <code>TokenCredential<\/code> for it. For example, before the Spring Boot application runs, register a token credential object for authentication to Key Vault:<\/p>\n<pre><code class=\"language-java\">public static void main(String[] args) {\r\n    SpringApplication application = new SpringApplication(YourSpringApplication.class);\r\n    application.addBootstrapRegistryInitializer(registry -&gt; \r\n        registry.register(TokenCredential.class, context -&gt; {\r\n            \/\/ Your concrete TokenCredential instance \r\n        }));\r\n    application.run(args);\r\n}<\/code><\/pre>\n<h3>New Java Diagnostic Tool on AKS<\/h3>\n<p>The Java Diagnostic Tool (diag4j) is a lightweight, nonintrusive monitoring and diagnostic solution for Java applications running on AKS.<\/p>\n<p>Key features of the tool include:<\/p>\n<ul>\n<li>Lightweight and noninvasive: By using Spring Boot Admin (SBA) and the Java Attach Agent, the tool is resource-efficient and doesn&#8217;t require extensive modifications to applications.<\/li>\n<li>Automatic Kubernetes Integration: The tool automatically discovers pods with exposed actuator endpoints, listing them on the SBA dashboard.<\/li>\n<li>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.<\/li>\n<li>Advanced diagnostics: The tool offers enhanced diagnostic features. These features include:\n<ul>\n<li>Inspection of stack traces<\/li>\n<li>Viewing of local variables<\/li>\n<li>Generation of heap and thread dumps<\/li>\n<li>Injection of logs dynamically for troubleshooting<\/li>\n<\/ul>\n<\/li>\n<li>IDE compatibility: The tool integrates with JetBrains IntelliJ to enable debugging without needing to rebuild or redeploy the application, enabling streamlined troubleshooting.<\/li>\n<\/ul>\n<p>For a detailed guide on getting started with diag4j, see <a href=\"https:\/\/learn.microsoft.com\/azure\/developer\/java\/fundamentals\/java-diagnostic-tools-on-aks-overview\">Get started with Java Diagnostic Tool<\/a>. Here&#8217;s a <a href=\"https:\/\/youtu.be\/srysxWp2tak\">video<\/a> about using diag4j.<\/p>\n<p>You can provide feedback or create an issue in <a href=\"https:\/\/github.com\/microsoft\/diag4j\">this GitHub repository<\/a>.<\/p>\n<h2>Common scenarios<\/h2>\n<p>In the following sections, we iterate through several common scenarios.<\/p>\n<h3>Dead-lettering a message using Service Bus JMS<\/h3>\n<p>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 <code>@JmsListener<\/code> annotation.<\/p>\n<p>First, use the following configuration:<\/p>\n<pre><code class=\"language-yaml\">spring:\r\n  jms:\r\n    listener:\r\n      session:\r\n        acknowledge-mode: CLIENT\r\n        transacted: false\r\n    servicebus:\r\n      pricing-tier: &lt;your-service-bus-pricing-tier&gt;\r\n      namespace: &lt;your-service-bus-namespace&gt;\r\n      passwordless-enabled: true<\/code><\/pre>\n<p>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:<\/p>\n<pre><code class=\"language-java\">@Component\r\npublic class QueueReceiveService {\r\n    private final Logger LOGGER = LoggerFactory.getLogger(QueueReceiveService.class);\r\n    private static final String QUEUE_NAME = \"&lt;your-queue-name&gt;\";\r\n\r\n    @JmsListener(destination = QUEUE_NAME, containerFactory = \"jmsListenerContainerFactory\")\r\n    public void receiveMessage(JmsObjectMessage message) throws JMSException {\r\n        User user = (User) message.getObject();\r\n        LOGGER.info(\"Received message from queue: {}.\", user);\r\n        if (user.getName().toLowerCase().contains(\"invalid\")) {\r\n            message.setIntProperty(JmsMessageSupport.JMS_AMQP_ACK_TYPE, REJECTED);\r\n            message.acknowledge();\r\n            LOGGER.info(\"Move message into dead letter queue: {}.\", user);\r\n        }\r\n    }\r\n}<\/code><\/pre>\n<p>Use the following sample code to consume DLQ messages from the Service Bus queue:<\/p>\n<pre><code class=\"language-java\">@Component\r\npublic class DeadLetterQueueReceiveService {\r\n    private final Logger LOGGER = LoggerFactory.getLogger(DeadLetterQueueReceiveService.class);\r\n    private static final String QUEUE_NAME = \"&lt;your-queue-name&gt;\";\r\n    private static final String DEAD_LETTER_QUEUE_NAME_SUFFIX = \"\/$deadletterqueue\";\r\n    private static final String DEAD_LETTER_QUEUE_NAME = QUEUE_NAME + DEAD_LETTER_QUEUE_NAME_SUFFIX;\r\n\r\n    @JmsListener(destination = DEAD_LETTER_QUEUE_NAME, containerFactory = \"jmsListenerContainerFactory\")\r\n    public void receiveDeadLetterMessage(JmsObjectMessage message) throws JMSException {\r\n        User user = (User) message.getObject();\r\n        LOGGER.info(\"Received message from dead letter queue: {}.\", user);\r\n    }\r\n}<\/code><\/pre>\n<h3>Refresh Key Vault property sources<\/h3>\n<p>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:<\/p>\n<pre><code class=\"language-yaml\">spring:\r\n  cloud:\r\n    azure:\r\n      keyvault:\r\n        secret:\r\n          property-source-enabled: true\r\n          property-sources:\r\n            - endpoint: ${KEY_VAULT_ENDPOINT_1}\r\n              name: KeyVault1\r\n              refresh-interval: 10s\r\n              secret-keys:\r\n                - one-minutes-available-username\r\n                - one-minutes-available-password\r\n            - endpoint: ${KEY_VAULT_ENDPOINT_2}\r\n              name: KeyVault2\r\n              refresh-interval: 30s\r\n              secret-keys: game-rules<\/code><\/pre>\n<h3>Configure passwordless connections with multiple data sources<\/h3>\n<p>Spring Data supports registering multiple data sources. As of Spring Cloud Azure JDBC Starter <code>5.18.0<\/code>, 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:<\/p>\n<pre><code class=\"language-yaml\">spring:\r\n  datasource:\r\n    read:\r\n      url: &lt;your-azure-database-jdbc-url&gt;\r\n      username: &lt;your-database-user-name-for-read&gt;\r\n      azure:\r\n        passwordless-enabled: true\r\n    write:\r\n      url: &lt;your-azure-database-jdbc-url&gt;\r\n      username: &lt;your-database-user-name-for-write&gt;\r\n      azure:\r\n        passwordless-enabled: true\r\n        credential:\r\n          token-credential-bean-name: myTokenCredential<\/code><\/pre>\n<p>This configuration uses different authentication methods for each data source. The first data source uses the Azure Identity library&#8217;s <code>DefaultAzureCredential<\/code> to authenticate with Microsoft Entra ID. The second data source uses the customized token credential bean.<\/p>\n<h2>Protect your applications with efficiency<\/h2>\n<p>Enhance your app&#8217;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 <code>TokenCredential<\/code> instances.<\/p>\n<h3>Key Vault JCA supports loading of intermediate certificates<\/h3>\n<p>Since version 2.10.0, the Key Vault Java Cryptography Architecture (JCA) can <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-java\/pull\/41303\">read intermediate certificates in certificate chains<\/a>. With the new version of <code>azure-security-keyvault-jca<\/code>, such kinds of certificates can be used too:<\/p>\n<ol>\n<li><a href=\"https:\/\/learn.microsoft.com\/azure\/developer\/java\/spring-framework\/configure-spring-boot-starter-java-app-with-azure-key-vault-certificates\">Enable HTTPS in Spring Boot application<\/a>.<\/li>\n<li><a href=\"https:\/\/techcommunity.microsoft.com\/blog\/appsonazureblog\/seamlessly-integrating-azure-keyvault-with-jarsigner-for-enhanced-security\/4125770\">Sign and verify jar files<\/a>.<\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/azure\/developer\/java\/fundamentals\/java-azure-keyvault-ssl-integration-jvm\">Use Azure Key Vault to deliver TLS\/SSL certificates to the Java Virtual Machine<\/a>.<\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/azure\/developer\/java\/fundamentals\/java-azure-keyvault-tomcat-integration?tabs=windows\">Use Azure Key Vault to deliver TLS\/SSL certificates to Apache Tomcat<\/a>.<\/li>\n<\/ol>\n<h3>Azure Identity Extensions now supports caching of token credential instances<\/h3>\n<p>As of Azure Identity Extensions version 1.2.0, the library supports caching of <code>TokenCredential<\/code> objects across multiple authentication invocations by default via the property <code>azure.tokenCredentialCacheEnabled<\/code>. This capability reduces the number of Microsoft Entra access token requests. For example, when using the Azure Identity library&#8217;s <code>WorkloadIdentityCredential<\/code>, 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:<\/p>\n<pre><code class=\"language-java\">Properties properties = new Properties();\r\nproperties.setProperty(\"user\", \"&lt;your-database-username&gt;\");\r\nproperties.setProperty(\"authenticationPluginClassName\", \r\n                           \"com.azure.identity.extensions.jdbc.postgresql.AzurePostgresqlAuthenticationPlugin\");\r\nproperties.setProperty(\"azure.tokenCredentialCacheEnabled\", \"false\");\r\nString url = \"&lt;your-database-jdbc-url&gt;\";\r\nConnection connection = DriverManager.getConnection(url, properties);\r\n\/\/ use connection to execute SQL<\/code><\/pre>\n<h2>Known issues<\/h2>\n<p>In the following section, note the known issues to be resolved as soon as possible after upgrading the newer version.<\/p>\n<h3>Use global managed identity credential<\/h3>\n<p>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:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-java\/issues\/42979\">#42979<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-java\/issues\/43787\">#43787<\/a><\/li>\n<\/ul>\n<h2>Feedback<\/h2>\n<p>Your feedback and contributions are always welcome on <a href=\"https:\/\/stackoverflow.com\/questions\/tagged\/spring-cloud-azure\">StackOverflow<\/a> or <a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-java\/issues?q=is%3Aissue+is%3Aopen+label%3Aazure-spring\">GitHub<\/a>.<\/p>\n<h2>Resources<\/h2>\n<p>To learn more about Spring Cloud Azure, we invite you to visit the following links:<\/p>\n<ul>\n<li><a href=\"https:\/\/aka.ms\/spring\/docs\">Reference Documentation<\/a><\/li>\n<li><a href=\"https:\/\/aka.ms\/spring\/msdocs\">Conceptual Documentation<\/a><\/li>\n<li><a href=\"https:\/\/aka.ms\/spring\/samples\">Code Samples<\/a><\/li>\n<li><a href=\"https:\/\/aka.ms\/spring\/versions\">Spring Version Mapping<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/Azure\/azure-sdk-for-java\/blob\/main\/sdk\/spring\/CHANGELOG.md\">CHANGELOGS of Spring Cloud Azure<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>This post shows the latest Spring Cloud Azure updates.<\/p>\n","protected":false},"author":109450,"featured_media":3332,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[160,871,872],"class_list":["post-3331","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-sdk","tag-java","tag-spring","tag-spring-cloud-azure"],"acf":[],"blog_post_summary":"<p>This post shows the latest Spring Cloud Azure updates.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/3331","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/users\/109450"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/comments?post=3331"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/posts\/3331\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media\/3332"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/media?parent=3331"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/categories?post=3331"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/azure-sdk\/wp-json\/wp\/v2\/tags?post=3331"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}