Files
spring-cloud-function/spring-cloud-function-samples/function-azure-di-samples/README.md
Christian Tzolov 8f1d063637 GH-968 Support Azure Functions DI hook
- Extend spring-cloud-function-adapter-azure with AzureFunctionInstanceInjector registered through the  META-INF/services/com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector
 - Add DI demos for HttpTrigger and TimeTrigger functions.

 Resolves #968
 Resolves #969
Add FunctionInvoker backward compatibiity

document the time trigger DI sample

Add generic instructions to implement Azure Function with the help of the DI hook

Add generic instructions to implement Azure Function with the help of the DI hook

Minor

Fix injector backward compatibility and add blob demo

disable the azure di samples maven module builds
2022-12-15 11:00:41 +01:00

5.8 KiB

Azure Functions with DI adapter

Common instructions to integrate Azure Functions with Spring Framework

  • Use the Spring Initializer to generate a pain, java Spring Boot project without additional dependencies. Set the boot version to 2.7.x, the build to Maven and the packaging to Jar.

  • Add the spring-cloud-function-adapter-azure POM dependency:

    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-function-adapter-azure</artifactId>
    	<version>3.2.9 or higher</version>
    </dependency>
    

    Having the adapter on the classpath activates the Azure Java Worker integration.

  • Implement the Azure Java Functions as @FunctionName annotated methods:

    import java.util.Optional;
    import java.util.function.Function;
    
    import com.microsoft.azure.functions.ExecutionContext;
    import com.microsoft.azure.functions.HttpMethod;
    import com.microsoft.azure.functions.HttpRequestMessage;
    import com.microsoft.azure.functions.annotation.AuthorizationLevel;
    import com.microsoft.azure.functions.annotation.FunctionName;
    import com.microsoft.azure.functions.annotation.HttpTrigger;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @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());
    	}
    }
    
    • The @FunctionName annotated methods represent the Azure Function implementations.
    • The class must be marked with the Spring @Component annotation.
    • You can use any Spring mechanism to auto-wire the Spring beans used for the function implementation.
  • Add the host.json configuration under the src/main/resources folder:

    {
    	"version": "2.0",
    	"extensionBundle": {
    		"id": "Microsoft.Azure.Functions.ExtensionBundle",
    		"version": "[3.*, 4.0.0)"
    	}
    }
    
  • When bootstrapped as Spring Boot project make sure to either disable the spring-boot-maven-plugin plugin or cover it into thin-layout:

    <plugin>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-maven-plugin</artifactId>
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.boot.experimental</groupId>
    			<artifactId>spring-boot-thin-layout</artifactId>
    			<version>${spring-boot-thin-layout.version}</version>
    		</dependency>
    	</dependencies>
    </plugin>
    

    Since Azure Functions requires a specific, custom, Jar packaging we have to disable SpringBoot one.

  • Add the azure-functions-maven-plugin to your POM configuration. A sample configuration would look like this.

    <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>
    
    • Set the AZURE subscription configuration such as app name, resource group, region, service plan, pricing Tier
    • Runtime configuration:
  • Build the project:

    ./mvnw clean package
    

Running Locally

NOTE: 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 here). For some configuration you would need the Azurite emulator as well.

Then build and run the sample:

./mvnw clean package
./mvnw azure-functions:run

Running on Azure

Make sure you are logged in your Azure account.

az login

Build and deploy

./mvnw clean package
./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:

{
	"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:

```json
{
	"version": "0.2.0",
	"configurations": [
		{
			"type": "java",
			"name": "Attach to Remote Program",
			"request": "attach",
			"hostName": "localhost",
			"port": "5005"
		},  
}
	
```