Panduan pengembang Azure Functions Java

Panduan ini berisi informasi terperinci agar Anda berhasil mengembangkan Azure Functions menggunakan Java.

Sebagai pengembang Java, jika Anda baru menggunakan Azure Functions, pertimbangkan untuk terlebih dahulu membaca salah satu artikel berikut:

Memulai Konsep Skenario/sampel

Dasar-dasar fungsi Java

Fungsi Java adalah metodepublic, dilengkapi dengan anotasi @FunctionName. Metode ini menentukan entri untuk fungsi Java, dan harus unik dalam paket tertentu. Paket dapat memiliki beberapa kelas dengan beberapa metode publik yang dianotasikan dengan @FunctionName. Satu paket disebarkan ke aplikasi fungsi di Azure. Di Azure, aplikasi fungsi menyediakan penyebaran, eksekusi, dan konteks manajemen untuk fungsi Java individual Anda.

Model pemrograman

Konsep pemicu dan pengikatan sangat penting bagi Azure Functions. Pemicu memulai eksekusi kode Anda. Pengikatan memberi Anda cara untuk meneruskan data ke dan mengembalikan data dari fungsi, tanpa harus menulis kode akses data kustom.

Membuat fungsi Java

Untuk memudahkan pembuatan fungsi Java, ada alat dan arketipe berbasis Maven yang menggunakan templat Java yang telah ditentukan sebelumnya untuk membantu Anda membuat proyek dengan pemicu fungsi tertentu.

Alat berbasis Maven

Lingkungan pengembang berikut memiliki alat Azure Functions yang memungkinkan Anda membuat proyek fungsi Java:

Artikel ini menunjukkan kepada Anda cara membuat fungsi pertama Anda menggunakan IDE pilihan Anda.

Perancah proyek

Jika Anda lebih suka pengembangan baris perintah dari Terminal, cara paling sederhana untuk membuat kerangka proyek fungsi berbasis Java adalah menggunakan arketipe Apache Maven. Arketipe Java Maven untuk Azure Functions diterbitkan di bawah groupId berikut:artifactId: com.microsoft.azure:azure-functions-archetype.

Perintah berikut menghasilkan proyek fungsi Java baru menggunakan arketipe ini:

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

Untuk mulai menggunakan arketipe ini, lihat mulai cepat Java.

Struktur folder

Berikut adalah struktur folder proyek Java 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

Anda dapat menggunakan file host.json bersama untuk mengonfigurasi aplikasi fungsi. Setiap fungsi memiliki file kode sendiri (.csx) dan file konfigurasi pengikatan (function.json).

Anda dapat menempatkan lebih dari satu fungsi dalam proyek. Jangan memasukkan fungsi Anda ke dalam jar terpisah. FunctionApp di direktori target adalah yang akan disebarkan ke aplikasi fungsi Anda di Azure.

Pemicu dan anotasi

Fungsi dipanggil oleh pemicu, seperti permintaan HTTP, timer, atau pembaruan data. Fungsi Anda perlu memproses pemicu tersebut, serta input lainnya, untuk menghasilkan satu atau beberapa output.

Gunakan anotasi Java yang disertakan dalam paket com.microsoft.azure.functions.annotation.* untuk mengikat input dan output ke metode Anda. Untuk informasi selengkapnya, lihat dokumen referensi Java.

Penting

Anda harus mengonfigurasi akun Azure Storage di local.settings.json untuk menjalankan pemicu penyimpanan Azure Blob, penyimpanan Azure Queue, atau penyimpanan Azure Table secara lokal.

Contoh:

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

Berikut adalah yang dihasilkan sesuai function.json dengan 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"
    }
  ]
}

Versi Java

Versi Java tempat aplikasi Anda berjalan di Azure ditentukan dalam file pom.xml. Arketipe Maven saat ini menghasilkan pom.xml untuk Java 8, yang dapat Anda ubah sebelum penerbitan. Versi Java di pom.xml harus cocok dengan versi yang telah Anda kembangkan dan uji aplikasi Anda secara lokal.

Versi yang didukung

Tabel berikut ini memperlihatkan versi Java yang didukung saat ini untuk setiap versi utama runtime Azure Functions, menurut sistem operasi:

Versi Azure Functions Versi Java (Windows) Versi Java (Linux)
4.x 17
11
8
21 (Pratinjau)
17
11
8
3.x 11
8
11
8
2.x 8 n/a

Kecuali Anda menentukan versi Java untuk penyebaran Anda, arketipe Maven bersifat default di Java 8 selama penyebaran ke Azure.

Menentukan versi penyebaran

Anda dapat mengontrol versi Java yang ditargetkan oleh arketipe Maven dengan menggunakan parameter -DjavaVersion. Nilai parameter ini dapat berupa 8, , 1117 atau 21.

Arketipe Maven menghasilkan pom.xml yang menargetkan versi Java tertentu. Elemen berikut dalam pom.xml menunjukkan versi Java yang akan digunakan:

Elemen Nilai Java 8 Nilai Java 11 Nilai Java 17 Nilai Java 21 (Pratinjau, Linux) Deskripsi
Java.version 1.8 11 17 21 Versi Java yang digunakan oleh maven-compiler-plugin.
JavaVersion 8 11 17 21 Versi Java yang dihosting oleh aplikasi fungsi di Azure.

Contoh berikut menunjukkan pengaturan untuk Java 8 di bagian yang relevan dari file 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>

Penting

Anda harus memiliki variabel lingkungan JAVA_HOME yang diatur dengan benar ke direktori JDK yang digunakan selama mengompilasi kode menggunakan Maven. Pastikan versi JDK minimal setinggi pengaturan Java.version.

Menentukan OS penyebaran

Maven juga memungkinkan Anda menentukan sistem operasi tempat aplikasi fungsi Anda berjalan di Azure. Gunakan elemen os untuk memilih sistem operasi.

Elemen Windows Linux Docker
os windows linux docker

Contoh berikut memperlihatkan pengaturan sistem pengoperasian di bagian runtime file 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>

Ketersediaan dan dukungan runtime JDK

Build Microsoft dan Adoptium OpenJDK disediakan dan didukung pada Functions untuk Java 8 (Adoptium), Java 11, 17 dan 21 (MSFT). Biner ini disediakan sebagai distribusi OpenJDK untuk Azure tanpa biaya, multi-platform, siap produksi. Mereka berisi semua komponen untuk membangun dan menjalankan aplikasi Java SE.

Untuk pengembangan atau pengujian lokal, Anda dapat mengunduh biner Microsoft build of OpenJDK atau Adoptum Temurin secara gratis. Dukungan Azure untuk masalah dengan JDK dan aplikasi fungsi tersedia dengan paket dukungan yang memenuhi syarat.

Jika Anda ingin terus menggunakan biner Zulu for Azure di aplikasi Function Anda, konfigurasikan aplikasi Anda yang sesuai. Anda dapat terus menggunakan biner Azul untuk situs Anda. Namun, patch atau peningkatan keamanan apa pun hanya tersedia dalam versi baru OpenJDK. Karena itu, Anda akhirnya harus menghapus konfigurasi ini sehingga aplikasi Anda menggunakan versi Java terbaru yang tersedia.

Menyesuaikan JVM

Functions memungkinkan Anda menyesuaikan komputer virtual Java (JVM) yang digunakan untuk menjalankan fungsi Java Anda. Opsi JVM berikut digunakan secara default:

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

Anda dapat memberikan argumen lain ke JVM dengan menggunakan salah satu pengaturan aplikasi berikut, tergantung pada jenis paket:

Jenis paket Nama pengaturan Komentar
Paket Konsumsi languageWorkers__java__arguments Pengaturan ini meningkatkan waktu mulai dingin untuk fungsi Java yang berjalan dalam paket Konsumsi.
Paket premium
Paket khusus
JAVA_OPTS

Bagian berikut ini memperlihatkan kepada Anda cara menambahkan pengaturan ini. Untuk mempelajari selengkapnya tentang bekerja dengan pengaturan aplikasi, lihat bagian Bekerja dengan pengaturan aplikasi.

Portal Azure

Di portal Azure, gunakan tab Pengaturan Aplikasi untuk menambahkan languageWorkers__java__arguments pengaturan atau JAVA_OPTS .

Azure CLI

Anda dapat menggunakan perintah az functionapp config appsettings set untuk menambahkan pengaturan ini, seperti yang ditunjukkan dalam contoh berikut untuk -Djava.awt.headless=true opsi:

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

Contoh ini memungkinkan mode tanpa induk. Ganti <APP_NAME> dengan nama aplikasi fungsi Anda, dan <RESOURCE_GROUP> dengan grup sumber daya.

Pustaka pihak ketiga

Azure Functions mendukung penggunaan pustaka pihak ketiga. Secara default, semua dependensi yang ditentukan dalam file pom.xml proyek secara otomatis digabungkan selama tujuan mvn package. Untuk pustaka yang tidak ditentukan sebagai dependensi dalam file pom.xml, masukkan di direktori lib di direktori akar fungsi. Dependensi yang ditempatkan di direktori lib ditambahkan ke pemuat kelas sistem pada runtime.

Dependensi com.microsoft.azure.functions:azure-functions-java-library disediakan pada classpath secara default, dan tidak perlu disertakan dalam direktori lib. Selain itu, azure-functions-java-worker menambahkan dependensi yang tercantum di sini ke classpath.

Dukungan jenis data

Anda dapat menggunakan jenis Plain old Java object (POJO) yang ditentukan di azure-functions-java-library, atau jenis data primitif seperti String dan Integer untuk mengikat pengikatan input atau output.

POJO

Untuk mengubah data input ke POJO, azure-functions-java-worker menggunakan pustaka gson. Jenis POJO yang digunakan sebagai input ke fungsi harus public.

Data biner

Ikat input atau output biner ke byte[], dengan mengatur bidang dataType di function.json Anda ke 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");
    }

Jika Anda mengharapkan nilai null, gunakan Optional<T>.

Pengikatan

Pengikatan input dan output memberikan cara deklaratif untuk menyambungkan ke data dari dalam kode Anda. Fungsi dapat memiliki beberapa pengikatan input dan output.

Contoh pengikatan input

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

Panggil fungsi ini dengan permintaan HTTP.

  • Payload permintaan HTTP diteruskan sebagai String untuk argumen inputReq.
  • Satu entri diambil dari penyimpanan Table, dan diteruskan sebagai TestInputData ke argumen inputData.

Untuk menerima sekumpulan input, Anda dapat mengikat String[], POJO[], List<String>, atau 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;
}

Fungsi ini dipicu setiap kali ada data baru di hub peristiwa yang dikonfigurasi. Karena cardinality ditetapkan ke MANY, fungsi tersebut menerima sekumpulan pesan dari hub peristiwa. EventData dari hub peristiwa dikonversi ke TestEventData untuk eksekusi fungsi.

Contoh pengikatan output

Anda dapat mengikat pengikatan output yang untuk mengembalikan nilai dengan menggunakan $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;
    }
}

Jika ada beberapa pengikatan output, gunakan nilai hasil hanya untuk salah satunya.

Untuk mengirim beberapa nilai output, gunakan OutputBinding<T> yang ditentukan dalam paket azure-functions-java-library.

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

Anda memanggil fungsi ini pada objek HttpRequest . Ini menulis beberapa nilai ke penyimpanan Queue.

HttpRequestMessage dan HttpResponseMessage

Ini ditentukan dalam azure-functions-java-library. Mereka adalah jenis pembantu untuk bekerja dengan fungsi HttpTrigger.

Jenis khusus Target Penggunaan umum
HttpRequestMessage<T> Pemicu HTTP Mendapatkan metode, header, atau kueri
HttpResponseMessage HTTP Output Pengikatan Mengembalikan status selain 200

Metadata

Beberapa pemicu mengirim metadata pemicu bersama dengan data input. Anda dapat menggunakan anotasi @BindingName untuk mengikat untuk memicu 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);
    }
}

Di contoh sebelumnya, queryValue terikat dengan parameter string kueri name di URL permintaan HTTP, http://{example.host}/api/metadata?name=test. Berikut adalah contoh lain, yang memperlihatkan cara mengikat Id dari metadata pemicu antrean.

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

Catatan

Nama yang disediakan dalam anotasi tersebut harus sesuai dengan properti metadata.

Konteks eksekusi

ExecutionContext, yang ditentukan dalam azure-functions-java-library, berisi metode helper untuk berkomunikasi dengan runtime fungsi. Untuk informasi selengkapnya, lihat artikel referensi ExecutionContext.

Pencatat

Gunakan getLogger, yang ditentukan dalam ExecutionContext, untuk menulis log dari kode fungsi.

Contoh:


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

Menampilkan log dan jejak

Anda dapat menggunakan Azure CLI untuk mengalirkan stdout Java dan pengelogan stderr, dan pengelogan aplikasi lainnya.

Berikut cara mengonfigurasi aplikasi fungsi Anda untuk menulis pengelogan aplikasi dengan menggunakan Azure CLI:

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

Untuk mengalirkan pengelogan output untuk aplikasi fungsi Anda dengan menggunakan Azure CLI, buka perintah, Bash, atau sesi Terminal baru, dan masukkan perintah berikut:

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

Perintah ekor log az webapp memiliki opsi untuk memfilter output dengan menggunakan opsi --provider.

Untuk mengunduh file log sebagai satu file ZIP dengan menggunakan Azure CLI, buka perintah, Bash, atau sesi Terminal baru, dan masukkan perintah berikut:

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

Anda harus mengaktifkan pengelogan sistem file di portal Microsoft Azure atau Azure CLI sebelum menjalankan perintah ini.

Variabel lingkungan

Di Azure Functions, pengaturan aplikasi, seperti string koneksi layanan, diekspos sebagai variabel lingkungan selama eksekusi. Anda dapat mengakses pengaturan ini dengan menggunakan, System.getenv("AzureWebJobsStorage").

Contoh berikut mendapatkan pengaturan aplikasi, dengan kunci bernama 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);
    }
}

Menggunakan injeksi dependensi di Java Functions

Azure Functions Java mendukung pola desain perangkat lunak injeksi dependensi (DI), yang merupakan teknik untuk mencapai Inversion of Control (IoC) antara kelas dan dependensinya. Java Azure Functions menyediakan kait untuk diintegrasikan dengan kerangka kerja Injeksi Dependensi populer di Aplikasi Functions Anda. Azure Functions Java SPI berisi antarmuka FunctionInstanceInjector. Dengan menerapkan antarmuka ini, Anda dapat mengembalikan instans kelas fungsi Anda dan fungsi Anda akan dipanggil pada instans ini. Ini memberikan kerangka kerja seperti Spring, Quarkus, Google Guice, Dagger, dll. kemampuan untuk membuat instans fungsi dan mendaftarkannya ke kontainer IOC mereka. Ini berarti Anda dapat menggunakan kerangka kerja Injeksi Dependensi tersebut untuk mengelola fungsi Anda secara alami.

Catatan

Jenis SPI Java Microsoft Azure Functions (azure-function-java-spi) adalah paket yang berisi semua antarmuka SPI bagi pihak ketiga untuk berinteraksi dengan runtime fungsi Microsoft Azure.

Injektor instans fungsi untuk injeksi dependensi

azure-function-java-spi berisi antarmuka 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; 

} 

Untuk contoh lebih lanjut yang menggunakan FunctionInstanceInjector untuk berintegrasi dengan kerangka kerja injeksi Dependensi, lihat repositori ini .

Langkah berikutnya

Untuk informasi selengkapnya tentang pengembangan Java Azure Functions, lihat sumber daya berikut ini: