From 69e29e347d99796ad583a3eaa193b03a9c826ea5 Mon Sep 17 00:00:00 2001 From: Christian Tzolov Date: Fri, 3 Mar 2023 10:36:35 +0100 Subject: [PATCH] Update the azure adapter doc - Add explanation for usiing Spring Cloud Function via the catalog (vs. plain bean) - minor text corrections. --- .../main/asciidoc/adapters/azure-intro.adoc | 86 ++++++++++++------- 1 file changed, 57 insertions(+), 29 deletions(-) diff --git a/docs/src/main/asciidoc/adapters/azure-intro.adoc b/docs/src/main/asciidoc/adapters/azure-intro.adoc index d47277cd2..230e1f6b7 100644 --- a/docs/src/main/asciidoc/adapters/azure-intro.adoc +++ b/docs/src/main/asciidoc/adapters/azure-intro.adoc @@ -2,40 +2,68 @@ === Microsoft Azure -The https://azure.microsoft.com[Azure] adapter bootstraps a Spring Cloud Function context and channels function calls from the Azure framework into the user functions, using Spring Boot configuration where necessary. -Azure Functions has quite a unique and invasive programming model, involving annotations in user code that are specific to the Azure platform. -However, it is important to understand that because of the style of integration provided by Spring Cloud Function, this annotation-based programming model is simply a type-safe way to configure your simple java function (function that has no awareness of Azure) to be recognized as Azure function. +The https://azure.microsoft.com[Azure] adapter bootstraps a Spring Cloud Function context and channels function calls from the Azure framework into the user functions, using Spring Boot configuration where necessary. +Azure Functions has quite a unique and invasive programming model, involving annotations in user code that are specific to the Azure platform. +However, it is important to understand that because of the style of integration provided by Spring Cloud Function, this annotation-based programming model is simply a type-safe way to configure your simple java function (function that has no awareness of Azure) to be recognized as Azure function. -All you need to annotate the your class with `@Component` or `@Service` annotations, auto-wire the required Spring Cloud Function beans, define and configure your Azure function handler. This Azure handler method provides input and output types as annotated method parameters (enabling Azure to inspect the class and create JSON bindings). +All you need to annotate the your class with `@Component` or `@Service` annotations, auto-wire the required Spring beans (or the `FunctionCatalog` when using Spring Cloud Function), define and configure your Azure function handler. This Azure handler method provides input and output types as annotated method parameters (enabling Azure to inspect the class and create JSON bindings). [source,java] ---- @Component public class MyAzureFunction { - @Autowired - private Function uppercase; + /** + * Plain Spring bean (not Spring Cloud Functions!) + */ + @Autowired + private Function uppercase; - @FunctionName("ditest") - public String execute( + /** + * The FunctionCatalog leverages the Spring Cloud Function framework. + */ + @Autowired + private FunctionCatalog functionCatalog; + + @FunctionName("bean") + public String plainBean( @HttpTrigger(name = "req", methods = { HttpMethod.GET, HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, ExecutionContext context) { return this.uppercase.apply(request.getBody().get()); } + + @FunctionName("scf") + public String springCloudFunction( + @HttpTrigger(name = "req", methods = { HttpMethod.GET, + 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"); + + return (String) composed.apply(request.getBody().get()); + } } ---- -Aside form providing configuration via Azure annotation, inside the body of this handler method we make use of the `uppercase` bean to compute the result. +The `plainBean` method will be mapped to the `bean` Azure function and when executed this method uses of the plain `uppercase` bean to compute the result. -The actual user function you're delagating to looks like this +The `springCloudFunction` method, mapped to the `scf` Azure function shows how to use the Spring Cloud Function composition. + +The actual Spring defined functions you're delegating to looks like this: [source,java] ---- @Bean public Function uppercase() { - return payload -> payload.toUpperCase(); + return payload -> payload.toUpperCase(); +} + +@Bean +public Function reverse() { + return payload -> new StringBuilder(payload).reverse().toString(); } ---- @@ -91,10 +119,10 @@ public Function, String> uppercase(JsonMapper mapper) { ==== Notes on JAR Layout -You don't need the Spring Cloud Function Web at runtime in Azure, so you can exclude this before you create the JAR you deploy to Azure, but it won't be used if you include it, so it doesn't hurt to leave it in. -A function application on Azure is an archive generated by the `azure-functions-maven-plugin` Maven plugin. -The function lives in the JAR file generated by this project. -The sample creates it as an executable jar, using the thin layout, so that Azure can find the handler classes. If you prefer you can just use a regular flat JAR file. +You don't need the Spring Cloud Function Web at runtime in Azure, so you can exclude this before you create the JAR you deploy to Azure, but it won't be used if you include it, so it doesn't hurt to leave it in. +A function application on Azure is an archive generated by the `azure-functions-maven-plugin` Maven plugin. +The function lives in the JAR file generated by this project. +The sample creates it as an executable jar, using the thin layout, so that Azure can find the handler classes. If you prefer you can just use a regular flat JAR file. The dependencies should *not* be included. ==== Build file setup @@ -120,7 +148,7 @@ You will need to provide Azure-specific configuration for your application, spec ${project.basedir}/src/main/resources/host.json - linux + linux 11 @@ -185,7 +213,7 @@ the cloud platform provider. ==== 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]). +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: @@ -213,7 +241,7 @@ and deploy Run the function in debug mode. ---- -./mvnw azure-functions:deploy -DenableDebug +./mvnw azure-functions:run -DenableDebug ---- Alternatively and the `JAVA_OPTS` value to your `local.settings.json` like this: @@ -244,19 +272,19 @@ VS Code remote debug configuration: "request": "attach", "hostName": "localhost", "port": "5005" - }, + }, } ---- ==== (Legacy) FunctionInvoker integration option -The https://azure.microsoft.com[Azure] adapter bootstraps a Spring Cloud Function context and channels function calls from the Azure -framework into the user functions, using Spring Boot configuration where necessary. Azure Functions has quite a unique and -invasive programming model, involving annotations in user code that are specific to the Azure platform. -However, it is important to understand that because of the style of integration provided by Spring Cloud Function, specifically `org.springframework.cloud.function.adapter.azure.FunctionInvoker`, this annotation-based programming model is simply a type-safe way to configure -your simple java function (function that has no awareness of Azure) to be recognized as Azure function. -All you need to do is create a handler that extends `FunctionInvoker`, define and configure your function handler method and -make a callback to `handleRequest(..)` method. This handler method provides input and output types as annotated method parameters +The https://azure.microsoft.com[Azure] adapter bootstraps a Spring Cloud Function context and channels function calls from the Azure +framework into the user functions, using Spring Boot configuration where necessary. Azure Functions has quite a unique and +invasive programming model, involving annotations in user code that are specific to the Azure platform. +However, it is important to understand that because of the style of integration provided by Spring Cloud Function, specifically `org.springframework.cloud.function.adapter.azure.FunctionInvoker`, this annotation-based programming model is simply a type-safe way to configure +your simple java function (function that has no awareness of Azure) to be recognized as Azure function. +All you need to do is create a handler that extends `FunctionInvoker`, define and configure your function handler method and +make a callback to `handleRequest(..)` method. This handler method provides input and output types as annotated method parameters (enabling Azure to inspect the class and create JSON bindings). @@ -273,7 +301,7 @@ public class UppercaseHandler extends FunctionInvoker, String> { } ``` -Note that aside form providing configuration via Azure annotation we create an instance of `Message` inside the body of this handler method and make a callback to `handleRequest(..)` method returning its result. +Note that aside form providing configuration via Azure annotation we create an instance of `Message` inside the body of this handler method and make a callback to `handleRequest(..)` method returning its result. The actual user function you're delagating to looks like this @@ -292,9 +320,9 @@ public Function, String> uppercase() { ``` -Note that when creating a Message you can copy HTTP headers effectively making them available to you if necessary. +Note that when creating a Message you can copy HTTP headers effectively making them available to you if necessary. -The `org.springframework.cloud.function.adapter.azure.FunctionInvoker` class has two useful +The `org.springframework.cloud.function.adapter.azure.FunctionInvoker` class has two useful methods (`handleRequest` and `handleOutput`) to which you can delegate the actual function call, so mostly the function will only ever have one line. The function name (definition) will be retrieved from Azure's `ExecutionContext.getFunctionName()` method, effectively supporting multiple function in the application context.