Spring Cloud Function en Azure
Este artículo le explica cómo usar Spring Cloud Function para desarrollar una función de Java y publicarla en Azure Functions. Cuando haya terminado, el código de la función se ejecuta en el Plan de consumo en Azure y puede activarse mediante una solicitud HTTP.
Requisitos previos
- Suscripción a Azure. Si no tiene una suscripción a Azure, cree una cuenta gratuita antes de empezar.
Para desarrollar funciones con Java, debe tener instalado lo siguiente:
- Kit para desarrolladores de Java, versión 11
- Apache Maven, versión 3.0 o posterior
- CLI de Azure
- Azure Functions Core Tools versión 4.
Importante
- Debe establecer la variable de entorno
JAVA_HOME
en la ubicación de instalación del JDK para completar esta guía de inicio rápido. - Asegúrese de que la versión de Core Tools sea al menos 4.0.5455.
Qué vamos a crear
Vamos a crear una función clásica "Hola mundo" que se ejecuta en Azure Functions y se configura con Spring Cloud Function.
Esta función recibe un objeto JSON User
, que contiene un nombre de usuario, y devuelve un objeto Greeting
, 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 directamente el ejemplo si quiere ver el trabajo final que se describe en esta guía de inicio rápido.
Creación de un nuevo proyecto de Maven
Vamos a crear un proyecto de Maven vacío y a configurarlo con Spring Cloud Function y Azure Functions.
En una carpeta vacía, cree un nuevo archivo pom.xml y copie y pegue el contenido del proyecto de ejemplo en el archivo pom.xml.
Nota:
Este archivo usa las dependencias de Maven tanto de Spring Boot como de Spring Cloud Function, y configura los complementos de Maven para Spring Boot y Azure Functions.
Deberá personalizar algunas propiedades de 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 se usa.
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.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>
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.
Ahora vamos a crear los objetos User
y Greeting
, que representan nuestro modelo de dominio.
Puede crear objetos más complejos, con más propiedades, si desea personalizar este inicio rápido y hacerlo más interesante para su caso.
Cree una carpetasrc/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 una aplicación de Spring Boot
Esta aplicación administra toda la lógica de negocios y tiene acceso a todo el ecosistema de Spring Boot. Esta funcionalidad ofrece dos ventajas principales en comparación con una función estándar de Azure Functions:
- No depende de las API de Azure Functions, por lo que se puede migrar fácilmente a otros sistemas. Por ejemplo, podría reutilizarse en una aplicación de Spring Boot normal.
- Puede usar todas las anotaciones
@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 de Spring Boot normal:
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 archivo siguiente en la carpeta src/main/java/com/example/hello. Este código contiene un componente de Spring Boot que representa la función que queremos 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 una
java.util.function.Function
. Contiene la lógica de negocios y usa una API de Java estándar para transformar un objeto en otro. - Como tiene la anotación
@Component
, es un bean de Spring y, de manera predeterminada, su nombre es el de la clase pero empezando con minúscula: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 en Azure Functions que crearemos en la sección siguiente.
Creación de la función de Azure
Para aprovechar las ventajas de la API de Azure Functions, vamos a codificar una función de Azure Functions que delega su ejecución en la función de Spring Cloud Function que hemos creado en el paso anterior.
En la carpeta src/main/java/com/example/hello, cree el siguiente archivo de clase de la 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 clase de Java es una función de Azure, con las siguientes características interesantes:
- 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
@FunctionName("hello")
, eshello
. - La clase implementa una función de Azure real, por lo que puede usar la API de Azure Functions completa aquí.
Adición de pruebas unitarias
Este paso es opcional, pero se recomienda validar que la aplicación funciona correctamente.
Cree la carpetasrc/test/java/com/example y agregue las siguientes pruebas de 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 con Maven:
mvn clean test
Ejecución de la función de forma local
Antes de implementar la aplicación en Azure Functions, vamos a probarla de forma local.
Primero debe empaquetar la aplicación en un archivo Jar:
mvn package
Ahora que la aplicación está empaquetada, puede ejecutarla mediante con el complemento azure-functions
de Maven:
mvn azure-functions:run
La función de Azure estará disponible en el host local, a través del puerto 7071. Para probar la función, envíe una solicitud POST con un objeto User
en formato JSON. Por ejemplo, con cURL:
curl -X POST http://localhost:7071/api/hello -d "{\"name\":\"Azure\"}"
La función responderá con un objeto Greeting
, aún 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:
Depuración local de la función
En las secciones siguientes, se explica cómo depurar la función.
Depuración mediante Intellij IDEA
Abra el proyecto en Intellij IDEA y, a continuación, cree la configuración de ejecución Depuración remota de JVM para adjuntarla. Para más información, consulte Tutorial: Depuración remota.
Ejecute la aplicación con el comando siguiente:
mvn azure-functions:run -DenableDebug
Cuando se inicie la aplicación, verá la siguiente salida:
Worker process started and initialized.
Listening for transport dt_socket at address: 5005
Inicie la depuración del proyecto en IntelliJ IDEA. Verá la salida siguiente:
Connected to the target VM, address: 'localhost:5005', transport: 'socket'
Marque los puntos de interrupción que desea depurar. Intellij IDEA entrará 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 contenido siguiente en el archivo launch.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 comando siguiente:
mvn azure-functions:run -DenableDebug
Cuando se inicie la aplicación, verá la siguiente salida:
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. Después de enviar una solicitud, Visual Studio Code entrará en modo de depuración. 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 pom.xml se usarán para configurar la función.
Nota:
El complemento de Maven se debe autenticar en Azure. Si ha instalado la CLI de Azure, use az login
antes de continuar.
Para más opciones de autenticación, consulte Autenticación en el repositorio azure-maven-plugins.
Ejecute Maven para implementar la función automáticamente:
mvn azure-functions:deploy
Ahora, vaya a Azure Portal 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, igual que 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 real de la función.
curl https://your-function-name.azurewebsites.net/api/hello -d "{\"name\":\"Azure\"}"
Igual que en la sección anterior, la función responderá con un objeto Greeting
, aún en formato JSON:
{
"message": "Hello, Azure!\n"
}
Enhorabuena, ya tiene una función de Spring Cloud Function en ejecución en Azure Functions. Para obtener más información y ejemplos de funciones de Spring Cloud, consulte los siguientes recursos:
- Blog de la función de Spring Cloud
- Documentos de referencia de funciones de Spring Cloud
- Ejemplos de funciones de Spring Cloud
Pasos siguientes
Para más información acerca de Spring y Azure, vaya al centro de documentación de Azure.