Aan de slag met Spring Cloud Function in Azure

Dit artikel helpt u bij het gebruik van Spring Cloud Functions om een Java-functie te ontwikkelen en deze te publiceren naar Azure Functions. Wanneer u klaar bent, wordt uw functiecode uitgevoerd in het Verbruiksabonnement in Azure en kan deze worden geactiveerd met behulp van een HTTP-aanvraag.

Als u geen Azure-abonnement hebt, maakt u een gratis account voordat u begint.

Vereisten

Als u functies wilt ontwikkelen met behulp van Java, moet het volgende zijn geïnstalleerd:

Belangrijk

U moet de omgevingsvariabele JAVA_HOME de installatielocatie van de JDK instellen om deze quickstart te voltooien.

Wat we gaan bouwen

We gaan een klassieke 'Hallo, wereld'-functie bouwen die wordt uitgevoerd op Azure Functions en die is geconfigureerd met Spring Cloud-functie.

Het ontvangt een eenvoudig JSON-object, dat een gebruikersnaam bevat, en stuurt een -object terug dat het welkomstbericht UserGreeting aan die gebruiker bevat.

Het project dat we gaan bouwen, is beschikbaar in de opslagplaats hello-spring-function-azure op GitHub. U kunt die voorbeeldopslagplaats rechtstreeks gebruiken als u het laatste werk wilt zien dat in deze quickstart wordt beschreven.

Een nieuw Maven-project maken

We gaan een leeg Maven-project maken en dit configureren met Spring Cloud-functie en Azure Functions.

Maak in een lege map een nieuw pom.xml en kopieer/plak de inhoud uit hetpom.xmlvoorbeeldproject.

Notitie

Dit bestand maakt gebruik van Maven-afhankelijkheden van zowel Spring Boot als Spring Cloud Function en wordt gebruikt om de Maven-invoegtoepassingen van Spring Boot en Azure Functions te configureren.

U moet een aantal eigenschappen voor uw toepassing aanpassen:

  • <functionAppName> is de naam van uw Azure-functie
  • <functionAppRegion> is de naam van de Azure-regio waar de functie wordt geïmplementeerd
  • <functionResourceGroup> is de naam van de Azure-resourcegroep die u gebruikt

Wijzig deze eigenschappen direct bovenaan hetpom.xml bestand, zoals wordt weergegeven in het volgende voorbeeld:

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>11</maven.compiler.source>
  <maven.compiler.target>11</maven.compiler.target>

  <azure.functions.java.library.version>1.4.2</azure.functions.java.library.version>
  <azure.functions.maven.plugin.version>1.13.0</azure.functions.maven.plugin.version>

  <!-- customize those two properties. The functionAppName should be unique across Azure -->
  <functionResourceGroup>my-spring-function-resource-group</functionResourceGroup>
  <functionAppName>my-spring-function</functionAppName>

  <functionAppRegion>westeurope</functionAppRegion>
  <stagingDirectory>${project.build.directory}/azure-functions/${functionAppName}</stagingDirectory>
  <start-class>com.example.DemoApplication</start-class>
</properties>

Azure-configuratiebestanden maken

Maak de map src/main/azure en voeg hieraan de volgende Azure Functions-configuratiebestanden toe.

host.json:

{
  "version": "2.0",
  "functionTimeout": "00:10:00"
}

local.settings.json:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "java",
    "MAIN_CLASS":"com.example.DemoApplication",
    "AzureWebJobsDashboard": ""
  }
}

Domeinobjecten maken

In Azure Functions kunt u objecten ontvangen en verzenden in JSON-indeling. We gaan nu onze - en -objecten UserGreeting maken die ons domeinmodel vertegenwoordigen. U kunt complexere objecten maken, met meer eigenschappen, als u deze quickstart wilt aanpassen en deze interessanter wilt maken.

Maak de map src/main/java/com/example/model en voeg de volgende twee bestanden toe:

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

De Spring Boot-toepassing maken

Met deze toepassing wordt alle bedrijfslogica beheerd. De toepassing biedt toegang tot het volledige Spring Boot-ecosysteem. Deze mogelijkheid biedt twee belangrijke voordelen ten opzichte van een standaard Azure-functie:

  • Het is niet afhankelijk van de Azure Functions API's, zodat u deze eenvoudig naar andere systemen kunt over poort. U kunt deze bijvoorbeeld opnieuw gebruiken in een normale Spring Boot toepassing.
  • U kunt alle aantekeningen @Enable uit de Spring Boot om nieuwe functies toe te voegen.

Maak in de map src/main/java/com/example het volgende bestand. Dit is een normale Spring Boot-toepassing:

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

Maak nu het volgende bestand, dat een onderdeel Spring Boot bevat dat staat voor de functie die we willen uitvoeren:

Hello.java:

package com.example;

import com.example.model.Greeting;
import com.example.model.User;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.function.Function;

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

    public Mono<Greeting> apply(Mono<User> mono) {
        return mono.map(user -> new Greeting("Hello, " + user.getName() + "!\n"));
    }
}

Notitie

De functie Hello is heel specifiek:

  • Het is een java.util.function.Function . Het bevat de bedrijfslogica en maakt gebruik van een standaard Java-API om het ene object in het andere te transformeren.
  • Omdat deze de aantekening heeft, is het een Spring Bean en is de naam standaard hetzelfde als de klasse, maar beginnend met een kleine @Component letter: hello . Het volgen van deze naamconventie is belangrijk als u andere functies in uw toepassing wilt maken. De naam moet overeenkomen met Azure Functions naam die we in de volgende sectie maken.

De Azure-functie maken

Om te profiteren van de volledige Azure Functions-API, gaan we nu een Azure-functie coden die de uitvoering delegeert aan de Spring Cloud-functie die we in de vorige stap hebben gemaakt.

Maak in de map src/main/java/com/example het volgende Azure Function-klassebestand:

HelloHandler.java:

package com.example;

import com.example.model.Greeting;
import com.example.model.User;
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 org.springframework.cloud.function.adapter.azure.FunctionInvoker;

import java.util.Optional;

public class HelloHandler extends FunctionInvoker<User, Greeting> {

    @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(handleRequest(user, context))
            .header("Content-Type", "application/json")
            .build();
    }
}

Deze Java-klasse is een Azure-functie, met de volgende interessante functies:

  • Het breidt FunctionInvoker uit, waarmee de koppeling tussen Azure Functions en Spring Cloud Functions wordt gemaakt. FunctionInvoker biedt de handleRequest() methode die wordt gebruikt in de methode body() .
  • De naam van de functie, zoals gedefinieerd door de @FunctionName("hello") aantekening, is hello .
  • Het is een echte Azure-functie, zodat u hier de volledige api Azure Functions gebruiken.

Eenheidstests toevoegen

Deze stap is optioneel, maar wordt aanbevolen om te controleren of de toepassing correct werkt.

Maak een map src/test/java/com/example en voeg de volgende JUnit-tests toe:

HelloTest.java:

package com.example;

import com.example.model.Greeting;
import com.example.model.User;
import com.microsoft.azure.functions.ExecutionContext;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.function.adapter.azure.FunctionInvoker;
import reactor.core.publisher.Mono;

import java.util.logging.Logger;

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

public class HelloTest {

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

    @Test
    public void start() {
        FunctionInvoker<User, Greeting> handler = new FunctionInvoker<>(
            Hello.class);
        Greeting result = handler.handleRequest(new User("foo"), new ExecutionContext() {
            @Override
            public Logger getLogger() {
                return Logger.getLogger(HelloTest.class.getName());
            }

            @Override
            public String getInvocationId() {
                return "id1";
            }

            @Override
            public String getFunctionName() {
                return "hello";
            }
        });
        handler.close();
        assertThat(result.getMessage()).isEqualTo("Hello, foo!\n");
    }
}

U kunt nu uw Azure-functie testen met Maven:

mvn clean test

De functie lokaal uitvoeren

Voordat u uw toepassing implementeert in Azure Function, moet u deze eerst lokaal testen.

Eerst moet u uw toepassing inpakken in een jar-bestand:

mvn package

Nu de toepassing is verpakt, kunt u deze uitvoeren met behulp van de azure-functions Maven-invoegtoepassing:

mvn azure-functions:run

De Azure-functie moet nu beschikbaar zijn op uw localhost met behulp van poort 7071. U kunt de functie testen door een POST-aanvraag te verzenden, met een User-object in JSON-indeling. Bijvoorbeeld met behulp van cURL:

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

U krijgt van de functie een Greeting-object als antwoord (ook weer in JSON-indeling):

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

Hier ziet u een schermopname van de cURL-aanvraag bovenaan het scherm en de lokale Azure-functie onderaan:

Azure-functie die lokaal wordt uitgevoerd

Lokaal fouten opsporen in de functie

In de volgende secties wordt beschreven hoe u fouten in de functie opsport.

Fouten opsporen met Behulp van Intellij IDEA

Open het project in Intellij IDEA en maak vervolgens een configuratie voor het uitvoeren van externe JVM-foutopsporing om te koppelen. Zie Zelfstudie: Externe foutopsporing voor meer informatie.

Een externe JVM-foutopsporingsrunconfiguratie maken

Voer de toepassing uit met de volgende opdracht:

mvn azure-functions:run -DenableDebug

Wanneer de toepassing wordt gestart, ziet u de volgende uitvoer:

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

Start project debugging in Intellij IDEA. U ziet de volgende uitvoer:

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

Markeer de onderbrekingspunten die u wilt opsporen. Nadat een aanvraag is verzonden, wordt de Intellij IDEA in de modus voor het debuggen van gegevens gebruikt.

Fouten opsporen met behulp Visual Studio Code

Open het project in Visual Studio Code en configureer de volgende bestandsinhoud launch.json:

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

Voer de toepassing uit met de volgende opdracht:

mvn azure-functions:run -DenableDebug

Wanneer de toepassing wordt gestart, ziet u de volgende uitvoer:

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

Start projectdebugging in Visual Studio Code en markeer vervolgens de onderbrekingspunten die u wilt opsporen. Nadat een aanvraag is verzonden, Visual Studio code de modus voor debuggen in. Zie Running and debugging Java (Java uitvoeren en debuggen) voor meer informatie.

De functie implementeren in Azure Functions

Nu gaat u de Azure-functie publiceren naar productie. Onthoud dat de eigenschappen , en die u hebt gedefinieerd in uwpom.xmlworden gebruikt <functionAppName> om uw functie te <functionAppRegion><functionResourceGroup> configureren. <functionAppName>

Notitie

De Maven-invoegvoegcode moet worden geverifieerd bij Azure. Als u Azure CLI hebt geïnstalleerd, gebruikt u az login voordat u doorgaat. Zie Verificatie in de opslagplaats azure-maven-plugins voor meer verificatieopties.

Voer Maven uit om uw functie automatisch te implementeren:

mvn azure-functions:deploy

Ga nu naar Azure Portal om de gemaakte te zoeken.

Selecteer de functie:

  • In het overzicht van functies ziet u de URL van de functie.
  • Selecteer het tabblad Platformfuncties om de Logboekstreaming-service te zoeken en selecteer vervolgens deze service om de actieve functie te controleren.

Gebruik nu, net als in de vorige sectie, cURL om toegang te krijgen tot de functie die wordt uitgevoerd, zoals wordt weergegeven in het volgende voorbeeld. Zorg ervoor dat u vervangt your-function-name door de naam van uw echte functie.

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

Als het goed is, krijgt u van de functie een Greeting-object als antwoord (ook weer in JSON-indeling), net als in de vorige sectie:

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

U hebt nu een Spring Cloud Function die wordt uitgevoerd in Azure Functions.

Volgende stappen

Voor meer informatie over Spring en Azure gaat u door naar het documentatiecentrum van Spring op Azure.