Definir el controlador de las funciones de Lambda en Java
El controlador de la función de Lambda es el método del código de la función que procesa eventos. Cuando se invoca una función, Lambda ejecuta el método del controlador. La función se ejecuta hasta que el controlador devuelve una respuesta, se cierra o se agota el tiempo de espera.
El repositorio de GitHub para esta guía contiene aplicaciones de ejemplo fáciles de implementar en las que se muestran diferentes tipos de controladores. Para obtener más información, consulte el final de este tema.
Secciones
Ejemplo de controlador: tiempos de ejecución de Java 17
En el siguiente ejemplo de Java 17, una clase llamada HandlerIntegerJava17
define un método de controlador denominado handleRequest
. El método del controlador incluye las siguientes entradas:
-
Un
IntegerRecord
, que es un registrode Java personalizado que representa los datos de eventos. En este ejemplo, definimos IntegerRecord
de la siguiente manera:record IntegerRecord(int x, int y, String message) { }
-
Un objeto de contexto, que proporciona métodos y propiedades que brindan información sobre la invocación, la función y el entorno de ejecución.
Supongamos que queremos escribir una función que registre el message
de la entrada IntegerRecord
y devuelva la suma de x
y y
. El siguiente es el código de la función:
ejemplo HandlerIntegerJava17.java
package example; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; import com.amazonaws.services.lambda.runtime.RequestHandler; // Handler value: example.HandlerInteger public class HandlerIntegerJava17 implements RequestHandler<IntegerRecord, Integer>{ @Override /* * Takes in an InputRecord, which contains two integers and a String. * Logs the String, then returns the sum of the two Integers. */ public Integer handleRequest(IntegerRecord event, Context context) { LambdaLogger logger = context.getLogger(); logger.log("String found: " + event.message()); return event.x() + event.y(); } } record IntegerRecord(int x, int y, String message) { }
Usted especifica qué método desea que invoque Lambda al establecer el parámetro del controlador en la configuración de su función. Puede expresar el controlador en los siguientes formatos:
-
: formato completo. Por ejemplo:package
.Class
::method
example.Handler::handleRequest
. -
: formato abreviado para las clases que implementan una interfaz de controlador. Por ejemplo:package
.Class
example.Handler
.
Cuando Lambda invoca su controlador, el tiempo de ejecución de Lambda recibe un evento como una cadena con formato JSON y lo convierte en un objeto. En el ejemplo anterior, un evento de ejemplo podría verse así:
ejemplo evento.json
{ "x": 1, "y": 20, "message": "Hello World!" }
Puede guardar este archivo y probar la función de forma local con el siguiente comando de AWS Command Line Interface (CLI):
aws lambda invoke --function-name
function_name
--payload file://event.json out.json
Ejemplo de controlador: tiempos de ejecución de Java 11 e inferiores
Lambda solo admite registros de Java 17 y tiempos de ejecución posteriores. En todos los entornos de ejecución de Java, puede usar una clase para representar los datos de eventos. En el siguiente ejemplo, se toma una lista de números enteros y un objeto de contexto como entrada y se devuelve la suma de todos los números enteros de la lista.
ejemplo Handler.java
En el siguiente ejemplo, la clase Handler
define un método de controlador llamado handleRequest
. El método handler toma un evento y un objeto contextual como entrada y devuelve una cadena.
ejemplo HandlerList.java
package example; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; import com.amazonaws.services.lambda.runtime.RequestHandler; import java.util.List; // Handler value: example.HandlerList public class HandlerList implements RequestHandler<List<Integer>, Integer>{ @Override /* * Takes a list of Integers and returns its sum. */ public Integer handleRequest(List<Integer> event, Context context) { LambdaLogger logger = context.getLogger(); logger.log("EVENT TYPE: " + event.getClass().toString()); return event.stream().mapToInt(Integer::intValue).sum(); } }
Para ver más ejemplos, consulte Ejemplo de código de controlador.
Código de inicialización
Lambda ejecuta su código estático y el constructor de clases durante la fase de inicialización antes de invocar la función por primera vez. Los recursos que se crean durante la inicialización permanecen en la memoria entre las invocaciones y el controlador puede reutilizarlos miles de veces. Por lo tanto, puede agregar un código de inicialización
En el siguiente ejemplo, el código de inicialización del cliente está fuera del método del controlador principal. El tiempo de ejecución inicializa el cliente antes de que la función publique su primer evento. Los eventos posteriores son mucho más rápidos porque Lambda no necesita volver a inicializar el cliente.
ejemplo Handler.java
package example; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.LambdaLogger; import com.amazonaws.services.lambda.runtime.RequestHandler; import java.util.Map; import software.amazon.awssdk.services.lambda.LambdaClient; import software.amazon.awssdk.services.lambda.model.GetAccountSettingsResponse; import software.amazon.awssdk.services.lambda.model.LambdaException; // Handler value: example.Handler public class Handler implements RequestHandler<Map<String,String>, String> { private static final LambdaClient lambdaClient = LambdaClient.builder().build(); @Override public String handleRequest(Map<String,String> event, Context context) { LambdaLogger logger = context.getLogger(); logger.log("Handler invoked"); GetAccountSettingsResponse response = null; try { response = lambdaClient.getAccountSettings(); } catch(LambdaException e) { logger.log(e.getMessage()); } return response != null ? "Total code size for your account is " + response.accountLimit().totalCodeSize() + " bytes" : "Error"; } }
Elección de los tipos de entrada y salida
Especifique el tipo de objeto al que se asigna el evento en la firma del método del controlador. En el ejemplo anterior, el entorno de ejecución de Java deserializa el evento en un tipo que implementa la interfaz Map<String,String>
. Los mapas de cadena a cadena funcionan para eventos planos como los siguientes:
ejemplo Event.json : datos del tiempo
{ "temperatureK": 281, "windKmh": -3, "humidityPct": 0.55, "pressureHPa": 1020 }
Sin embargo, el valor de cada campo debe ser una cadena o un número. Si el evento contiene un campo que tiene un objeto como valor, el entorno de ejecución no puede deserializarlo y devuelve un error.
Elija un tipo de entrada que funcione con los datos del evento que procesa la función. Puede utilizar un tipo básico, un tipo genérico o un tipo bien definido.
Tipos de entrada
-
Integer
,Long
,Double
, etc.: - El evento es un número sin formato adicional; por ejemplo,3.5
. El entorno de ejecución convierte el valor en un objeto del tipo especificado. -
String
: el evento es una cadena JSON, incluidas las comillas; por ejemplo,"My string."
. El tiempo de ejecución convierte el valor (sin comillas) en un objetoString
. -
,Type
Map<String,
, etc.: - El evento es un objeto JSON. El entorno de ejecución lo deserializa en un objeto del tipo especificado o una interfaz.Type
> -
List<Integer>
,List<String>
,List<Object>
, etc.: - El evento es una matriz JSON. El entorno de ejecución lo deserializa en un objeto del tipo especificado o una interfaz. -
InputStream
: el evento es cualquier tipo JSON. El entorno de ejecución pasa una secuencia de bytes del documento al controlador sin modificaciones. Usted deserializa la entrada y escribe la salida en una secuencia de salida. -
Tipo de biblioteca: en el caso de los eventos enviados por los servicios de AWS, utilice los tipos de la biblioteca aws-lambda-java-events.
Si define su propio tipo de entrada, debería ser un objeto Java estándar (POJO) mutable y deserializable, con un constructor predeterminado y unas propiedades predeterminadas para cada campo del evento. Las claves del evento que no se asignan a una propiedad, así como las propiedades que no están incluidas en el evento, se eliminan sin errores.
El tipo de salida puede ser un objeto o void
. El entorno de ejecución serializa los valores devueltos en texto. Si la salida es un objeto con campos, el entorno de ejecución lo serializa en un documento JSON. Si se trata de un tipo que encapsula un valor primitivo, el tiempo de ejecución devuelve una representación de texto de ese valor.
Interfaces de controlador
La biblioteca aws-lambda-java-core
La interfaz RequestHandler
es un tipo genérico que toma dos parámetros: el tipo de entrada y el tipo de salida. Los dos tipos deben ser objetos. Cuando se utiliza esta interfaz, el entorno de ejecución de Java deserializa el evento en un objeto con el tipo de entrada y serializa la salida en texto. Utilice esta interfaz si la serialización integrada funcione con los tipos de entrada y salida.
ejemplo Handler.java : interfaz del controlador
// Handler value: example.Handler public class Handler implements RequestHandler<Map<String,String>, String>{ @Override
public String handleRequest(Map<String,String> event, Context context)
Para usar su propia serialización, implemente la interfaz RequestStreamHandler
. Con esta interfaz, Lambda pasa al controlador un flujo de entrada y otrp flujo de salida. El controlador lee los bytes de la secuencia de entrada, escribe en la secuencia de salida y devuelve void.
En el ejemplo siguiente se utilizan unos tipos de lectores y escritores almacenados en el búfer para trabajar con las secuencias de entrada y salida.
ejemplo HandlerStream.java
import com.amazonaws.services.lambda.runtime.Context import com.amazonaws.services.lambda.runtime.LambdaLogger import com.amazonaws.services.lambda.runtime.RequestStreamHandler ... // Handler value: example.HandlerStream
public class HandlerStream implements RequestStreamHandler
{ @Override /* * Takes an InputStream and an OutputStream. Reads from the InputStream, * and copies all characters to the OutputStream. */public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException
{ LambdaLogger logger = context.getLogger(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("US-ASCII"))); PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream, Charset.forName("US-ASCII")))); int nextChar; try { while ((nextChar = reader.read()) != -1) { outputStream.write(nextChar); } } catch (IOException e) { e.printStackTrace(); } finally { reader.close(); String finalString = writer.toString(); logger.log("Final string result: " + finalString); writer.close(); } } }
Ejemplo de código del controlador
El repositorio de GitHub para esta guía contiene aplicaciones de ejemplo en las que se muestra el uso de diferentes tipos de controladores e interfaces. Cada una de las aplicaciones de ejemplo contiene scripts para facilitar la implementación y la limpieza, una plantilla de AWS SAM y recursos de soporte.
Aplicaciones de Lambda de ejemplo en Java
-
java17-examples
: una función de Java que demuestra cómo utilizar un registro de Java para representar un objeto de datos de eventos de entrada. -
java-basic
: una colección de funciones de Java mínimas con pruebas unitarias y configuración de registro variable. -
java-events
: una colección de funciones Java que contiene un código básico sobre cómo gestionar los eventos de varios servicios, como Amazon API Gateway, Amazon SQS y Amazon Kinesis. Estas funciones utilizan la última versión de la biblioteca aws-lambda-java-events (3.0.0 y más recientes). Estos ejemplos no requieren utilizar AWS SDK como una dependencia. -
s3-java
: una función de Java que procesa los eventos de notificación de Amazon S3 y utiliza Java Class Library (JCL) para crear miniaturas de los archivos de imagen cargados. -
Uso de API Gateway para invocar una función de Lambda: una función Java que escanea una tabla de Amazon DynamoDB que contiene información sobre los empleados. Luego, utiliza Amazon Simple Notification Service para enviar un mensaje de texto a los empleados que celebran sus aniversarios laborales. En este ejemplo, se utiliza API Gateway para invocar la función.
Las aplicaciones java-events
y s3-java
toman un evento de un servicio de AWS como entrada y devuelven una cadena. La aplicación java-basic
contiene varios tipos de controladores:
-
Handler.java
: toma Map<String,String>
como entrada. -
HandlerInteger.java
: toma Integer
como entrada. -
HandlerList.java
: toma List<Integer>
como entrada. -
HandlerStream.java
: toma InputStream
yOutputStream
como entrada. -
HandlerString.java
: toma String
como entrada. -
HandlerWeatherData.java
: toma un tipo personalizado como entrada.
Para probar diferentes tipos de controlador, solo tiene que cambiar el valor del controlador en la plantilla de AWS SAM. Para obtener instrucciones detalladas, consulte el archivo readme (léame) de la aplicación de ejemplo.