<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Julien Dubois</title>
    <description>The latest articles on DEV Community by Julien Dubois (@jdubois).</description>
    <link>https://dev.to/jdubois</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F164968%2F7f6a964f-b6cf-44d2-a573-802ecf77bbd5.jpg</url>
      <title>DEV Community: Julien Dubois</title>
      <link>https://dev.to/jdubois</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jdubois"/>
    <language>en</language>
    <item>
      <title>Announcing NubesGen, an Open Source tool to automate Azure deployments</title>
      <dc:creator>Julien Dubois</dc:creator>
      <pubDate>Wed, 05 May 2021 14:22:07 +0000</pubDate>
      <link>https://dev.to/azure/announcing-nubesgen-an-open-source-tool-to-automate-azure-deployments-1l4a</link>
      <guid>https://dev.to/azure/announcing-nubesgen-an-open-source-tool-to-automate-azure-deployments-1l4a</guid>
      <description>&lt;p&gt;&lt;strong&gt;Going to production on Azure is only one &lt;code&gt;git push&lt;/code&gt; away&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is NubesGen?
&lt;/h2&gt;

&lt;p&gt;NubesGen &lt;a href="https://nubesgen.com/"&gt;https://nubesgen.com/&lt;/a&gt; is a Microsoft Open Source project, which provides a Web application that generates an Azure infrastructure graphically: you select easy-to-understand options ("an application server", "a PostgreSQL database"), and it'll generate a state-of-the-art Terraform configuration that you can import and tweak in your project.&lt;/p&gt;

&lt;p&gt;Using &lt;a href="https://github.com/microsoft/NubesGen/blob/main/docs/gitops-overview.md"&gt;GitOps practices&lt;/a&gt;, NubesGen can also fully automate applying that configuration: it provides one cloud infrastructure per branch in your project, and will build and deploy your code to this infrastructure.&lt;/p&gt;

&lt;p&gt;As a result, you can just &lt;code&gt;git push&lt;/code&gt; your code to Azure and both the infrastructure and the application deployment are handled for you. No need to go to the Azure portal, or learn how to configure everything!&lt;/p&gt;

&lt;h2&gt;
  
  
  Video tour of NubesGen, in less than 15 minutes
&lt;/h2&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/BHAX8BIkP-s"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the state of the project?
&lt;/h2&gt;

&lt;p&gt;NubesGen is Open Source, and uses the &lt;a href="https://github.com/microsoft/NubesGen/blob/main/LICENSE"&gt;MIT license&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's currently under development, but we already have a good number of people who tested it, which makes us confident to do a first technical preview release.&lt;/p&gt;

&lt;p&gt;You can already use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is a running instance of the project at &lt;a href="https://nubesgen.com/"&gt;https://nubesgen.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The source code is available at &lt;a href="https://github.com/microsoft/nubesgen/"&gt;https://github.com/microsoft/nubesgen/&lt;/a&gt;, as well as pre-built packages and Docker images on our &lt;a href="https://github.com/microsoft/NubesGen/releases"&gt;release page&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contributing to the project
&lt;/h2&gt;

&lt;p&gt;Currently NubesGen supports Azure App Service and Azure Functions, as well as some of their most popular options (MySQL, PostgreSQL, Blob Storage, Redis, Cosmos DB, etc.). We're looking for feedback and contributions to improve this existing support first.&lt;/p&gt;

&lt;p&gt;Once we have a stable code base for those popular options, we'll then expand the number of supported services, with offers like Azure Kubernetes Services, Azure Spring Cloud, Azure Service Bus. So if you know any of those technologies and are willing to contribute, don't hesitate to ping us and join!&lt;/p&gt;

&lt;p&gt;And as any new project, we'll be delighted to count you as one of our stargazers at &lt;a href="https://github.com/microsoft/NubesGen/stargazers"&gt;https://github.com/microsoft/NubesGen/stargazers&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;The best way to learn about NubesGen is to go to &lt;a href="https://nubesgen.com/"&gt;https://nubesgen.com/&lt;/a&gt; and use it!&lt;/p&gt;

</description>
      <category>azure</category>
      <category>terraform</category>
      <category>github</category>
      <category>docker</category>
    </item>
    <item>
      <title>New Java learning path on Microsoft Learn</title>
      <dc:creator>Julien Dubois</dc:creator>
      <pubDate>Thu, 10 Dec 2020 15:27:09 +0000</pubDate>
      <link>https://dev.to/azure/new-java-learning-path-on-microsoft-learn-jna</link>
      <guid>https://dev.to/azure/new-java-learning-path-on-microsoft-learn-jna</guid>
      <description>&lt;p&gt;&lt;a href="https://docs.microsoft.com/learn/?WT.mc_id=java-11777-judubois" rel="noopener noreferrer"&gt;MS Learn&lt;/a&gt; is Microsoft's flagship learning platform, delivering free online tutorials for everyone to study, understand and deliver great technical projects to the cloud.&lt;/p&gt;

&lt;p&gt;Today, we deliver a &lt;a href="https://docs.microsoft.com/learn/paths/java-on-azure/?WT.mc_id=java-11777-judubois" rel="noopener noreferrer"&gt;Java learning path on MS Learn&lt;/a&gt;, so all Java developers can benefit from the power of Azure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Java at Microsoft is huge
&lt;/h2&gt;

&lt;p&gt;It's been a long journey for Java at Microsoft. Java is currently used in many products and services by Microsoft: from Minecraft, to LinkedIn and Yammer, and Azure itself, where we have several Java specific offers like &lt;a href="https://azure.microsoft.com/services/spring-cloud/?WT.mc_id=java-11777-judubois" rel="noopener noreferrer"&gt;Azure Spring Cloud&lt;/a&gt; (for Spring developers) and &lt;a href="https://techcommunity.microsoft.com/t5/apps-on-azure/public-preview-a-managed-jboss-eap-experience-on-azure/ba-p/1700210/?WT.mc_id=java-11777-judubois" rel="noopener noreferrer"&gt;JBoss EAP on App Service&lt;/a&gt; (for Jakarta EE developers).&lt;/p&gt;

&lt;p&gt;Azure product groups and Microsoft's Java developer advocacy team are building this Java learning path. If you want to learn more about Java on Azure, you can head up to our &lt;a href="https://www.youtube.com/channel/UCySRyO_0qCXxnHb6p7vMFnQ" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt;, where we have interviews of Java Champions, tutorials, online conference sessions...&lt;/p&gt;

&lt;h2&gt;
  
  
  The MS Learn Java learning path
&lt;/h2&gt;

&lt;p&gt;The Java learning path is for Java developers who want to better understand what they can achieve with Azure. It starts with the basics of Azure, and will make you discover our main services relevant for Java developers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.microsoft.com/learn/paths/java-on-azure/?WT.mc_id=java-11777-judubois" rel="noopener noreferrer"&gt;Here is the Java learning path on MS Learn&lt;/a&gt;, in which you will be able to find the following modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/learn/modules/intro-to-java-azure/?WT.mc_id=java-11777-judubois" rel="noopener noreferrer"&gt;Introduction to Java on Azure&lt;/a&gt; will give you an overview of Java applications and related Azure services.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/learn/modules/java-target-destinations/?WT.mc_id=java-11777-judubois" rel="noopener noreferrer"&gt;Choose the right Azure service for deploying your Java application&lt;/a&gt; goes into the details of the main Azure services for Java developers, so you can choose the best service depending on your specific needs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/learn/modules/deploy-java-spring-boot-app-service-mysql/?WT.mc_id=java-11777-judubois" rel="noopener noreferrer"&gt;Deploy a Spring Boot app to Azure&lt;/a&gt; is for Spring Boot developers who want to deploy their application to Azure.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/learn/modules/create-java-webapp-to-app-service-linux/?WT.mc_id=java-11777-judubois" rel="noopener noreferrer"&gt;Deploy a Java web app to Azure&lt;/a&gt; is for Jakarta EE developers who want to deploy a JSF application to Azure.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/learn/modules/azure-spring-cloud-workshop/?WT.mc_id=java-11777-judubois" rel="noopener noreferrer"&gt;Deploy Spring microservices to Azure&lt;/a&gt; is for Spring Boot developers working on microservices architectures.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/learn/modules/build-cosmos-db-java-app/?WT.mc_id=java-11777-judubois" rel="noopener noreferrer"&gt;Build a Java app with cloud-scale NoSQL Cosmos DB&lt;/a&gt; is for Java developers who want to use the Cosmos DB NoSQL database on Azure.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/learn/modules/publish-web-app-with-maven-plugin-for-azure-app-service/?WT.mc_id=java-11777-judubois" rel="noopener noreferrer"&gt;Publish a web app to Azure by using the Maven Plugin for Azure App Service&lt;/a&gt; focuses on the Maven Azure plugin, and provides a sandbox environment for you to deploy a simple "Hello, world" Java application.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/learn/modules/develop-azure-functions-app-with-maven-plugin/?WT.mc_id=java-11777-judubois" rel="noopener noreferrer"&gt;Develop an App using the Maven Plugin for Azure Functions&lt;/a&gt; uses the Maven Azure plugin to create and deploy a Java serverless application, running on Azure Functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Meet the team
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjcplidujhqxw2qmb11nh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjcplidujhqxw2qmb11nh.jpg" alt="The Java learning path team"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This learning path was created by Java experts at Microsoft, here in alphabetical order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sandra Ahlgrimm - &lt;a href="https://twitter.com/sKriemhild" rel="noopener noreferrer"&gt;@sKriemhild&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Ashish Chhabria - &lt;a href="https://twitter.com/ashishc1" rel="noopener noreferrer"&gt;@ashishc1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Julien Dubois - &lt;a href="https://twitter.com/juliendubois" rel="noopener noreferrer"&gt;@juliendubois&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Andy Feldman&lt;/li&gt;
&lt;li&gt;Rory Preddy - &lt;a href="https://twitter.com/rorypreddy" rel="noopener noreferrer"&gt;@rorypreddy&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Yoshio Terada - &lt;a href="https://twitter.com/yoshioterada" rel="noopener noreferrer"&gt;@yoshioterada&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Asir Vedamuthu Selvasingh - &lt;a href="https://twitter.com/asirselvasingh" rel="noopener noreferrer"&gt;@asirselvasingh&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Nick Walker&lt;/li&gt;
&lt;li&gt;Yuchen Wang&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;This learning path is only the beginning! In the next few months, we expect to deliver several more modules for Java developers, covering broad topics like caching (with Azure Cache for Redis), immutable infrastructure (with Terraform), event messaging (with Azure Service Bus), serverless (with Azure Functions), or security (with Azure Active Directory).&lt;/p&gt;

&lt;p&gt;If you want to have the latest news on Java on Azure, please follow &lt;a href="https://twitter.com/JavaAtMicrosoft" rel="noopener noreferrer"&gt;@JavaAtMicrosoft&lt;/a&gt; on Twitter and subscribe to the &lt;a href="https://www.youtube.com/channel/UCySRyO_0qCXxnHb6p7vMFnQ" rel="noopener noreferrer"&gt;Java on Azure YouTube channel&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>azure</category>
      <category>spring</category>
    </item>
    <item>
      <title>Terraform for Java developers video series</title>
      <dc:creator>Julien Dubois</dc:creator>
      <pubDate>Fri, 04 Dec 2020 10:37:32 +0000</pubDate>
      <link>https://dev.to/azure/terraform-for-java-developers-video-series-1pfm</link>
      <guid>https://dev.to/azure/terraform-for-java-developers-video-series-1pfm</guid>
      <description>&lt;p&gt;&lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt; is one of those tools that many people talk about, but which can be a bit frightening for a Java developer.&lt;br&gt;
There are several reasons for this, but mainly it's because Terraform is an infrastructure tool: this is going to create cloud resources for you, which isn't something most Java developers are used to do, and while doing so it's going to cost you some money.&lt;br&gt;
And obviously, you are afraid that doing a wrong configuration is going to cost you a lot!&lt;br&gt;
This series of videos is made exactly with this issue in mind: using a classical Java project, the &lt;a href="https://github.com/spring-projects/spring-petclinic"&gt;Spring Petclinic&lt;/a&gt;, we'll gently introduce the most important Terraform concepts, so that at the end you'll be able to deploy with confidence a Spring Boot and MySQL infrastructure to the cloud.&lt;/p&gt;

&lt;p&gt;Each video is about 10 minutes long, so they are easy to consume, and they all have subtitles: if you have any issue following them, don't forget to turn those subtitles on!&lt;/p&gt;

&lt;p&gt;The final project is avaible on &lt;a href="https://github.com/jdubois/spring-petclinic/tree/deploy-to-azure/terraform"&gt;https://github.com/jdubois/spring-petclinic/tree/deploy-to-azure/terraform&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Terraform for Java developers, part (1/4)
&lt;/h2&gt;

&lt;p&gt;In this first video, we describe what Terraform is, and we fork the Spring Petclinic project (available at &lt;a href="https://github.com/spring-projects/spring-petclinic"&gt;https://github.com/spring-projects/spring-petclinic&lt;/a&gt;) to add a Terraform configuration.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/b0APzGlBWMA"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform for Java developers, part (2/4)
&lt;/h2&gt;

&lt;p&gt;In this second video, we create a MySQL server and configure it using Terraform, learning how Terraform manages state, and how it can create or update resources.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/mYZJqBVfACM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform for Java developers, part (3/4)
&lt;/h2&gt;

&lt;p&gt;In this third video, we talk about best practices to improve your Terraform code, as well as tooling to facilitate understanding your code.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/lCMhpqE4h3c"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform for Java developers, part (4/4)
&lt;/h2&gt;

&lt;p&gt;In this fourth video, we complete our Terraform configuration and add a Java application service, configure our Spring Boot project to be deployed on Azure, run everything in the cloud, and finish by destroying our infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/GBY_MvAF3Vg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Don't forget to subscribe to the &lt;a href="https://www.youtube.com/channel/UCySRyO_0qCXxnHb6p7vMFnQ"&gt;Java on Azure YouTube channel&lt;/a&gt; for more Java tutorials and content!&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>java</category>
      <category>azure</category>
      <category>spring</category>
    </item>
    <item>
      <title>Java distributed caching in the cloud with the new Azure discovery plugin for Hazelcast</title>
      <dc:creator>Julien Dubois</dc:creator>
      <pubDate>Tue, 14 Apr 2020 08:36:25 +0000</pubDate>
      <link>https://dev.to/azure/java-distributed-caching-in-the-cloud-with-the-new-azure-discovery-plugin-for-hazelcast-bme</link>
      <guid>https://dev.to/azure/java-distributed-caching-in-the-cloud-with-the-new-azure-discovery-plugin-for-hazelcast-bme</guid>
      <description>&lt;p&gt;Many thanks to &lt;a href="https://twitter.com/alparslan_avci" rel="noopener noreferrer"&gt;Alparslan Avci&lt;/a&gt; and &lt;a href="https://twitter.com/mesutcelik" rel="noopener noreferrer"&gt;Mesut Celik&lt;/a&gt; from Hazelcast for their very precious help when writing this blog entry!&lt;/p&gt;

&lt;h2&gt;
  
  
  The need for distributed caching in the cloud
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Scaling stateless applications in the cloud is easy, scaling a database is a lot more trouble.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you want to run applications efficiently in the cloud, you'll need to use a caching mechanism: if you don't cache your data, any spike in traffic will automatically result in a spike in your database requests. And your database is probably the part of your architecture that scales less, in particular if you're using an SQL database. Also, this is probably the most costly part of your architecture, so even if it does scale up, your bill is going to scale up too, and you probably don't want that.&lt;/p&gt;

&lt;p&gt;That's why in &lt;a href="https://www.jhipster.tech/" rel="noopener noreferrer"&gt;JHipster&lt;/a&gt;, we have worked very hard, for years, and with several major cache providers, in order to give you the best solution possible.&lt;/p&gt;

&lt;p&gt;Typically, we have two types of usage for cache:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hibernate second-level cache (often called "L2 cache"), that directly caches your entities.&lt;/li&gt;
&lt;li&gt;Spring Cache abstraction, that will cache more complex business objects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both have their advantages, and that's why we set them both up in JHipster.&lt;/p&gt;

&lt;p&gt;Then, we have different caching implementations, that fall in the following 3 main categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Local caches (like Caffeine): they are the most efficient, but they don't scale across nodes. So when you add more application nodes, you will have cache synchronization issues, and you will see old (stale) data.&lt;/li&gt;
&lt;li&gt;Remote caches (like Redis): they use a remote server, so they will scale up easily, but their performance is often order of magnitudes slower (to get an object you need to fetch it over the network, and then deserialize it - when for a local cache you are just doing a pointer to an object which is already inside your heap).&lt;/li&gt;
&lt;li&gt;Distributed caches (like Hazelcast): they would act as a local cache, but are able to scale when you add application nodes thanks to a distributed synchronization mechanism. High-end solutions like Hazelcast can also work as remote caches, but will benefit from having a local cache (often called "near cache") for improved performance. Those look like the best solution, but they come at a price: they are more complex to set up! Years ago, people would use multicast to find nodes automatically, but in the cloud you cannot use such a network feature, and you need a specific mechanism for the nodes to find each other.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post, we're going to have a look at a new solution, the Azure discovery plugin for Hazelcast: it uses a specific Azure API in order to scale automatically, solving the complex issue of configuring the distributed cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to the new Azure discovery plugin for Hazelcast
&lt;/h2&gt;

&lt;p&gt;The Azure discovery plugin for Hazelcast is an Open Source project developed by &lt;a href="https://twitter.com/alparslan_avci" rel="noopener noreferrer"&gt;Alparslan Avci&lt;/a&gt; from Hazelcast, and available on GitHub at &lt;a href="https://github.com/hazelcast/hazelcast-azure" rel="noopener noreferrer"&gt;https://github.com/hazelcast/hazelcast-azure&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Such a plugin has been released many years ago, so you might find information about an older version: this new release is a complete rewrite, that is much better has it uses the &lt;a href="https://docs.microsoft.com/azure/virtual-machines/windows/instance-metadata-service/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure Instance Metadata service&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.microsoft.com/azure/virtual-machines/windows/instance-metadata-service/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure Instance Metadata service&lt;/a&gt; is a REST Endpoint accessible to all IaaS virtual machines created via the Azure Resource Manager. The endpoint is available at a well-known non-routable IP address (169.254.169.254) that can be accessed only from within a virtual machine.&lt;/p&gt;

&lt;p&gt;The Azure discovery plugin for Hazelcast will need to authenticate to that REST endpoint, and then will query it to know which other virtual machines should be in the cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the Azure discovery plugin for Hazelcast
&lt;/h2&gt;

&lt;p&gt;All the code shown in this article comes from a specific Open Source project that I have created, and which you can check at &lt;a href="https://github.com/jdubois/jhipster-hazelcast-azure" rel="noopener noreferrer"&gt;https://github.com/jdubois/jhipster-hazelcast-azure&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is a modified &lt;a href="https://www.jhipster.tech/" rel="noopener noreferrer"&gt;JHipster&lt;/a&gt; application, as this plug in only works with the newly-released Hazelcast 4, which is not does not fully supports Spring Boot yet (Spring Boot Actuator isn't compatible with Hazelcast 4, but this will fixed with the next Micrometer release).&lt;/p&gt;

&lt;p&gt;To install Hazelcast 4 and the new Azure discovery plugin for Hazelcast, you need to add them as dependencies in your &lt;code&gt;pom.xml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.hazelcast&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;hazelcast&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;4.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.hazelcast&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;hazelcast-hibernate53&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.0.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we are not going to use it, if you have the Spring Boot support for Hazelcast in your dependencies (which would be the case for a JHipster application), you can remove this dependency, namely &lt;code&gt;com.hazelcast:hazelcast-spring&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring the Azure discovery plugin for Hazelcast
&lt;/h2&gt;

&lt;p&gt;For this example, we will use JHipster's &lt;code&gt;CacheConfiguration&lt;/code&gt; object, but greatly simplify it so you can use it easily in any classical Spring Boot application, and also to make it easier to understand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.mycompany.myapp.config&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.hazelcast.config.Config&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.hazelcast.core.Hazelcast&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.hazelcast.core.HazelcastInstance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.slf4j.Logger&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.slf4j.LoggerFactory&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.context.annotation.Bean&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.context.annotation.Configuration&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.core.env.Environment&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.core.env.Profiles&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CacheConfiguration&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoggerFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CacheConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Environment&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CacheConfiguration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Environment&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@PreDestroy&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Closing Cache Manager"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Hazelcast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;shutdownAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;HazelcastInstance&lt;/span&gt; &lt;span class="nf"&gt;hazelcastInstance&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Configuring Hazelcast"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Config&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setInstanceName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hazelcasttest"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// If running in Azure, use the Hazelcast Azure plugin&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;acceptsProfiles&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Profiles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"azure"&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Configuring the Hazelcast Azure plug-in"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNetworkConfig&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getJoin&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getMulticastConfig&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;setEnabled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNetworkConfig&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getJoin&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getAzureConfig&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;setEnabled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Hazelcast&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newHazelcastInstance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part here is the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNetworkConfig&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getJoin&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getAzureConfig&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;setEnabled&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are many more available configuration options detailed at &lt;a href="https://github.com/hazelcast/hazelcast-azure" rel="noopener noreferrer"&gt;https://github.com/hazelcast/hazelcast-azure&lt;/a&gt;, but that default setup is already good enough for most usual needs: the plugin will use the &lt;a href="https://docs.microsoft.com/azure/virtual-machines/windows/instance-metadata-service/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure Instance Metadata service&lt;/a&gt; to find other virtual machines in the same resource group, and will create a cluster with all of them.&lt;/p&gt;

&lt;p&gt;Some important notes on this cluster:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It will use the default private Virtual Network that is created when creating the Virtual Machines. That means that all communications will be hidden to the outside world, and that you don't need to configure a firewall for it (it is already open by default on that private network).&lt;/li&gt;
&lt;li&gt;This network uses the &lt;code&gt;10.0.0.0\24&lt;/code&gt; IP addresses, so you will probably see your Virtual Machines using IPs like &lt;code&gt;10.0.0.4&lt;/code&gt; and &lt;code&gt;10.0.0.5&lt;/code&gt; to communicate.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuring the virtual machines to access the Azure Instance Metadata service
&lt;/h2&gt;

&lt;p&gt;The plugin will only work if it can query the &lt;a href="https://docs.microsoft.com/azure/virtual-machines/windows/instance-metadata-service/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure Instance Metadata service&lt;/a&gt; and get the list of the other virtual machines that are configured in the current resource group.&lt;/p&gt;

&lt;p&gt;You will need to go to the &lt;a href="https://portal.azure.com/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure Portal&lt;/a&gt;, and for each virtual machine you will need to do the following operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable a system assigned managed identity to each virtual machine
&lt;/h3&gt;

&lt;p&gt;For each virtual machine, look at the &lt;code&gt;Identity&lt;/code&gt; menu item in the left menu, and enable a "System assigned" identity:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7z95cdiohtfjygehk6e3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7z95cdiohtfjygehk6e3.png" alt="Enable a system assigned managed identity"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will allow you to give roles to that virtual machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Give the "READ" role on the resource group to each virtual machine
&lt;/h3&gt;

&lt;p&gt;Still in the &lt;a href="https://portal.azure.com/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure Portal&lt;/a&gt;, go the resource group in which your virtual machines have been created.&lt;/p&gt;

&lt;p&gt;In the left menu, select &lt;code&gt;Access control (IAM)&lt;/code&gt;, and give the &lt;code&gt;Reader&lt;/code&gt; role to all the &lt;code&gt;Virtual Machines&lt;/code&gt; that you want in your cluster:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcookf9rxkj9vvbn9dlc0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcookf9rxkj9vvbn9dlc0.png" alt="Give the READ role"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Running everything and testing the cluster
&lt;/h2&gt;

&lt;p&gt;Now that everything is configured, you can run your Spring Boot applications in each Virtual Machine.&lt;/p&gt;

&lt;p&gt;If everything is correctly set up, each of them should have Hazelcast starting, and the nodes should all join the same cluster, like in this screenshot below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu0js6rutbd87gwcvji0u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu0js6rutbd87gwcvji0u.png" alt="Cluster running"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In that example, we can see that we have 2 nodes, using the private network that we described above (the IPs are &lt;code&gt;10.0.0.4&lt;/code&gt; and &lt;code&gt;10.0.0.5&lt;/code&gt;). You can see that the current node is &lt;code&gt;10.0.0.4&lt;/code&gt; (it has a &lt;code&gt;this&lt;/code&gt; next to it), and obviously you'll see the opposite on the other node (&lt;code&gt;10.0.0.4   ...   this&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;If you want to test that the cluster is working fine, an easy solution with the sample application that we created on &lt;a href="https://github.com/jdubois/jhipster-hazelcast-azure" rel="noopener noreferrer"&gt;https://github.com/jdubois/jhipster-hazelcast-azure&lt;/a&gt; is to do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open up port &lt;code&gt;8080&lt;/code&gt; on the public IP of each virtual machine&lt;/li&gt;
&lt;li&gt;Access each application using that public IP&lt;/li&gt;
&lt;li&gt;Modify some cached data on one node (as we use the Hibernate L2 cache, all database data is cached), and verify on the other node that the data changed accordingly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4h175amki5biw9eblqhu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4h175amki5biw9eblqhu.png" alt="Synchronized data"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A distributed cache is the best solution to scale cloud-native applications, but configuring it in the cloud can be challenging: the new Azure discovery plugin for Hazelcast is a great solution to solve that issue efficiently.&lt;/p&gt;

&lt;p&gt;This solution will work great when running virtual machines in Azure, but how will it work with more advanced Azure services?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you use &lt;a href="https://docs.microsoft.com/azure/app-service/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure App Services&lt;/a&gt;, the PaaS offering from Azure, you won't be able to use the private interface to connect nodes. However, you will still be able to use the Hazelcast Azure Discovery Plugin with Hazelcast Client to connect to a Hazelcast cluster running in Azure VMs. &lt;a href="https://github.com/hazelcast/hazelcast-azure#azure-app-services-support" rel="noopener noreferrer"&gt;Documentation is available here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you use &lt;a href="https://docs.microsoft.com/azure/aks/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure Kubernetes Service&lt;/a&gt;, have a look at the &lt;a href="https://github.com/hazelcast/charts" rel="noopener noreferrer"&gt;Hazelcast Helm Chart&lt;/a&gt; and the &lt;a href="https://github.com/hazelcast/hazelcast-operator" rel="noopener noreferrer"&gt;Hazelcast Kubernetes Operator&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you use JHipster with &lt;a href="https://docs.microsoft.com/azure/aks/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure Kubernetes Service&lt;/a&gt; or &lt;a href="https://docs.microsoft.com/azure/spring-cloud/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure Spring Cloud&lt;/a&gt;, you should have a look at how JHipster uses the &lt;a href="https://www.jhipster.tech/using-cache/" rel="noopener noreferrer"&gt;JHipster Registry&lt;/a&gt; to discover nodes, which will work in the same way as the Azure discovery plugin for Hazelcast, using Eureka to discover nodes instead of the Azure Instance Metadata Service.&lt;/li&gt;
&lt;li&gt;If you want a pure Java solution, but do not use JHipster, have a look at the &lt;a href="https://github.com/hazelcast/hazelcast-eureka" rel="noopener noreferrer"&gt;Hazelcast Eureka plugin&lt;/a&gt; that works the same way as the JHipster Registry, using Eureka to discover nodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to check the code used in this article, it is available at &lt;a href="https://github.com/jdubois/jhipster-hazelcast-azure" rel="noopener noreferrer"&gt;https://github.com/jdubois/jhipster-hazelcast-azure&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>azure</category>
      <category>spring</category>
      <category>performance</category>
    </item>
    <item>
      <title>Spring Boot performance benchmarks with Tomcat, Undertow and Webflux</title>
      <dc:creator>Julien Dubois</dc:creator>
      <pubDate>Mon, 06 Apr 2020 13:41:28 +0000</pubDate>
      <link>https://dev.to/azure/spring-boot-performance-benchmarks-with-tomcat-undertow-and-webflux-4d8k</link>
      <guid>https://dev.to/azure/spring-boot-performance-benchmarks-with-tomcat-undertow-and-webflux-4d8k</guid>
      <description>&lt;h2&gt;
  
  
  Tomcat vs Undertow vs Webflux
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.jhipster.tech/" rel="noopener noreferrer"&gt;JHipster&lt;/a&gt; is used by thousands of people to generate production-ready Spring Boot applications. We've been using Undertow for years, with great success, but as we are planning for JHipster 7 we started discussing &lt;a href="https://github.com/jhipster/generator-jhipster/issues/11528" rel="noopener noreferrer"&gt;migrating away from Undertow&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is the kind of discussion which happens very frequently in the JHipster community: with so many people contributing, we often test and try alternatives to our current approach.&lt;/p&gt;

&lt;p&gt;We ended up discussing about 3 different application servers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Undertow, from Red Hat/IBM: it is known for being lightweight, and we have years of (good) experiences with it.&lt;/li&gt;
&lt;li&gt;Tomcat, from the Apache Software Foundation: by far, the most popular option. It is also the default solution coming with Spring Boot.&lt;/li&gt;
&lt;li&gt;Webflux, from VMWare: this isn't really an application server, this is Spring Webflux running on top of Netty. This implies using reactive APIs, which are supposed to provide better performance and scalability. It's a whole different approach, which is also supported by JHipster.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The test applications
&lt;/h2&gt;

&lt;p&gt;I created a &lt;a href="https://github.com/jdubois/jhipster-benchmarks" rel="noopener noreferrer"&gt;performance benchmarks GitHub repository&lt;/a&gt;, with applications generated by JHipster.&lt;/p&gt;

&lt;p&gt;Those applications are more complex and realistic than simple "hello, world" applications created with Spring Boot. For instance, they use Spring Security and Spring Boot Actuator: those libraries will impact application start-up time and performance, but they are what you would use in the real world.&lt;/p&gt;

&lt;p&gt;Then, they are not as complex as they could be: I didn't configure a database or an application cache. Those would make running performance tests a lot more complicated, and wouldn't add any specific value: as we would use the same drivers or caching solution with all three application servers, we would end up testing the same things.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://github.com/jdubois/jhipster-benchmarks" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;, you will find 4 directories: one for each application, and one with the performance tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Azure Virtual Machines for the test
&lt;/h2&gt;

&lt;p&gt;As we needed to set up a test environment, using the cloud was obviously the best solution! For this test, I have created 2 virtual machines, with their own private network.&lt;/p&gt;

&lt;p&gt;I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2 &lt;a href="https://azure.microsoft.com/services/virtual-machines/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure Virtual Machines&lt;/a&gt;, using their default configuration called "Standard D2s v3" (&lt;code&gt;2 vcpus, 8 GiB memory&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;1 private &lt;a href="https://docs.microsoft.com/azure/virtual-network/virtual-networks-overview/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure Virtual Network&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the machines was hosting the application server, and the other one was used to run the performance test suite.&lt;/p&gt;

&lt;p&gt;The VMs were created using the Ubuntu image provided by default by Azure, on which I installed the latest LTS AdoptOpenJDK JVM (&lt;code&gt;openjdk version "11.0.6" 2020-01-14&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To configure your virtual machines easily, I maintain this script which you might find useful: &lt;a href="https://github.com/jdubois/jdubois-configuration" rel="noopener noreferrer"&gt;https://github.com/jdubois/jdubois-configuration&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start-up time
&lt;/h2&gt;

&lt;p&gt;Start-up time is all the rage now, but on JHipster we usually give more importance to runtime performance. For example, that's the reason why we use &lt;a href="https://github.com/FasterXML/jackson-modules-base/tree/master/afterburner" rel="noopener noreferrer"&gt;Afterburner&lt;/a&gt;: this slows down our start-up time, but gives about 10% higher runtime performance over a "normal" Spring Boot application.&lt;/p&gt;

&lt;p&gt;Here are the results after 10 rounds, for each application server:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt; &lt;/th&gt;
&lt;th&gt;Undertow&lt;/th&gt;
&lt;th&gt;Tomcat&lt;/th&gt;
&lt;th&gt;Webflux&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;4,879&lt;/td&gt;
&lt;td&gt;5,237&lt;/td&gt;
&lt;td&gt;4,285&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4,847&lt;/td&gt;
&lt;td&gt;5,125&lt;/td&gt;
&lt;td&gt;4,225&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4,889&lt;/td&gt;
&lt;td&gt;5,103&lt;/td&gt;
&lt;td&gt;4,221&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5,013&lt;/td&gt;
&lt;td&gt;5,129&lt;/td&gt;
&lt;td&gt;4,232&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;4,84&lt;/td&gt;
&lt;td&gt;5,134&lt;/td&gt;
&lt;td&gt;4,271&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;5,007&lt;/td&gt;
&lt;td&gt;5,141&lt;/td&gt;
&lt;td&gt;4,191&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;4,868&lt;/td&gt;
&lt;td&gt;5,214&lt;/td&gt;
&lt;td&gt;4,147&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;4,826&lt;/td&gt;
&lt;td&gt;5,032&lt;/td&gt;
&lt;td&gt;4,251&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;4,856&lt;/td&gt;
&lt;td&gt;5,069&lt;/td&gt;
&lt;td&gt;4,274&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;4,908&lt;/td&gt;
&lt;td&gt;5,078&lt;/td&gt;
&lt;td&gt;4,128&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mean&lt;/td&gt;
&lt;td&gt;4,8933&lt;/td&gt;
&lt;td&gt;5,1262&lt;/td&gt;
&lt;td&gt;4,2225&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Difference&lt;/td&gt;
&lt;td&gt; &lt;/td&gt;
&lt;td&gt;4,76%&lt;/td&gt;
&lt;td&gt;-13,71%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As expected, Undertow is lighter than the competition, but the difference is quite small.&lt;/p&gt;

&lt;h2&gt;
  
  
  The runtime performance test
&lt;/h2&gt;

&lt;p&gt;For our runtime performance, we needed to have a specific test suite.&lt;/p&gt;

&lt;p&gt;The performance test were written in Scala for the &lt;a href="https://gatling.io/" rel="noopener noreferrer"&gt;Gatling load-testing tool&lt;/a&gt;. They are pretty simple (we are just doing POST and GET requests), and are available &lt;a href="https://github.com/jdubois/jhipster-benchmarks/blob/master/gatling-charts-highcharts-bundle-3.3.1/user-files/simulations/TodoGatlingTest.scala" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This test does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each user does 100 GET requests and 100 POST requests, every 1.5 seconds.&lt;/li&gt;
&lt;li&gt;We will have 10,000 users doing those requests, with a ramp up of 1 minute.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The objective here is to stay under 5,000 requests per second, as when you go above that level you will usually need to do some specific OS tuning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Undertow performance benchmarks
&lt;/h2&gt;

&lt;p&gt;The Undertow results were quite good: it could handle the whole load without losing one single request, and it was delivering about 2,700 requests per second:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkpotb6rti4lut5w5ggc4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkpotb6rti4lut5w5ggc4.png" alt="Undertow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The response time was quite slow, with nearly all users having to wait about 3 seconds to get a response. But it was also quite stable (or "fair" for all users), as the 50th percentile is not that far away from the 99th percentile (or even the "max" time!):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft8qn2in9g5kdop5164as.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft8qn2in9g5kdop5164as.png" alt="Undertow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tomcat performance benchmarks
&lt;/h2&gt;

&lt;p&gt;Tomcat had about 5% of its requests failing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5rzwmywz5il43v0cs10e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5rzwmywz5il43v0cs10e.png" alt="Tomcat errors"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Those failures explain why the graph below doesn't look very good. Also, it was only delivering about 2,100 requests per second (compared to 2,700 requests per second for Undertow):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7i1973ofirgguk1mnj88.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7i1973ofirgguk1mnj88.png" alt="Tomcat"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Last but not least, the response time was good for about 10% of the requests, but it was much worse than Undertow at the 95th and 99th percentile, which shows that it could not handle all requests correctly. That's also why it had such a bad standard deviation (2,760 seconds!):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1mng45u12h8vissb0rqt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1mng45u12h8vissb0rqt.png" alt="Tomcat"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Webflux performance benchmarks
&lt;/h2&gt;

&lt;p&gt;Webflux had about 1% of its requests failing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqm4uzyqlv6thwgbuibob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqm4uzyqlv6thwgbuibob.png" alt="Webflux errors"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Those failures were at the beginning of the tests, and then the server could correctly handle the load: it looks like it had to trouble to handle the traffic growth because it was quite sudden, and then stabilized.&lt;/p&gt;

&lt;p&gt;Then, we can notice that once stabilized, Webflux had some strange variations - this is why we see all those peaks in the blue graph below: it would go suddenly from handling nearly 5,000 requests/second to less than 1,000 requests/second. In average, it was handling a bit more than 2,700 requests/second, so that's the same as Undertow, but with big variations that Undertow didn't have.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw2mtc9usjzk5qi05xnuj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw2mtc9usjzk5qi05xnuj.png" alt="Webflux"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The variations that we noticed in the previous graph also explain why, compared to Undertow, Webflux has a lower 50th percentile, but a higher 95th percentile. And that's also why its standard deviation is much worse:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4ubedhvca3zggxq1ikje.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4ubedhvca3zggxq1ikje.png" alt="Webflux"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Undertow definitely had impressive results in those tests! Compared to Tomcat, it proved to start up faster, handle more load, and also had a far more stable throughput. Compared to Webflux, which has a completely different programming model, the difference was less important: Webflux started faster, but had 1% of errors at the beginning of the test - it looks like it had some trouble to handle the load at the beginning, but that wasn't a huge issue.&lt;/p&gt;

&lt;p&gt;On &lt;a href="https://www.jhipster.tech/" rel="noopener noreferrer"&gt;JHipster&lt;/a&gt;, this is probably one of the many different choices that we have made, which make JHipster applications much faster and more stable than classical Spring Boot applications. So this performance test is definitely very important in our future decision to keep Undertow or move away from it. If you'd like to participate in the discussion, because you ran more tests or have any good insight, please don't hesitate to comment on our &lt;a href="https://github.com/jhipster/generator-jhipster/issues/11528" rel="noopener noreferrer"&gt;"migrating away from Undertow" ticket&lt;/a&gt;, or on this blog post.&lt;/p&gt;

</description>
      <category>java</category>
      <category>azure</category>
      <category>spring</category>
      <category>performance</category>
    </item>
    <item>
      <title>Using the new Gradle plugin for Azure Functions to deploy Spring Boot serverless applications</title>
      <dc:creator>Julien Dubois</dc:creator>
      <pubDate>Tue, 31 Mar 2020 14:36:21 +0000</pubDate>
      <link>https://dev.to/azure/using-the-new-gradle-plugin-for-azure-functions-to-deploy-spring-boot-serverless-applications-4594</link>
      <guid>https://dev.to/azure/using-the-new-gradle-plugin-for-azure-functions-to-deploy-spring-boot-serverless-applications-4594</guid>
      <description>&lt;h2&gt;
  
  
  Introducing the new Gradle plugins for Azure
&lt;/h2&gt;

&lt;p&gt;For building and deploying Java projects, Azure always had great Maven support, but it was lacking Gradle support. As many people love Gradle, in particular when building complex projects, I was thrilled to learn that a new set of Gradle plugins were being developed! They will all be Open Source, and their code will be available on GitHub at &lt;a href="https://github.com/microsoft/azure-gradle-plugins"&gt;https://github.com/microsoft/azure-gradle-plugins&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first plugin to be released is the one for Azure Functions, at &lt;a href="https://github.com/microsoft/azure-gradle-plugins/tree/master/azure-functions-gradle-plugin"&gt;https://github.com/microsoft/azure-gradle-plugins/tree/master/azure-functions-gradle-plugin&lt;/a&gt;. &lt;a href="https://docs.microsoft.com/azure/azure-functions/?WT.mc_id=devto-blog-judubois"&gt;Azure Functions&lt;/a&gt; is the Azure serverless offer, and you can use it to run your Java workloads in a managed, event-driven, fully scalable and inexpensive environment.&lt;/p&gt;

&lt;p&gt;If you want to run this Gradle plugin for a simple Java serverless application, the full documentation is available &lt;a href="https://docs.microsoft.com/azure/azure-functions/functions-create-first-java-maven?pivots=java-build-tools-gradle/?WT.mc_id=devto-blog-judubois"&gt;on the Microsoft Docs website&lt;/a&gt;. This is good for a simple Java application, which you would use for a very simple Function, but what about more complex applications, the ones that typically would benefit more from using Gradle?&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Spring Boot in a serverless environnement
&lt;/h2&gt;

&lt;p&gt;Thanks to Microsoft's work with Pivotal/VMWare, you can run Spring Boot on Azure Functions using the &lt;a href="https://spring.io/projects/spring-cloud-function"&gt;Spring Cloud Function&lt;/a&gt; project, which has specific &lt;a href="https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-samples/function-sample-azure"&gt;Azure support&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to test Spring Cloud Function and Azure Functions, I maintain the official sample application at &lt;a href="https://github.com/Azure-Samples/hello-spring-function-azure"&gt;https://github.com/Azure-Samples/hello-spring-function-azure&lt;/a&gt;. This is using Maven by default, and in this blog post we are going see how to use it with the new Gradle plugin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the new Gradle plugin to deploy Spring Boot to Azure Functions
&lt;/h2&gt;

&lt;p&gt;I have created a specific &lt;code&gt;gradle&lt;/code&gt; branch in the official sample project, which you can check at &lt;a href="https://github.com/Azure-Samples/hello-spring-function-azure/tree/gradle"&gt;https://github.com/Azure-Samples/hello-spring-function-azure/tree/gradle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With that code, you will be able to use the new Azure Gradle plugin to deploy a Spring Cloud Function application to Azure Functions.&lt;/p&gt;

&lt;p&gt;It uses one specific trick to have Azure Functions run the "Main" Spring Boot class, and this is why we added this block in the &lt;code&gt;build.gradle&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jar {
    manifest {
        attributes 'Main-Class' : 'com.example.HelloFunction'
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The block of code above will create a specific Java manifest file, which points to the main Spring Boot class, so that Azure Functions will execute it.&lt;/p&gt;

&lt;p&gt;If you look at the Maven version of this application, we are copying a specific &lt;code&gt;local.settings.json&lt;/code&gt; file to achieve the same goal (helping Azure Functions find the main class). This solution looks more elegant with Gradle.&lt;/p&gt;

&lt;p&gt;Then, the rest of the configuration uses the Gradle plugin normally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;azurefunctions {
    resourceGroup = 'my-spring-function-resource-group'
    appName = 'my-spring-function'
    appSettings {
        WEBSITE_RUN_FROM_PACKAGE = '1'
        FUNCTIONS_EXTENSION_VERSION = '~2'
        FUNCTIONS_WORKER_RUNTIME = 'java'
        MAIN_CLASS = 'com.example.HelloFunction'
    }
    authentication {
        type = 'azure_cli'
    }
    // enable local debug
    // localDebug = "transport=dt_socket,server=y,suspend=n,address=5005"
    deployment {
        type = 'run_from_blob'
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You will need to configure a specific Azure Resource Group in which your Function will run.&lt;/li&gt;
&lt;li&gt;You will need to give a unique &lt;code&gt;appName&lt;/code&gt; to your Function: this name should be unique across all of Azure, so usually people prefix it with their username.&lt;/li&gt;
&lt;li&gt;We are using the latest &lt;code&gt;FUNCTIONS_EXTENSION_VERSION&lt;/code&gt; available at the time of this writing, as it has much better cold start performance when running Java.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that the plugin is installed, you can use the following Gradle commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;gradle azureFunctionsRun
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will run Azure Functions locally, so this is the best way to develop and debug your Function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;gradle azureFunctionsPackage
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will package your application, so it is ready to be deployed to Azure Functions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;gradle azureFunctionsDeploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will deploy your Function to Azure Functions, so it is available in the cloud.&lt;/p&gt;

&lt;p&gt;The application then works exactly the same as the one built with Maven, of course! So you can test it by doing a cURL request as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://&amp;lt;YOUR_SPRING_FUNCTION_NAME&amp;gt;.azurewebsites.net/api/hello &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Azure&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>spring</category>
      <category>azure</category>
      <category>java</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Screencast: using Spring Boot, JHipster and Azure Spring Cloud together</title>
      <dc:creator>Julien Dubois</dc:creator>
      <pubDate>Fri, 13 Mar 2020 09:51:45 +0000</pubDate>
      <link>https://dev.to/azure/screencast-using-spring-boot-jhipster-and-azure-spring-cloud-together-404d</link>
      <guid>https://dev.to/azure/screencast-using-spring-boot-jhipster-and-azure-spring-cloud-together-404d</guid>
      <description>&lt;p&gt;Join me for a live-coding session using Spring Boot, JHipster and Azure Spring Cloud, in order to deliver microservices to cloud efficiently.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/I2czvj3V1AQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Some useful links from the video:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.jhipster.tech/"&gt;The JHipster website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jhipster.tech/microservices-architecture/"&gt;Microservices documentation for JHipster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://portal.azure.com/?WT.mc_id=devto-blog-judubois"&gt;The Azure portal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://start.jhipster.tech/"&gt;JHipster Online&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jhipster.tech/azure/"&gt;Azure documentation for JHipster&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azure</category>
      <category>java</category>
      <category>spring</category>
      <category>jhipster</category>
    </item>
    <item>
      <title>Using Logz.io to make logging Spring Boot Applications easier and faster</title>
      <dc:creator>Julien Dubois</dc:creator>
      <pubDate>Mon, 16 Dec 2019 09:59:19 +0000</pubDate>
      <link>https://dev.to/azure/using-logz-io-to-make-logging-spring-boot-applications-easier-and-faster-4k7a</link>
      <guid>https://dev.to/azure/using-logz-io-to-make-logging-spring-boot-applications-easier-and-faster-4k7a</guid>
      <description>&lt;p&gt;This blog post is jointly written by Julien Dubois (Microsoft) and Charlie Klein (Logz.io), in order for Spring Boot users to better understand the benefits of using a logs ingestion and analysis tool, like &lt;a href="https://logz.io/?source=ck" rel="noopener noreferrer"&gt;Logz.io&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How logging works in a classical Spring Boot application
&lt;/h2&gt;

&lt;p&gt;Spring Boot applications usually use Logback (&lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-configure-logback-for-logging" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;) or Log4J 2 (&lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto-configure-log4j-for-logging" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;) to manage application logs.&lt;/p&gt;

&lt;p&gt;This configuration is usually modified depending on each project or company’s usage, and it is common (and good) practice to follow the &lt;a href="https://12factor.net/logs" rel="noopener noreferrer"&gt;Twelve-Factor App chapter on logging&lt;/a&gt; and output everything to the console.&lt;/p&gt;

&lt;p&gt;Advanced users, using for example &lt;a href="https://www.jhipster.tech/" rel="noopener noreferrer"&gt;JHipster&lt;/a&gt;, typically use some customized version of Logback, which is usually configured in three different ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using the &lt;code&gt;src/main/resources/logback-spring.xml&lt;/code&gt; file. For example, here is JHipster’s default configuration: &lt;a href="https://github.com/jhipster/jhipster-sample-app/blob/master/src/main/resources/logback-spring.xml" rel="noopener noreferrer"&gt;https://github.com/jhipster/jhipster-sample-app/blob/master/src/main/resources/logback-spring.xml&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Using Spring Boot’s configuration file, under the &lt;code&gt;logging.*&lt;/code&gt; properties keys. This is documented at &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html" rel="noopener noreferrer"&gt;https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html&lt;/a&gt; and you can also find an example in JHipster’s default Spring Boot configuration file for development: &lt;a href="https://github.com/jhipster/jhipster-sample-app/blob/master/src/main/resources/config/application-dev.yml" rel="noopener noreferrer"&gt;https://github.com/jhipster/jhipster-sample-app/blob/master/src/main/resources/config/application-dev.yml&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;At runtime, as Logback can be programmatically reconfigured. For instance, this is what JHipster users do with their custom &lt;code&gt;LoggingConfiguration.java&lt;/code&gt; file or when they use their log management screen.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configuring logs is great, but once they are sent to the console the real interesting work begins: you need to have a system to aggregate and analyze them! In this article, we’ll use Logz.io to understand what needs to be configured, and most importantly what benefit we can expect from such a solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shipping logs to Logz.io
&lt;/h2&gt;

&lt;p&gt;The first step for shipping your logs to Logz.io is adding the Logz.io dependency to your Maven &lt;code&gt;pom.xml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;io.logz.logback&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;logzio-logback-appender&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.0.22&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you need to configure your &lt;code&gt;src/main/resources/logback-spring.xml&lt;/code&gt; file to use this library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Use shutdownHook so that we can close gracefully and finish the log drain --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;shutdownHook&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ch.qos.logback.core.hook.DelayingShutdownHook"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;appender&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"LogzioLogbackAppender"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"io.logz.logback.LogzioLogbackAppender"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;token&amp;gt;&amp;lt;your-logz-io-token&amp;gt;&amp;lt;/token&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;logzioUrl&amp;gt;&lt;/span&gt;https://&lt;span class="nt"&gt;&amp;lt;your-logz-io-listener-host&amp;gt;&lt;/span&gt;:8071&lt;span class="nt"&gt;&amp;lt;/logzioUrl&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;logzioType&amp;gt;&lt;/span&gt;java-application&lt;span class="nt"&gt;&amp;lt;/logzioType&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;filter&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ch.qos.logback.classic.filter.ThresholdFilter"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;level&amp;gt;&lt;/span&gt;INFO&lt;span class="nt"&gt;&amp;lt;/level&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/filter&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/appender&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;root&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"debug"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;appender-ref&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"LogzioLogbackAppender"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/root&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A good way to ensure your logs made it to the platform is to open up the “Live Tail” tab in the Logz.io platform. After pressing play, you should see a stream of logs showing up in the application. If you don’t, visit the Logz.io log shipping &lt;a href="https://docs.logz.io/user-guide/log-shipping/log-shipping-troubleshooting.html" rel="noopener noreferrer"&gt;troubleshooting page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want more information, you should follow this more in-depth tutorial (which was co-written by Julien Dubois) at &lt;a href="https://docs.microsoft.com/en-us/azure/java/java-get-started-with-logzio/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/azure/java/java-get-started-with-logzio&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analyzing logs with &lt;a href="http://logz.io/?source=ck" rel="noopener noreferrer"&gt;Logz.io&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;After shipping your logs to &lt;a href="http://logz.io/?source=ck" rel="noopener noreferrer"&gt;Logz.io&lt;/a&gt;, the fun part begins.&lt;/p&gt;

&lt;p&gt;Logz.io delivers the ELK Stack and Grafana – the most popular open source monitoring solutions in the world – as a fully-managed service so engineers can use the open source they know without the hassle of building or maintaining scalable logging or metrics pipelines themselves. Users can query and visualize their logs and metrics to monitor for production issues, security incidents, user activity, and and many more user-cases. In this section, we’ll focus on Logz.io’s logging capabilities.&lt;/p&gt;

&lt;p&gt;Logz.io users interact with logs on a high-powered version of Kibana (the “K” in the “ELK Stack”) which offers engineers broad flexibility to slice and dice their log data. Logz.io users benefit from Kibana’s complete functionality with additional advanced analytical features that make Kibana faster, more integrated, and easier to use. The following tutorial will take place in the “Kibana” tab on the upper toolbar (Box A). &lt;/p&gt;

&lt;p&gt;Upon opening Kibana, you can view all logs generated by your environment. According to our queries below (Box B), there were 1.7 million logs generated by “service-10” within the last 2 days.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvlnlokp4wqlzlxo4597w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fvlnlokp4wqlzlxo4597w.png" alt="Kibana"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Obviously, sorting through this list of logs to identify production issues or monitor user activity is impossible. Clicking on the “Patterns” tab (Box C) will cluster similar groups of logs together so you can quickly understand what kind of log data your service is generating without needing to scroll through the entire list of logs. For each pattern, you can see the time, count, ratio (percentage of logs that fall under the pattern), and the pattern itself.&lt;/p&gt;

&lt;p&gt;Scrolling through the log patterns, you can quickly query for the most important log data by clicking the “filter out” or “filter in” buttons to the right of every pattern (Box D). In this case, as we scroll down we find a pattern indicating an “SSL Library error” – something that is clearly worth investigating.&lt;/p&gt;

&lt;p&gt;After opening up the SSL error pattern, we can see it was flagged as a “Cognitive Insight”. Cognitive Insights leverages AI to cross reference incoming logs against online discussion forums such as StackOverflow and GitHub to identify critical logged events in your environment. &lt;/p&gt;

&lt;p&gt;This feature helps us find the needle in the haystack. Upon opening the Insight, we see contextual information around the event and links to the forums that discuss the SSL Error.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fot04i3gespqxhp2654ep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fot04i3gespqxhp2654ep.png" alt="Insights"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Teams can open these links to see how other engineers addressed the issue.&lt;/p&gt;

&lt;p&gt;The last bit of information you may want to know about this SSL error is its origin. In other words, what is the actual code producing this issue? To get this information, you can go to the “Insights” tab in the upper right corner.&lt;/p&gt;

&lt;p&gt;This graph helps us correlate issues with specific deployments. The colorful lines represent production issues and the grey dotted lines represent recent deployments. As you can see, the SSL error – represented by the blue dot – did not appear until after the “Updating puppet certificate” deployment at 3:20pm on Dec 4th. Therefore, we can conclude that this deployment led to the SSL error so it can quickly be addressed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fgrvhw8zehu5n2m14qjpl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fgrvhw8zehu5n2m14qjpl.png" alt="Graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Cognitive Insights and the ability to plot issues on a deployment timeline, you can close the loop with engineers by showing them the root cause and origin of the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  See it for yourself!
&lt;/h2&gt;

&lt;p&gt;In addition to the capabilities explored above, you can monitor metrics on Grafana, build your own Kibana visualizations, set alerts, and do a whole lot more.&lt;/p&gt;

&lt;p&gt;Learn more about Logz.io &lt;a href="http://logz.io/?source=ck" rel="noopener noreferrer"&gt;here&lt;/a&gt; or try it for yourself &lt;a href="https://logz.io/freetrial/?source=ck" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>monitoring</category>
      <category>azure</category>
      <category>java</category>
      <category>spring</category>
    </item>
    <item>
      <title>Configuring the free TLS/SSL certificates on Azure App Service</title>
      <dc:creator>Julien Dubois</dc:creator>
      <pubDate>Mon, 02 Dec 2019 09:19:58 +0000</pubDate>
      <link>https://dev.to/azure/configuring-the-free-tls-ssl-certificates-on-azure-app-service-j2a</link>
      <guid>https://dev.to/azure/configuring-the-free-tls-ssl-certificates-on-azure-app-service-j2a</guid>
      <description>&lt;h2&gt;
  
  
  Free TLS/SSL certificates for Azure App Service
&lt;/h2&gt;

&lt;p&gt;Last month, it was &lt;a href="https://azure.microsoft.com/en-us/updates/secure-your-custom-domains-at-no-cost-with-app-service-managed-certificates-preview/?WT.mc_id=devto-blog-judubois"&gt;announced at MS Ignite&lt;/a&gt; that users of Azure App Service would have free, managed TLS/SSL certificates:&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--4VSoC0PP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/729555955030044673/jBxOqmsB_normal.jpg" alt="Julien Dubois profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Julien Dubois
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @juliendubois
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Free SSL certificates on Azure App Services! It's one of my most-awaited announcement at MS Ignite!!&lt;br&gt;&lt;a href="https://t.co/HnGjXvT2el"&gt;azure.microsoft.com/en-us/updates/…&lt;/a&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      07:35 AM - 05 Nov 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1191620079206719488" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-reply-action.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1191620079206719488" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-retweet-action.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      8
      &lt;a href="https://twitter.com/intent/like?tweet_id=1191620079206719488" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="/assets/twitter-like-action.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
      24
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Azure App Service is a very popular Platform-as-a-Service, which supports Docker images as well as many different languages and frameworks. For example, if you are using Java and Spring Boot, I believe it's the &lt;a href="https://dev.to/azure/the-easy-way-to-deploy-a-spring-boot-application-to-production-on-azure-2joi"&gt;easiest way to go to production on Azure&lt;/a&gt;. And using TLS/SSL is of course mandatory when going to production!&lt;/p&gt;

&lt;p&gt;Configuring those certificates isn't totally obvious, as you probably don't use Azure to manage your DNS: this short guide is here to help you!&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure your DNS records
&lt;/h2&gt;

&lt;p&gt;Configuring your DNS records is probably the trickiest part, as it will depend on your DNS provider.&lt;/p&gt;

&lt;p&gt;Here we will setup a very generic configuration, which should work on most DNS providers. But as a concrete example, we are going to use &lt;a href="https://www.gandi.net/en"&gt;Gandi&lt;/a&gt;, which is a French DNS provider, and which is the one I use for &lt;a href="https://www.julien-dubois.com/"&gt;my julien-dubois.com personal website&lt;/a&gt; as well as the &lt;a href="https://www.jhipster.tech/"&gt;different JHipster websites&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What you need to do is add a "CNAME" record that will point from your production DNS name to your Azure App Service instance.&lt;/p&gt;

&lt;p&gt;For example, here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;My production website will be &lt;code&gt;https://petclinic.julien-dubois.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;My App Service instance is called &lt;code&gt;jdubois-petclinic&lt;/code&gt;, so it is hosted by default on &lt;code&gt;https://jdubois-petclinic.azurewebsites.net&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0ppiz7k2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vb1zkwfnueqyrq0iid59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0ppiz7k2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vb1zkwfnueqyrq0iid59.png" alt="DNS Record"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WARNING:&lt;/strong&gt; a hostname entry usually ends with a dot (&lt;code&gt;.&lt;/code&gt;) unless you specifically want it to be suffixed by the current domain. This is what most DNS provider will require, and this is why in the screenshot we have &lt;code&gt;jdubois-petclinic.azurewebsites.net.&lt;/code&gt; (notice the &lt;code&gt;.&lt;/code&gt; at the end).&lt;/p&gt;

&lt;p&gt;Your DNS provider probably also allow you to configure directly those DNS records, without using a Web control panel. In that case, your DNS entry would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;petclinic 1800 IN CNAME jdubois-petclinic.azurewebsites.net.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once this configuration is saved, remember that DNS records can take up to 48 hours to propagate, but it is usually much faster.&lt;/p&gt;

&lt;p&gt;In order to check the propagation of your record, you can use a tool like &lt;a href="https://dnschecker.org/"&gt;https://dnschecker.org/&lt;/a&gt;. In our example, you can see on &lt;a href="https://dnschecker.org/#CNAME/petclinic.julien-dubois.com"&gt;https://dnschecker.org/#CNAME/petclinic.julien-dubois.com&lt;/a&gt; that our CNAME record was correctly propagated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure your Azure App Service instance
&lt;/h2&gt;

&lt;p&gt;You can now go to the &lt;a href="https://portal.azure.com/?WT.mc_id=devto-blog-judubois"&gt;Azure portal&lt;/a&gt;, and select your Azure App Service instance.&lt;/p&gt;

&lt;h3&gt;
  
  
  "Custom domains" configuration
&lt;/h3&gt;

&lt;p&gt;In the "Custom domains" menu on the left:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check the "HTTPS Only" box, as there is no need to keep an unsecured HTTP option.&lt;/li&gt;
&lt;li&gt;Click on "Add custom domain", and add the domain name you have configured with your DNS provider&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kV_ELQL7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ovpohzgy44bxjncmbu0b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kV_ELQL7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ovpohzgy44bxjncmbu0b.png" alt="Add custom domain"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The "Validate" button here will check if your DNS record is correct: if you misconfigured your record, or if your record hasn't been propagated yet, this is where you get an error.&lt;/p&gt;

&lt;h2&gt;
  
  
  "TLS/SSL settings" configuration
&lt;/h2&gt;

&lt;p&gt;In the "TLS/SSL settings" menu on the left, go to the "Private Key Certificates (.pfx)" tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8f6yGFlM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0kot7mfv65otyccnj8bw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8f6yGFlM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/0kot7mfv65otyccnj8bw.png" alt="Private Key Certificates"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on "Create App Service Managed Certificate", this will show a specific screen where you can select the domain name you have previously configured:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--drrzfHXp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5tmlbr1snhw39j9xpzw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--drrzfHXp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5tmlbr1snhw39j9xpzw6.png" alt="Create App Service Managed Certificate"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on "Create" and wait a few seconds for your certificate to be created:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7MFNWfuy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/aapig33coalndybq61zt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7MFNWfuy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/aapig33coalndybq61zt.png" alt="Created certificate"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, still in the "TLS/SSL settings" page, click on the "Bindings" tab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vAw2iuz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/awo2ky0uv0jciyc4feu7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vAw2iuz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/awo2ky0uv0jciyc4feu7.png" alt="SSL Bindings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on "Add TLS/SSL Binding", and select the previously generated certificate. You should use "SNI SSL" as it will work on all modern browsers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gl3At2Fo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3a6m79dvmrrzdhxprsd7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gl3At2Fo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3a6m79dvmrrzdhxprsd7.png" alt="Add SSL Binding"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on "Add Binding", and you're all set up!&lt;/p&gt;

&lt;p&gt;You can now enjoy your website using TLS/SSL:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bP21czuj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ngkkc0ysadtkg5b36goo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bP21czuj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ngkkc0ysadtkg5b36goo.png" alt="HTTPS Website"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>azure</category>
      <category>java</category>
    </item>
    <item>
      <title>The easy way to deploy a Spring Boot application to production on Azure</title>
      <dc:creator>Julien Dubois</dc:creator>
      <pubDate>Thu, 28 Nov 2019 10:58:16 +0000</pubDate>
      <link>https://dev.to/azure/the-easy-way-to-deploy-a-spring-boot-application-to-production-on-azure-2joi</link>
      <guid>https://dev.to/azure/the-easy-way-to-deploy-a-spring-boot-application-to-production-on-azure-2joi</guid>
      <description>&lt;p&gt;In this blog post, we are going to deploy a classical Spring Boot application to production on Azure, with a strong focus on ease-of-use, both from a developer and operations perspective.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "the easy way"?
&lt;/h2&gt;

&lt;p&gt;While it is fun to &lt;a href="https://github.com/kelseyhightower/kubernetes-the-hard-way" rel="noopener noreferrer"&gt;use Kubernetes the hard way&lt;/a&gt;, if your goal is to deploy and host a Spring Boot application in production, your customer probably doesn't have the time and money to let you work like this.&lt;/p&gt;

&lt;p&gt;We are aiming here at deploying and maintaining a production application with as little work as possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As a developer, our goal is just to &lt;code&gt;git push&lt;/code&gt; to production and not worry about anything else.&lt;/li&gt;
&lt;li&gt;As an ops engineer, our goal is to do the easiest setup possible, and not have any maintenance or scalability work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The sample application
&lt;/h2&gt;

&lt;p&gt;For this blog post we will use &lt;a href="https://github.com/jdubois/spring-petclinic" rel="noopener noreferrer"&gt;a fork of the famous Spring Petclinic&lt;/a&gt;. This is a well-known and well-documented sample Spring Boot application, and we will detail the choices that were made in order to deploy it easily.&lt;/p&gt;

&lt;p&gt;There is nothing specific about this application, so if you use a Spring Boot application (or even better, a &lt;a href="https://www.jhipster.tech/" rel="noopener noreferrer"&gt;JHipster application&lt;/a&gt;!), you should be able to follow the next steps and be in the cloud very quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Azure App Service overview
&lt;/h2&gt;

&lt;p&gt;There are many ways to deploy a Spring Boot application to Azure. You can obviously use a virtual machine (VM): you'll need to set up everything manually, take care of the OS and JVM maintenance, handle HTTPS and scalability yourself... So while it looks easy at first sight, it's time consuming and the maintenance is going to be a big issue.&lt;/p&gt;

&lt;p&gt;We are going to use &lt;a href="https://azure.microsoft.com/en-us/services/app-service/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure App Service&lt;/a&gt;, which is a Platform-as-a-Service solution. It supports different languages, as well as Docker images, so it can effectively host any kind of application. It is also &lt;a href="https://azure.microsoft.com/en-us/pricing/details/app-service/linux/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;very cost-efficient&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a managed service, there is much less maintenance overhead than with a VM, and scalability is already included, which makes it a great way to host monolithic Spring Boot applications. If you have more complex needs, we recommend using &lt;a href="https://azure.microsoft.com/en-us/services/spring-cloud/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure Spring Cloud&lt;/a&gt;, which shares many similar concepts, but which targets microservices architectures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Jar or Docker?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://azure.microsoft.com/en-us/services/app-service/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure App Service&lt;/a&gt; supports both Jar deployments and Docker deployments, which are both well-documented and popular ways to deploy Spring Boot applications.&lt;/p&gt;

&lt;p&gt;We recommend using Jar deployment here: both the OS and the JVM will be managed (and supported!) by Microsoft, which means you will have far less maintenance work to do. For example, if a security vulnerability is discovered in the JVM, it will be automatically patched without any manual intervention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Azure App Service setup
&lt;/h2&gt;

&lt;p&gt;First, we'll create an Azure resource group in which we will work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the &lt;a href="https://portal.azure.com/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure portal&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In the search box, look for "Resource groups".&lt;/li&gt;
&lt;li&gt;Create a new resource group called &lt;code&gt;spring-petclinic&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, create the Azure App Service instance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the Azure portal search box, look for "App Services".&lt;/li&gt;
&lt;li&gt;Create a new Web App in the &lt;code&gt;spring-petclinic&lt;/code&gt; resource group, using Java 11 on Linux, as in the screenshot below:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fagna82dysckkj9adib26.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fagna82dysckkj9adib26.png" alt="Creating App Service"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  MySQL setup
&lt;/h2&gt;

&lt;p&gt;Like many Spring Boot applications, the Spring Petclinic uses the MySQL database: if you are using another database, like PostgreSQL, your setup should be similar.&lt;/p&gt;

&lt;p&gt;Azure App Service has a feature called "MySQL in-app", that you can use to lower your hosting costs, as MySQL will run inside your Azure App Service instance. While this can be used in development, it comes with several important limitations and is not a production-grade database, so we are not going to use it here.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the &lt;a href="https://portal.azure.com/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure portal&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In the search box, look for "Azure Database for MySQL".&lt;/li&gt;
&lt;li&gt;Create a MySQL server (and be careful to select the correct pricing tier for your usage!).&lt;/li&gt;
&lt;li&gt;Note your database name, your username and password, as we will need them later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In your MySQL database, go to "Connection security", and select "Allow access to Azure services". You should also click on the "Add client IP" button to automatically add your current IP to the firewall rules, so you can access it from your current machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2h63af96ndfgzta0o6lg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2h63af96ndfgzta0o6lg.png" alt="MySQL firewall rules"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment variables
&lt;/h2&gt;

&lt;p&gt;The Spring Petclinic is configured using properties files, which are located in the &lt;code&gt;src/main/resources&lt;/code&gt; directory. One of them is called &lt;code&gt;application-mysql.properties&lt;/code&gt;, which means it will be used when the &lt;code&gt;mysql&lt;/code&gt; Spring Boot profile will be triggered.&lt;/p&gt;

&lt;p&gt;In the Azure App Service we created above, select the &lt;code&gt;Settings &amp;gt; Configuration&lt;/code&gt; menu on the left.&lt;/p&gt;

&lt;p&gt;We need to configure two different settings here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set Spring Boot to use the &lt;code&gt;mysql&lt;/code&gt; profile, using the &lt;code&gt;SPRING_PROFILES_ACTIVE&lt;/code&gt; environment key.&lt;/li&gt;
&lt;li&gt;Override the database configuration using environment variables for the &lt;code&gt;SPRING_DATASOURCE_URL&lt;/code&gt;, &lt;code&gt;SPRING_DATASOURCE_USERNAME&lt;/code&gt; and &lt;code&gt;SPRING_DATASOURCE_PASSWORD&lt;/code&gt; keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This configuration should look like the screenshot below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F878u16kvrhigjh484a10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F878u16kvrhigjh484a10.png" alt="Environment variables"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we are handling secrets here, another solution it to use &lt;a href="https://azure.microsoft.com/en-us/services/key-vault/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Azure Key Vault&lt;/a&gt;. With Spring Boot, this can be configured using the &lt;a href="https://github.com/microsoft/azure-spring-boot/blob/master/azure-spring-boot-starters/azure-keyvault-secrets-spring-boot-starter/README.md" rel="noopener noreferrer"&gt;Azure Key Vault Secrets Spring Boot Starter&lt;/a&gt;. This adds some complexity to the project, and isn't more secure than environment variables in our particular use-case (in the end, both become Spring Boot properties, and can be read from the code), so for just storing one secret this is outside of the scope of this "deploy the easy way" article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying using the Azure Webapp Maven plugin
&lt;/h2&gt;

&lt;p&gt;Now that our App Service is configured, all we need to do is deploy our application. In this first solution, we are going to use the Azure Webapp Maven plugin. This is what most developers would use, as it's easily integrated inside their IDEs.&lt;/p&gt;

&lt;p&gt;Inside your &lt;code&gt;pom.xml&lt;/code&gt; file, add the following Maven plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;      &lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.microsoft.azure&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;azure-webapp-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.8.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;schemaVersion&amp;gt;&lt;/span&gt;V2&lt;span class="nt"&gt;&amp;lt;/schemaVersion&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;resourceGroup&amp;gt;&lt;/span&gt;spring-petclinic&lt;span class="nt"&gt;&amp;lt;/resourceGroup&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;appName&amp;gt;&lt;/span&gt;jdubois-petclinic&lt;span class="nt"&gt;&amp;lt;/appName&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;region&amp;gt;&lt;/span&gt;westeurope&lt;span class="nt"&gt;&amp;lt;/region&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;pricingTier&amp;gt;&lt;/span&gt;B1&lt;span class="nt"&gt;&amp;lt;/pricingTier&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;runtime&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;os&amp;gt;&lt;/span&gt;linux&lt;span class="nt"&gt;&amp;lt;/os&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;javaVersion&amp;gt;&lt;/span&gt;java11&lt;span class="nt"&gt;&amp;lt;/javaVersion&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;webContainer&amp;gt;&lt;/span&gt;java11&lt;span class="nt"&gt;&amp;lt;/webContainer&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/runtime&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;deployment&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;resources&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;resource&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;directory&amp;gt;&lt;/span&gt;${project.basedir}/target&lt;span class="nt"&gt;&amp;lt;/directory&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;includes&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;include&amp;gt;&lt;/span&gt;*.jar&lt;span class="nt"&gt;&amp;lt;/include&amp;gt;&lt;/span&gt;
                  &lt;span class="nt"&gt;&amp;lt;/includes&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/resource&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;/resources&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/deployment&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, you will need to configure the correct parameters for your &lt;code&gt;resourceGroup&lt;/code&gt;, &lt;code&gt;appName&lt;/code&gt;, &lt;code&gt;region&lt;/code&gt; and &lt;code&gt;pricingTier&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This solution is very easy to use for developers, but it has a few drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Its configuration is stored inside the project's &lt;code&gt;pom.xml&lt;/code&gt;, including configuration that should change depending on environments.&lt;/li&gt;
&lt;li&gt;It requires a local build and a manual work for the developer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Automating deployment with a GitHub Action
&lt;/h2&gt;

&lt;p&gt;A newer alternative to the Azure Webapp Maven plugin is to use a GitHub Action.&lt;/p&gt;

&lt;p&gt;You will need to authorize your GitHub Action to publish applications on Azure, here is how to do this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the Azure portal, select your App Service and in the overview panel, click on &lt;code&gt;Get publish profile&lt;/code&gt;. You will download a &lt;code&gt;.PublishSettings&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;In your GitHub project, go to &lt;code&gt;Settings &amp;gt; Secrets&lt;/code&gt; and create a new secret called &lt;code&gt;azureWebAppPublishProfile&lt;/code&gt;. Paste the content of the previous  &lt;code&gt;.PublishSettings&lt;/code&gt; file into that secret.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, add the following GitHub Action to your project. Create a file called &lt;code&gt;.github/workflows/build-and-deploy.yml&lt;/code&gt; and paste the following content in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and deploy to Azure App Service&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-and-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up JDK &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-java@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;11&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cache Maven archetypes&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.m2/repository&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}&lt;/span&gt;
          &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;${{ runner.os }}-maven-&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build with Maven&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mvn clean package&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;azure/webapps-deploy@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;app-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;spring-petclinic&lt;/span&gt;
          &lt;span class="na"&gt;publish-profile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.azureWebAppPublishProfile }}&lt;/span&gt; &lt;span class="c1"&gt;# See https://github.com/Azure/actions-workflow-samples/tree/master/AppService&lt;/span&gt;
          &lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github.workspace&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}/target/*.jar'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a brief description of this GitHub Action:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It publishes an updated Azure App Service application as soon as code is pushed to the &lt;code&gt;master&lt;/code&gt; branch. You can do a similar GitHub Action for other branches: you could have this setup for each project developer, or for each environment.&lt;/li&gt;
&lt;li&gt;It checks the latest code and installs Java 11.&lt;/li&gt;
&lt;li&gt;It uses the &lt;code&gt;actions/cache&lt;/code&gt; GitHub Action to cache Maven archetypes: this considerably improves build times, so it is highly recommended.&lt;/li&gt;
&lt;li&gt;It builds and tests the application using Maven.&lt;/li&gt;
&lt;li&gt;It deploys the final application using the &lt;code&gt;azure/webapps-deploy&lt;/code&gt; GitHub Action. This deployment could also have been made using the &lt;code&gt;Azure Webapp Maven plugin&lt;/code&gt; we detailed in the previous section, but this GitHub Action allows to better decouple the code (the &lt;code&gt;pom.xml&lt;/code&gt; doesn't have any specific Azure configuration or library), and it's also faster to execute.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Our two goals are fulled reached:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers only need to &lt;code&gt;git push&lt;/code&gt; to deploy their Spring Boot application, without even needing to know anything about Azure App Services.&lt;/li&gt;
&lt;li&gt;Operations engineers had to do a minimal setup (creating the MySQL and App Service instances, and configuring 4 environment variables), but now the application can run in production without much maintenance. The OS and the JVM will be automatically patched and supported by Microsoft, and scalability is included.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to achieve those goals, we didn't have to modify any code in our Spring Boot application. Using GitHub Actions to deploy, all we needed to do is add a hidden file inside the &lt;code&gt;.github&lt;/code&gt; repository.&lt;/p&gt;

&lt;p&gt;If you want to have a closer look at the final application, &lt;a href="https://github.com/jdubois/spring-petclinic" rel="noopener noreferrer"&gt;my fork of Spring Petclinic is available here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>spring</category>
      <category>azure</category>
      <category>java</category>
    </item>
    <item>
      <title>Using Spring Security with Azure Active Directory</title>
      <dc:creator>Julien Dubois</dc:creator>
      <pubDate>Mon, 09 Sep 2019 06:47:14 +0000</pubDate>
      <link>https://dev.to/azure/using-spring-security-with-azure-active-directory-mga</link>
      <guid>https://dev.to/azure/using-spring-security-with-azure-active-directory-mga</guid>
      <description>&lt;h2&gt;
  
  
  Why use Active Directory?
&lt;/h2&gt;

&lt;p&gt;Let's be honnest, &lt;a href="https://azure.microsoft.com/en-us/services/active-directory/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;Active Directory&lt;/a&gt; isn't "cool" today. People see it has very complex, which is true - but security is a complex matter! And it doesn't have the hype of new products like Red Hat's Keycloak, even if both are often used for the same goal, at least with Spring Boot: securing a business application using OpenID Connect.&lt;/p&gt;

&lt;p&gt;However, there's one really nice feature of Active Directory: your company has probably it already installed, and probably already pays for it (hint: for a security product, you'd better pay if you want support and the latest patches - that's why I always recommend to pay for Keycloak!). Officially, 85% of Fortune 500 companies are using Active Directory, which is in fact (unofficially!) confirmed by &lt;a href="https://www.shawntabrizi.com/aad/does-company-x-have-an-azure-active-directory-tenant/" rel="noopener noreferrer"&gt;this clever hacker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So securing a Spring Boot application with Active Directory makes a lot of sense :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's probably already installed, validated and secured in your company&lt;/li&gt;
&lt;li&gt;You'll have access to the official employee list of your company: no need to create new users, handle lost passwords, invalidate old employees...&lt;/li&gt;
&lt;li&gt;It's highly secured: you'll have 2 factor authentication, etc, everything is included&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But there's a last reason: it's free! Well, not totally free, but if you &lt;a href="https://azure.microsoft.com/en-us/pricing/details/active-directory/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;look at the pricing model&lt;/a&gt;, there's a very generous free tier. So you can use it for development or for your start-up idea, without paying anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Azure Spring Boot Starter for Active Directory
&lt;/h2&gt;

&lt;p&gt;Thankfully, the Azure engineering team is providing a Spring Boot Starter for Azure Active Directory, which is available at &lt;a href="https://github.com/microsoft/azure-spring-boot/tree/master/azure-spring-boot-starters/azure-active-directory-spring-boot-starter" rel="noopener noreferrer"&gt;https://github.com/microsoft/azure-spring-boot/tree/master/azure-spring-boot-starters/azure-active-directory-spring-boot-starter&lt;/a&gt;. There are two official tutorials available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The official tutorial is &lt;a href="https://docs.microsoft.com/en-us/java/azure/spring-framework/configure-spring-boot-starter-java-app-with-azure-active-directory?view=azure-java-stable/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;available here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;There's also a tutorial in the &lt;a href="https://github.com/microsoft/azure-spring-boot/tree/master/azure-spring-boot-starters/azure-active-directory-spring-boot-starter" rel="noopener noreferrer"&gt;project GitHub repository&lt;/a&gt;, which is updated along with the code: this one works with the latest version of the code, and is less detailed than the official one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both of them are a bit outdated at the time of this writing, and as it's my work to update them, I'm first doing this blog post to gather feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We'll be using the latest and greatest version of both Spring Boot (2.1.8, released a few hours ago at the time of this writing) and the Azure Spring Boot starters (2.1.7)&lt;/li&gt;
&lt;li&gt;We'll be using the new Active Directory user interface: this is a huge case of problem here, as all the screenshots currently available are from the older user interface, so you can't find anything easily&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please, don't hesitate to add comments to this blog post, so I can clean up everything, and create an awesome &lt;em&gt;official&lt;/em&gt; tutorial!&lt;/p&gt;

&lt;h2&gt;
  
  
  The sample project
&lt;/h2&gt;

&lt;p&gt;The sample project we do here is available at &lt;a href="https://github.com/jdubois/spring-active-directory" rel="noopener noreferrer"&gt;https://github.com/jdubois/spring-active-directory&lt;/a&gt;, so if you want to see the real code and test it, it's all there.&lt;/p&gt;

&lt;p&gt;This is a Spring Boot project generated with &lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;Spring Initializr&lt;/a&gt; as I wanted to have something extremely simple. It uses the following important components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spring Web&lt;/li&gt;
&lt;li&gt;OAuth2 Client, which transitively includes Spring Security&lt;/li&gt;
&lt;li&gt;Azure Support&lt;/li&gt;
&lt;li&gt;Spring Data JPA and MySQL, so we can build a "real" application in the future&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fcmizty0ph6d01msg3ddj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fcmizty0ph6d01msg3ddj.png" alt="Spring components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Active Directory
&lt;/h2&gt;

&lt;p&gt;Now is the tricky part of this post! Configuring Active Directory is complicated, so we'll go step-by-step and provide screenshots.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create your own tenant
&lt;/h3&gt;

&lt;p&gt;Active Directory provides &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-create-new-tenant/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;tenants&lt;/a&gt;, which are basically instances that you can use. There are two types of instances: work and school (the one I will use here), and social accounts (called "Azure Active Directory B2C").&lt;/p&gt;

&lt;p&gt;As discussed earlier, there's a generous free tier, so you can create your own tenant without paying anything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the &lt;a href="https://portal.azure.com/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;the Azure portal&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Select "All resources", and look for "Azure Active Directory" and click "create"&lt;/li&gt;
&lt;li&gt;Fill in your organization's name, domain and country, and you're done!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fz51edjpgzvu10ikwvwtt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fz51edjpgzvu10ikwvwtt.png" alt="Create resource"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Accessing your Active Directory tenant
&lt;/h3&gt;

&lt;p&gt;You can now switch to your Active Directory tenant by clicking on the "Directory + Subscription" icon on the top menu:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fuvb2scptgotjq5q29dnd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fuvb2scptgotjq5q29dnd.png" alt="Switch directory"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring your tenant
&lt;/h3&gt;

&lt;p&gt;Once you have switched to your tenant, select "Active Directory", and you can now configure it with full admin rights. Here's what's important to do.&lt;/p&gt;

&lt;h4&gt;
  
  
  Click on "App registrations" and create a new registration:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5doi2l51he34plbrcfw1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5doi2l51he34plbrcfw1.png" alt="create tenant"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please note that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The account type must be "multitenant". The current Spring Boot starter does not work with single tenants, which is an issue being currently addressed.&lt;/li&gt;
&lt;li&gt;The redirect URI must be "&lt;a href="http://localhost:8080/login/oauth2/code/azure" rel="noopener noreferrer"&gt;http://localhost:8080/login/oauth2/code/azure&lt;/a&gt;". Of course you can replace "localhost:8080" by your own domain, but the suffix is the default one that will be configured by the Spring Boot starter, and if those URI do not match, you will not be able to log in.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Select the registered application
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;In the "overview", note the "Application (client) ID", this is what will be used in Spring Security as "client-id", as well as the "Directory (tenant) ID", which will be Spring Security's "tenant-id".&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select "Authentication", and in the Web "Platform configuration", check both options under "Implicit grant" ("Access tokens" and "ID tokens")&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fmma3d7s5yhntyzol65ay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fmma3d7s5yhntyzol65ay.png" alt="Implicit grant"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on "Certificates &amp;amp; secrets", and create a new client secret, which will be Spring Security's "client-secret"&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8ugdj0p6s5du4eo2gm9q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8ugdj0p6s5du4eo2gm9q.png" alt="client secret"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on "API permissions", and under "Microsoft Graph", give your application the "Directory.AccessAsUser.All" and "User.Read" permissions&lt;/li&gt;
&lt;li&gt;Click on the "Grant admin consent" button at the bottom of the page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fqjj2cxyox3gbvne7if2k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fqjj2cxyox3gbvne7if2k.png" alt="API permissions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Go back to your Active Directory tenant and click on "User settings"
&lt;/h4&gt;

&lt;p&gt;Under "Manage how end users launch and view their applications", validate the "Users can consent to apps accessing company data on their behalf" is set to "Yes" (this should be good by default).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1w7wwmfzcuduxt8nlfre.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1w7wwmfzcuduxt8nlfre.png" alt="consent"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Create users and groups
&lt;/h4&gt;

&lt;p&gt;Still in your Active Directory tenant, select "Groups" and create a new group, for example "group1".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F22t20mkzckj0xy06q8do.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F22t20mkzckj0xy06q8do.png" alt="Create group"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now select "Users", create a new user, and give that user the "group1" group that we just created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8cjaaw8v1ov812408cdr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8cjaaw8v1ov812408cdr.png" alt="Create user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure the Spring Boot application
&lt;/h2&gt;

&lt;p&gt;Now let's use that configured tenant, with this new user, in our Spring Boot application.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;pom.xml&lt;/code&gt; file, add the &lt;code&gt;azure-active-directory-spring-boot-starter&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.microsoft.azure&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;azure-active-directory-spring-boot-starter&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your &lt;code&gt;application.yml&lt;/code&gt; file (or &lt;code&gt;application.properties&lt;/code&gt; file if you don't like YAML), configure the following properties. Please note that we got the 3 required values when we registered our application in our Active Directory tenant.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;azure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;activedirectory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;tenant-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;tenant-id&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;active-directory-groups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;group1, group2&lt;/span&gt;

&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;oauth2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;registration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;azure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;client-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;client-id&amp;gt;&lt;/span&gt;
            &lt;span class="na"&gt;client-secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;client-secret&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now need to configure our Spring Boot application to use Active Directory. Create a new &lt;code&gt;SecurityConfiguration&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@EnableWebSecurity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SecurityConfiguration&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;WebSecurityConfigurerAdapter&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;OAuth2UserService&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OidcUserRequest&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;OidcUser&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;oidcUserService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SecurityConfiguration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OAuth2UserService&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OidcUserRequest&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;OidcUser&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;oidcUserService&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;oidcUserService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oidcUserService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpSecurity&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;authorizeRequests&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;anyRequest&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;authenticated&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;and&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;oauth2Login&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userInfoEndpoint&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;oidcUserService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oidcUserService&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration will require that each request is secured, and will therefore redirect any user to Active Directory when he tries to connect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running everything
&lt;/h2&gt;

&lt;p&gt;When running the Spring Boot application, we recommend you add a &lt;code&gt;src/main/resources/logback-spring.xmllogback-spring.xml&lt;/code&gt; file with the following configuration, in order to better understand the issues you might encounter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE configuration&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;configuration&lt;/span&gt; &lt;span class="na"&gt;scan=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;include&lt;/span&gt; &lt;span class="na"&gt;resource=&lt;/span&gt;&lt;span class="s"&gt;"org/springframework/boot/logging/logback/base.xml"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;logger&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"org.springframework.security"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"DEBUG"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;logger&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"com.microsoft"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"DEBUG"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;logger&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"com.example"&lt;/span&gt; &lt;span class="na"&gt;level=&lt;/span&gt;&lt;span class="s"&gt;"DEBUG"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if you run the application, accessing it on &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt; should point you to Active Directory, where you can sign it using the user we just created earlier:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5f8dsl9e2p7wzs2684oz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5f8dsl9e2p7wzs2684oz.png" alt="Log in"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the security
&lt;/h2&gt;

&lt;p&gt;In order to know if everything is correct, including if our user really receive the "group1" role that we configured earlier, let's add a specific Spring MVC controller called &lt;code&gt;AccountRessource&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.demo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.security.core.Authentication&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.security.core.context.SecurityContextHolder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.bind.annotation.GetMapping&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.bind.annotation.RestController&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AccountResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/account"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Authentication&lt;/span&gt; &lt;span class="nf"&gt;getAccount&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;SecurityContextHolder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getContext&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getAuthentication&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Accessing &lt;a href="http://localhost:8080/account" rel="noopener noreferrer"&gt;http://localhost:8080/account&lt;/a&gt; should now give you all the user's security information, including his roles! Congratulations, you have secured your Spring Boot application using Active Directory!&lt;/p&gt;

</description>
      <category>spring</category>
      <category>azure</category>
      <category>java</category>
      <category>security</category>
    </item>
    <item>
      <title>Using the new Azure SDK for Java to upload images asynchronously, using Spring Reactor</title>
      <dc:creator>Julien Dubois</dc:creator>
      <pubDate>Wed, 04 Sep 2019 16:04:51 +0000</pubDate>
      <link>https://dev.to/azure/using-the-new-azure-sdk-for-java-to-upload-images-asynchronously-using-spring-reactor-20ha</link>
      <guid>https://dev.to/azure/using-the-new-azure-sdk-for-java-to-upload-images-asynchronously-using-spring-reactor-20ha</guid>
      <description>&lt;h2&gt;
  
  
  The new Azure SDK for Java
&lt;/h2&gt;

&lt;p&gt;This blog post uses the upcoming Azure SDK for Java: at the time of this writing, this is still a preview release, but many people have already started using it.&lt;/p&gt;

&lt;p&gt;To be more precise, we are talking here of the &lt;a href="https://azure.github.io/azure-sdk/posts/2019-08-06/java-preview2.html" rel="noopener noreferrer"&gt;Azure SDK for Java (August 2019 Preview)&lt;/a&gt;, also seen as "1.0.0-preview.2" on Maven Central.&lt;/p&gt;

&lt;p&gt;This new release is important as it uses some new, modern &lt;a href="https://azure.github.io/azure-sdk/java_design.html" rel="noopener noreferrer"&gt;API guidelines&lt;/a&gt;, and also because its asynchronous features are powered by &lt;a href="https://projectreactor.io/" rel="noopener noreferrer"&gt;Spring Reactor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Those new reactive APIs are interesting as they deliver better scalability, and work very well with Spring. Unfortunately, they come at the cost of using an API that is more complex to understand, and more complex to debug: this is why we are doing this blog post!&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with uploading data
&lt;/h2&gt;

&lt;p&gt;Uploading data takes time, and usually need a good connection: if you're working with mobile devices, this can definitely be an issue! If we use a thread-based model, this means that sending several files is going to block several threads, and is not going to be very scalable. Or you could put all files in a queue that you would manage yourself: this is probably quite complex to code, and this will prevent you from uploading those files in parallel, so performance won't be very good. This is where Spring Reactor comes into play!&lt;/p&gt;

&lt;p&gt;The idea here is to upload that data in an asynchronous, non-blocking way, so we can upload many files in parallel without blocking the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spring Reactor and Spring Webflux
&lt;/h2&gt;

&lt;p&gt;Please note that the example here works with Spring Webflux: this is the reactive version of Spring, and as this works in a totally different way than the classical Spring MVC (which is thread-based), this code won't work with Spring MVC. This is one of the issues when doing reactive programming: it's not really possible to mix reactive code and thread-based code, so all your project will need be made and thought with a reactive API. In my opinion, this is best suited in a microservice architecture, where you will code some specific services with a reactive API, and some with a traditional thread-based API. Reactive microservices will probably be a bit more complex to develop and debug, but will provide better scalability, start-up time, memory consumption, so they will be used for some specific, resource-intensive tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Storage Account
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://portal.azure.com/?WT.mc_id=devto-blog-judubois" rel="noopener noreferrer"&gt;the Azure portal&lt;/a&gt;, create a new storage account:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2s9225pemizk8rqy7ays.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F2s9225pemizk8rqy7ays.png" alt="create a new storage account"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once it is created, go to that storage account and select "Shared access signature", or SAS. A SAS is a signature that allows to access some resources, for a limited period of time: it is perfect for uploading data on a specific location, without compromising security.&lt;/p&gt;

&lt;p&gt;After clicking on "Generate SAS and connection string", copy the last generated text field, named "Blob service SAS URL". This is the one we will use with the Azure SDK for Java.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fplc0vr5x7kmde65fwdgc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fplc0vr5x7kmde65fwdgc.png" alt="Blob service SAS URL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add the Azure SDK for Java to the pom.xml
&lt;/h2&gt;

&lt;p&gt;As the Azure SDK for Java preview is on Maven Central, this is just a matter of adding the dependency to the project's pom.xml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.azure&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;azure-storage-blob&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;12.0.0-preview.2&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the new asynchronous API
&lt;/h2&gt;

&lt;p&gt;Let's first have a look at the final code, which is available on &lt;a href="https://github.com/jdubois/jhipster-azure-blob-storage/blob/master/src/main/java/com/example/demo/PictureResource.java" rel="noopener noreferrer"&gt;https://github.com/jdubois/jhipster-azure-blob-storage/blob/master/src/main/java/com/example/demo/PictureResource.java&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PictureResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoggerFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PictureResource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nd"&gt;@Value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${AZURE_BLOB_ENDPOINT}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/picture"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;uploadPicture&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Configuring storage client"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;BlobServiceAsyncClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BlobServiceClientBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buildAsyncClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createContainer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pictures"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doOnError&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Container already exists"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;})&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientResponse&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Uploading picture"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;clientResponse&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBlockBlobAsyncClient&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"picture.png"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uploadFromFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"src/main/resources/image.png"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="o"&gt;})&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subscribe&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt; This API only works when using Spring Reactive, so please note you need to use this in a Spring Webflux project, and not a Spring MVC project.&lt;/p&gt;

&lt;p&gt;Authentication is done using the "Blob service SAS URL" that we copied above, and which is provided using the &lt;code&gt;AZURE_BLOB_ENDPOINT&lt;/code&gt; environment variable in this example: please note that the SAS is included in the URL, so there is no need to authenticate elsewhere (there is a &lt;code&gt;credentials()&lt;/code&gt; method in the API, that might be misleading, but which is useless in our case). This URL should thus be stored securely, and not commited with your code.&lt;/p&gt;

&lt;p&gt;Sending the image uses the Spring Reactor API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We create a specific &lt;code&gt;pictures&lt;/code&gt; container to store some data&lt;/li&gt;
&lt;li&gt;We then use Spring Reactor's API to upload a picture&lt;/li&gt;
&lt;li&gt;And we finish by using the &lt;code&gt;subscribe()&lt;/code&gt; method, which makes our code run asynchronously&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, this method will return very quickly, and then the container will be created and the image uploaded, in another thread. This can make debugging harder, but allows our application to accept many more requests, and process them asynchronously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improving the reactive code
&lt;/h2&gt;

&lt;p&gt;This tip was provided by &lt;a href="https://twitter.com/cbornet_" rel="noopener noreferrer"&gt;Christophe Bornet&lt;/a&gt;, many thanks to him!&lt;/p&gt;

&lt;p&gt;The previous code is what we usually see in projects, but that can be improved, in order to let Spring Webflux handle the &lt;code&gt;.subscribe()&lt;/code&gt; part: this will preserve the backpressure between Spring Webflux and the Azure SDK. Also, that means that errors will be managed by Spring Webflux, instead of being lost: in the case of an error while uploading a file using the Azure SDK, with this new code you will have a clean 500 error.&lt;/p&gt;

&lt;p&gt;The change can be seen in &lt;a href="https://github.com/jdubois/jhipster-azure-blob-storage/commit/17dfd0ea13e582b889b4e54534fdd098ecc3ab96" rel="noopener noreferrer"&gt;this commit&lt;/a&gt;, where we replace the &lt;code&gt;.subscribe()&lt;/code&gt; by a &lt;code&gt;.then()&lt;/code&gt; and we return a &lt;code&gt;Mono&amp;lt;Void&amp;gt;&lt;/code&gt; instead of not returning anything. It will be Spring Webflux's responsibility to handle that &lt;code&gt;Mono&lt;/code&gt; and call &lt;code&gt;.subscribe()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The resulting code is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@PostMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/picture"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Mono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;uploadPicture&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Configuring storage client"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;BlobServiceAsyncClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BlobServiceClientBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;buildAsyncClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createContainer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pictures"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doOnError&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Container already exists"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="o"&gt;})&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;flatMap&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientResponse&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Uploading picture"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;clientResponse&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBlockBlobAsyncClient&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"picture.png"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uploadFromFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"src/main/resources/image.png"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="o"&gt;})&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's a bit more advanced usage of the reactive APIs, but the result should be worth the trouble.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion and feedback
&lt;/h2&gt;

&lt;p&gt;We are currently lacking documentation and samples on this new asynchronous API in Azure SDK for Java. I believe that it is very important in some specific scenarios like the one we have here, as typically you should not upload or download data in the current thread if you want a scalable application.&lt;/p&gt;

&lt;p&gt;This SDK is still in preview, so if you have feedback on this API, please comment on this post!&lt;/p&gt;

&lt;p&gt;For example, the current API allows you to create a container (and this will fail if a container already exist) or get an existing container (and this will fail if it does not exist yet). Do you think there should be an option to have something like &lt;code&gt;getOrCreateContainer("name")&lt;/code&gt;, that will automatically create a container if it is requested?&lt;/p&gt;

</description>
      <category>spring</category>
      <category>azure</category>
      <category>java</category>
      <category>reactive</category>
    </item>
  </channel>
</rss>
