Spring Cloud Function in Azure

Dieser Artikel führt Sie durch die Verwendung von Spring Cloud Functions zum Entwickeln einer Java-Funktion und deren Veröffentlichung in Azure Functions. Wenn Sie fertig sind, wird Ihr Funktionscode für den Verbrauchstarif in Azure ausgeführt und kann mithilfe einer HTTP-Anforderung ausgelöst werden.

Voraussetzungen

Um Funktionen mit Java zu entwickeln, muss Folgendes installiert sein:

Wichtig

  1. Sie müssen die JAVA_HOME-Umgebungsvariable auf den Installationsspeicherort des JDK festlegen, um diese Schnellstartanleitung abzuschließen.
  2. Stellen Sie sicher, dass Ihre Haupttoolversion mindestens 4.0.5455 ist.

Durchzuführende Erstellungen

Wir erstellen eine klassische „Hello, World“-Funktion, die unter Azure Functions ausgeführt und mit Spring Cloud Function konfiguriert wird.

Die Funktion empfängt ein User-JSON-Objekt, das einen Benutzernamen enthält, und sendet ein Greeting-Objekt zurück, das die Begrüßung für den Benutzer enthält.

Das Projekt ist im Spring Cloud Function in Azure-Beispiel des azure-function-java-worker-Repositorys in GitHub verfügbar. Sie können dieses Beispiel direkt verwenden, wenn Sie sich das Endprodukt ansehen möchten, das in dieser Schnellstartanleitung beschrieben wird.

Erstellen eines neuen Maven-Projekts

Wir erstellen ein leeres Maven-Projekt und konfigurieren es mit Spring Cloud Function und Azure Functions.

Erstellen Sie in einem leeren Ordner die neue Datei pom.xml, und kopieren Sie den Inhalt aus der Datei pom.xml des Beispielprojekts in diese Datei.

Hinweis

Diese Datei verwendet Maven-Abhängigkeiten von Spring Boot und Spring Cloud Function und konfiguriert die Spring Boot- und Azure Functions Maven-Plug-Ins.

Sie müssen einige Eigenschaften für Ihre Anwendung anpassen:

  • <functionAppName> ist der Name Ihrer Azure-Funktion.
  • <functionAppRegion> ist der Name der Azure-Region, in der die Funktion bereitgestellt wird.
  • <functionResourceGroup> ist der Name der von Ihnen verwendeten Azure-Ressourcengruppe.

Ändern Sie diese Eigenschaften direkt im oberen Bereich der Datei pom.xml. Dies ist im folgenden Beispiel dargestellt:

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

Erstellen von Azure-Konfigurationsdateien

Erstellen Sie einen src/main/resources-Ordner, und fügen Sie die folgenden Azure Functions-Konfigurationsdateien dort ein.

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

Erstellen von Domänenobjekten

Azure Functions kann Objekte im JSON-Format empfangen und senden. Nun erstellen wir die Objekte User und Greeting, die für unser Domänenmodell stehen. Sie können komplexere Objekte mit weiteren Eigenschaften erstellen, wenn Sie diese Schnellstartanleitung anpassen und für sich interessanter gestalten möchten.

Erstellen Sie einen Ordner src/main/java/com/example/model, und fügen Sie die folgenden beiden Dateien hinzu:

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

Erstellen der Spring Boot-Anwendung

Diese Anwendung verwaltet die gesamte Geschäftslogik und hat Zugriff auf das gesamte Spring Boot-Ökosystem. Diese Funktion bietet Ihnen zwei wesentliche Vorteile gegenüber einer Azure-Standardfunktion:

  • Sie beruht nicht auf den Azure Functions-APIs und kann von Ihnen daher problemlos auf andere Systeme portiert werden. Beispielsweise ist die Wiederverwendung in einer normalen Spring Boot-Anwendung möglich.
  • Sie können alle @Enable-Anmerkungen aus Spring Boot nutzen, um neue Features hinzuzufügen.

Erstellen Sie im Ordner src/main/java/com/example die folgende Datei, die eine normale Spring Boot-Anwendung ist:

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

Erstellen Sie nun die folgende Datei im Ordner src/main/java/com/example/hello. Dieser Code enthält eine Spring Boot-Komponente, die die Funktion darstellt, die wir ausführen möchten:

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

Hinweis

Die Hello-Funktion ist recht spezifisch:

  • Es handelt sich um eine java.util.function.Function. Die Funktion enthält die Geschäftslogik und verwendet eine Standard-Java-API, um ein Objekt in ein anderes zu transformieren.
  • Da sie die @Component-Anmerkung enthält, ist es eine Spring Bean-Funktion. Sie hat standardmäßig den Namen der Klasse, aber sie beginnt mit einem Kleinbuchstaben: hello. Die Einhaltung dieser Namenskonvention ist wichtig, falls Sie noch andere Funktionen in Ihrer Anwendung erstellen möchten. Der Name muss mit dem Azure Functions-Namen übereinstimmen, den wir im nächsten Abschnitt erstellen.

Erstellen der Azure-Funktion

Um die gesamte Azure Functions-API nutzen zu können, werden wir jetzt eine Azure Function programmieren. Bei dieser Azure Function wird die Ausführung an die Spring Cloud Function-Instanz delegiert, die wir im vorherigen Schritt erstellt haben.

Erstellen Sie im Ordner src/main/java/com/example/hello die folgende Klassendatei für die Azure Function:

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

Diese Java-Klasse ist eine Azure-Funktion mit den folgenden interessanten Features:

  • Die Klasse hat die @Component-Anmerkung, sodass es sich um eine Spring-Bean-Klasse handeln kann.
  • Der Name der Funktion lautet hello (gemäß Definition durch die Anmerkung @FunctionName("hello")).
  • Die Klasse implementiert eine echte Azure Function, sodass Sie hier die vollständige Azure Functions-API verwenden können.

Komponententests hinzufügen

Dieser Schritt ist optional. Die Ausführung wird aber empfohlen, um zu überprüfen, ob die Anwendung richtig funktioniert.

Erstellen Sie den Ordner src/test/java/com/example, und fügen Sie die folgenden JUnit-Tests hinzu:

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

Nun können Sie Ihre Azure-Funktion mit Maven testen:

mvn clean test

Lokales Ausführen der Funktion

Bevor Sie Ihre Anwendung in Azure Functions bereitstellen, testen Sie sie zuerst lokal.

Zuerst müssen Sie Ihre Anwendung in eine JAR-Datei packen:

mvn package

Nachdem die Anwendung gepackt wurde, können Sie sie mithilfe des Maven-Plug-Ins azure-functions ausführen:

mvn azure-functions:run

Die Azure-Funktion sollte nun auf dem Localhost mit Port 7071 verfügbar sein. Sie können die Funktion testen, indem Sie Ihr eine POST-Anforderung mit einem User-Objekt im JSON-Format senden. Verwenden Sie beispielsweise cURL:

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

Die Funktion sollte Ihnen mit einem Greeting-Objekt antworten, immer noch im JSON-Format:

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

Hier ist ein Screenshot angegeben, auf dem sich die cURL-Anforderung am oberen und die lokale Azure-Funktion am unteren Bildschirmrand befindet:

Lokale Ausführung der Azure-Funktion

Lokales Debuggen der Funktion

In den folgenden Abschnitten wird beschrieben, wie Sie die Funktion debuggen.

Debuggen per Intellij IDEA

Öffnen Sie das Projekt in Intellij IDEA, und erstellen Sie eine Laufzeitkonfiguration vom Typ Remote JVM Debug, die angefügt werden kann. Weitere Informationen finden Sie unter Tutorial: Remotedebuggen.

Erstellen einer Remote JVM Debug-Laufzeitkonfiguration

Führen Sie die Anwendung mit dem folgenden Befehl aus:

mvn azure-functions:run -DenableDebug

Nach dem Starten der Anwendung wird die folgende Ausgabe angezeigt:

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

Starten Sie das Debuggen des Projekts in IntelliJ IDEA. Die folgende Ausgabe wird angezeigt:

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

Markieren Sie die gewünschten Breakpoints für das Debuggen. Intellij IDEA wechselt nach dem Senden einer Anforderung in den Debugmodus.

Debuggen mit Visual Studio Code

Öffnen Sie das Projekt in Visual Studio Code, und konfigurieren Sie den Inhalt der Datei launch.json wie folgt:

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

Führen Sie die Anwendung mit dem folgenden Befehl aus:

mvn azure-functions:run -DenableDebug

Nach dem Starten der Anwendung wird die folgende Ausgabe angezeigt:

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

Starten Sie das Debuggen des Projekts in Visual Studio Code, und markieren Sie die gewünschten Breakpoints für das Debuggen. Nach dem Senden einer Anforderung wird in Visual Studio Code der Debugmodus aktiviert. Weitere Informationen finden Sie unter Ausführen und Debuggen von Java.

Bereitstellen der Funktion in Azure Functions

Jetzt veröffentlichen Sie die Azure Function für die Produktion. Beachten Sie, dass die Eigenschaften <functionAppName>, <functionAppRegion> und <functionResourceGroup>, die Sie in der Datei pom.xml definiert haben, zum Konfigurieren der Funktion verwendet werden.

Hinweis

Für das Maven-Plug-In muss die Authentifizierung für Azure durchgeführt werden. Wenn Sie die Azure CLI installiert haben, sollten Sie az login verwenden, bevor Sie fortfahren. Weitere Authentifizierungsoptionen finden Sie unter Authentifizierung im Repository azure-maven-plugins.

Führen Sie Maven aus, um die Funktion automatisch bereitzustellen:

mvn azure-functions:deploy

Wechseln Sie nun zum Azure-Portal, um die Function App zu suchen, die erstellt wurde.

Wählen Sie die Funktion aus:

  • Beachten Sie in der Funktionsübersicht die URL der Funktion.
  • Um die ausgeführte Funktion zu überprüfen, wählen Sie Protokollstreaming im Navigationsmenü aus.

Verwenden Sie nun wie im vorherigen Abschnitt cURL, um auf die ausgeführte Funktion zuzugreifen. Dies ist im folgenden Beispiel dargestellt. Ersetzen Sie your-function-name durch Ihren tatsächlichen Namen der Funktion.

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

Die Funktion sollte Ihnen wie im vorherigen Abschnitt mit einem Greeting-Objekt antworten, immer noch im JSON-Format:

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

Herzlichen Glückwunsch, bei Ihnen wird unter Azure Functions eine Spring Cloud Function-Instanz ausgeführt! Weitere Informationen und Beispiele für Spring Cloud Functions finden Sie in den folgenden Ressourcen:

Nächste Schritte

Weitere Informationen zu Spring und Azure finden Sie im Dokumentationscenter zu Spring in Azure.