Utvecklarguide för Azure Functions Java

Den här guiden innehåller detaljerad information som hjälper dig att lyckas utveckla Azure Functions med Hjälp av Java.

Om du är nybörjare på Azure Functions som Java-utvecklare bör du överväga att först läsa någon av följande artiklar:

Komma igång Begrepp Scenarier/exempel

Grunderna i Java-funktionen

En Java-funktion är en public metod som är dekorerad med anteckningen @FunctionName. Den här metoden definierar posten för en Java-funktion och måste vara unik i ett visst paket. Paketet kan ha flera klasser med flera offentliga metoder kommenterade med @FunctionName. Ett enda paket distribueras till en funktionsapp i Azure. I Azure tillhandahåller funktionsappen distributions-, körnings- och hanteringskontexten för dina enskilda Java-funktioner.

Programmeringsmodell

Begreppen utlösare och bindningar är grundläggande för Azure Functions. Utlösare startar körningen av koden. Bindningar ger dig ett sätt att skicka data till och returnera data från en funktion, utan att behöva skriva anpassad dataåtkomstkod.

Skapa Java-funktioner

För att göra det enklare att skapa Java-funktioner finns det Maven-baserade verktyg och arketyper som använder fördefinierade Java-mallar som hjälper dig att skapa projekt med en specifik funktionsutlösare.

Maven-baserade verktyg

Följande utvecklarmiljöer har Azure Functions-verktyg som gör att du kan skapa Java-funktionsprojekt:

De här artiklarna visar hur du skapar dina första funktioner med valfri IDE.

Projektställningar

Om du föredrar kommandoradsutveckling från terminalen är det enklaste sättet att skapa javabaserade funktionsprojekt att använda Apache Maven arketyper. Java Maven-arketypen för Azure Functions publiceras under följande groupId:artifactId: com.microsoft.azure:azure-functions-archetype.

Följande kommando genererar ett nytt Java-funktionsprojekt med den här arketypen:

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

Information om hur du kommer igång med den här arketypen finns i Snabbstart för Java.

Mappstrukturen

Här är mappstrukturen för ett Azure Functions Java-projekt:

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

Du kan använda en delad host.json-fil för att konfigurera funktionsappen. Varje funktion har en egen kodfil (.java) och en bindningskonfigurationsfil (function.json).

Du kan placera mer än en funktion i ett projekt. Undvik att placera dina funktioner i separata burkar. I FunctionApp målkatalogen är det som distribueras till din funktionsapp i Azure.

Utlösare och anteckningar

Funktioner anropas av en utlösare, till exempel en HTTP-begäran, en timer eller en uppdatering av data. Din funktion måste bearbeta utlösaren och andra indata för att generera en eller flera utdata.

Använd Java-anteckningarna som ingår i paketet com.microsoft.azure.functions.annotation.* för att binda indata och utdata till dina metoder. Mer information finns i Java-referensdokumenten.

Viktigt!

Du måste konfigurera ett Azure Storage-konto i din local.settings.json för att köra Azure Blob Storage, Azure Queue Storage eller Azure Table Storage-utlösare lokalt.

Exempel:

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

Här är den genererade motsvarande function.json av plugin-programmet azure-functions-maven-:

{
  "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"
    }
  ]
}

Java-versioner

Den version av Java som appen körs på i Azure anges i filen pom.xml. Maven-arketypen genererar för närvarande en pom.xml för Java 8, som du kan ändra innan du publicerar. Java-versionen i pom.xml ska matcha den version där du har utvecklat och testat appen lokalt.

Versioner som stöds

I följande tabell visas aktuella Java-versioner som stöds för varje huvudversion av Functions-körningen, efter operativsystem:

Funktionsversion Java-versioner (Windows) Java-versioner (Linux)
4.x 17
11
8
21 (förhandsversion)
17
11
8
3.x 11
8
11
8
2.x 8 saknas

Såvida du inte anger en Java-version för distributionen är Maven-arketypen som standard Java 8 under distributionen till Azure.

Ange distributionsversionen

Du kan styra vilken version av Java som maven-arketypen riktar in sig på med hjälp av parametern -DjavaVersion . Värdet för den här parametern kan vara antingen 8, 1711eller 21.

Maven-arketypen genererar en pom.xml som riktar sig mot den angivna Java-versionen. Följande element i pom.xml anger vilken Java-version som ska användas:

Element Java 8-värde Java 11-värde Java 17-värde Java 21-värde (förhandsversion, Linux) beskrivning
Java.version 1.8 11 17 21 Version av Java som används av plugin-programmet maven-compiler-.
JavaVersion 8 11 17 21 Java-version som hanteras av funktionsappen i Azure.

I följande exempel visas inställningarna för Java 8 i relevanta avsnitt i pom.xml-filen:

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>

Viktigt!

Du måste ha JAVA_HOME miljövariabeln korrekt inställd på den JDK-katalog som används vid kodkompilering med Maven. Kontrollera att JDK-versionen är minst lika hög som inställningen Java.version .

Ange distributionsoperativsystemet

Med Maven kan du också ange det operativsystem som funktionsappen körs på i Azure. Använd elementet os för att välja operativsystemet.

Element Windows Linux Docker
os windows linux docker

I följande exempel visas operativsystemets inställning i runtime avsnittet i filen 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>

Tillgänglighet och support för JDK-körning

Microsoft- och Adoptium-versioner av OpenJDK tillhandahålls och stöds på Functions for Java 8 (Adoptium), Java 11, 17 och 21 (MSFT). Dessa binärfiler tillhandahålls som en kostnadsfri distribution med flera plattformar och produktionsklara distributioner av OpenJDK för Azure. De innehåller alla komponenter för att skapa och köra Java SE-program.

För lokal utveckling eller testning kan du ladda ned Microsoft-versionen av OpenJDK eller Adoptium Temurin-binärfiler kostnadsfritt. Azure-stöd för problem med JDK:er och funktionsappar är tillgängligt med en kvalificerad supportplan.

Om du vill fortsätta använda binärfilerna Zulu för Azure i funktionsappen konfigurerar du appen i enlighet med detta. Du kan fortsätta att använda Azul-binärfilerna för din webbplats. Säkerhetskorrigeringar eller förbättringar är dock endast tillgängliga i nya versioner av OpenJDK. Därför bör du så småningom ta bort den här konfigurationen så att dina appar använder den senaste tillgängliga versionen av Java.

Anpassa JVM

Med Functions kan du anpassa den virtuella Java-dator (JVM) som används för att köra dina Java-funktioner. Följande JVM-alternativ används som standard:

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

Du kan ange andra argument för JVM genom att använda någon av följande programinställningar, beroende på plantyp:

Abonnemangstyp Inställningsnamn Kommentar
Förbrukningsplan languageWorkers__java__arguments Den här inställningen ökar de kalla starttiderna för Java-funktioner som körs i en förbrukningsplan.
Premium-plan
Dedikerad plan
JAVA_OPTS

Följande avsnitt visar hur du lägger till de här inställningarna. Mer information om hur du arbetar med programinställningar finns i avsnittet Arbeta med programinställningar .

Azure Portal

I Azure-portalen använder du fliken Program Inställningar för att lägga till antingen languageWorkers__java__arguments inställningen eller JAVA_OPTS .

Azure CLI

Du kan använda kommandot az functionapp config appsettings set för att lägga till de här inställningarna, som du ser i följande exempel för alternativet -Djava.awt.headless=true :

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

Det här exemplet aktiverar huvudlöst läge. Ersätt <APP_NAME> med namnet på funktionsappen och <RESOURCE_GROUP> med resursgruppen.

Bibliotek från tredje part

Azure Functions stöder användning av bibliotek från tredje part. Som standard paketeras alla beroenden som anges i projektfilen pom.xml automatiskt under mvn package målet. För bibliotek som inte har angetts som beroenden pom.xml i filen placerar du dem i en lib katalog i funktionens rotkatalog. Beroenden som placeras i lib katalogen läggs till i systemklassinläsaren vid körning.

Beroendet com.microsoft.azure.functions:azure-functions-java-library tillhandahålls på klassökvägen som standard och behöver inte ingå i lib katalogen. Dessutom lägger azure-functions-java-worker till beroenden som anges här i klassökvägen.

Stöd för datatyp

Du kan använda vanliga gamla Java-objekt (POJO), typer som definierats i azure-functions-java-library, eller primitiva datatyper som Sträng och Heltal för att binda till indata- eller utdatabindningar.

POJO:er

För att konvertera indata till POJO använder azure-functions-java-worker gson-biblioteket. POJO-typer som används som indata till funktioner ska vara public.

Binära data

Binda binära indata eller utdata till genom att byte[]ange dataType fältet i din function.json till 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");
    }

Om du förväntar dig null-värden använder du Optional<T>.

Bindningar

Indata- och utdatabindningar är ett deklarativt sätt att ansluta till data inifrån koden. En funktion kan ha flera in- och utdatabindningar.

Exempel på indatabindning

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

Du anropar den här funktionen med en HTTP-begäran.

  • Nyttolasten för HTTP-begäran skickas som en String för argumentet inputReq.
  • En post hämtas från Table Storage och skickas TestInputData till argumentet inputData.

Om du vill ta emot en batch med indata kan du binda till String[], POJO[], List<String>eller 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;
}

Den här funktionen utlöses när det finns nya data i den konfigurerade händelsehubben. cardinality Eftersom är inställt på MANYtar funktionen emot en batch med meddelanden från händelsehubben. EventData från händelsehubben konverteras till TestEventData för funktionskörningen.

Exempel på utdatabindning

Du kan binda en utdatabindning till returvärdet med hjälp $returnav .

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

Om det finns flera utdatabindningar använder du returvärdet för endast en av dem.

Om du vill skicka flera utdatavärden använder du OutputBinding<T> definierat i azure-functions-java-library paketet.

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

Du anropar den här funktionen på ett HttpRequest objekt. Den skriver flera värden till Queue Storage.

HttpRequestMessage och HttpResponseMessage

Dessa definieras i azure-functions-java-library. De är hjälptyper som fungerar med HttpTrigger-funktioner.

Specialiserad typ Mål Typisk användning
HttpRequestMessage<T> HTTP-utlösare Hämtar metod, rubriker eller frågor
HttpResponseMessage HTTP-utdatabindning Returnerar annan status än 200

Metadata

Få utlösare skickar utlösarmetadata tillsammans med indata. Du kan använda anteckningar @BindingName för att binda för att utlösa metadata.

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

I föregående exempel är bundet queryValue till frågesträngsparametern name i HTTP-begärande-URL:en, http://{example.host}/api/metadata?name=test. Här är ett annat exempel som visar hur du binder till Id från metadata för köutlösare.

 @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);
    }

Kommentar

Namnet som anges i anteckningen måste matcha metadataegenskapen.

Körningskontext

ExecutionContext, som definieras i azure-functions-java-library, innehåller hjälpmetoder för att kommunicera med funktionskörningen. Mer information finns i referensartikeln ExecutionContext.

Logger

Använd getLogger, definierat i ExecutionContext, för att skriva loggar från funktionskoden.

Exempel:


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

Visa loggar och spårning

Du kan använda Azure CLI för att strömma Java stdout- och stderr-loggning samt annan programloggning.

Så här konfigurerar du funktionsappen för att skriva programloggning med hjälp av Azure CLI:

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

Om du vill strömma loggningsutdata för funktionsappen med hjälp av Azure CLI öppnar du en ny kommandotolk, Bash eller terminalsession och anger följande kommando:

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

Kommandot az webapp log tail har alternativ för att filtrera utdata med hjälp --provider av alternativet .

Om du vill ladda ned loggfilerna som en enda ZIP-fil med hjälp av Azure CLI öppnar du en ny kommandotolk, Bash eller terminalsession och anger följande kommando:

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

Du måste ha aktiverat filsystemloggning i Azure-portalen eller Azure CLI innan du kör det här kommandot.

Miljövariabler

I Functions exponeras appinställningar, till exempel tjänst anslutningssträng, som miljövariabler under körningen. Du kan komma åt de här inställningarna med hjälp av , System.getenv("AzureWebJobsStorage").

I följande exempel hämtas programinställningen med nyckeln med namnet 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);
    }
}

Använda beroendeinmatning i Java Functions

Azure Functions Java stöder designmönstret för beroendeinmatning (DI), vilket är en teknik för att uppnå inversion av kontroll (IoC) mellan klasser och deras beroenden. Java Azure Functions ger en krok för att integrera med populära ramverk för beroendeinmatning i dina Functions Apps. Azure Functions Java SPI innehåller ett gränssnitt för FunctionInstanceInjector. Genom att implementera det här gränssnittet kan du returnera en instans av funktionsklassen och dina funktioner anropas på den här instansen. Detta ger ramverk som Spring, Quarkus, Google Guice, Dagger osv. möjligheten att skapa funktionsinstansen och registrera den i sin IOK-container. Det innebär att du kan använda dessa ramverk för beroendeinmatning för att hantera dina funktioner på ett naturligt sätt.

Kommentar

Microsoft Azure Functions Java SPI Types (azure-function-java-spi) är ett paket som innehåller alla SPI-gränssnitt för tredje part att interagera med Microsoft Azure Functions-körning.

Injektor för funktionsinstans för beroendeinmatning

azure-function-java-spi innehåller ett gränssnitt för 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; 

} 

Fler exempel som använder FunctionInstanceInjector för att integrera med beroendeinmatningsramverk finns på den här lagringsplatsen.

Nästa steg

Mer information om Azure Functions Java-utveckling finns i följande resurser: