Spring Cloud Function dans Azure

Cet article vous guide pendant l’utilisation de Spring Cloud Functions pour développer une fonction Java et la publier sur Azure Functions. Lorsque vous avez terminé, le code de votre fonction s’exécute sur le plan de consommation dans Azure et peut être déclenché à l’aide d’une requête HTTP.

Si vous n’avez pas d’abonnement Azure, créez un compte gratuit avant de commencer.

Prérequis

Pour développer des fonctions avec Java, les éléments suivants doivent être installés :

Important

  1. Vous devez définir la JAVA_HOME variable d’environnement sur l’emplacement d’installation du JDK pour suivre ce guide de démarrage rapide.
  2. Vérifiez que la version de vos outils de base est au moins 4.0.5455.

Ce que vous allez créer

Nous allons créer une fonction classique « Hello, World » qui s’exécute sur Azure Functions et qui est configurée avec Spring Cloud Function.

La fonction reçoit un User objet JSON, qui contient un nom d’utilisateur et renvoie un Greeting objet, qui contient le message d’accueil à cet utilisateur.

Le projet est disponible dans la fonction Spring Cloud dans l’exemple Azure du référentiel azure-function-java-worker sur GitHub. Vous pouvez utiliser cet exemple directement si vous souhaitez voir le travail final décrit dans ce guide de démarrage rapide.

Création d’un projet Maven

Vous allez créer un projet Maven vide et le configurer avec Spring Cloud Function et Azure Functions.

Dans un dossier vide, créez un fichier pom.xml et copiez/collez le contenu du fichier pom.xml figurant dans l’exemple de projet.

Remarque

Ce fichier utilise des dépendances Maven à partir de Spring Boot et de Spring Cloud Function et configure les plug-ins Maven Spring Boot et Azure Functions.

Vous devez personnaliser quelques propriétés pour votre application :

  • <functionAppName> est le nom de votre fonction Azure.
  • <functionAppRegion> est le nom de la région Azure dans laquelle votre fonction est déployée.
  • <functionResourceGroup> est le nom du groupe de ressources Azure que vous utilisez

Modifiez directement ces propriétés dans la partie supérieure du fichier pom.xml, comme indiqué dans l’exemple suivant :

    <properties>
        <java.version>11</java.version>

        <!-- Spring Boot start class. WARNING: correct class must be set -->
        <start-class>com.example.DemoApplication</start-class>

        <!-- customize those properties. WARNING: the functionAppName should be unique across Azure -->
        <azure.functions.maven.plugin.version>1.29.0</azure.functions.maven.plugin.version>
        <functionResourceGroup>my-spring-function-resource-group</functionResourceGroup>
        <functionAppServicePlanName>my-spring-function-service-plan</functionAppServicePlanName>
        <functionAppName>my-spring-function</functionAppName>
        <functionPricingTier>Y1</functionPricingTier>
        <functionAppRegion>eastus</functionAppRegion>
    </properties>

Créer des fichiers de configuration Azure

Créez un dossier src/main/resources et ajoutez-y les fichiers de configuration Azure Functions suivants.

host.json :

{
  "version": "2.0",
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[4.*, 5.2.0)"
  },
  "functionTimeout": "00:10:00"
}

local.settings.json :

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "java",
    "FUNCTIONS_EXTENSION_VERSION": "~4",
    "AzureWebJobsDashboard": ""
  }
}

Créer des objets de domaine

Azure Functions peut recevoir et envoyer des objets au format JSON. Vous allez maintenant créer les objets User et Greeting, qui représentent le modèle de domaine. Vous pouvez créer des objets plus complexes, avec davantage de propriétés, si vous souhaitez personnaliser ce guide de démarrage rapide et le rendre plus intéressant pour vous.

Créez un dossier src/main/Java/com/example/model et ajoutez les deux fichiers suivants :

User.java :

package com.example.model;

public class User {

    private String name;

    public User() {
    }

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Greeting.java :

package com.example.model;

public class Greeting {

    private String message;

    public Greeting() {
    }

    public Greeting(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

Créer l’application Spring Boot

Cette application gère toute la logique métier et a accès à l’écosystème Spring Boot complet. Cette fonctionnalité vous offre deux avantages principaux par rapport à une fonction Azure standard :

  • Elle ne repose pas sur les API Azure Functions et peut donc être facilement portée sur d’autres systèmes. Par exemple, vous pouvez la réutiliser dans une application Spring Boot normale.
  • Vous pouvez utiliser toutes les annotations @Enable de Spring Boot pour ajouter de nouvelles fonctionnalités.

Dans le dossier src/main/Java/com/example, créez le fichier suivant, qui est une application Spring Boot normale :

DemoApplication.java :

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(DemoApplication.class, args);
    }
}

Créez maintenant le fichier suivant dans le dossier src/main/java/com/example/hello . Ce code contient un composant Spring Boot qui représente la fonction que nous voulons exécuter :

Hello.java :

package com.example.hello;

import com.example.model.*;
import org.springframework.stereotype.Component;
import java.util.function.Function;

@Component
public class Hello implements Function<User, Greeting> {

    @Override
    public Greeting apply(User user) {
        return new Greeting("Hello, " + user.getName() + "!\n");
    }
}

Remarque

La fonction Hello est assez spécifique :

  • Il s’agit d’une java.util.function.Function. Elle contient la logique métier et utilise une API Java standard pour transformer un objet en autre objet.
  • Comme elle a l’annotation @Component, il s’agit d’un bean Spring et, par défaut, son nom est le même que celui de la classe, mais avec une minuscule : hello. Il est important de suivre cette convention de nommage si vous souhaitez créer d’autres fonctions dans votre application. Le nom doit correspondre au nom Azure Functions que nous allons créer dans la section suivante.

Créer la fonction Azure

Pour tirer parti de l’API Azure Functions complète, nous codeons maintenant une fonction Azure qui délègue son exécution à la fonction Spring Cloud créée à l’étape précédente.

Dans le dossier src/main/java/com/example/hello , créez le fichier de classe de fonction Azure suivant :

HelloHandler.java :

package com.example.hello;

import com.microsoft.azure.functions.*;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;
import com.example.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Optional;

@Component
public class HelloHandler {

    @Autowired
    private Hello hello;

    @FunctionName("hello")
    public HttpResponseMessage execute(
        @HttpTrigger(name = "request", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<User>> request, ExecutionContext context) {
        User user = request.getBody()
                           .filter(u -> u.getName() != null)
                           .orElseGet(() -> new User(request.getQueryParameters().getOrDefault("name", "world")));
        context.getLogger().info("Greeting user name: " + user.getName());
        return request.createResponseBuilder(HttpStatus.OK)
                      .body(hello.apply(user))
                      .header("Content-Type", "application/json")
                      .build();
    }
}

Cette classe Java est une fonction Azure, avec les fonctionnalités intéressantes suivantes :

  • La classe a l’annotation @Component . Il s’agit donc d’un Spring Bean.
  • Le nom de la fonction, comme défini par l’annotation @FunctionName("hello"), est hello.
  • La classe implémente une vraie fonction Azure. Vous pouvez donc utiliser l’API Azure Functions complète ici.

Ajouter des tests unitaires

Cette étape est facultative mais recommandée pour valider le bon fonctionnement de l’application.

Créez un dossier src/test/java/com/example, puis ajoutez les tests JUnit suivants :

HelloTest.java :

package com.example;

import com.example.hello.Hello;
import com.example.model.Greeting;
import com.example.model.User;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class HelloTest {

    @Test
    public void test() {
        Greeting result = new Hello().apply(new User("foo"));
        assertThat(result.getMessage()).isEqualTo("Hello, foo!\n");
    }
}

Vous pouvez maintenant tester votre fonction Azure à l’aide de Maven :

mvn clean test

Exécuter la fonction localement

Avant de déployer votre application sur Azure Functions, vous allez la tester localement.

Tout d’abord, vous devez empaqueter votre application dans un fichier jar :

mvn package

Maintenant que l’application est empaquetée, vous pouvez l’exécuter à l’aide du plug-in Maven azure-functions :

mvn azure-functions:run

La fonction Azure doit maintenant être disponible sur votre localhost, à l’aide du port 7071. Vous pouvez tester la fonction en lui envoyant une demande POST, avec un objet User au format JSON. Par exemple, à l’aide de cURL :

curl -X POST http://localhost:7071/api/hello -d "{\"name\":\"Azure\"}"

La fonction doit vous répondre avec un objet Greeting, toujours au format JSON :

{
  "message": "Hello, Azure!\n"
}

Voici une capture d’écran de la demande cURL en haut de l’écran et de la fonction Azure locale en bas :

Azure Function running locally

Déboguer la fonction localement

Les sections suivantes décrivent comment déboguer la fonction.

Déboguer avec IntelliJ IDEA

Ouvrez le projet dans IntelliJ IDEA, puis créez une configuration d’exécution Remote JVM Debug à attacher. Pour plus d’informations, consultez le tutoriel sur le débogage distant.

Create a Remote JVM Debug run configuration

Exécutez l’application avec la commande suivante :

mvn azure-functions:run -DenableDebug

Au démarrage de l’application, la sortie suivante s’affiche :

Worker process started and initialized.
Listening for transport dt_socket at address: 5005

Démarrez le débogage de projet dans IntelliJ IDEA. La sortie suivante s’affiche :

Connected to the target VM, address: 'localhost:5005', transport: 'socket'

Marquez les points d’arrêt que vous souhaitez déboguer. Intellij IDEA entre en mode débogage après l’envoi d’une demande.

Déboguer avec Visual Studio Code

Ouvrez le projet dans Visual Studio Code, puis configurez le contenu du fichier launch.json suivant :

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "java",
            "name": "Attach to Remote Program",
            "request": "attach",
            "hostName": "127.0.0.1",
            "port": 5005
        }
    ]
}

Exécutez l’application avec la commande suivante :

mvn azure-functions:run -DenableDebug

Au démarrage de l’application, la sortie suivante s’affiche :

Worker process started and initialized.
Listening for transport dt_socket at address: 5005

Démarrez le débogage du projet dans Visual Studio Code, puis marquez les points d’arrêt à déboguer. Visual Studio Code entre en mode débogage après l’envoi d’une demande. Pour plus d’informations, consultez Exécution et débogage de Java.

Déployer la fonction sur Azure Functions

À présent, vous allez publier la fonction Azure en production. N’oubliez pas que les <functionAppName>propriétés que <functionAppRegion><functionResourceGroup> vous avez définies dans votre fichier pom.xml sont utilisées pour configurer votre fonction.

Remarque

Le plugin Maven doit s’authentifier auprès d’Azure. Si Azure CLI est installé, utilisez az login avant de continuer. Pour plus d’options d’authentification, consultez Authentication dans le dépôt azure-maven-plugins.

Exécutez Maven pour déployer votre fonction automatiquement :

mvn azure-functions:deploy

Accédez maintenant au portail Azure pour rechercher l’Function App qui a été créée.

Sélectionnez la fonction :

  • Dans la vue d’ensemble de la fonction, notez l’URL de la fonction.
  • Pour case activée votre fonction en cours d’exécution, sélectionnez Journal de diffusion en continu dans le menu de navigation.

Maintenant, comme vous l’avez fait dans la section précédente, utilisez cURL pour accéder à la fonction en cours d’exécution, comme dans l’exemple suivant. Veillez à remplacer your-function-name par le nom de votre fonction réelle.

curl https://your-function-name.azurewebsites.net/api/hello -d "{\"name\":\"Azure\"}"

Comme dans la section précédente, la fonction doit vous répondre avec un objet Greeting, toujours au format JSON :

{
  "message": "Hello, Azure!\n"
}

Félicitations, vous disposez d’une fonction Spring Cloud Function exécutée sur Azure Functions. Pour plus d’informations et des exemples de fonctions Spring Cloud, consultez les ressources suivantes :

Étapes suivantes

Pour en savoir plus sur Spring et Azure, poursuivez vers le centre de documentation Spring sur Azure.