Spring Cloud Function en Azure

En este artículo se muestra cómo compilar, probar, depurar e implementar una función de Java Spring Cloud en Azure Functions. Cuando haya terminado, la función se ejecuta en el Plan de consumo y responde a las solicitudes HTTP.

Prerrequisitos

  • Una suscripción de Azure. Si no tiene una suscripción de Azure , cree una cuenta gratuita de antes de empezar.

Para desarrollar funciones mediante Java, instale las siguientes herramientas:

Importante

Establezca la JAVA_HOME variable de entorno en la ubicación de instalación del JDK para completar este inicio rápido.

Asegúrese de que la versión de las herramientas principales sea al menos 4.0.5455.

Lo que vas a crear

Va a compilar una función clásica "Hello, World" que se ejecuta en Azure Functions y está configurada con Spring Cloud Function.

La función recibe un User objeto JSON, que contiene un nombre de usuario, y devuelve un Greeting objeto , que contiene el mensaje de bienvenida para ese usuario.

El proyecto está disponible en el ejemplo de Spring Cloud Function en Azure del repositorio azure-function-java-worker en GitHub. Puede usar ese ejemplo directamente si desea ver el trabajo final descrito en este inicio rápido.

Creación de un nuevo proyecto de Maven

Cree un proyecto de Maven vacío y configúrelo con Spring Cloud Function y Azure Functions.

En una carpeta vacía, cree un nuevo archivo pom.xml . A continuación, copie el contenido del archivo pom.xml del proyecto de ejemplo.

Nota

Este archivo usa dependencias de Maven desde Spring Boot y Spring Cloud Function. También configura los complementos de Spring Boot y Azure Functions Maven.

Personalice algunas propiedades para la aplicación:

  • <functionAppName>es el nombre de la función de Azure.
  • <functionAppRegion>es el nombre de la región de Azure donde se implementa la función.
  • <functionResourceGroup>es el nombre del grupo de recursos de Azure que está usando.

Cambie esas propiedades directamente cerca de la parte superior del archivo pom.xml, como se muestra en el ejemplo siguiente:

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

Creación de archivos de configuración de Azure

Cree una carpeta src/main/resources y agregue los siguientes archivos de configuración de Azure Functions.

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

Creación de objetos de dominio

Azure Functions puede recibir y enviar objetos en formato JSON. Cree los objetos User y Greeting que representen su modelo de dominio. Puede crear objetos más complejos con más propiedades si desea personalizar este inicio rápido.

Cree una carpeta src/main/java/com/example/model y agregue los dos archivos siguientes:

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

Creación de la aplicación Spring Boot

Esta aplicación administra toda la lógica de negocios y tiene acceso al ecosistema completo de Spring Boot. Esta funcionalidad ofrece dos ventajas principales sobre una función estándar de Azure:

  • No se basa en las API de Azure Functions, por lo que puede migrarla fácilmente a otros sistemas. Por ejemplo, puede reutilizarlo en una aplicación de Spring Boot normal.
  • Puede usar todas las anotaciones de @Enable de Spring Boot para agregar nuevas características.

En la carpeta src/main/java/com/example, cree el siguiente archivo, que es una aplicación normal de 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);
    }
}

Ahora cree el siguiente archivo en la carpeta src/main/java/com/example/hello. Este código contiene un componente de Spring Boot que representa la función que desea ejecutar:

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 función Hello es bastante específica:

  • Es un java.util.function.Function. Contiene la lógica de negocios y usa una API de Java estándar para transformar un objeto en otro.
  • Al tener la anotación @Component, es un bean de Spring. De forma predeterminada, su nombre es el mismo que la clase , pero comienza con un carácter en minúsculas: hello. Seguir esta convención de nomenclatura es importante si desea crear otras funciones en la aplicación. El nombre debe coincidir con el nombre de Azure Functions que cree en la sección siguiente.

Creación de la función de Azure

Para usar la API de Azure Functions completa, cree una función de Azure que delegue su ejecución a la función de Spring Cloud que creó en el paso anterior.

En la carpeta src/main/java/com/example/hello, cree el siguiente archivo de clase de función de Azure:

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

Esta Java clase es una función Azure con las siguientes características:

  • La clase tiene la anotación @Component, por lo que es un Bean de Spring.
  • El nombre de la función, tal como se define en la anotación de @FunctionName("hello"), es hello.
  • La clase implementa una función real de Azure, por lo que puede usar la API completa de Azure Functions aquí.

Agregar pruebas unitarias

Este paso es opcional, pero se recomienda validar que la aplicación funciona correctamente.

Cree una carpeta src/test/java/com/example y agregue las siguientes pruebas JUnit:

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

Ahora puede probar la función de Azure mediante Maven:

mvn clean test

Ejecución local de la función

Antes de implementar la aplicación en Azure Function, pruóbela localmente.

En primer lugar, empaquete la aplicación en un archivo JAR:

mvn package

Ahora que la aplicación está empaquetada, ejecútelo mediante el azure-functions complemento Maven:

mvn azure-functions:run

La función Azure ahora está disponible en el host local, mediante el puerto 7071. Pruebe la función mediante el envío de una solicitud POST, con un User objeto en formato JSON. Por ejemplo, use cURL:

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

La función responde con un Greeting objeto, en formato JSON:

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

Esta es una captura de pantalla de la solicitud cURL en la parte superior de la pantalla y la función local de Azure en la parte inferior:

función de Azure que se ejecuta localmente

Depuración local de la función

Las siguientes secciones describen cómo depurar la función.

Depuración mediante Intellij IDEA

Abra el proyecto en IntelliJ IDEA y, a continuación, cree una configuración de ejecución Remote JVM Debug para conectarse. Para más información, consulte Tutorial: Depuración remota.

Creación de una configuración de ejecución de depuración remota de JVM

Ejecute la aplicación con el siguiente comando:

mvn azure-functions:run -DenableDebug

Cuando se inicia la aplicación, verá la salida siguiente:

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

Comience a depurar el proyecto en IntelliJ IDEA. Verá la siguiente salida:

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

Marque los puntos de interrupción que desea depurar. IntelliJ IDEA entra en modo de depuración después de enviar una solicitud.

Depuración mediante Visual Studio Code

Abra el proyecto en Visual Studio Code y, a continuación, configure el siguiente contenido de archivolaunch.json:

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

Ejecute la aplicación con el siguiente comando:

mvn azure-functions:run -DenableDebug

Cuando se inicia la aplicación, verá la salida siguiente:

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

Inicie la depuración del proyecto en Visual Studio Code y, a continuación, marque los puntos de interrupción que desea depurar. Visual Studio Code entra en modo de depuración después de enviar una solicitud. Para más información, consulte Ejecución y depuración en Java.

Implementación de la función en Azure Functions

Ahora, va a publicar la función de Azure en el entorno de producción. Recuerde que las propiedades <functionAppName>, <functionAppRegion>y <functionResourceGroup> que ha definido en el archivo de pom.xml se usan para configurar la función.

Nota

El complemento maven debe autenticarse con Azure. Si tiene instalada la CLI de Azure, use az login antes de continuar.

Para obtener más opciones de autenticación, consulte Autenticación en el azure-maven-plugins repositorio.

Ejecute Maven para implementar la función automáticamente:

mvn azure-functions:deploy

Ahora, vaya al portal de Azure para buscar el Function App que se ha creado.

Seleccione la función :

  • En la información general de la función, anote la dirección URL de la función.
  • Para comprobar la función en ejecución, seleccione Streaming de registro en el menú de navegación.

Ahora, como hizo en la sección anterior, use cURL para acceder a la función en ejecución, como se muestra en el ejemplo siguiente. Asegúrese de reemplazar your-function-name por el nombre de la función real.

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

Al igual que en la sección anterior, la función debe responderle con un objeto Greeting, todavía en formato JSON:

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

Enhorabuena, tiene una función de Spring Cloud que se ejecuta en Azure Functions. Para obtener más información y ejemplos de funciones de Spring Cloud, consulte los siguientes recursos:

Pasos siguientes

Para más información sobre Spring y Azure, continúe con el Centro de documentación de Spring en Azure.