Add support for different handler->function mappings in Azure
This commit is contained in:
@@ -3,44 +3,14 @@
|
||||
This project provides an adapter layer for a Spring Cloud Function application onto Azure.
|
||||
You can write an app with a single `@Bean` of type `Function` and it will be deployable in Azure if you get the JAR file laid out right.
|
||||
|
||||
This project provides an adapter layer for a Spring Cloud Function application onto Azure.
|
||||
You can write an app with a single `@Bean` of type `Function` and it will be deployable in Azure if you get the JAR file laid out right.
|
||||
There is a `AzureSpringBootRequestHandler` which you must extend, and provide the input and output types as annotated method parameters (enabling Azure to inspect the class and create JSON bindings). The base class has two useful methods (`handleRequest` and `handleOutput`) to which you can delegate the actual function call, so mostly the function will only ever have one line.
|
||||
|
||||
The adapter has a generic HTTP request handler that you can use optionally.
|
||||
There is a `AzureSpringBootRequestHandler` which you must extend, and provide the input and output types as type parameters (enabling Azure to inspect the class and do the JSON conversions itself).
|
||||
|
||||
If your app has more than one `@Bean` of type `Function` etc. then you can choose the one to use by configuring `function.name`.
|
||||
The functions are extracted from the Spring Cloud `FunctionCatalog`.
|
||||
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`.
|
||||
|
||||
=== Notes on JAR Layout
|
||||
|
||||
You don't need the Spring Cloud Function Web at runtime in Azure, so you need to exclude this before you create the JAR you deploy to Azure.
|
||||
A function application on Azure has to be shaded, but a Spring Boot standalone application does not, so you can run the same app using 2 separate jars (as per the sample here).
|
||||
The sample app creates the shaded jar file, with an `azure` classifier for deploying in Azure.
|
||||
|
||||
=== JSON Configuration
|
||||
|
||||
The Azure tooling needs to find some JSON configuration files to tell it how to deploy and integrate the function (e.g. which Java class to use as the entry point, and which triggers to use). Those files can be created with the Maven plugin for a non-Spring function, but the tooling doesn't work yet with the adapter in its current form. There is an example `function.json` in the sample which hooks the function up as an HTTP endpoint:
|
||||
|
||||
```
|
||||
{
|
||||
"scriptFile" : "../function-sample-azure-2.0.0.BUILD-SNAPSHOT-azure.jar",
|
||||
"entryPoint" : "example.FooHandler.execute",
|
||||
"bindings" : [ {
|
||||
"type" : "httpTrigger",
|
||||
"name" : "foo",
|
||||
"direction" : "in",
|
||||
"authLevel" : "anonymous",
|
||||
"methods" : [ "get", "post" ]
|
||||
}, {
|
||||
"type" : "http",
|
||||
"name" : "$return",
|
||||
"direction" : "out"
|
||||
} ],
|
||||
"disabled" : false
|
||||
}
|
||||
```
|
||||
|
||||
You don't need the Spring Cloud Function Web at runtime in Azure, so you can optionally exclude this before you create the JAR you deploy to Azure.
|
||||
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.
|
||||
|
||||
== Build
|
||||
|
||||
@@ -58,7 +28,13 @@ You can run the sample locally, just like the other Spring Cloud Function sample
|
||||
|
||||
and `curl -H "Content-Type: text/plain" localhost:8080/function -d '{"value": "hello foobar"}'`.
|
||||
|
||||
You will need the `az` CLI app and some node.js fu (see https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-java-maven for more detail). To deploy the function on Azure runtime:
|
||||
Or you can run locally in an Azure host:
|
||||
|
||||
---
|
||||
./mvnw azure-functions:run
|
||||
---
|
||||
|
||||
You will need the `az` and `func` CLI apps (see https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-java-maven for more detail). To deploy the function on Azure runtime:
|
||||
|
||||
----
|
||||
$ az login
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.microsoft.azure.functions.ExecutionContext;
|
||||
import com.microsoft.azure.functions.OutputBinding;
|
||||
@@ -45,14 +46,15 @@ public class AzureSpringBootRequestHandler<I, O> extends AzureSpringFunctionInit
|
||||
String name = null;
|
||||
try {
|
||||
if (context != null) {
|
||||
context.getLogger().fine("Handler processed a request.");
|
||||
name = context.getFunctionName();
|
||||
context.getLogger().info("Handler processing a request for: " + name);
|
||||
}
|
||||
initialize(context);
|
||||
|
||||
Object convertedEvent = convertEvent(input);
|
||||
Publisher<?> output = apply(name, extract(convertedEvent));
|
||||
return result(convertedEvent, output);
|
||||
Function<Publisher<?>, Publisher<?>> function = lookup(name);
|
||||
Publisher<?> events = extract(function, convertEvent(input));
|
||||
Publisher<?> output = function.apply(events);
|
||||
return result(function, input, output);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if (context != null) {
|
||||
@@ -68,7 +70,7 @@ public class AzureSpringBootRequestHandler<I, O> extends AzureSpringFunctionInit
|
||||
}
|
||||
finally {
|
||||
if (context != null) {
|
||||
context.getLogger().fine("Handler processed a request.");
|
||||
context.getLogger().fine("Handler processed a request for: " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -83,19 +85,26 @@ public class AzureSpringBootRequestHandler<I, O> extends AzureSpringFunctionInit
|
||||
return input;
|
||||
}
|
||||
|
||||
private Flux<?> extract(Object input) {
|
||||
if (input instanceof Collection) {
|
||||
return Flux.fromIterable((Iterable<?>) input);
|
||||
private Flux<?> extract(Function<?, ?> function, Object input) {
|
||||
if (!isSingleInput(function, input)) {
|
||||
if (input instanceof Collection) {
|
||||
return Flux.fromIterable((Iterable<?>) input);
|
||||
}
|
||||
}
|
||||
return Flux.just(input);
|
||||
}
|
||||
|
||||
private O result(Object input, Publisher<?> output) {
|
||||
private O result(Function<?, ?> function, Object input, Publisher<?> output) {
|
||||
List<Object> result = new ArrayList<>();
|
||||
for (Object value : Flux.from(output).toIterable()) {
|
||||
result.add(convertOutput(value));
|
||||
}
|
||||
if (isSingleValue(input) && result.size() == 1) {
|
||||
if (isSingleInput(function, input) && result.size() == 1) {
|
||||
@SuppressWarnings("unchecked")
|
||||
O value = (O) result.get(0);
|
||||
return value;
|
||||
}
|
||||
if (isSingleOutput(function, input) && result.size() == 1) {
|
||||
@SuppressWarnings("unchecked")
|
||||
O value = (O) result.get(0);
|
||||
return value;
|
||||
@@ -105,10 +114,6 @@ public class AzureSpringBootRequestHandler<I, O> extends AzureSpringFunctionInit
|
||||
return value;
|
||||
}
|
||||
|
||||
private boolean isSingleValue(Object input) {
|
||||
return !(input instanceof Collection);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected O convertOutput(Object output) {
|
||||
return (O) output;
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -36,6 +37,7 @@ import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.function.context.FunctionCatalog;
|
||||
import org.springframework.cloud.function.context.catalog.FunctionInspector;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -53,6 +55,9 @@ public class AzureSpringFunctionInitializer implements Closeable {
|
||||
@Autowired(required = false)
|
||||
private FunctionCatalog catalog;
|
||||
|
||||
@Autowired(required = false)
|
||||
private FunctionInspector inspector;
|
||||
|
||||
private volatile static ConfigurableApplicationContext context;
|
||||
|
||||
public AzureSpringFunctionInitializer(Class<?> configurationClass) {
|
||||
@@ -68,6 +73,7 @@ public class AzureSpringFunctionInitializer implements Closeable {
|
||||
public void close() throws IOException {
|
||||
if (AzureSpringFunctionInitializer.context != null) {
|
||||
AzureSpringFunctionInitializer.context.close();
|
||||
AzureSpringFunctionInitializer.context = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +86,7 @@ public class AzureSpringFunctionInitializer implements Closeable {
|
||||
return;
|
||||
}
|
||||
if (ctxt != null) {
|
||||
ctxt.getLogger().info("Initializing function");
|
||||
ctxt.getLogger().info("Initializing functions");
|
||||
}
|
||||
|
||||
if (context == null) {
|
||||
@@ -119,13 +125,37 @@ public class AzureSpringFunctionInitializer implements Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
protected Publisher<?> apply(String name, Publisher<?> input) {
|
||||
protected boolean isSingleInput(Function<?,?> function, Object input) {
|
||||
if (!(input instanceof Collection)) {
|
||||
return true;
|
||||
}
|
||||
if (this.inspector != null) {
|
||||
return Collection.class.isAssignableFrom(inspector.getInputType(function));
|
||||
}
|
||||
return ((Collection<?>)input).size() <= 1;
|
||||
}
|
||||
|
||||
protected boolean isSingleOutput(Function<?,?> function, Object output) {
|
||||
if (!(output instanceof Collection)) {
|
||||
return true;
|
||||
}
|
||||
if (this.inspector != null) {
|
||||
return Collection.class.isAssignableFrom(inspector.getOutputType(function));
|
||||
}
|
||||
return ((Collection<?>)output).size() <= 1;
|
||||
}
|
||||
|
||||
protected Function<Publisher<?>, Publisher<?>> lookup(String name) {
|
||||
Function<Publisher<?>, Publisher<?>> function = this.function;
|
||||
if (function == null && name != null) {
|
||||
function = this.catalog.lookup(Function.class, name);
|
||||
if (name != null && this.catalog != null) {
|
||||
Function<Publisher<?>, Publisher<?>> preferred = this.catalog
|
||||
.lookup(Function.class, name);
|
||||
if (preferred != null) {
|
||||
function = preferred;
|
||||
}
|
||||
}
|
||||
if (function != null) {
|
||||
return function.apply(input);
|
||||
return function;
|
||||
}
|
||||
throw new IllegalStateException("No function defined");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.adapter.azure;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class AzureSpringBootRequestHandlerTests {
|
||||
|
||||
private AzureSpringBootRequestHandler<?, ?> handler = null;
|
||||
|
||||
<I, O> AzureSpringBootRequestHandler<I, O> handler(Class<?> config) {
|
||||
AzureSpringBootRequestHandler<I, O> handler = new AzureSpringBootRequestHandler<I, O>(
|
||||
config);
|
||||
this.handler = handler;
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bareConfig() {
|
||||
AzureSpringBootRequestHandler<Foo, Bar> handler = handler(BareConfig.class);
|
||||
Bar bar = handler.handleRequest(new Foo("bar"),
|
||||
new TestExecutionContext("uppercase"));
|
||||
assertThat(bar.getValue()).isEqualTo("BAR");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void autoConfig() {
|
||||
AzureSpringBootRequestHandler<Foo, Bar> handler = handler(AutoConfig.class);
|
||||
Bar bar = handler.handleRequest(new Foo("bar"),
|
||||
new TestExecutionContext("uppercase"));
|
||||
assertThat(bar.getValue()).isEqualTo("BAR");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiConfig() {
|
||||
AzureSpringBootRequestHandler<Foo, Bar> handler = handler(MultiConfig.class);
|
||||
Bar bar = handler.handleRequest(new Foo("bar"),
|
||||
new TestExecutionContext("uppercase"));
|
||||
assertThat(bar.getValue()).isEqualTo("BAR");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void implicitListConfig() {
|
||||
AzureSpringBootRequestHandler<List<Foo>, List<Bar>> handler = handler(
|
||||
AutoConfig.class);
|
||||
List<Bar> bar = handler.handleRequest(Arrays.asList(new Foo("bar")),
|
||||
new TestExecutionContext("uppercase"));
|
||||
assertThat(bar).hasSize(1);
|
||||
assertThat(bar.get(0).getValue()).isEqualTo("BAR");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listToListConfig() {
|
||||
AzureSpringBootRequestHandler<List<Foo>, List<Bar>> handler = handler(
|
||||
ListConfig.class);
|
||||
List<Bar> bar = handler.handleRequest(
|
||||
Arrays.asList(new Foo("bar"), new Foo("baz")),
|
||||
new TestExecutionContext("uppercase"));
|
||||
assertThat(bar).hasSize(2);
|
||||
assertThat(bar.get(0).getValue()).isEqualTo("BAR");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listToListSingleConfig() {
|
||||
AzureSpringBootRequestHandler<List<Foo>, List<Bar>> handler = handler(
|
||||
ListConfig.class);
|
||||
List<Bar> bar = handler.handleRequest(Arrays.asList(new Foo("bar")),
|
||||
new TestExecutionContext("uppercase"));
|
||||
assertThat(bar).hasSize(1);
|
||||
assertThat(bar.get(0).getValue()).isEqualTo("BAR");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void collectConfig() {
|
||||
AzureSpringBootRequestHandler<List<Foo>, Bar> handler = handler(CollectConfig.class);
|
||||
Bar bar = handler.handleRequest(Arrays.asList(new Foo("bar")),
|
||||
new TestExecutionContext("uppercase"));
|
||||
assertThat(bar.getValue()).isEqualTo("BAR");
|
||||
}
|
||||
|
||||
@After
|
||||
public void close() throws IOException {
|
||||
if (handler != null)
|
||||
handler.close();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class BareConfig {
|
||||
@Bean
|
||||
public Function<Flux<Foo>, Flux<Bar>> function() {
|
||||
return foos -> foos.map(foo -> new Bar(foo.getValue().toUpperCase()));
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
protected static class AutoConfig {
|
||||
@Bean
|
||||
public Function<Foo, Bar> uppercase() {
|
||||
return foo -> new Bar(foo.getValue().toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
protected static class ListConfig {
|
||||
@Bean
|
||||
public Function<List<Foo>, List<Bar>> uppercase() {
|
||||
return foos -> foos.stream().map(foo -> new Bar(foo.getValue().toUpperCase()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
protected static class CollectConfig {
|
||||
@Bean
|
||||
public Function<List<Foo>, Bar> uppercase() {
|
||||
return foos -> new Bar(foos.stream().map(foo -> foo.getValue().toUpperCase())
|
||||
.collect(Collectors.joining(",")));
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
protected static class MultiConfig {
|
||||
@Bean
|
||||
public Function<Foo, Bar> uppercase() {
|
||||
return foo -> new Bar(foo.getValue().toUpperCase());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Function<Bar, Foo> lowercase() {
|
||||
return bar -> new Foo(bar.getValue().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Foo {
|
||||
|
||||
private String value;
|
||||
|
||||
Foo() {
|
||||
}
|
||||
|
||||
public String lowercase() {
|
||||
return value.toLowerCase();
|
||||
}
|
||||
|
||||
public Foo(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String uppercase() {
|
||||
return value.toUpperCase();
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
class Bar {
|
||||
|
||||
private String value;
|
||||
|
||||
Bar() {
|
||||
}
|
||||
|
||||
public Bar(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.adapter.azure;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.microsoft.azure.functions.ExecutionContext;
|
||||
|
||||
public class TestExecutionContext implements ExecutionContext {
|
||||
private String name;
|
||||
|
||||
public TestExecutionContext(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return Logger.getAnonymousLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInvocationId() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFunctionName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
extensions.csproj
|
||||
obj/
|
||||
lib/
|
||||
node/
|
||||
package-lock.json
|
||||
node_modules/
|
||||
etc/
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
<functionAppName>function-sample-azure</functionAppName>
|
||||
<functionAppRegion>westus</functionAppRegion>
|
||||
<functionResourceGroup>java-function-group</functionResourceGroup>
|
||||
<stagingDirectory>${project.build.directory}/azure-functions/${functionAppName}</stagingDirectory>
|
||||
<start-class>example.Config</start-class>
|
||||
<wrapper.version>1.0.11.RELEASE</wrapper.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -61,6 +63,26 @@
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<configuration>
|
||||
<filesets>
|
||||
<fileset>
|
||||
<directory>${basedir}</directory>
|
||||
<includes>
|
||||
<include>obj/**</include>
|
||||
</includes>
|
||||
</fileset>
|
||||
<fileset>
|
||||
<directory>${basedir}</directory>
|
||||
<includes>
|
||||
<include>extensions.csproj</include>
|
||||
</includes>
|
||||
</fileset>
|
||||
</filesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.0.2</version>
|
||||
@@ -68,7 +90,7 @@
|
||||
<plugin>
|
||||
<groupId>com.microsoft.azure</groupId>
|
||||
<artifactId>azure-functions-maven-plugin</artifactId>
|
||||
<version>1.0.0-beta-1</version>
|
||||
<version>1.0.0-beta-4</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
@@ -81,6 +103,26 @@
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${stagingDirectory}/lib</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
<overWriteSnapshots>false</overWriteSnapshots>
|
||||
<overWriteIfNewer>true</overWriteIfNewer>
|
||||
<includeScope>runtime</includeScope>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.microsoft.azure</groupId>
|
||||
<artifactId>azure-functions-maven-plugin</artifactId>
|
||||
@@ -93,8 +135,20 @@
|
||||
<name>FUNCTIONS_EXTENSION_VERSION</name>
|
||||
<value>beta</value>
|
||||
</property>
|
||||
<property>
|
||||
<name>MSDEPLOY_RENAME_LOCKED_FILES</name>
|
||||
<value>1</value>
|
||||
</property>
|
||||
</appSettings>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>package-functions</id>
|
||||
<goals>
|
||||
<goal>package</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
@@ -121,42 +175,17 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||
<shadedClassifierName>azure</shadedClassifierName>
|
||||
<outputDirectory>${project.build.directory}/azure-functions/${functionAppName}</outputDirectory>
|
||||
</configuration>
|
||||
<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>${wrapper.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>azure</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<inherited>false</inherited>
|
||||
<configuration>
|
||||
<attach>false</attach>
|
||||
<descriptors>
|
||||
<descriptor>${basedir}/src/assembly/azure.xml</descriptor>
|
||||
</descriptors>
|
||||
<outputDirectory>${project.build.directory}/azure-functions</outputDirectory>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>${functionAppName}</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
|
||||
<id>azure</id>
|
||||
<formats>
|
||||
<format>zip</format>
|
||||
</formats>
|
||||
<baseDirectory></baseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/azure-functions/${functionAppName}</directory>
|
||||
<outputDirectory></outputDirectory>
|
||||
<includes>
|
||||
<include>*-azure.jar</include>
|
||||
<include>**/*.json</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
@@ -2,6 +2,7 @@
|
||||
"IsEncrypted": false,
|
||||
"Values": {
|
||||
"AzureWebJobsStorage": "",
|
||||
"AzureWebJobsDashboard": ""
|
||||
"AzureWebJobsDashboard": "",
|
||||
"FUNCTIONS_WORKER_RUNTIME": "java"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"scriptFile": "../function-sample-azure-2.0.0.BUILD-SNAPSHOT-azure.jar",
|
||||
"entryPoint": "example.FooHandler.execute",
|
||||
"bindings": [
|
||||
{
|
||||
"type": "httpTrigger",
|
||||
"name": "foo",
|
||||
"direction": "in",
|
||||
"authLevel": "anonymous",
|
||||
"methods": [
|
||||
"post"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "http",
|
||||
"name": "$return",
|
||||
"direction": "out"
|
||||
}
|
||||
],
|
||||
"disabled": false
|
||||
}
|
||||
@@ -17,6 +17,10 @@
|
||||
package example;
|
||||
|
||||
import com.microsoft.azure.functions.ExecutionContext;
|
||||
import com.microsoft.azure.functions.HttpMethod;
|
||||
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.AzureSpringBootRequestHandler;
|
||||
|
||||
@@ -24,8 +28,11 @@ import org.springframework.cloud.function.adapter.azure.AzureSpringBootRequestHa
|
||||
* @author Soby Chacko
|
||||
*/
|
||||
public class FooHandler extends AzureSpringBootRequestHandler<Foo, Bar> {
|
||||
|
||||
public Bar execute(Foo foo, ExecutionContext context) {
|
||||
@FunctionName("uppercase")
|
||||
public Bar execute(
|
||||
@HttpTrigger(name = "req", methods = { HttpMethod.GET,
|
||||
HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) Foo foo,
|
||||
ExecutionContext context) {
|
||||
return handleRequest(foo, context);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
buildscript {
|
||||
ext {
|
||||
springBootVersion = '1.5.12.RELEASE'
|
||||
wrapperVersion = '1.0.11.RELEASE'
|
||||
springBootVersion = '2.0.3.RELEASE'
|
||||
wrapperVersion = '1.0.13.RELEASE'
|
||||
}
|
||||
repositories {
|
||||
mavenLocal()
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<spring-cloud-function.version>2.0.0.BUILD-SNAPSHOT</spring-cloud-function.version>
|
||||
<wrapper.version>1.0.11.RELEASE</wrapper.version>
|
||||
<wrapper.version>1.0.13.RELEASE</wrapper.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
Reference in New Issue
Block a user