Update the azure adapter doc

- Add explanation for usiing Spring Cloud Function via the catalog (vs. plain bean)
 - minor text corrections.
This commit is contained in:
Christian Tzolov
2023-03-03 10:36:35 +01:00
parent ebd8b3138b
commit 69e29e347d

View File

@@ -2,40 +2,68 @@
=== Microsoft Azure === 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. 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. 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. 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] [source,java]
---- ----
@Component @Component
public class MyAzureFunction { public class MyAzureFunction {
@Autowired /**
private Function<String, String> uppercase; * Plain Spring bean (not Spring Cloud Functions!)
*/
@Autowired
private Function<String, String> 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, @HttpTrigger(name = "req", methods = { HttpMethod.GET,
HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request, HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
ExecutionContext context) { ExecutionContext context) {
return this.uppercase.apply(request.getBody().get()); return this.uppercase.apply(request.getBody().get());
} }
@FunctionName("scf")
public String springCloudFunction(
@HttpTrigger(name = "req", methods = { HttpMethod.GET,
HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> 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] [source,java]
---- ----
@Bean @Bean
public Function<String, String> uppercase() { public Function<String, String> uppercase() {
return payload -> payload.toUpperCase(); return payload -> payload.toUpperCase();
}
@Bean
public Function<String, String> reverse() {
return payload -> new StringBuilder(payload).reverse().toString();
} }
---- ----
@@ -91,10 +119,10 @@ public Function<Message<String>, String> uppercase(JsonMapper mapper) {
==== Notes on JAR Layout ==== 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. 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. 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 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 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. The dependencies should *not* be included.
==== Build file setup ==== Build file setup
@@ -120,7 +148,7 @@ You will need to provide Azure-specific configuration for your application, spec
<hostJson>${project.basedir}/src/main/resources/host.json</hostJson> <hostJson>${project.basedir}/src/main/resources/host.json</hostJson>
<runtime> <runtime>
<os>linux</os> <os>linux</os>
<javaVersion>11</javaVersion> <javaVersion>11</javaVersion>
</runtime> </runtime>
@@ -185,7 +213,7 @@ the cloud platform provider.
==== 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]). 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. 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: Then run the sample:
@@ -213,7 +241,7 @@ and deploy
Run the function in debug mode. 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: Alternatively and the `JAVA_OPTS` value to your `local.settings.json` like this:
@@ -244,19 +272,19 @@ VS Code remote debug configuration:
"request": "attach", "request": "attach",
"hostName": "localhost", "hostName": "localhost",
"port": "5005" "port": "5005"
}, },
} }
---- ----
==== (Legacy) FunctionInvoker integration option ==== (Legacy) FunctionInvoker integration option
The https://azure.microsoft.com[Azure] adapter bootstraps a Spring Cloud Function context and channels function calls from the 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 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. 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 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. 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 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 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). (enabling Azure to inspect the class and create JSON bindings).
@@ -273,7 +301,7 @@ public class UppercaseHandler extends FunctionInvoker<Message<String>, 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 The actual user function you're delagating to looks like this
@@ -292,9 +320,9 @@ public Function<Message<String>, 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. 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. The function name (definition) will be retrieved from Azure's `ExecutionContext.getFunctionName()` method, effectively supporting multiple function in the application context.