-
Notifications
You must be signed in to change notification settings - Fork 62
Dependency Injection on Azure Functions Java
azure-function-java-spi contains an interface FunctionInstanceInjector
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for
* license information.
*/
package com.microsoft.azure.functions.spi.inject;
/**
* The instance factory used by DI framework to initialize function instance.
*
* @since 1.0.0
*/
public interface FunctionInstanceInjector {
/**
* This method is used by DI framework to initialize the function instance. This method takes in the customer class and returns
* an instance create by the DI framework, later customer functions will be invoked on this instance.
* @param functionClass the class that contains customer functions
* @param <T> customer functions class type
* @return the instance that will be invoked on by azure functions java worker
* @throws Exception any exception that is thrown by the DI framework during instance creation
*/
<T> T getInstance(Class<T> functionClass) throws Exception;
}
By implementing this interface, you can return an instance of your function class and your functions will be invoked on this instance. This gives frameworks like Spring, Quarkus, Google Juice, Dagger, etc the ability to create the function instance and register it into their IOC container. This means you can use those Dependency Injection frameworks to manage your functions naturally.
Below are examples using FunctionInstanceInjector
to integrate with Google Juice and Dagger. Examples on github
The FunctionGuiceFactory
class that implement FunctionInstanceInjector
interface
package com.azfs.dihook;
import com.google.inject.Guice;
import com.azfs.BasicModule;
import com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector;
public class FunctionGuiceFactory implements FunctionInstanceInjector {
@Override
public <T> T getInstance(Class<T> functionClass) throws Exception {
return Guice.createInjector(new BasicModule()).getInstance(functionClass);
}
}
Function.class
that contains the functions. We use @Inject
annotation to autowire the Communicator
here which used latter to send out an message.
package com.azfs;
import com.google.inject.Inject;
import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.HttpMethod;
import com.microsoft.azure.functions.HttpRequestMessage;
import com.microsoft.azure.functions.HttpResponseMessage;
import com.microsoft.azure.functions.HttpStatus;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;
import java.util.Optional;
/**
* Azure Functions with HTTP Trigger.
*/
public class Function {
/**
* This function listens at endpoint "/api/HttpExample". Two ways to invoke it using "curl" command in bash:
* 1. curl -d "HTTP Body" {your host}/api/HttpExample
* 2. curl "{your host}/api/HttpExample?name=HTTP%20Query"
*/
@Inject
public Communicator communicator;
@FunctionName("HttpExample")
public HttpResponseMessage run(
@HttpTrigger(
name = "req",
methods = {HttpMethod.GET, HttpMethod.POST},
authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
// Parse query parameter
final String query = request.getQueryParameters().get("name");
final String name = request.getBody().orElse(query);
//use the injected communicator to send out message
communicator.sendMessage(context);
if (name == null) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
} else {
return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
}
}
}
You can find full code for this example at here
MyFunctionInstanceInjector
implement the 'FunctionInstanceInjector ' interface to return an instance of the Function.class
.
package com.azfs.dihook;
import com.azfs.component.DaggerFunctionComponent;
import com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector;
public class MyFunctionInstanceInjector implements FunctionInstanceInjector {
@Override
public <T> T getInstance(Class<T> aClass) throws Exception {
return (T) DaggerFunctionComponent.create().buildFunction();
}
}
The Function.class
that contains the functions. We use @Inject
annotation on the constructor to inject the communicator.
package com.azfs;
import com.azfs.model.Communicator;
import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.HttpMethod;
import com.microsoft.azure.functions.HttpRequestMessage;
import com.microsoft.azure.functions.HttpResponseMessage;
import com.microsoft.azure.functions.HttpStatus;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;
import javax.inject.Inject;
import java.util.Optional;
/**
* Azure Functions with HTTP Trigger.
*/
public class Function {
/**
* This function listens at endpoint "/api/HttpExample". Two ways to invoke it using "curl" command in bash:
* 1. curl -d "HTTP Body" {your host}/api/HttpExample
* 2. curl "{your host}/api/HttpExample?name=HTTP%20Query"
*/
private final Communicator communicator;
@Inject
public Function(Communicator communicator) {
this.communicator = communicator;
}
@FunctionName("HttpExample")
public HttpResponseMessage run(
@HttpTrigger(
name = "req",
methods = {HttpMethod.GET, HttpMethod.POST},
authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
// Parse query parameter
final String query = request.getQueryParameters().get("name");
final String name = request.getBody().orElse(query);
communicator.communicate(context);
if (name == null) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
} else {
return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
}
}
}
You can find full code for this example at here
This feature will be soon adopted by Spring and Quarkus for better user experience when using those frameworks on azure functions.