[[microsoft-azure-functions]] = Microsoft Azure Functions :page-aliases: adapters/azure.adoc https://azure.microsoft.com[Azure] function adapter for deploying `Spring Cloud Function` applications as native Azure Java Functions. The `Azure Functions` https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-java[programming model] relays, extensively, on Java https://learn.microsoft.com/en-us/java/api/com.microsoft.azure.functions.annotation?view=azure-java-stable[annotations] for defining the function's handler methods and their input and output types. At compile time the annotated classes are processed by the provided Azure Maven/Gradle plugins to generate the necessary Azure Function binding files, configurations and package artifacts. The Azure annotations are just a type-safe way to configure your java function to be recognized as Azure function. The https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-adapters/spring-cloud-function-adapter-azure[spring-cloud-function-adapter-azure] extends the basic programming model to provide Spring and Spring Cloud Function support. With the adapter you can build your Spring Cloud Function application using dependency injections and then auto-wire the necessary services into your Azure handler methods. image::{github-raw}/docs/src/main/asciidoc/images/scf-azure-adapter.svg[width=800,scaledwidth="75%",align="center"] TIP: For Web-based function applications, you can replace the generic `adapter-azure` with the specialized https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-adapters/spring-cloud-function-adapter-azure-web[spring-cloud-function-adapter-azure-web]. With the Azure Web Adapter you can deploy any Spring Web application as an Azure, HttpTrigger, function. This adapter hides the Azure annotations complexity and uses the familiar https://docs.spring.io/spring-boot/docs/current/reference/html/web.html[Spring Web] programming model instead. For further information follow the xref:adapters/azure-intro.adoc#azure.web.adapter[Azure Web Adapter] section below. [[azure-adapter]] == Azure Adapter Provides `Spring` & `Spring Cloud Function` integration for Azure Functions. [[dependencies]] === Dependencies In order to enable the Azure Function integration add the azure adapter dependency to your `pom.xml` or `build.gradle` files: [tabs] ====== Maven:: + [source,xml,indent=0,subs="verbatim,attributes",role="primary"] ---- org.springframework.cloud spring-cloud-function-adapter-azure ---- Gradle:: + [source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] ---- dependencies { implementation 'org.springframework.cloud:spring-cloud-function-adapter-azure' } ---- ====== NOTE: version `4.0.0+` is required. Having the adapter on the classpath activates the Azure Java Worker integration. [[azure.development.guidelines]] === Development Guidelines Use the `@Component` (or `@Service`) annotation to turn any exiting Azure Function class (e.g. with `@FunctionName` handlers) into a Spring component. Then you can auto-wire the required dependencies (or the xref:spring-cloud-function/programming-model.adoc#function.catalog[Function Catalog] for Spring Cloud Function composition) and use those inside the Azure function handlers. [source,java] ---- @Component // <1> public class MyAzureFunction { // Plain Spring bean - not a Spring Cloud Functions! @Autowired private Function uppercase; // <2> // The FunctionCatalog leverages the Spring Cloud Function framework. @Autowired private FunctionCatalog functionCatalog; // <2> @FunctionName("spring") // <3> public String plainBean( // <4> @HttpTrigger(name = "req", methods = { HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, ExecutionContext context) { return this.uppercase.apply(request.getBody().get()); } @FunctionName("scf") // <3> public String springCloudFunction( // <5> @HttpTrigger(name = "req", methods = { HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, ExecutionContext context) { // Use SCF composition. Composed functions are not just spring beans but SCF such. Function composed = this.functionCatalog.lookup("reverse|uppercase"); // <6> return (String) composed.apply(request.getBody().get()); } } ---- <1> Indicates that the `MyAzureFunction` class is a "component" to be considered by the Spring Framework as a candidate for auto-detection and classpath scanning. <2> Auto-wire the `uppercase` and `functionCatalog` beans defined in the `HttpTriggerDemoApplication` (below). <3> The https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-java?tabs=bash%2Cconsumption#java-function-basics[@FunctionName] annotation identifies the designated Azure function handlers. When invoked by a trigger (such as `@HttpTrigger`), functions process that trigger, and any other inputs, to produce one or more outputs. <4> The `plainBean` method handler is mapped to an Azure function that uses of the auto-wired `uppercase` spring bean to compute the result. It demonstrates how to use "plain" Spring components in your Azure handlers. <5> The `springCloudFunction` method handler is mapped to another Azure function, that uses the auto-wired `FunctionCatalog` instance to compute the result. <6> Shows how to leverage the Spring Cloud Function xref:spring-cloud-function/programming-model.adoc#function.catalog[Function Catalog] composition API. TIP: Use the Java annotations included in the https://learn.microsoft.com/en-us/java/api/com.microsoft.azure.functions.annotation?view=azure-java-stable[com.microsoft.azure.functions.annotation.*] package to bind input and outputs to your methods. The implementation of the business logic used inside the Azure handlers looks like a common Spring application: [[HttpTriggerDemoApplication]] [source,java] ---- @SpringBootApplication // <1> public class HttpTriggerDemoApplication { public static void main(String[] args) { SpringApplication.run(HttpTriggerDemoApplication.class, args); } @Bean public Function uppercase() { // <2> return payload -> payload.toUpperCase(); } @Bean public Function reverse() { // <2> return payload -> new StringBuilder(payload).reverse().toString(); } } ---- <1> The `@SpringBootApplication` annotated class is used as a `Main-Class` as explained in xref:adapters/azure-intro.adoc#star-class-configuration[main class configuration]. <2> Functions auto-wired and used in the Azure function handlers. [[function-catalog]] === Function Catalog The Spring Cloud Function supports a range of type signatures for user-defined functions, while providing a consistent execution model. For this it uses the xref:spring-cloud-function/programming-model.adoc#function.catalog[Function Catalog] to transform all user defined functions into a canonical representation. The Azure adapter can auto-wire any Spring component, such as the `uppercase` above. But those are treated as plain Java class instances, not as a canonical Spring Cloud Functions! To leverage Spring Cloud Function and have access to the canonical function representations, you need to auto-wire the `FunctionCatalog` and use it in your handler, like the `functionCatalog` instance the `springCloudFunction()` handler above. [[accessing-azure-executioncontext]] === Accessing Azure ExecutionContext Some time there is a need to access the target execution context provided by the Azure runtime in the form of `com.microsoft.azure.functions.ExecutionContext`. For example one of such needs is logging, so it can appear in the Azure console. For that purpose the `AzureFunctionUtil.enhanceInputIfNecessary` allow you to add an instance of the `ExecutionContext` as a Message header so you can retrieve it via `executionContext` key. [source,java] ---- @FunctionName("myfunction") public String execute( @HttpTrigger(name = "req", methods = { HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, ExecutionContext context) { Message message = (Message) AzureFunctionUtil.enhanceInputIfNecessary(request.getBody().get(), context); // <1> return this.uppercase.apply(message); } ---- <1> Leverages the `AzureFunctionUtil` utility to inline the `context` as message header using the `AzureFunctionUtil.EXECUTION_CONTEXT` header key. Now you can retrieve the ExecutionContext from message headers: [source,java] ---- @Bean public Function, String> uppercase(JsonMapper mapper) { return message -> { String value = message.getPayload(); ExecutionContext context = (ExecutionContext) message.getHeaders().get(AzureFunctionUtil.EXECUTION_CONTEXT); // <1> . . . } } ---- <1> Retrieve the ExecutionContext instance from the header. [[azure.configuration]] == Configuration To run your function applications on Microsoft Azure, you have to provide the necessary configurations, such as `function.json` and `host.json`, and adhere to the compulsory https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-java?tabs=bash%2Cconsumption#folder-structure[packaging format]. Usually the Azure Maven (or Gradle) plugins are used to generate the necessary configurations from the annotated classes and to produce the required package format. IMPORTANT: The Azure https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-java?tabs=bash%2Cconsumption#folder-structure[packaging format] is not compatible with the default Spring Boot packaging (e.g. `uber jar`). The xref:adapters/azure-intro.adoc#disable.spring.boot.plugin[Disable Spring Boot Plugin] section below explains how to handle this. [[azure-maven-gradle-plugins]] === Azure Maven/Gradle Plugins Azure provides https://github.com/microsoft/azure-maven-plugins/tree/develop/azure-functions-maven-plugin[Maven] and https://github.com/microsoft/azure-gradle-plugins/tree/master/azure-functions-gradle-plugin[Gradle] plugins to process the annotated classes, generate the necessary configurations and produce the expected package layout. Plugins are used to set the platform, runtime and app-settings properties like this: [tabs] ====== Maven:: + [source,xml,indent=0,subs="verbatim,attributes",role="primary"] ---- com.microsoft.azure azure-functions-maven-plugin 1.22.0 or higher YOUR-AZURE-FUNCTION-APP-NAME YOUR-AZURE-FUNCTION-RESOURCE-GROUP YOUR-AZURE-FUNCTION-APP-REGION YOUR-AZURE-FUNCTION-APP-SERVICE-PLANE-NAME YOUR-AZURE-FUNCTION-PRICING-TIER ${project.basedir}/src/main/resources/host.json linux 11 FUNCTIONS_EXTENSION_VERSION ~4 package-functions package ---- Gradle:: + [source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] ---- plugins { id "com.microsoft.azure.azurefunctions" version "1.11.0" // ... } apply plugin: "com.microsoft.azure.azurefunctions" azurefunctions { appName = 'YOUR-AZURE-FUNCTION-APP-NAME' resourceGroup = 'YOUR-AZURE-FUNCTION-RESOURCE-GROUP' region = 'YOUR-AZURE-FUNCTION-APP-REGION' appServicePlanName = 'YOUR-AZURE-FUNCTION-APP-SERVICE-PLANE-NAME' pricingTier = 'YOUR-AZURE-FUNCTION-APP-SERVICE-PLANE-NAME' runtime { os = 'linux' javaVersion = '11' } auth { type = 'azure_cli' } appSettings { FUNCTIONS_EXTENSION_VERSION = '~4' } // Uncomment to enable local debug // localDebug = "transport=dt_socket,server=y,suspend=n,address=5005" } ---- ====== More information about the runtime configurations: https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-java?tabs=bash%2Cconsumption#java-versions[Java Versions], https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-java?tabs=bash%2Cconsumption#specify-the-deployment-os[Deployment OS]. [[disable.spring.boot.plugin]] === Disable Spring Boot Plugin Expectedly, the Azure Functions run inside the Azure execution runtime, not inside the SpringBoot runtime! Furthermore, Azure expects a specific packaging format, generated by the Azure Maven/Gradle plugins, that is not compatible with the default Spring Boot packaging. You have to either disable the SpringBoot Maven/Gradle plugin or use the https://github.com/dsyer/spring-boot-thin-launcher[Spring Boot Thin Launcher] as shown in this Maven snippet: [source,xml] ---- org.springframework.boot spring-boot-maven-plugin org.springframework.boot.experimental spring-boot-thin-layout ---- [[star-class-configuration]] === Main-Class Configuration Specify the `Main-Class`/`Start-Class` to point to your Spring application entry point, such as the xref:adapters/azure-intro.adoc#HttpTriggerDemoApplication[HttpTriggerDemoApplication] class in the example above. You can use the Maven `start-class` property or set the `Main-Class` attribute of your `MANIFEST/META-INFO`: [tabs] ====== Maven:: + [source,xml,indent=0,subs="verbatim,attributes",role="primary"] ---- YOUR APP MAIN CLASS ... ---- Gradle:: + [source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] ---- jar { manifest { attributes( "Main-Class": "YOUR-APP-MAIN-CLASS" ) } } ---- ====== TIP: Alternatively you can use the `MAIN_CLASS` environment variable to set the class name explicitly. For local runs, add the `MAIN_CLASS` variable to your `local.settings.json` file and for Azure portal deployment set the variable in the https://learn.microsoft.com/en-us/azure/azure-functions/functions-how-to-use-azure-function-app-settings?tabs=portal#get-started-in-the-azure-portal[App Settings]. IMPORTANT: If the `MAIN_CLASS` variable is not set, the Azure adapter lookups the `MANIFEST/META-INFO` attributes from the jars found on the classpath and selects the first `Main-Class:` annotated with either a `@SpringBootApplication` or `@SpringBootConfiguration` annotation. [[metadata-configuration]] === Metadata Configuration You can use a shared https://learn.microsoft.com/en-us/azure/azure-functions/functions-host-json[host.json] file to configure the function app. [source,json] ---- { "version": "2.0", "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[4.*, 5.0.0)" } } ---- The host.json metadata file contains configuration options that affect all functions in a function app instance. TIP: If the file is not in the project top folder you need to configure your plugins accordingly (like `hostJson` maven attribute). [[samples]] == Samples Here is a list of various Spring Cloud Function Azure Adapter samples you can explore: - https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-samples/function-sample-azure-http-trigger[Http Trigger (Maven)] - https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-samples/function-sample-azure-http-trigger-gradle[Http Trigger (Gradle)] - https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-samples/function-sample-azure-blob-trigger[Blob Trigger (Maven)] - https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-samples/function-sample-azure-timer-trigger[Timer Trigger (Maven)] - https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-samples/function-sample-azure-kafka-trigger[ Kafka Trigger & Output Binding (Maven)]. [[azure.web.adapter]] == Azure Web Adapter For, pure, Web-based function applications, you can replace the generic `adapter-azure` with the specialized https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-adapters/spring-cloud-function-adapter-azure-web[spring-cloud-function-adapter-azure-web]. The Azure Web Adapter can deploy any Spring Web application as a native Azure function, using the HttpTrigger internally. It hides the Azure annotations complexity and relies on the familiar https://docs.spring.io/spring-boot/docs/current/reference/html/web.html[Spring Web] programming model instead. To enable the Azure Web Adapter, add the adapter dependency to your `pom.xml` or `build.gradle` files: [tabs] ====== Maven:: + [source,xml,indent=0,subs="verbatim,attributes",role="primary"] ---- org.springframework.cloud spring-cloud-function-adapter-azure-web ---- Gradle:: + [source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] ---- dependencies { implementation 'org.springframework.cloud:spring-cloud-function-adapter-azure-web' } ---- ====== The same xref:adapters/azure-intro.adoc#azure.configuration[Configuration] and xref:adapters/azure-intro.adoc#azure.usage[Usage] instructions apply to the `Azure Web Adapter` as well. == Azure Samples For further information, explore the following, Azure Web Adapter, sample: - https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-samples/function-sample-azure-web[ Azure Web Adapter (Maven)]. [[azure.usage]] == Usage Common instructions for building and deploying both, `Azure Adapter` and `Azure Web Adapter` type of applications. [[build]] == Build [tabs] ====== Maven:: + [source,xml,indent=0,subs="verbatim,attributes",role="primary"] ---- ./mvnw -U clean package ---- Gradle:: + [source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] ---- ./gradlew azureFunctionsPackage ---- ====== [[running-locally]] == Running locally To run locally on top of `Azure Functions`, and to deploy to your live Azure environment, you will need `Azure Functions Core Tools` installed along with the Azure CLI (see https://docs.microsoft.com/en-us/azure/azure-functions/create-first-function-cli-java?tabs=bash%2Cazure-cli%2Cbrowser#configure-your-local-environment[here]). For some configuration you would need the https://learn.microsoft.com/en-us/azure/storage/common/storage-use-emulator[Azurite emulator] as well. Then run the sample: [tabs] ====== Maven:: + [source,xml,indent=0,subs="verbatim,attributes",role="primary"] ---- ./mvnw azure-functions:run ---- Gradle:: + [source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] ---- ./gradlew azureFunctionsRun ---- ====== [[running-on-azure]] == Running on Azure Make sure you are logged in your Azure account. ---- az login ---- and deploy [tabs] ====== Maven:: + [source,xml,indent=0,subs="verbatim,attributes",role="primary"] ---- ./mvnw azure-functions:deploy ---- Gradle:: + [source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] ---- ./gradlew azureFunctionsDeploy ---- ====== [[debug-locally]] == Debug locally Run the function in debug mode. [tabs] ====== Maven:: + [source,xml,indent=0,subs="verbatim,attributes",role="primary"] ---- ./mvnw azure-functions:run -DenableDebug ---- Gradle:: + [source,groovy,indent=0,subs="verbatim,attributes",role="secondary"] ---- // If you want to debug your functions, please add the following line // to the azurefunctions section of your build.gradle. azurefunctions { ... localDebug = "transport=dt_socket,server=y,suspend=n,address=5005" } ---- ====== Alternatively and the `JAVA_OPTS` value to your `local.settings.json` like this: [source,json] ---- { "IsEncrypted": false, "Values": { ... "FUNCTIONS_WORKER_RUNTIME": "java", "JAVA_OPTS": "-Djava.net.preferIPv4Stack=true -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=127.0.0.1:5005" } } ---- Here is snippet for a `VSCode` remote debugging configuration: [source,json] ---- { "version": "0.2.0", "configurations": [ { "type": "java", "name": "Attach to Remote Program", "request": "attach", "hostName": "localhost", "port": "5005" }, ] } ---- [[functioninvoker-deprecated]] == FunctionInvoker (deprecated) WARNING: The legacy `FunctionInvoker` programming model is deprecated and will not be supported going forward. For additional documentation and samples about the Function Integration approach follow the https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-samples/function-sample-azure/[azure-sample] README and code. [[relevant-links]] == Relevant Links - https://learn.microsoft.com/en-us/azure/developer/java/spring-framework/getting-started-with-spring-cloud-function-in-azure[Spring Cloud Function in Azure] - https://spring.io/blog/2023/02/24/spring-cloud-function-for-azure-function[Spring Cloud Function for Azure Function (blog)] - <> - https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-java?tabs=bash%2Cconsumption[Azure Functions Java developer guide] - https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference?tabs=blob[Azure Functions developer guide] :sectnums!: