Guia do desenvolvedor Java do Azure Functions
Este guia contém informações detalhadas para ajudá-lo a desenvolver com êxito o Azure Functions usando Java.
Como desenvolvedor Java, se você é novo no Azure Functions, considere ler primeiro 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 para uma função Java e deve ser exclusivo em um pacote específico. O pacote pode ter várias classes com vários métodos públicos anotados com @FunctionName
. Um único pacote é implantado em um aplicativo de função no Azure. No Azure, o aplicativo de função fornece o contexto de implantação, execução e gerenciamento para suas funções Java individuais.
Modelo de programação
Os conceitos de gatilhos e ligações são fundamentais para o Azure Functions. Os gatilhos iniciam a execução do seu código. As ligações oferecem uma maneira de passar e retornar dados de uma função, sem ter que 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 usam modelos Java predefinidos para ajudá-lo a criar projetos com um gatilho de função específico.
Ferramentas baseadas em Maven
Os seguintes ambientes de desenvolvedor têm ferramentas do Azure Functions que permitem criar projetos de função Java:
Estes artigos mostram como criar suas primeiras funções usando o IDE de sua escolha.
Projeto andaimes
Se você preferir o desenvolvimento de linha de comando a partir do Terminal, a maneira mais simples de criar projetos de função baseados em Java é usar Apache Maven
arquétipos. O arquétipo Java Maven para Azure Functions é publicado sob o seguinte groupId:artifactId: com.microsoft.azure:azure-functions-archetype.
O comando a seguir gera um novo projeto de função Java usando esse arquétipo:
mvn archetype:generate \
-DarchetypeGroupId=com.microsoft.azure \
-DarchetypeArtifactId=azure-functions-archetype
Para começar a usar esse arquétipo, consulte o Guia de início rápido do Java.
Estrutura de pastas
Aqui está a estrutura de pastas de um projeto Java do Azure Functions:
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
Você pode usar um arquivo de host.json compartilhado para configurar o aplicativo de função. Cada função tem seu próprio arquivo de código (.java) e arquivo de configuração de vinculação (function.json).
Você pode ter mais de uma função em um projeto. No entanto, não coloque suas funções em frascos separados. Não há suporte para o uso de vários jars em um único aplicativo funcional. O FunctionApp
no diretório de destino é o que é implantado em seu aplicativo de função no Azure.
Gatilhos e anotações
As funções são invocadas por um gatilho, como uma solicitação HTTP, um temporizador ou uma atualização de dados. Sua função precisa processar esse gatilho e quaisquer outras entradas para produzir uma ou mais saídas.
Use 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, consulte os documentos de referência Java.
Importante
Você deve configurar uma conta de Armazenamento do Azure em seu local.settings.json para executar o armazenamento de Blob do Azure, o armazenamento de Filas do Azure ou gatilhos de armazenamento de Tabela 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);
}
}
Aqui está o correspondente function.json
gerado 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 seu aplicativo é executado no Azure é especificada no arquivo pom.xml. O arquétipo Maven atualmente gera um pom.xml para Java 8, que você pode alterar antes de publicar. A versão do Java em pom.xml deve corresponder à versão na qual você desenvolveu e testou localmente seu aplicativo.
Versões suportadas
A tabela a seguir mostra as versões atuais suportadas do Java para cada versão principal do tempo de execução do Functions, por sistema operacional:
Versão das funções | Versões Java (Windows) | Versões Java (Linux) |
---|---|---|
4.x | 17 11 8 |
21 (Pré-visualização) 17 11 8 |
3.x | 11 8 |
11 8 |
2.x | 8 | n/d |
A menos que você especifique uma versão do Java para sua implantação, o arquétipo do Maven assume como padrão o Java 8 durante a implantação no Azure.
Especificar a versão de implantação
Você pode controlar a versão do Java direcionada pelo arquétipo Maven usando o -DjavaVersion
parâmetro. O valor desse parâmetro pode ser 8
, 11
17
ou 21
.
O arquétipo Maven gera um pom.xml que tem como alvo a versão Java especificada. Os seguintes elementos no pom.xml indicam a versão Java a ser usada:
Elemento | Valor Java 8 | Valor Java 11 | Valor Java 17 | Valor Java 21 (Preview, Linux) | Description |
---|---|---|---|---|---|
Java.version |
1.8 | 11 | 17 | 21 | Versão do Java usada pelo maven-compiler-plugin. |
JavaVersion |
8 | 11 | 17 | 21 | Versão Java hospedada pelo aplicativo de função no Azure. |
Os exemplos a seguir mostram as configurações do Java 8 nas seções relevantes do arquivo 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
Você deve ter a variável de ambiente JAVA_HOME definida corretamente para o diretório JDK usado durante a compilação de código usando o Maven. Certifique-se de que a versão do JDK seja pelo menos tão alta quanto a Java.version
configuração.
Especificar o SO de implementação
O Maven também permite especificar o sistema operacional no qual seu aplicativo de função é executado no Azure. Use o os
elemento para escolher o sistema operacional.
Elemento | Windows | Linux | Docker |
---|---|---|---|
os |
windows |
linux |
docker |
O exemplo a seguir mostra a configuração do sistema operacional na runtime
seção do arquivo 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 ao tempo de execução do JDK
As compilações Microsoft e Adoptium do OpenJDK são fornecidas e suportadas no Functions for Java 8 (Adoptium), Java 11, 17 e 21 (MSFT). Esses binários são fornecidos como uma distribuição gratuita, multiplataforma e pronta para produção do OpenJDK para Azure. Contêm todos os componentes para compilar e executar aplicações Java SE.
Para desenvolvimento local ou testes, você pode baixar a compilação da Microsoft dos binários OpenJDK ou Adoptium Temurin gratuitamente. O suporte do Azure para problemas com os JDKs e aplicativos de função está disponível com um plano de suporte qualificado.
Se você quiser continuar usando os binários Zulu para Azure em seu aplicativo Function, configure seu aplicativo de acordo. Você pode continuar a usar os binários da Azul para o seu site. No entanto, quaisquer patches de segurança ou melhorias só estão disponíveis em novas versões do OpenJDK. Por isso, você deve eventualmente remover essa configuração para que seus aplicativos usem a versão mais recente disponível do Java.
Personalizar a JVM
O Functions permite personalizar a máquina virtual Java (JVM) usada para executar suas funções Java. As seguintes opções da JVM são usadas por padrão:
-XX:+TieredCompilation
-XX:TieredStopAtLevel=1
-noverify
-Djava.net.preferIPv4Stack=true
-jar
Você pode fornecer outros argumentos para a JVM usando uma das seguintes configurações do aplicativo, dependendo do tipo de plano:
Tipo de plano | Nome da definição | Comentário |
---|---|---|
Plano de consumo | languageWorkers__java__arguments |
Essa configuração aumenta os tempos de inicialização a frio para funções Java em execução em um plano de consumo. |
Plano Premium Plano dedicado |
JAVA_OPTS |
As seções a seguir mostram como adicionar essas configurações. Para saber mais sobre como trabalhar com configurações de aplicativos, consulte a seção Trabalhar com configurações de aplicativos.
Portal do Azure
No portal do Azure, use a guia Configurações do Aplicativo para adicionar a languageWorkers__java__arguments
ou a JAVA_OPTS
configuração.
CLI do Azure
Você pode usar o comando az functionapp config appsettings set para adicionar essas configurações, conforme mostrado no exemplo a seguir para a -Djava.awt.headless=true
opção:
az functionapp config appsettings set \
--settings "languageWorkers__java__arguments=-Djava.awt.headless=true" \
--name <APP_NAME> --resource-group <RESOURCE_GROUP>
Este exemplo habilita o modo headless. Substitua <APP_NAME>
pelo nome do seu aplicativo de função e <RESOURCE_GROUP>
pelo grupo de recursos.
Bibliotecas de terceiros
O Azure Functions dá suporte ao uso de bibliotecas de terceiros. Por padrão, todas as dependências especificadas no arquivo de projeto pom.xml
são agrupadas automaticamente durante a mvn package
meta. Para bibliotecas não especificadas como dependências no pom.xml
arquivo, coloque-as em um lib
diretório no diretório raiz da função. As dependências colocadas no lib
diretório são adicionadas ao carregador de classes do sistema em tempo de execução.
A com.microsoft.azure.functions:azure-functions-java-library
dependência é fornecida no classpath por padrão e não precisa ser incluída no lib
diretório. Além disso, azure-functions-java-worker adiciona dependências listadas aqui ao classpath.
Suporte a tipos de dados
Você pode usar POJOs (Plain old Java objects), tipos definidos em azure-functions-java-library
, ou tipos de dados primitivos, como String e Integer, para vincular a ligações de entrada ou saída.
POJOs
Para converter dados de entrada em POJO, azure-functions-java-worker usa a biblioteca gson . Os tipos de POJO usados como entradas para funções devem ser public
.
Dados binários
Vincule entradas ou saídas binárias ao byte[]
, definindo o dataType
campo em seu 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 você espera valores nulos, use Optional<T>
.
Enlaces
As ligações de entrada e saída fornecem uma maneira declarativa de se conectar a dados de dentro do seu código. Uma função pode ter várias ligações de entrada e saída.
Exemplo de vinculação 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;
}
}
}
Você invoca essa função com uma solicitação HTTP.
- A carga útil da solicitação HTTP é passada como um
String
para o argumentoinputReq
. - Uma entrada é recuperada do armazenamento de tabela e é passada para
TestInputData
o argumentoinputData
.
Para receber um lote de entradas, você 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;
}
Essa função é acionada sempre que há novos dados no hub de eventos configurado. Como o cardinality
está definido como MANY
, a função recebe um lote de mensagens do hub de eventos. EventData
do hub de eventos é convertido para para TestEventData
a execução da função.
Exemplo de vinculação de saída
Você pode vincular uma associação de saída ao valor de retorno usando $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 houver várias ligações de saída, use o valor de retorno para apenas uma delas.
Para enviar vários valores de saída, use OutputBinding<T>
definido azure-functions-java-library
no 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;
}
Você invoca essa função em um HttpRequest
objeto. Ele grava vários valores no armazenamento de filas.
HttpRequestMessage e HttpResponseMessage
Estes são definidos em azure-functions-java-library
. Eles são tipos auxiliares para trabalhar com funções HttpTrigger.
Tipo especializado | Destino | Uso típico |
---|---|---|
HttpRequestMessage<T> |
Acionador HTTP | Obtém método, cabeçalhos ou consultas |
HttpResponseMessage |
Vinculação de saída HTTP | Devolve o estado diferente de 200 |
Metadados
Poucos gatilhos enviam metadados de gatilho junto com dados de entrada. Você pode usar 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
de cadeia de caracteres de consulta na URL de solicitação HTTP, http://{example.host}/api/metadata?name=test
. Aqui está outro exemplo, mostrando como vincular a Id
metadados de gatilho 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 fornecido na anotação precisa corresponder à propriedade de metadados.
Contexto de execução
ExecutionContext
, definido no azure-functions-java-library
, contém métodos auxiliares para se comunicar com o tempo de execução das funções. Para obter mais informações, consulte o artigo de referência ExecutionContext.
Registador
Use getLogger
, definido em ExecutionContext
, para gravar logs a partir do código da 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);
}
}
Exibir logs e rastreamento
Você pode usar a CLI do Azure para transmitir o log do Java stdout e stderr e outros logs de aplicativos.
Veja como configurar seu aplicativo de função para escrever o log do aplicativo usando a CLI do Azure:
az webapp log config --name functionname --resource-group myResourceGroup --application-logging true
Para transmitir a saída de log para seu aplicativo de função usando a CLI do Azure, abra um novo prompt de comando, Bash ou sessão Terminal e digite o seguinte comando:
O comando az webapp log tail tem opções para filtrar a saída usando a --provider
opção.
Para baixar os arquivos de log como um único arquivo ZIP usando a CLI do Azure, abra um novo prompt de comando, Bash ou sessão Terminal e digite o seguinte comando:
az webapp log download --resource-group resourcegroupname --name functionappname
Você deve ter habilitado o log do sistema de arquivos no portal do Azure ou na CLI do Azure antes de executar esse comando.
Variáveis de ambiente
Em Funções, as configurações do aplicativo, como cadeias de conexão de serviço, são expostas como variáveis de ambiente durante a execução. Você pode acessar essas configurações usando, System.getenv("AzureWebJobsStorage")
.
O exemplo a seguir obtém a configuração do aplicativo, com a chave chamada 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);
}
}
Usar injeção de dependência no Java Functions
O Azure Functions Java dá suporte ao padrão de design de software de injeção de dependência (DI), que é uma técnica para obter Inversão de Controle (IoC) entre classes e suas dependências. O Java Azure Functions fornece um gancho para integração com estruturas populares de injeção de dependência em seus aplicativos do Functions. O Azure Functions Java SPI contém uma interface FunctionInstanceInjector. Ao implementar essa interface, você pode retornar uma instância de sua classe de função e suas funções serão invocadas nessa instância. Isso dá a frameworks como Spring, Quarkus, Google Guice, Dagger, etc. a capacidade de criar a instância da função e registrá-la em seu contêiner IOC. Isso significa que você pode usar essas estruturas de injeção de dependência para gerenciar suas funções naturalmente.
Nota
Microsoft Azure Functions Java SPI Types (azure-function-java-spi) é um pacote que contém todas as interfaces SPI para terceiros interagirem com o tempo de execução das funções do Microsoft Azure.
Injetor de instância de função para injeção de dependência
azure-function-java-spi contém uma interface FunctionInstanceInjector
package com.microsoft.azure.functions.spi.inject;
/**
* The instance factory used by DI framework to initialize function instance.
*
* @since 1.0.0
*/
public interface FunctionInstanceInjector {
/**
* This method is used by DI framework to initialize the function instance. This method takes in the customer class and returns
* an instance create by the DI framework, later customer functions will be invoked on this instance.
* @param functionClass the class that contains customer functions
* @param <T> customer functions class type
* @return the instance that will be invoked on by azure functions java worker
* @throws Exception any exception that is thrown by the DI framework during instance creation
*/
<T> T getInstance(Class<T> functionClass) throws Exception;
}
Para obter mais exemplos que usam FunctionInstanceInjector para integrar com estruturas de injeção de dependência, consulte este repositório.
Próximos passos
Para obter mais informações sobre o desenvolvimento Java do Azure Functions, consulte os seguintes recursos:
- Best Practices for Azure Functions (Melhores Práticas para as Funções do Azure)
- Referência para programadores das Funções do Azure
- Gatilhos e associações do Azure Functions
- Desenvolvimento local e depuração com Visual Studio Code, IntelliJ e Eclipse
- Depuração remota de funções Java usando o Visual Studio Code
- Plug-in Maven para Azure Functions
- Simplifique a criação de funções através do objetivo e prepare um diretório de preparo para a implantação do
azure-functions:add
arquivo ZIP.