GH-265 Added support for injecting execution context
- Added support for injecting target execution context into the ApplicationContext in AbstractSpringFunctionAdapterInitializer, effectively making it available to all adapters (if one is provided) - Added test, docs Resolves #265
This commit is contained in:
@@ -22,6 +22,25 @@ This Azure handler will delegate to a `Function<Foo,Bar>` bean (or a `Function<P
|
||||
|
||||
If your app has more than one `@Bean` of type `Function` etc. then you can choose the one to use by configuring `function.name`. Or if you make the `@FunctionName` in the Azure handler method match the function name it should work that way (also for function apps with multiple functions). The functions are extracted from the Spring Cloud `FunctionCatalog` so the default function names are the same as the bean names.
|
||||
|
||||
=== Accessing Azure ExecutionContext
|
||||
|
||||
Some time there is a need to access the target execution context provided by 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 Spring Cloud Function will register `ExecutionContext` as bean in the Application context, so it could be injected into your function.
|
||||
For example
|
||||
```java
|
||||
@Bean
|
||||
public Function<Foo, Bar> uppercase(ExecutionContext targetContext) {
|
||||
return foo -> {
|
||||
targetContext.getLogger().info("Invoking 'uppercase' on " + foo.getValue());
|
||||
return new Bar(foo.getValue().toUpperCase());
|
||||
};
|
||||
}
|
||||
```
|
||||
Normally type-based injection should suffice, however if need to you can also utilise the bean name under which it is registered which is `targetExecutionContext`.
|
||||
|
||||
|
||||
=== 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 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.
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.microsoft.azure.functions.ExecutionContext;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
@@ -151,8 +152,11 @@ public class AzureSpringBootRequestHandlerTests {
|
||||
protected static class AutoConfig {
|
||||
|
||||
@Bean
|
||||
public Function<Foo, Bar> uppercase() {
|
||||
return foo -> new Bar(foo.getValue().toUpperCase());
|
||||
public Function<Foo, Bar> uppercase(ExecutionContext targetContext) {
|
||||
return foo -> {
|
||||
targetContext.getLogger().info("Invoking 'uppercase' on " + foo.getValue());
|
||||
return new Bar(foo.getValue().toUpperCase());
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,7 +42,9 @@ import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.cloud.function.context.catalog.FunctionInspector;
|
||||
import org.springframework.cloud.function.context.config.FunctionContextUtils;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
@@ -57,6 +59,11 @@ public abstract class AbstractSpringFunctionAdapterInitializer<C> implements Clo
|
||||
|
||||
private static Log logger = LogFactory.getLog(AbstractSpringFunctionAdapterInitializer.class);
|
||||
|
||||
/**
|
||||
* Name of the bean for registering the target execution context passed to `initialize(context)` operation.
|
||||
*/
|
||||
public static final String TARGET_EXECUTION_CTX_BEAN_NAME = "targetExecutionContext";
|
||||
|
||||
private final Class<?> configurationClass;
|
||||
|
||||
private Function<Publisher<?>, Publisher<?>> function;
|
||||
@@ -102,6 +109,8 @@ public abstract class AbstractSpringFunctionAdapterInitializer<C> implements Clo
|
||||
}
|
||||
logger.info("Initializing: " + this.configurationClass);
|
||||
SpringApplication builder = springApplication();
|
||||
|
||||
this.registerTargetContext(targetContext, builder);
|
||||
ConfigurableApplicationContext context = builder.run();
|
||||
context.getAutowireCapableBeanFactory().autowireBean(this);
|
||||
this.context = context;
|
||||
@@ -113,6 +122,19 @@ public abstract class AbstractSpringFunctionAdapterInitializer<C> implements Clo
|
||||
}
|
||||
}
|
||||
|
||||
private void registerTargetContext(C targetContext, SpringApplication builder) {
|
||||
if (targetContext != null) {
|
||||
builder.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
((GenericApplicationContext) applicationContext).registerBean(TARGET_EXECUTION_CTX_BEAN_NAME,
|
||||
(Class<C>) targetContext.getClass(), (Supplier<C>) () -> targetContext);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected FunctionInspector getInspector() {
|
||||
return inspector;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user