Funzione Spring Cloud in Azure

Questo articolo illustra come usare Spring Cloud Function per sviluppare una funzione Java e pubblicarla in Funzioni di Azure. Al termine, il codice della funzione viene eseguito nel piano a consumo in Azure e può essere attivato usando una richiesta HTTP.

Se non si ha una sottoscrizione di Azure, creare un account gratuito prima di iniziare.

Prerequisiti

Per sviluppare funzioni con Java, è necessario che siano installati gli elementi seguenti:

Importante

  1. Per completare questa guida introduttiva, è necessario impostare la JAVA_HOME variabile di ambiente sul percorso di installazione di JDK.
  2. Assicurarsi che la versione degli strumenti di base sia almeno 4.0.5455.

Quello che creeremo

Verrà creata una funzione classica "Hello, World" che viene eseguita in Funzioni di Azure ed è configurata con Spring Cloud Function.

La funzione riceve un User oggetto JSON che contiene un nome utente e invia un Greeting oggetto che contiene il messaggio di benvenuto all'utente.

Il progetto è disponibile nell'esempio spring cloud function in Azure del repository azure-function-java-worker su GitHub. È possibile usare questo esempio direttamente se si vuole visualizzare il lavoro finale descritto in questa guida introduttiva.

Creare un nuovo progetto Maven

Verrà creato un progetto Maven vuoto e configurato con Spring Cloud Function e Funzioni di Azure.

In una cartella vuota creare un nuovo file pom.xml e copiare/incollare il contenuto dal file pom.xml del progetto di esempio.

Nota

Questo file usa le dipendenze Maven di Spring Boot e Spring Cloud Function e configura i plug-in Maven di Spring Boot e Funzioni di Azure.

È necessario personalizzare alcune proprietà per l'applicazione:

  • <functionAppName> è il nome della funzione di Azure
  • <functionAppRegion> è il nome dell'area di Azure in cui è distribuita la funzione
  • <functionResourceGroup> è il nome del gruppo di risorse di Azure in uso

Modificare tali proprietà direttamente nella parte superiore del file pom.xml , come illustrato nell'esempio seguente:

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

Creare i file di configurazione di Azure

Creare una cartella src/main/resources e aggiungervi i file di configurazione Funzioni di Azure seguenti.

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": ""
  }
}

Creare gli oggetti di dominio

Funzioni di Azure può ricevere e inviare oggetti in formato JSON. Verranno ora creati gli User oggetti e Greeting che rappresentano il modello di dominio. È possibile creare oggetti più complessi, con un numero maggiore di proprietà, se si vuole personalizzare questo avvio rapido e renderlo più interessante.

Creare una cartella src/main/java/com/example/model e aggiungere i due file seguenti:

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

Creare l'applicazione Spring Boot

Questa applicazione gestisce tutta la logica di business e ha accesso all'ecosistema Spring Boot completo. Questa funzionalità offre due vantaggi principali rispetto a una funzione di Azure standard:

  • Non si basa sulle API Funzioni di Azure, quindi è possibile convertirla facilmente in altri sistemi. Ad esempio, è possibile riutilizzarlo in una normale applicazione Spring Boot.
  • È possibile usare tutte le @Enable annotazioni di Spring Boot per aggiungere nuove funzionalità.

Nella cartella src/main/java/com/example creare il file seguente, che è una normale applicazione Spring Boot:

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

Creare ora il file seguente nella cartella src/main/java/com/example/hello . Questo codice contiene un componente Spring Boot che rappresenta la funzione da eseguire:

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

Nota

La funzione Hello è piuttosto specifica:

  • Si tratta di un oggetto java.util.function.Function. Contiene la logica di business e usa un'API Java standard per trasformare un oggetto in un altro.
  • Poiché ha l'annotazione @Component , si tratta di un bean Spring e per impostazione predefinita il nome è uguale alla classe , ma a partire da un carattere minuscolo: hello. Se si vuole creare altre funzioni nell'applicazione, seguire questa convenzione di denominazione è importante. Il nome deve corrispondere al nome Funzioni di Azure che verrà creato nella sezione successiva.

Creare la funzione di Azure

Per trarre vantaggio dall'API Funzioni di Azure completa, viene ora codificata una funzione di Azure che delega l'esecuzione alla funzione Spring Cloud creata nel passaggio precedente.

Nella cartella src/main/java/com/example/hello creare il file di classe della funzione di Azure seguente:

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

Questa classe Java è una funzione di Azure con interessanti caratteristiche, come descritto di seguito:

  • La classe ha l'annotazione @Component , quindi è un bean spring.
  • Il nome della funzione, come definito dall'annotazione @FunctionName("hello") , è hello.
  • La classe implementa una funzione di Azure reale, quindi è possibile usare l'API Funzioni di Azure completa qui.

Aggiungere unit test

Questo passaggio è facoltativo, ma consigliato per verificare che l'applicazione funzioni correttamente.

Creare una cartella src/test/java/com/example e aggiungere i test JUnit seguenti:

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

È ora possibile testare la funzione di Azure con Maven:

mvn clean test

Eseguire la funzione in locale

Prima di distribuire l'applicazione in Funzioni di Azure, è opportuno eseguirne il test in locale.

Per prima cosa è necessario creare il pacchetto dell'applicazione in un file con estensione jar:

mvn package

Ora che l'applicazione è assemblata in un pacchetto, è possibile eseguirla usando il plug-in azure-functions di Maven:

mvn azure-functions:run

La funzione di Azure dovrebbe ora essere disponibile nel localhost, sulla porta 7071. È possibile testare la funzione inviando una richiesta POST, con un oggetto User in formato JSON. È ad esempio possibile usare cURL:

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

La funzione dovrebbe rispondere con un oggetto Greeting, sempre in formato JSON:

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

Ecco uno screenshot della richiesta cURL nella parte superiore della schermata e della funzione di Azure locale nella parte inferiore:

Azure Function running locally

Eseguire il debug della funzione in locale

Le sezioni seguenti descrivono come eseguire il debug della funzione.

Eseguire il debug con Intellij IDEA

Aprire il progetto in Intellij IDEA, quindi creare una configurazione di esecuzione di debug JVM remota da collegare. Per altre informazioni, vedere Esercitazione: Debug remoto.

Create a Remote JVM Debug run configuration

Eseguire l'applicazione con il comando seguente:

mvn azure-functions:run -DenableDebug

All'avvio dell'applicazione viene visualizzato l'output seguente:

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

Avviare il debug del progetto in IntelliJ IDEA. Viene visualizzato l'output seguente:

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

Contrassegnare i punti di interruzione di cui si vuole eseguire il debug. Intellij IDEA passerà alla modalità di debug dopo l'invio di una richiesta.

Eseguire il debug con Visual Studio Code

Aprire il progetto in Visual Studio Code, quindi configurare il contenuto del file launch.json seguente:

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

Eseguire l'applicazione con il comando seguente:

mvn azure-functions:run -DenableDebug

All'avvio dell'applicazione viene visualizzato l'output seguente:

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

Avviare il debug del progetto in Visual Studio Code, quindi contrassegnare i punti di interruzione di cui si vuole eseguire il debug. Visual Studio Code passerà alla modalità di debug dopo l'invio di una richiesta. Per altre informazioni, vedere Esecuzione e debug di Java.

Distribuire la funzione in Funzioni di Azure

Si pubblicherà ora la funzione di Azure nell'ambiente di produzione. Tenere presente che le <functionAppName>proprietà , <functionAppRegion>e <functionResourceGroup> definite nel file pom.xml vengono usate per configurare la funzione.

Nota

Il plug-in Maven deve eseguire l'autenticazione con Azure. Se è installata l'interfaccia della riga di comando di Azure, usare az login prima di continuare. Per altre opzioni di autenticazione, vedere Autenticazione nel repository azure-maven-plugins .

Eseguire Maven per distribuire automaticamente la funzione:

mvn azure-functions:deploy

Passare ora al portale di Azure per trovare la risorsa Function App che è stata creata.

Selezionare la funzione :

  • Nella panoramica della funzione prendere nota del relativo URL.
  • Per controllare la funzione in esecuzione, selezionare Flusso di log nel menu di spostamento.

Come è stato fatto nella sezione precedente, usare cURL per accedere alla funzione in esecuzione, come illustrato nell'esempio seguente. Assicurarsi di sostituire your-function-name con il nome della funzione reale.

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

Come nella sezione precedente, la funzione dovrebbe rispondere con un oggetto Greeting, sempre in formato JSON:

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

A questo punto è stata creata una funzione Spring Cloud che viene eseguita in Funzioni di Azure. Per altre informazioni ed esempi di funzioni spring cloud, vedere le risorse seguenti:

Passaggi successivi

Per altre informazioni su Spring e Azure, passare al centro di documentazione di Spring in Azure.