Opciones de implementación de Java
Tienes dos opciones para implementar una función de Java:
- Desde la fuente. Para ver un análisis general de este tema, consulta Cómo implementar una Cloud Function.
- Desde un archivo JAR ya empaquetado.
Implementa desde la fuente
El código fuente de la función debe estar en la ubicación habitual para proyectos de Maven (src/main/java
). Las funciones de muestra de este documento están directamente en src/main/java
, sin declaración de paquete en el archivo de origen .java
. En el caso de código no trivial, se recomienda ingresar un paquete. Si ese paquete es com.example
, tu jerarquía debería verse de la siguiente manera:
myfunction/ ├─ pom.xml ├─ src ├─main ├─ java ├─ com ├─ example ├─ MyFunction.java
Usa el siguiente comando para implementar una función de HTTP:
gcloud functions deploy $name --trigger-http \
--entry-point $function_class --runtime java17
Aquí:
$name
es un nombre arbitrario y descriptivo que será el nombre de la función una vez implementada.$name
solo puede contener letras, números, guiones bajos y guiones.$function_class
es el nombre completamente calificado de tu clase (por ejemplo,com.example.MyFunction
o soloMyFunction
si no usas un paquete).
Usa el siguiente comando para implementar una función basada en eventos:
gcloud functions deploy $name --no-gen2 --entry-point $function_class \
--trigger-resource $resource_name \
--trigger-event $event_name \
--runtime java17
Aquí:
$name
es un nombre arbitrario y descriptivo que será el nombre de la función una vez implementada.$function_class
es el nombre completamente calificado de tu clase (por ejemplo,com.example.MyFunction
o soloMyFunction
si no usas un paquete).$resource_name
y$event_name
son específicos de los eventos que activan la función. Los ejemplos de recursos y eventos compatibles son Google Cloud Pub/Sub y Google Cloud Storage.
Cuando implementas una función desde la fuente, Google Cloud CLI sube el directorio del código fuente (y todo su contenido) a Google Cloud para su compilación. Para evitar enviar archivos innecesarios, puedes usar el archivo .gcloudignore
. Edita el archivo .gcloudignore
para ignorar los directorios comunes, como .git
y target/
. Por ejemplo, un archivo .gcloudignore
puede contener lo siguiente:
.git
target
build
.idea
Implementa desde un archivo JAR
Puedes implementar un JAR ya compilado que contenga la función. Esto es útil, en especial, si necesitas implementar una función que usa dependencias de un repositorio de artefactos privados al que no se puede acceder desde la canalización de compilación de Google Cloud cuando compilas desde la fuente. El JAR puede ser un uber JAR que contenga la clase de función y todas sus clases de dependencias o un JAR delgado que tenga entradas Class-Path
para los archivos JAR de dependencias en el archivo META-INF/MANIFEST.MF
.
Compila e implementa un archivo uber JAR
Un uber JAR es un archivo JAR que contiene las clases de función y todas sus dependencias. Puedes compilar un archivo uber JAR con Maven y Gradle. Para implementar un uber JAR, este debe ser el único archivo JAR en su propio directorio, por ejemplo:
my-function-deployment/ ├─ my-function-with-all-dependencies.jar
Puedes copiar el archivo en esta estructura de directorio o usar los complementos de Maven y Gradle para generar el directorio de implementación correcto.
Maven
Usa el complemento Maven Shade para compilar un archivo uber JAR. Configura el archivo pom.xml
con el complemento Shade:
<?xml version="1.0" encoding="UTF-8"?>
<project ...>
...
<build>
...
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<outputFile>${project.build.directory}/deployment/${build.finalName}.jar</outputFile>
<transformers>
<!-- This may be needed if you need to shade a signed JAR -->
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
<resource>.SF</resource>
<resource>.DSA</resource>
<resource>.RSA</resource>
</transformer>
<!-- This is needed if you have dependencies that use Service Loader. Most Google Cloud client libraries does. -->
<transformer implementation=
"org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Compila el archivo uber JAR:
mvn package
Luego, realiza una implementación con el siguiente comando:
gcloud functions deploy jar-example \
--entry-point=Example \
--runtime=java17 \
--trigger-http \
--source=target/deployment
Gradle
Usa el complemento Shadow para Gradle. Configura el complemento en el archivo build.gradle
:
buildscript { repositories { jcenter() } dependencies { ... classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0" } } plugins { id 'java' ... } sourceCompatibility = '17.0' targetCompatibility = '17.0' apply plugin: 'com.github.johnrengelman.shadow' shadowJar { mergeServiceFiles() } ...
Ahora puedes ejecutar Gradle con el comando shadowJar
:
gradle shadowJar
Luego, realiza una implementación con el siguiente comando:
gcloud functions deploy jar-example \
--entry-point=Example \
--runtime=java17 \
--trigger-http \
--source=build/libs
Compila e implementa un archivo JAR delgado con dependencias externas
Puedes compilar e implementar un archivo JAR delgado en lugar de un uber JAR. Un JAR delgado es un archivo JAR que contiene solo las clases de función sin las dependencias incorporadas en el mismo archivo JAR. Debido a que las dependencias aún son necesarias para la implementación, debes configurar lo siguiente:
- Las dependencias deben estar en un subdirectorio relacionado con el archivo JAR para que se implemente.
- El JAR debe tener un archivo
META-INF/MANIFEST.MF
que incluya un atributoClass-Path
cuyo valor enumere las rutas de dependencias requeridas.
Por ejemplo, tu archivo JAR my-function.jar tiene un archivo META-INF/MANIFEST.MF
con 2 dependencias en el directorio libs/
(una lista separada por espacios de las rutas relativas):
Manifest-Version: 1.0
Class-Path: libs/dep1.jar libs/dep2.jar
El directorio de implementación debe contener el archivo JAR de la función principal y un subdirectorio con las dos dependencias de las que depende la función:
function-deployment/ ├─ my-function.jar ├─ libs ├─ dep1.jar ├─ dep2.jar
Puedes compilar un JAR delgado con Maven y Gradle:
Maven
Usa el complemento JAR de Maven a fin de configurar de forma automática MANIFEST.MF
con las rutas a las dependencias y, luego, usa el complemento Maven Dependency para copiar las dependencias.
<?xml version="1.0" encoding="UTF-8"?>
<project ...>
...
<build>
...
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>libs/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<overWriteReleases>false</overWriteReleases>
<includeScope>runtime</includeScope>
<outputDirectory>${project.build.directory}/libs</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals><goal>copy-resources</goal></goals>
<configuration>
<outputDirectory>${project.build.directory}/deployment</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}</directory>
<includes>
<include>${build.finalName}.jar</include>
<include>libs/**</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Compila el JAR delgado:
mvn package
Luego, realiza una implementación con el siguiente comando:
gcloud functions deploy jar-example \
--entry-point=Example \
--runtime=java17 \
--trigger-http \
--source=target/deployment
Gradle
Actualiza el archivo del proyecto build.gradle
para agregar una tarea nueva a fin de recuperar las dependencias:
dependencies { // API available at compilation only, but provided at runtime compileOnly 'com.google.cloud.functions:functions-framework-api:1.0.1' // dependencies needed by the function // ... } jar { manifest { attributes( "Class-Path": provider { configurations.runtimeClasspath .collect { "libs/${it.name}" }.join(' ') } ) } } task prepareDeployment(type: Copy) { into("${buildDir}/deployment") into('.') { from jar } into('libs') { from configurations.runtimeClasspath } }