committed by
Oleg Zhurakousky
parent
65b17b820c
commit
d5bff8e7ee
@@ -2,6 +2,254 @@
|
||||
|
||||
=== 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.
|
||||
|
||||
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).
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Component
|
||||
public class MyAzureFunction {
|
||||
|
||||
@Autowired
|
||||
private Function<String, String> uppercase;
|
||||
|
||||
@FunctionName("ditest")
|
||||
public String execute(
|
||||
@HttpTrigger(name = "req", methods = { HttpMethod.GET,
|
||||
HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
|
||||
ExecutionContext context) {
|
||||
|
||||
return this.uppercase.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 actual user function you're delagating to looks like this
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public Function<String, String> uppercase() {
|
||||
return payload -> payload.toUpperCase();
|
||||
}
|
||||
----
|
||||
|
||||
In order to enable the Azure Function integration add the azure adapter dependency to your `pom.xml`
|
||||
file:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-function-adapter-azure</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
----
|
||||
|
||||
Note: version `4.0.0+` is requried. Having the adapter on the classpath activates the Azure Java Worker integration.
|
||||
|
||||
==== 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("ditest")
|
||||
public String execute(
|
||||
@HttpTrigger(name = "req", methods = { HttpMethod.GET,
|
||||
HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
|
||||
ExecutionContext context) {
|
||||
|
||||
Message message = AzureFunctionUtil.enhanceInputIfNecessary(request.getBody().get(), context);
|
||||
|
||||
return this.uppercase.apply(message);
|
||||
}
|
||||
----
|
||||
|
||||
now you can retrieve it via the via `executionContext` key.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public Function<Message<String>, String> uppercase(JsonMapper mapper) {
|
||||
return message -> {
|
||||
String value = message.getPayload();
|
||||
ExecutionContext context = (ExecutionContext) message.getHeaders().get("executionContext");
|
||||
. . .
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
==== 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.
|
||||
The dependencies should *not* be included.
|
||||
|
||||
==== Build file setup
|
||||
|
||||
In order to run Spring Cloud Function applications on Microsoft Azure, you can leverage the `azure-functions-maven-plugin` Maven plugin offered by the cloud platform provider.
|
||||
|
||||
You will need to provide Azure-specific configuration for your application, specifying the `resourceGroup`, `appName` and other optional properties, and add the `package` goal execution so that the `function.json` file required by Azure is generated for you. Full plugin documentation can be found in the https://github.com/microsoft/azure-maven-plugins[plugin repository].
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<plugin>
|
||||
<groupId>com.microsoft.azure</groupId>
|
||||
<artifactId>azure-functions-maven-plugin</artifactId>
|
||||
<version>1.22.0 or higher</version>
|
||||
|
||||
<configuration>
|
||||
<appName>YOUR-AZURE-FUNCTION-APP-NAME</appName>
|
||||
<resourceGroup>YOUR-AZURE-FUNCTION-RESOURCE-GROUP</resourceGroup>
|
||||
<region>YOUR-AZURE-FUNCTION-APP-REGION</region>
|
||||
<appServicePlanName>YOUR-AZURE-FUNCTION-APP-SERVICE-PLANE-NAME</appServicePlanName>
|
||||
<pricingTier>YOUR-AZURE-FUNCTION-PRICING-TIER</pricingTier>
|
||||
|
||||
<hostJson>${project.basedir}/src/main/resources/host.json</hostJson>
|
||||
|
||||
<runtime>
|
||||
<os>linux</os>
|
||||
<javaVersion>11</javaVersion>
|
||||
</runtime>
|
||||
|
||||
<funcPort>7072</funcPort>
|
||||
|
||||
<appSettings>
|
||||
<property>
|
||||
<name>FUNCTIONS_EXTENSION_VERSION</name>
|
||||
<value>~4</value>
|
||||
</property>
|
||||
</appSettings>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>package-functions</id>
|
||||
<goals>
|
||||
<goal>package</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
----
|
||||
|
||||
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]
|
||||
|
||||
Add the `start-class` POM property to point to your main (e.g. SpringApplication) class.
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<start-class>YOUR MAIN CLASS</start-class>
|
||||
...
|
||||
</properties>
|
||||
----
|
||||
|
||||
You will also have to ensure that the files to be scanned by the plugin can be found in the Azure functions staging directory (see the https://github.com/microsoft/azure-maven-plugins[plugin repository] for more details on the staging directory and it's default location).
|
||||
|
||||
Add the `host.json` configuration under the `src/main/resources` folder:
|
||||
|
||||
[source,json]
|
||||
----
|
||||
{
|
||||
"version": "2.0",
|
||||
"extensionBundle": {
|
||||
"id": "Microsoft.Azure.Functions.ExtensionBundle",
|
||||
"version": "[3.*, 4.0.0)"
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
You can find the entire sample `pom.xml` file for deploying Spring Cloud Function applications to Microsoft Azure with Maven https://github.com/spring-cloud/spring-cloud-function/blob/{branch}/spring-cloud-function-samples/function-azure-di-samples/azure-blob-trigger-demo/pom.xml[here].
|
||||
|
||||
NOTE: As of yet, only Maven plugin is available. Gradle plugin has not been created by
|
||||
the cloud platform provider.
|
||||
|
||||
==== Build
|
||||
|
||||
----
|
||||
./mvnw -U clean package
|
||||
----
|
||||
|
||||
==== 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:
|
||||
|
||||
----
|
||||
./mvnw azure-functions:run
|
||||
----
|
||||
|
||||
==== Running on Azure
|
||||
|
||||
Make sure you are logged in your Azure account.
|
||||
|
||||
----
|
||||
az login
|
||||
----
|
||||
|
||||
and deploy
|
||||
|
||||
----
|
||||
./mvnw azure-functions:deploy
|
||||
----
|
||||
|
||||
==== Debug locally
|
||||
|
||||
Run the function in debug mode.
|
||||
|
||||
----
|
||||
./mvnw azure-functions:deploy -DenableDebug
|
||||
----
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
VS Code remote debug configuration:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "java",
|
||||
"name": "Attach to Remote Program",
|
||||
"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.
|
||||
|
||||
Reference in New Issue
Block a user