Função Spring Cloud no Azure

Este artigo mostra como criar, testar, depurar e implantar uma função do Spring Cloud Java no Azure Functions. Quando terminar, sua função será executada no Plano de Consumo e responderá às solicitações HTTP.

Pré-requisitos

  • Uma assinatura do Azure. Se você não tiver uma assinatura do Azure, crie uma conta gratuita antes de começar.

Para desenvolver funções usando Java, instale as seguintes ferramentas:

Importante

Defina a JAVA_HOME variável de ambiente para o local de instalação do JDK para concluir este início rápido.

Verifique se a versão principal das ferramentas é pelo menos 4.0.5455.

O que você vai criar

Você criará uma função clássica "Olá, Mundo" que é executada no Azure Functions e está configurada com a Função Spring Cloud.

A função recebe um User objeto JSON, que contém um nome de usuário, e envia de volta um Greeting objeto, que contém a mensagem de boas-vindas para esse usuário.

O projeto está disponível no exemplo do Spring Cloud Function no Azure no repositório azure-function-java-worker do GitHub. Você poderá usar esse exemplo diretamente se quiser ver o trabalho final descrito neste guia de início rápido.

Criar um novo projeto maven

Crie um projeto maven vazio e configure-o com o Spring Cloud Function e Azure Functions.

Em uma pasta vazia, crie um novo arquivo pom.xml . Em seguida, copie o conteúdo do arquivo pom.xml do projeto de exemplo.

Nota

Este arquivo usa dependências do Maven do Spring Boot e do Spring Cloud Function. Ele também configura os plug-ins Spring Boot e Azure Functions Maven.

Personalize algumas propriedades para seu aplicativo:

  • <functionAppName>é o nome da função Azure.
  • <functionAppRegion>é o nome da região Azure em que você implanta sua Função.
  • <functionResourceGroup>é o nome do grupo de recursos Azure que você está usando.

Altere essas propriedades diretamente perto da parte superior do arquivo pom.xml, conforme mostrado no exemplo a seguir:

    <properties>
        <java.version>11</java.version>

        <!-- Spring Boot start class. WARNING: correct class must be set -->
        <start-class>com.example.DemoApplication</start-class>

        <!-- customize those properties. WARNING: the functionAppName should be unique across Azure -->
        <azure.functions.maven.plugin.version>1.36.0</azure.functions.maven.plugin.version>
        <functionResourceGroup>my-spring-function-resource-group</functionResourceGroup>
        <functionAppServicePlanName>my-spring-function-service-plan</functionAppServicePlanName>
        <functionAppName>my-spring-function</functionAppName>
        <functionPricingTier>Y1</functionPricingTier>
        <functionAppRegion>eastus</functionAppRegion>
    </properties>

Criar arquivos de configuração do Azure

Crie uma pasta src/main/resources e adicione os seguintes arquivos de configuração do Azure Functions a ela.

host.json:

{
  "version": "2.0",
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[4.*, 5.2.0)"
  },
  "functionTimeout": "00:10:00"
}

local.settings.json:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "java",
    "FUNCTIONS_EXTENSION_VERSION": "~4",
    "AzureWebJobsDashboard": ""
  }
}

Criar objetos de domínio

O Azure Functions pode receber e enviar objetos no formato JSON. Criar User e Greeting objetos que representam seu modelo de domínio. Você pode criar objetos mais complexos com mais propriedades se quiser personalizar este início rápido.

Crie uma pasta src/main/java/com/example/model e adicione os dois seguintes arquivos:

User.java:

package com.example.model;

public class User {

    private String name;

    public User() {
    }

    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Greeting.java:

package com.example.model;

public class Greeting {

    private String message;

    public Greeting() {
    }

    public Greeting(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

Criar o aplicativo Spring Boot

Esse aplicativo gerencia toda a lógica de negócios e tem acesso ao ecossistema completo do Spring Boot. Essa funcionalidade oferece dois benefícios principais em relação a uma função padrão do Azure:

  • Ele não depende das APIs do Azure Functions, portanto, você pode porta-lo facilmente para outros sistemas. Por exemplo, você pode reutilizá-lo em um aplicativo Spring Boot normal.
  • Você pode usar todas as anotações @Enable do Spring Boot para adicionar novos recursos.

Na pasta src/main/java/com/example do , crie o seguinte arquivo, que é um aplicativo Spring Boot normal:

DemoApplication.java:

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(DemoApplication.class, args);
    }
}

Agora, crie o arquivo a seguir na pasta src/main/java/com/example/hello. Este código contém um componente spring boot que representa a função que você deseja executar:

Hello.java:

package com.example.hello;

import com.example.model.*;
import org.springframework.stereotype.Component;
import java.util.function.Function;

@Component
public class Hello implements Function<User, Greeting> {

    @Override
    public Greeting apply(User user) {
        return new Greeting("Hello, " + user.getName() + "!\n");
    }
}

Nota

A função Hello é bastante específica:

  • É um java.util.function.Function. Ele contém a lógica de negócios e usa uma API Java padrão para transformar um objeto em outro.
  • Porque tem a @Component anotação, é um Spring Bean. Por padrão, seu nome é o mesmo que a classe, mas começa com um caractere minúsculo: hello. Seguir essa convenção de nomenclatura é importante se você quiser criar outras funções em seu aplicativo. O nome deve corresponder ao nome Azure Functions que você criar na próxima seção.

Criar a Função do Azure

Para usar a API de Azure Functions completa, crie uma função Azure que delega sua execução à Função Spring Cloud que você criou na etapa anterior.

Na pasta src/main/java/com/example/hello, crie o seguinte arquivo de classe de função do Azure:

HelloHandler.java:

package com.example.hello;

import com.microsoft.azure.functions.*;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;
import com.example.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Optional;

@Component
public class HelloHandler {

    @Autowired
    private Hello hello;

    @FunctionName("hello")
    public HttpResponseMessage execute(
        @HttpTrigger(name = "request", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<User>> request, ExecutionContext context) {
        User user = request.getBody()
                           .filter(u -> u.getName() != null)
                           .orElseGet(() -> new User(request.getQueryParameters().getOrDefault("name", "world")));
        context.getLogger().info("Greeting user name: " + user.getName());
        return request.createResponseBuilder(HttpStatus.OK)
                      .body(hello.apply(user))
                      .header("Content-Type", "application/json")
                      .build();
    }
}

Esta classe Java é uma função Azure com os seguintes recursos:

  • A classe tem a anotação @Component, então é um Spring Bean.
  • O nome da função, conforme definido pela anotação @FunctionName("hello"), é hello.
  • A classe implementa uma função real do Azure, para que você possa usar a API completa do Azure Functions aqui.

Adicionar testes de unidade

Essa etapa é opcional, mas é recomendável validar se o aplicativo funciona corretamente.

Crie uma pasta src/test/java/com/example e adicione os seguintes testes JUnit:

HelloTest.java:

package com.example;

import com.example.hello.Hello;
import com.example.model.Greeting;
import com.example.model.User;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class HelloTest {

    @Test
    public void test() {
        Greeting result = new Hello().apply(new User("foo"));
        assertThat(result.getMessage()).isEqualTo("Hello, foo!\n");
    }
}

Agora você pode testar sua função Azure usando o Maven:

mvn clean test

Executar a função localmente

Antes de implantar seu aplicativo na Função Azure, teste-o localmente.

Primeiro, empacote seu aplicativo em um arquivo JAR:

mvn package

Agora que o aplicativo está empacotado, execute-o usando o plug-in do azure-functions Maven:

mvn azure-functions:run

A Função Azure agora está disponível em seu localhost, usando a porta 7071. Teste a função enviando-lhe uma solicitação POST, com um User objeto no formato JSON. Por exemplo, use cURL:

curl -X POST http://localhost:7071/api/hello -d "{\"name\":\"Azure\"}"

A Função responde com um Greeting objeto, no formato JSON:

{
  "message": "Hello, Azure!\n"
}

Aqui está uma captura de tela da solicitação cURL na parte superior da tela e da Função do Azure local na parte inferior:

Azure Function em execução localmente

Depurar a função localmente

As seções a seguir descrevem como depurar a função.

Depuração com o IntelliJ IDEA

Abra o projeto no IntelliJ IDEA e crie uma configuração de execução de depuração de JVM remota para anexar. Para obter mais informações, confira Tutorial: Depuração remota.

Criar uma configuração de execução de depuração remota de JVM

Execute o aplicativo com o seguinte comando:

mvn azure-functions:run -DenableDebug

Quando o aplicativo é iniciado, você vê a seguinte saída:

Worker process started and initialized.
Listening for transport dt_socket at address: 5005

Inicie a depuração do projeto no IntelliJ IDEA. Você verá esta saída:

Connected to the target VM, address: 'localhost:5005', transport: 'socket'

Marque os pontos de interrupção que você deseja depurar. O IntelliJ IDEA entra no modo de depuração depois de enviar uma solicitação.

Depuração com o Visual Studio Code

Abra o projeto em Visual Studio Code e configure o seguinte launch.json conteúdo do arquivo:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "java",
            "name": "Attach to Remote Program",
            "request": "attach",
            "hostName": "127.0.0.1",
            "port": 5005
        }
    ]
}

Execute o aplicativo com o seguinte comando:

mvn azure-functions:run -DenableDebug

Quando o aplicativo é iniciado, você vê a seguinte saída:

Worker process started and initialized.
Listening for transport dt_socket at address: 5005

Inicie a depuração de projeto em Visual Studio Code e marque os pontos de interrupção que você deseja depurar. Visual Studio Code entra no modo de depuração depois de enviar uma solicitação. Para obter mais informações, confira Como executar e depurar o Java.

Implantar a função no Azure Functions

Agora, você publicará a função do Azure em produção. Lembre-se de que as propriedades <functionAppName>, <functionAppRegion>e <functionResourceGroup> definidas no arquivo pom.xml são usadas para configurar sua função.

Nota

O plug-in do Maven precisa ser autenticado com o Azure. Se você tiver a CLI do Azure instalada, use az login antes de continuar.

Para obter mais opções de autenticação, consulte Autenticação no azure-maven-plugins repositório.

Execute o Maven para implantar sua função automaticamente:

mvn azure-functions:deploy

Agora, acesse o portal do Azure para encontrar o Function App que foi criado.

Selecione a função:

  • Na visão geral da função, observe a URL da função.
  • Para verificar sua função em execução, selecione Streaming de log no menu de navegação.

Agora, como você fez na seção anterior, use cURL para acessar a função em execução, conforme mostrado no exemplo a seguir. Substitua your-function-name pelo nome da função real.

curl https://your-function-name.azurewebsites.net/api/hello -d "{\"name\":\"Azure\"}"

Como na seção anterior, a Função deve responder a você com um objeto Greeting, ainda no formato JSON:

{
  "message": "Hello, Azure!\n"
}

Parabéns, você tem uma Função spring cloud em execução no Azure Functions! Para obter mais informações e exemplos de funções do Spring Cloud, consulte os seguintes recursos:

Próximas etapas

Para saber mais sobre o Spring e o Azure, prossiga para o centro de documentação do Spring on Azure.