Java 部署选项

您可以通过以下两种方式部署 Java 函数:

从源代码部署

函数的源代码必须位于 Maven 项目的常规位置 (src/main/java)。本文档中的示例函数直接位于 src/main/java 中,.java 源文件中没有软件包声明。对于非常重要的代码,则可能要引入软件包。如果该软件包为 com.example,则层次结构如下所示:

myfunction/
├─ pom.xml
├─ src
    ├─main
        ├─ java
            ├─ com
                ├─ example
                    ├─ MyFunction.java

使用以下命令部署 HTTP 函数:

gcloud functions deploy $name --trigger-http \
    --entry-point $function_class --runtime java17

其中:

  • $name 是任意的描述性名称,是部署后的函数名称。$name 只能包含字母、数字、下划线和连字符。
  • $function_class 是类的完全限定名称(例如 com.example.MyFunction,如果您不使用软件包,则为 MyFunction)。

使用以下命令部署事件驱动型函数:

gcloud functions deploy $name --no-gen2 --entry-point $function_class \
    --trigger-resource $resource_name \
    --trigger-event $event_name \
    --runtime java17

其中:

  • $name 是任意的描述性名称,是部署后的函数名称。
  • $function_class 是类的完全限定名称(例如 com.example.MyFunction,如果您不使用软件包,则为 MyFunction)。
  • $resource_name$event_name 特定于触发函数的事件。例如,受支持的资源和事件可以是 Google Cloud Pub/SubGoogle Cloud Storage

从源代码部署函数时,Google Cloud CLI 会将源目录(以及其中的所有内容)上传到 Google Cloud 以进行构建。为避免发送不必要的文件,您可以使用 .gcloudignore 文件。修改 .gcloudignore 文件以忽略 .gittarget/ 等常用目录。例如,.gcloudignore 文件可能包含以下内容:

.git
target
build
.idea

从 JAR 部署

您可以部署包含该函数的预构建 JAR。如果您需要部署使用来自私有工件代码库(从源代码构建时,无法从 Google Cloud 的构建流水线访问该代码库)的依赖项的函数,这将非常有用。JAR 可以是包含函数类及其所有依赖项类的超级 JAR,也可以是在 META-INF/MANIFEST.MF 文件中具有依赖项 JAR 的 Class-Path 条目的精简 JAR。

构建和部署超级 JAR

超级 JAR 文件包含函数类及其所有依赖项。您可以使用 Maven 和 Gradle 构建超级 JAR。如需部署超级 JAR,它必须是自己的目录中唯一的 JAR 文件,例如:

my-function-deployment/
 ├─ my-function-with-all-dependencies.jar

您可以将文件复制到此目录结构,也可以使用 Maven 和 Gradle 插件生成正确的部署目录。

Maven

使用 Maven Shade 插件构建超级 JAR。使用 Shade 插件配置 pom.xml

<?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>

构建 Uber JAR:

mvn package

然后使用以下命令进行部署:

gcloud functions deploy jar-example \
    --entry-point=Example \
    --runtime=java17 \
    --trigger-http \
    --source=target/deployment

Gradle

使用 Gradle 的 Shadow 插件。在 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()
}
...

现在,您可以使用 shadowJar 命令运行 Gradle:

gradle shadowJar

然后使用以下命令进行部署:

gcloud functions deploy jar-example \
   --entry-point=Example \
   --runtime=java17 \
   --trigger-http \
   --source=build/libs

构建和部署使用外部依赖项的精简 JAR

您可以构建和部署一个精简 JAR 文件,而不是超级 JAR。精简 JAR 文件仅包含函数类,不包含嵌入到同一 JAR 文件中的依赖项。由于部署仍需要依赖项,因此您需要按如下所示进行设置:

  • 依赖项必须位于要部署的 JAR 的相对子目录中。
  • JAR 文件必须具有一个 META-INF/MANIFEST.MF 文件,其中包含的 Class-Path 属性的值列出所需的依赖项路径。

例如,您的 JAR 文件 my-function.jar 的 META-INF/MANIFEST.MF 文件在 libs/ 目录中有两个依赖项(以空格分隔的相对路径的列表):

Manifest-Version: 1.0
Class-Path: libs/dep1.jar libs/dep2.jar

然后,您的部署目录应包含主函数 JAR 文件,以及包含函数依赖的两个依赖项的子目录:

function-deployment/
├─ my-function.jar
├─ libs
       ├─ dep1.jar
       ├─ dep2.jar

您可以使用 Maven 和 Gradle 构建精简 JAR:

Maven

使用 Maven JAR 插件自动为 MANIFEST.MF 配置依赖项路径,然后使用 Maven Dependency 插件复制依赖项。

<?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>

构建精简 JAR:

mvn package

然后使用以下命令进行部署:

gcloud functions deploy jar-example \
    --entry-point=Example \
    --runtime=java17 \
    --trigger-http \
    --source=target/deployment

Gradle

更新 build.gradle 项目文件以添加新的任务以提取依赖项:

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