Funções do Azure guia para programadores Java

Este guia contém informações detalhadas para o ajudar a desenvolver Funções do Azure com Java.

Enquanto programador java, se não estiver familiarizado com Funções do Azure, considere primeiro ler um dos seguintes artigos:

Introdução Conceitos Cenários/exemplos

Noções básicas da função Java

Uma função Java é um public método, decorado com a anotação @FunctionName. Este método define a entrada de uma função Java e tem de ser exclusivo num pacote específico. O pacote pode ter várias classes com vários métodos públicos anotados com @FunctionName. Um único pacote é implementado numa aplicação de funções no Azure. No Azure, a aplicação de funções fornece o contexto de implementação, execução e gestão para as suas funções Java individuais.

Modelo de programação

Os conceitos de acionadores e enlaces são fundamentais para Funções do Azure. Os acionadores iniciam a execução do código. Os enlaces dão-lhe uma forma de transmitir dados para e devolver dados de uma função, sem ter de escrever código de acesso a dados personalizado.

Criar funções Java

Para facilitar a criação de funções Java, existem ferramentas e arquétipos baseados no Maven que utilizam modelos Java predefinidos para o ajudar a criar projetos com um acionador de função específico.

Ferramentas baseadas no Maven

Os seguintes ambientes de programador têm ferramentas Funções do Azure que lhe permitem criar projetos de funções Java:

Estes artigos mostram-lhe como criar as suas primeiras funções com o seu IDE de eleição.

Estrutura do projeto

Se preferir o desenvolvimento da linha de comandos do Terminal, a forma mais simples de estruturar projetos de funções baseados em Java é utilizar Apache Maven arquétipos. O arquétipo do Java Maven para Funções do Azure é publicado no seguinte groupId:artifactId: com.microsoft.azure:azure-functions-archetype.

O seguinte comando gera um novo projeto de função Java com este arquétipo:

mvn archetype:generate \
    -DarchetypeGroupId=com.microsoft.azure \
    -DarchetypeArtifactId=azure-functions-archetype

Para começar a utilizar este arquétipo, veja o início rápido de Java.

Estrutura de pastas

Eis a estrutura de pastas de um projeto Java Funções do Azure:

FunctionsProject
 | - src
 | | - main
 | | | - java
 | | | | - FunctionApp
 | | | | | - MyFirstFunction.java
 | | | | | - MySecondFunction.java
 | - target
 | | - azure-functions
 | | | - FunctionApp
 | | | | - FunctionApp.jar
 | | | | - host.json
 | | | | - MyFirstFunction
 | | | | | - function.json
 | | | | - MySecondFunction
 | | | | | - function.json
 | | | | - bin
 | | | | - lib
 | - pom.xml

Pode utilizar um ficheiro host.json partilhado para configurar a aplicação de funções. Cada função tem o seu próprio ficheiro de código (.java) e o ficheiro de configuração de enlace (function.json).

Pode colocar mais do que uma função num projeto. Evite colocar as suas funções em jars separados. O FunctionApp no diretório de destino é o que é implementado na sua aplicação de funções no Azure.

Acionadores e anotações

As funções são invocadas por um acionador, como um pedido HTTP, um temporizador ou uma atualização dos dados. A função tem de processar esse acionador e quaisquer outras entradas para produzir uma ou mais saídas.

Utilize as anotações Java incluídas no pacote com.microsoft.azure.functions.annotation.* para vincular entradas e saídas aos seus métodos. Para obter mais informações, veja os documentos de referência de Java.

Importante

Tem de configurar uma conta de Armazenamento do Azure no local.settings.json para executar o armazenamento de Blobs do Azure, o armazenamento de Filas do Azure ou os acionadores de armazenamento de Tabelas do Azure localmente.

Exemplo:

public class Function {
    public String echo(@HttpTrigger(name = "req", 
      methods = {HttpMethod.POST},  authLevel = AuthorizationLevel.ANONYMOUS) 
        String req, ExecutionContext context) {
        return String.format(req);
    }
}

Eis o que é gerado correspondente function.json pelo azure-functions-maven-plugin:

{
  "scriptFile": "azure-functions-example.jar",
  "entryPoint": "com.example.Function.echo",
  "bindings": [
    {
      "type": "httpTrigger",
      "name": "req",
      "direction": "in",
      "authLevel": "anonymous",
      "methods": [ "GET","POST" ]
    },
    {
      "type": "http",
      "name": "$return",
      "direction": "out"
    }
  ]
}

Versões java

A versão do Java na qual a sua aplicação é executada no Azure é especificada no ficheiro pom.xml. O arquétipo maven gera atualmente uma pom.xml para Java 8, que pode alterar antes de publicar. A versão Java no pom.xml deve corresponder à versão na qual desenvolveu e testou localmente a sua aplicação.

Versões suportadas

A tabela seguinte mostra as versões Java suportadas atuais para cada versão principal do runtime de Funções, por sistema operativo:

Versão das funções Versões java (Windows) Versões java (Linux)
4.x 17
11
8
17
11
8
3.x 11
8
11
8
2.x 8 n/a

A menos que especifique uma versão Java para a sua implementação, o arquétipo maven é predefinido para Java 8 durante a implementação no Azure.

Especificar a versão de implementação

Pode controlar a versão de Java direcionada pelo arquétipo maven com o -DjavaVersion parâmetro . O valor deste parâmetro pode ser ou 811.

O arquétipo maven gera uma pom.xml que visa a versão java especificada. Os seguintes elementos no pom.xml indicam a versão java a utilizar:

Elemento Valor java 8 Valor java 11 Valor java 17 Descrição
Java.version 1.8 11 17 Versão do Java utilizada pelo maven-compiler-plugin.
JavaVersion 8 11 17 Versão java alojada pela aplicação de funções no Azure.

Os exemplos seguintes mostram as definições do Java 8 nas secções relevantes do ficheiro pom.xml:

Java.version

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <azure.functions.maven.plugin.version>1.6.0</azure.functions.maven.plugin.version>
    <azure.functions.java.library.version>1.3.1</azure.functions.java.library.version>
    <functionAppName>fabrikam-functions-20200718015742191</functionAppName>
    <stagingDirectory>${project.build.directory}/azure-functions/${functionAppName}</stagingDirectory>
</properties>

JavaVersion

<runtime>
    <!-- runtime os, could be windows, linux or docker-->
    <os>windows</os>
    <javaVersion>8</javaVersion>
    <!-- for docker function, please set the following parameters -->
    <!-- <image>[hub-user/]repo-name[:tag]</image> -->
    <!-- <serverId></serverId> -->
    <!-- <registryUrl></registryUrl>  -->
</runtime>

Importante

Tem de ter a variável de ambiente JAVA_HOME definida corretamente para o diretório JDK utilizado durante a compilação de código com o Maven. Certifique-se de que a versão do JDK é, pelo menos, tão alta como a Java.version definição.

Especificar o SO de implementação

O Maven também lhe permite especificar o sistema operativo no qual a sua aplicação de funções é executada no Azure. Utilize o os elemento para escolher o sistema operativo.

Elemento Windows Linux Docker
os windows linux docker

O exemplo seguinte mostra a definição do sistema operativo na runtime secção do ficheiro de pom.xml:

<runtime>
    <!-- runtime os, could be windows, linux or docker-->
    <os>windows</os>
    <javaVersion>8</javaVersion>
    <!-- for docker function, please set the following parameters -->
    <!-- <image>[hub-user/]repo-name[:tag]</image> -->
    <!-- <serverId></serverId> -->
    <!-- <registryUrl></registryUrl>  -->
</runtime>

Disponibilidade e suporte do runtime do JDK

As compilações Microsoft e Adoptium do OpenJDK são fornecidas e suportadas em Funções para Java 8 (Adoptium), 11 (MSFT) e 17 (MSFT). Estes binários são fornecidos como uma distribuição sem custos, multiplataformas e pronta para produção do OpenJDK para o Azure. Contêm todos os componentes para compilar e executar aplicações Java SE.

Para desenvolvimento ou teste local, pode transferir gratuitamente a compilação da Microsoft dos binários OpenJDK ou Adoptium Temurin . suporte do Azure para problemas com os JDKs e as aplicações de funções está disponível com um plano de suporte qualificado.

Se quiser continuar a utilizar o Zulu para binários do Azure na sua aplicação de Funções, configure a sua aplicação em conformidade. Pode continuar a utilizar os binários Azul para o seu site. No entanto, quaisquer patches ou melhoramentos de segurança só estão disponíveis em novas versões do OpenJDK. Por este motivo, deverá eventualmente remover esta configuração para que as suas aplicações utilizem a versão mais recente disponível do Java.

Personalizar JVM

As funções permitem-lhe personalizar a máquina virtual Java (JVM) utilizada para executar as suas funções Java. As seguintes opções JVM são utilizadas por predefinição:

  • -XX:+TieredCompilation
  • -XX:TieredStopAtLevel=1
  • -noverify
  • -Djava.net.preferIPv4Stack=true
  • -jar

Pode fornecer outros argumentos ao JVM através de uma das seguintes definições de aplicação, consoante o tipo de plano:

Tipo de plano Nome da definição Comentário
Plano de consumo languageWorkers__java__arguments Esta definição aumenta as horas de início frias para as funções Java em execução num plano de Consumo.
Plano Premium
Plano dedicado
JAVA_OPTS

As secções seguintes mostram-lhe como adicionar estas definições. Para saber mais sobre como trabalhar com as definições da aplicação, consulte a secção Trabalhar com as definições da aplicação .

Portal do Azure

No portal do Azure, utilize o separador Definições da Aplicação para adicionar a languageWorkers__java__arguments ou a JAVA_OPTS definição.

CLI do Azure

Pode utilizar o comando az functionapp config appsettings set para adicionar estas definições, conforme mostrado no exemplo seguinte para a opção -Djava.awt.headless=true :

az functionapp config appsettings set \
    --settings "languageWorkers__java__arguments=-Djava.awt.headless=true" \
    --name <APP_NAME> --resource-group <RESOURCE_GROUP>

Este exemplo ativa o modo sem cabeça. Substitua <APP_NAME> pelo nome da sua aplicação de funções e <RESOURCE_GROUP> pelo grupo de recursos.

Bibliotecas de terceiros

Funções do Azure suporta a utilização de bibliotecas de terceiros. Por predefinição, todas as dependências especificadas no ficheiro de projeto pom.xml são automaticamente agrupadas durante o mvn package objetivo. Para bibliotecas não especificadas como dependências no pom.xml ficheiro, coloque-as num lib diretório no diretório de raiz da função. As dependências colocadas no lib diretório são adicionadas ao carregador de classe do sistema no runtime.

A com.microsoft.azure.functions:azure-functions-java-library dependência é fornecida no caminho de classe por predefinição e não precisa de ser incluída no lib diretório. Além disso, azure-functions-java-worker adiciona dependências listadas aqui ao classpath.

Suporte de tipo de dados

Pode utilizar objetos Java antigos simples (POJOs), tipos definidos em azure-functions-java-librarytipos de dados primitivos, como Cadeia e Número Inteiro, para vincular a enlaces de entrada ou saída.

POJOs

Para converter dados de entrada em POJO, azure-functions-java-worker utiliza a biblioteca gson . Os tipos de POJO utilizados como entradas para funções devem ser public.

Dados binários

Vincular entradas binárias ou saídas a byte[], ao definir o dataType campo em function.json como binary:

   @FunctionName("BlobTrigger")
    @StorageAccount("AzureWebJobsStorage")
     public void blobTrigger(
        @BlobTrigger(name = "content", path = "myblob/{fileName}", dataType = "binary") byte[] content,
        @BindingName("fileName") String fileName,
        final ExecutionContext context
    ) {
        context.getLogger().info("Java Blob trigger function processed a blob.\n Name: " + fileName + "\n Size: " + content.length + " Bytes");
    }

Se esperar valores nulos, utilize Optional<T>.

Enlaces

Os enlaces de entrada e saída fornecem uma forma declarativa de ligar aos dados a partir do seu código. Uma função pode ter vários enlaces de entrada e saída.

Exemplo de enlace de entrada

package com.example;

import com.microsoft.azure.functions.annotation.*;

public class Function {
    @FunctionName("echo")
    public static String echo(
        @HttpTrigger(name = "req", methods = { HttpMethod.PUT }, authLevel = AuthorizationLevel.ANONYMOUS, route = "items/{id}") String inputReq,
        @TableInput(name = "item", tableName = "items", partitionKey = "Example", rowKey = "{id}", connection = "AzureWebJobsStorage") TestInputData inputData,
        @TableOutput(name = "myOutputTable", tableName = "Person", connection = "AzureWebJobsStorage") OutputBinding<Person> testOutputData
    ) {
        testOutputData.setValue(new Person(httpbody + "Partition", httpbody + "Row", httpbody + "Name"));
        return "Hello, " + inputReq + " and " + inputData.getKey() + ".";
    }

    public static class TestInputData {
        public String getKey() { return this.RowKey; }
        private String RowKey;
    }
    public static class Person {
        public String PartitionKey;
        public String RowKey;
        public String Name;

        public Person(String p, String r, String n) {
            this.PartitionKey = p;
            this.RowKey = r;
            this.Name = n;
        }
    }
}

Invoca esta função com um pedido HTTP.

  • O payload de pedido HTTP é transmitido como um String para o argumento inputReq.
  • Uma entrada é obtida a partir do armazenamento de Tabelas e é transmitida quanto TestInputData ao argumento inputData.

Para receber um lote de entradas, pode vincular a String[], POJO[], List<String>ou List<POJO>.

@FunctionName("ProcessIotMessages")
    public void processIotMessages(
        @EventHubTrigger(name = "message", eventHubName = "%AzureWebJobsEventHubPath%", connection = "AzureWebJobsEventHubSender", cardinality = Cardinality.MANY) List<TestEventData> messages,
        final ExecutionContext context)
    {
        context.getLogger().info("Java Event Hub trigger received messages. Batch size: " + messages.size());
    }
    
    public class TestEventData {
    public String id;
}

Esta função é acionada sempre que existirem novos dados no hub de eventos configurado. Uma vez que o cardinality está definido como MANY, a função recebe um lote de mensagens do hub de eventos. EventData a partir do hub de eventos é convertido para para TestEventData a execução da função.

Exemplo de enlace de saída

Pode vincular um enlace de saída ao valor devolvido com $return.

package com.example;

import com.microsoft.azure.functions.annotation.*;

public class Function {
    @FunctionName("copy")
    @StorageAccount("AzureWebJobsStorage")
    @BlobOutput(name = "$return", path = "samples-output-java/{name}")
    public static String copy(@BlobTrigger(name = "blob", path = "samples-input-java/{name}") String content) {
        return content;
    }
}

Se existirem vários enlaces de saída, utilize o valor devolvido apenas para um deles.

Para enviar vários valores de saída, utilize OutputBinding<T> definidos no azure-functions-java-library pacote.

@FunctionName("QueueOutputPOJOList")
    public HttpResponseMessage QueueOutputPOJOList(@HttpTrigger(name = "req", methods = { HttpMethod.GET,
            HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
            @QueueOutput(name = "itemsOut", queueName = "test-output-java-pojo", connection = "AzureWebJobsStorage") OutputBinding<List<TestData>> itemsOut, 
            final ExecutionContext context) {
        context.getLogger().info("Java HTTP trigger processed a request.");
       
        String query = request.getQueryParameters().get("queueMessageId");
        String queueMessageId = request.getBody().orElse(query);
        itemsOut.setValue(new ArrayList<TestData>());
        if (queueMessageId != null) {
            TestData testData1 = new TestData();
            testData1.id = "msg1"+queueMessageId;
            TestData testData2 = new TestData();
            testData2.id = "msg2"+queueMessageId;

            itemsOut.getValue().add(testData1);
            itemsOut.getValue().add(testData2);

            return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + queueMessageId).build();
        } else {
            return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("Did not find expected items in CosmosDB input list").build();
        }
    }

     public static class TestData {
        public String id;
    }

Invoca esta função num HttpRequest objeto. Escreve vários valores no Armazenamento de filas.

HttpRequestMessage e HttpResponseMessage

Estes são definidos em azure-functions-java-library. São tipos auxiliares para trabalhar com funções HttpTrigger.

Tipo especializado Destino Utilização típica
HttpRequestMessage<T> Acionador HTTP Obtém método, cabeçalhos ou consultas
HttpResponseMessage Enlace de Saída HTTP Devolve um estado diferente de 200

Metadados

Poucos acionadores enviam metadados do acionador juntamente com dados de entrada. Pode utilizar a anotação @BindingName para vincular para acionar metadados.

package com.example;

import java.util.Optional;
import com.microsoft.azure.functions.annotation.*;


public class Function {
    @FunctionName("metadata")
    public static String metadata(
        @HttpTrigger(name = "req", methods = { HttpMethod.GET, HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) Optional<String> body,
        @BindingName("name") String queryValue
    ) {
        return body.orElse(queryValue);
    }
}

No exemplo anterior, o queryValue está vinculado ao parâmetro name da cadeia de consulta no URL do pedido HTTP, http://{example.host}/api/metadata?name=test. Eis outro exemplo que mostra como vincular aos metadados do acionador Id de fila.

 @FunctionName("QueueTriggerMetadata")
    public void QueueTriggerMetadata(
        @QueueTrigger(name = "message", queueName = "test-input-java-metadata", connection = "AzureWebJobsStorage") String message,@BindingName("Id") String metadataId,
        @QueueOutput(name = "output", queueName = "test-output-java-metadata", connection = "AzureWebJobsStorage") OutputBinding<TestData> output,
        final ExecutionContext context
    ) {
        context.getLogger().info("Java Queue trigger function processed a message: " + message + " with metadaId:" + metadataId );
        TestData testData = new TestData();
        testData.id = metadataId;
        output.setValue(testData);
    }

Nota

O nome indicado na anotação tem de corresponder à propriedade de metadados.

Contexto de execução

ExecutionContext, definido no azure-functions-java-library, contém métodos auxiliares para comunicar com o runtime de funções. Para obter mais informações, veja o artigo ExecutionContext reference (Referência executionContext).

Logger

Utilize getLogger, definido em ExecutionContext, para escrever registos a partir do código de função.

Exemplo:


import com.microsoft.azure.functions.*;
import com.microsoft.azure.functions.annotation.*;

public class Function {
    public String echo(@HttpTrigger(name = "req", methods = {HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) String req, ExecutionContext context) {
        if (req.isEmpty()) {
            context.getLogger().warning("Empty request body received by function " + context.getFunctionName() + " with invocation " + context.getInvocationId());
        }
        return String.format(req);
    }
}

Ver registos e rastreio

Pode utilizar a CLI do Azure para transmitir em fluxo registos de stdout e stderr java e outros registos de aplicações.

Eis como configurar a aplicação de funções para escrever o registo de aplicações com a CLI do Azure:

az webapp log config --name functionname --resource-group myResourceGroup --application-logging true

Para transmitir em fluxo a saída do registo para a sua aplicação de funções com a CLI do Azure, abra uma nova linha de comandos, Bash ou sessão de Terminal e introduza o seguinte comando:

az webapp log tail --name webappname --resource-group myResourceGroup

O comando az webapp log tail tem opções para filtrar a saída com a opção --provider .

Para transferir os ficheiros de registo como um único ficheiro ZIP com a CLI do Azure, abra uma nova linha de comandos, Bash ou sessão de Terminal e introduza o seguinte comando:

az webapp log download --resource-group resourcegroupname --name functionappname

Tem de ter ativado o registo do sistema de ficheiros no portal do Azure ou na CLI do Azure antes de executar este comando.

Variáveis de ambiente

Em Funções, as definições da aplicação, como cadeias de ligação de serviço, são expostas como variáveis de ambiente durante a execução. Pode aceder a estas definições com, System.getenv("AzureWebJobsStorage").

O exemplo seguinte obtém a definição da aplicação, com a chave denominada myAppSetting:


public class Function {
    public String echo(@HttpTrigger(name = "req", methods = {HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) String req, ExecutionContext context) {
        context.getLogger().info("My app setting value: "+ System.getenv("myAppSetting"));
        return String.format(req);
    }
}

Passos seguintes

Para obter mais informações sobre Funções do Azure desenvolvimento Java, veja os seguintes recursos: