Início Rápido: Criar uma função Java no Azure a partir da linha de comandos

Neste artigo, vai utilizar ferramentas de linha de comandos para criar uma função Java que responde a pedidos HTTP. Depois de testar o código localmente, implemente-o no ambiente sem servidor do Funções do Azure.

Se o Maven não for a sua ferramenta de desenvolvimento preferida, veja os nossos tutoriais semelhantes para programadores de Java:

A conclusão deste início rápido implica um pequeno custo de alguns cêntimos de USD ou menos na sua conta do Azure.

Configurar o ambiente local

Antes de começar, tem de ter o seguinte:

Verificação de pré-requisitos

  • Numa janela de terminal ou comando, execute func --version para verificar se o Funções do Azure Core Tools é a versão 4.x.

  • Execute az --version para verificar se a versão da CLI do Azure é a 2.4 ou posterior.

  • Execute az login para iniciar sessão no Azure e verificar uma subscrição ativa.

Criar um projeto de função local

No Funções do Azure, um projeto de função é um contentor para uma ou mais funções individuais que cada uma responde a um acionador específico. Todas as funções num projeto partilham as mesmas configurações locais e de alojamento. Nesta secção, vai criar um projeto de função que contém uma única função.

  1. Numa pasta vazia, execute o seguinte comando para gerar o projeto das Funções a partir de um arquétipo do Maven.

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

    Importante

    • Se quiser que as suas funções sejam executadas no Java 11, utilize -DjavaVersion=11. Para saber mais, veja Versões java.
    • A JAVA_HOME variável de ambiente tem de ser definida para a localização de instalação da versão correta do JDK para concluir este artigo.
  2. O Maven pede-lhe os valores necessários para concluir a geração do projeto na implementação.
    Indique os seguintes valores quando lhe for pedido:

    Prompt Valor Descrição
    groupId com.fabrikam Um valor que identifica exclusivamente o seu projeto em todos os projetos, seguindo as regras de nomenclatura de pacotes para Java.
    artifactId fabrikam-functions Um valor que é o nome do jar, sem um número de versão.
    versão 1.0-SNAPSHOT Escolha o valor predefinido.
    pacote com.fabrikam Um valor que é o pacote Java para o código de função gerado. Utilize a predefinição.
  3. Escreva Y ou prima Enter para confirmar.

    O Maven cria os ficheiros do projeto numa nova pasta com um nome de artifactId, que neste exemplo é fabrikam-functions.

  4. Navegue para a pasta do projeto:

    cd fabrikam-functions
    

    Esta pasta contém vários ficheiros para o projeto, incluindo ficheiros de configurações denominados local.settings.json e host.json. Uma vez que local.settings.json pode conter segredos transferidos do Azure, o ficheiro é excluído do controlo de origem por predefinição no ficheiro .gitignore .

(Opcional) Examinar o conteúdo do ficheiro

Se pretender, pode avançar para Executar a função localmente e examinar o conteúdo do ficheiro mais tarde.

Function.java

Function.java contém um run método que recebe dados de pedido na request variável é um HttpRequestMessage que está decorado com a anotação HttpTrigger , que define o comportamento do acionador.

/**
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See License.txt in the project root for
 * license information.
 */

package com.functions;

import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.HttpMethod;
import com.microsoft.azure.functions.HttpRequestMessage;
import com.microsoft.azure.functions.HttpResponseMessage;
import com.microsoft.azure.functions.HttpStatus;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FixedDelayRetry;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;

import java.io.File;
import java.nio.file.Files;
import java.util.Optional;

/**
 * Azure Functions with HTTP Trigger.
 */
public class Function {
    /**
     * This function listens at endpoint "/api/HttpExample". Two ways to invoke it using "curl" command in bash:
     * 1. curl -d "HTTP Body" {your host}/api/HttpExample
     * 2. curl "{your host}/api/HttpExample?name=HTTP%20Query"
     */
    @FunctionName("HttpExample")
    public HttpResponseMessage run(
            @HttpTrigger(
                name = "req",
                methods = {HttpMethod.GET, HttpMethod.POST},
                authLevel = AuthorizationLevel.ANONYMOUS)
                HttpRequestMessage<Optional<String>> request,
            final ExecutionContext context) {
        context.getLogger().info("Java HTTP trigger processed a request.");

        // Parse query parameter
        final String query = request.getQueryParameters().get("name");
        final String name = request.getBody().orElse(query);

        if (name == null) {
            return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
        } else {
            return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
        }
    }

    public static int count = 1;

    /**
     * This function listens at endpoint "/api/HttpExampleRetry". The function is re-executed in case of errors until the maximum number of retries occur.
     * Retry policies: https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-error-pages?tabs=java
     */
    @FunctionName("HttpExampleRetry")
    @FixedDelayRetry(maxRetryCount = 3, delayInterval = "00:00:05")
    public HttpResponseMessage HttpExampleRetry(
        @HttpTrigger(
            name = "req",
            methods = {HttpMethod.GET, HttpMethod.POST},
            authLevel = AuthorizationLevel.ANONYMOUS)
            HttpRequestMessage<Optional<String>> request,
        final ExecutionContext context) throws Exception {
        context.getLogger().info("Java HTTP trigger processed a request.");

        if(count<3) {
            count ++;
            throw new Exception("error");
        }

        // Parse query parameter
        final String query = request.getQueryParameters().get("name");
        final String name = request.getBody().orElse(query);

        if (name == null) {
            return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
        } else {
            return request.createResponseBuilder(HttpStatus.OK).body(name).build();
        }
    }

    /**
     * This function listens at endpoint "/api/HttpTriggerJavaVersion".
     * It can be used to verify the Java home and java version currently in use in your Azure function
     */
    @FunctionName("HttpTriggerJavaVersion")
    public static HttpResponseMessage HttpTriggerJavaVersion(
        @HttpTrigger(
            name = "req",
            methods = {HttpMethod.GET, HttpMethod.POST},
            authLevel = AuthorizationLevel.ANONYMOUS)
            HttpRequestMessage<Optional<String>> request,
        final ExecutionContext context
    ) {
        context.getLogger().info("Java HTTP trigger processed a request.");
        final String javaVersion = getJavaVersion();
        context.getLogger().info("Function - HttpTriggerJavaVersion" + javaVersion);
        return request.createResponseBuilder(HttpStatus.OK).body("HttpTriggerJavaVersion").build();
    }

    public static String getJavaVersion() {
        return String.join(" - ", System.getProperty("java.home"), System.getProperty("java.version"));
    }

    /**
     * This function listens at endpoint "/api/StaticWebPage".
     * It can be used to read and serve a static web page.
     * Note: Read the file from the right location for local machine and azure portal usage.
     */
    @FunctionName("StaticWebPage")
    public HttpResponseMessage getStaticWebPage(
        @HttpTrigger(
            name = "req",
            methods = {HttpMethod.GET, HttpMethod.POST},
            authLevel = AuthorizationLevel.ANONYMOUS)
        HttpRequestMessage<Optional<String>> request,
        final ExecutionContext context) {
        context.getLogger().info("Java HTTP trigger processed a request.");

        File htmlFile = new File("index.html");
        try{
            byte[] fileContent = Files.readAllBytes(htmlFile.toPath());
            return request.createResponseBuilder(HttpStatus.OK).body(fileContent).build();
        }catch (Exception e){
            context.getLogger().info("Error reading file.");
            return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }
}

A mensagem de resposta é gerada pela API HttpResponseMessage.Builder .

pom.xml

As definições dos recursos do Azure criados para alojar a sua aplicação são definidas no elemento de configuração do plug-in com um groupId de com.microsoft.azure no ficheiro de pom.xml gerado. Por exemplo, o elemento de configuração abaixo indica a uma implementação baseada no Maven para criar uma aplicação de funções no java-functions-group grupo de recursos na westus região. A própria aplicação de funções é executada no Windows alojado no java-functions-app-service-plan plano, que por predefinição é um plano de Consumo sem servidor.

    </configuration>
</plugin>
<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
</plugin>
<plugin>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>azure-functions-maven-plugin</artifactId>
    <version>${azure.functions.maven.plugin.version}</version>
    <configuration>
        <!-- function app name -->
        <appName>${functionAppName}</appName>
        <!-- function app resource group -->
        <resourceGroup>${functionResourceGroup}</resourceGroup>
        <!-- function app service plan name -->
        <appServicePlanName>java-functions-app-service-plan</appServicePlanName>
        <!-- function app region-->
        <!-- refers https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details#supported-regions for all valid values -->
        <region>${functionAppRegion}</region>
        <!-- function pricingTier, default to be consumption if not specified -->
        <!-- refers https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details#supported-pricing-tiers for all valid values -->
        <!-- <pricingTier></pricingTier> -->

        <!-- Whether to disable application insights, default is false -->
        <!-- refers https://github.com/microsoft/azure-maven-plugins/wiki/Azure-Functions:-Configuration-Details for all valid configurations for application insights-->
        <!-- <disableAppInsights></disableAppInsights> -->
        <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>
        <appSettings>
            <property>
                <name>FUNCTIONS_EXTENSION_VERSION</name>
                <value>~3</value>
            </property>
        </appSettings>
    </configuration>
    <executions>
        <execution>
            <id>package-functions</id>

Pode alterar estas definições para controlar a forma como os recursos são criados no Azure, como ao alterar runtime.os de para linux antes da windows implementação inicial. Para obter uma lista completa das definições suportadas pelo plug-in do Maven, veja os detalhes da configuração.

FunctionTest.java

O arquétipo também gera um teste de unidades para a sua função. Quando alterar a função para adicionar enlaces ou adicionar novas funções ao projeto, também terá de modificar os testes no ficheiro FunctionTest.java .

Executar a função localmente

  1. Execute a função ao iniciar o anfitrião de runtime Funções do Azure local a partir da pasta LocalFunctionProj:

    mvn clean package
    mvn azure-functions:run
    

    No final da saída, deverão ser apresentadas as seguintes linhas:

     ...
    
     Now listening on: http://0.0.0.0:7071
     Application started. Press Ctrl+C to shut down.
    
     Http Functions:
    
             HttpExample: [GET,POST] http://localhost:7071/api/HttpExample
     ...
    
     

    Nota

    Se HttpExample não aparecer como mostrado acima, é provável que tenha iniciado o anfitrião fora da pasta raiz do projeto. Nesse caso, utilize Ctrl+C para parar o anfitrião, navegue para a pasta raiz do projeto e execute novamente o comando anterior.

  2. Copie o URL da função HttpExample desta saída para um browser e acrescente a cadeia de ?name=<YOUR_NAME>consulta, tornando o URL completo como http://localhost:7071/api/HttpExample?name=Functions. O browser deve apresentar uma mensagem que ecoa o valor da cadeia de consulta. O terminal no qual iniciou o projeto também mostra a saída do registo à medida que faz pedidos.

  3. Quando terminar, utilize Ctrl+C e opte por y parar o anfitrião de funções.

Implementar o projeto de função no Azure

Uma aplicação de funções e recursos relacionados são criados no Azure quando implementa o projeto de funções pela primeira vez. As definições dos recursos do Azure criados para alojar a sua aplicação são definidas no ficheiro depom.xml. Neste artigo, irá aceitar as predefinições.

Dica

Para criar uma aplicação de funções em execução no Linux em vez do Windows, altere o runtime.os elemento no ficheiro de pom.xml de windows para linux. A execução do Linux num plano de consumo é suportada nestas regiões. Não pode ter aplicações executadas no Linux e aplicações que são executadas no Windows no mesmo grupo de recursos.

  1. Antes de poder implementar, inicie sessão na sua subscrição do Azure com a CLI do Azure ou Azure PowerShell.

    az login
    

    O comando az login inicia sessão na sua conta do Azure.

  2. Utilize o seguinte comando para implementar o projeto numa nova aplicação de funções.

    mvn azure-functions:deploy
    

    Isto cria os seguintes recursos no Azure:

    • Grupo de recursos. Denominado java-functions-group.
    • Conta de armazenamento. Obrigatório pelas Funções. O nome é gerado aleatoriamente com base nos requisitos de nome da conta de armazenamento.
    • Plano de alojamento. Alojamento sem servidor para a sua aplicação de funções na região westus . O nome é java-functions-app-service-plan.
    • Aplicação de funções. Uma aplicação de funções é a unidade de implementação e execução das suas funções. O nome é gerado aleatoriamente com base no seu artifactId, anexado com um número gerado aleatoriamente.

    A implementação empacota os ficheiros do projeto e implementa-os na nova aplicação de funções com a implementação zip. O código é executado a partir do pacote de implementação no Azure.

Invocar a função no Azure

Uma vez que a função utiliza um acionador HTTP, pode invocá-lo ao fazer um pedido HTTP para o respetivo URL no browser ou com uma ferramenta como curl.

Copie o URL de Invocação completo apresentado na saída do comando de publicação para uma barra de endereço do browser, anexando o parâmetro ?name=Functionsde consulta . O browser deve apresentar um resultado semelhante ao de quando executou a função localmente.

A saída da função executada no Azure num browser

Execute o seguinte comando para ver registos de transmissão em fluxo quase em tempo real:

func azure functionapp logstream <APP_NAME> 

Numa janela de terminal separada ou no browser, chame novamente a função remota. É apresentado um registo verboso da execução da função no Azure no terminal.

Limpar os recursos

Se continuar para o passo seguinte e adicionar um enlace de saída da fila de Armazenamento do Azure, mantenha todos os seus recursos implementados, uma vez que irá basear-se no que já fez.

Caso contrário, utilize o seguinte comando para eliminar o grupo de recursos e todos os recursos contidos para evitar incorrer em custos adicionais.

az group delete --name java-functions-group

Passos seguintes