javaspringazuredependency-injectionspring-cloud-function

How can I autowire my beans in Spring Cloud Functions in Azure?


Is there any way I can do dependency injection in a Spring Cloud Function that will be running in Azure ?

For example:

package com.example;

import com.example.model.Greeting;
import com.example.model.User;
import com.microsoft.azure.functions.*;
import com.microsoft.azure.functions.annotation.AuthorizationLevel;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.annotation.HttpTrigger;
import org.springframework.cloud.function.adapter.azure.FunctionInvoker;

import java.util.Optional;

public class HelloHandler extends FunctionInvoker<User, Greeting> {

    @FunctionName("hello")
    public HttpResponseMessage execute(
        @HttpTrigger(name = "request", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<User>> request,
        ExecutionContext context) {
        User user = request.getBody()
                           .filter((u -> u.getName() != null))
                           .orElseGet(() -> new User(
                               request.getQueryParameters()
                                      .getOrDefault("name", "world")));
        context.getLogger().info("Greeting user name: " + user.getName());
        return request
            .createResponseBuilder(HttpStatus.OK)
            .body(handleRequest(user, context))
            .header("Content-Type", "application/json")
            .build();
    }
}

How can I use the @Autowired annotation here ? Its evaluated during runtime, right.

How can I achieve dependency injection ?

I need DI to inject mocks in place my actual beans during testing.


Solution

  • Staring with Spring Cloud Function 4.0.0 you can use dependency injections like this:

    package com.example;
    
    import java.util.Optional;
    import java.util.function.Function;
    
    import com.example.model.Greeting;
    import com.example.model.User;
    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 reactor.core.publisher.Mono;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class HelloHandler {
    
        @Autowired    
        Function<Mono<User>, Mono<Greeting>> hello;
        
        @FunctionName("hello")
        public HttpResponseMessage execute(
                @HttpTrigger(name = "request", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<User>> request,
                ExecutionContext context) {
            User user = request.getBody()
                    .filter((u -> u.getName() != null))
                    .orElseGet(() -> new User(
                            request.getQueryParameters()
                                    .getOrDefault("name", "world")));
            
            context.getLogger().info("DI Greeting user name: " + user.getName());
            
            return request
                    .createResponseBuilder(HttpStatus.OK)
                    .body(hello.apply(Mono.just(user)).block())
                    .header("Content-Type", "application/json")
                    .build();
        }
    }
    

    E.g. no need to extend FunctionInvoker. Just mark the hander as @Component and inject all necessary dependencies you need to use in your functions.

    You can check this PR that updates the same example code. Note that the PR code significantly simplifies the pom configurations as well.

    Update:

    This is a new feature recently released by the Azure Java Function Runtime and supported by Spring Cloud Function 4.0.0+.

    Here are the related blog Spring Cloud Function for Azure Function, the updated ref. doc and few samples.

    The azure-functions-core-tools version 4.0.5030 or newer is required.