Add Supplier Exporter sample
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
AWS Lambda custom runtime.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ ./build.sh
|
||||||
|
$ ./mvnw package -P native
|
||||||
|
```
|
||||||
|
|
||||||
|
builds a native-zip ZIP file in target. Upload it to AWS and set the handler to "foobar".
|
||||||
|
|
||||||
|
To test locally, run the `TestServer` and then the `DemoApplication` (either in a JVM or natively). Then POST some data into the test server:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ curl localhost:8000/add -d world -H "Content-Type: text/plain"
|
||||||
|
```
|
||||||
|
|
||||||
|
There is a unit test that does the same thing. Also the `build.sh` script orchestrates the same test for the native image.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Useful for running locally (hence not in src/main/resources)
|
||||||
|
spring.cloud.function.web.export.source.url=http://localhost:8000/home
|
||||||
|
spring.cloud.function.web.export.sink.url=http://localhost:8000/echo
|
||||||
|
spring.cloud.function.web.export.debug=true
|
||||||
|
logging.level.org.springframework=DEBUG
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
printf "=== ${BLUE}Building %s sample${NC} ===\n" "${PWD##*/}"
|
||||||
|
|
||||||
|
./compile.sh || exit 1
|
||||||
|
|
||||||
|
JARDIR=target/native-image
|
||||||
|
java -cp $JARDIR/BOOT-INF/lib/*:$JARDIR/BOOT-INF/classes:$JARDIR:target/test-classes com.example.test.TestServer &
|
||||||
|
SPID=$!
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
${PWD%/*samples/*}/scripts/test.sh --spring.cloud.function.web.export.source.url=http://localhost:8000/home --spring.cloud.function.web.export.sink.url=http://localhost:8000/echo
|
||||||
|
|
||||||
|
kill $SPID
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
ARTIFACT=function-aws
|
||||||
|
MAINCLASS=com.example.demo.DemoApplication
|
||||||
|
VERSION=0.0.1-SNAPSHOT
|
||||||
|
FEATURE=../../../../spring-graal-native/target/spring-graal-native-0.7.0.BUILD-SNAPSHOT.jar
|
||||||
|
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
rm -rf target
|
||||||
|
mkdir -p target/native-image
|
||||||
|
|
||||||
|
echo "Packaging $ARTIFACT with Maven"
|
||||||
|
mvn -DskipTests package > target/native-image/output.txt
|
||||||
|
|
||||||
|
JAR="$ARTIFACT-$VERSION.jar"
|
||||||
|
rm -f $ARTIFACT
|
||||||
|
echo "Unpacking $JAR"
|
||||||
|
cd target/native-image
|
||||||
|
jar -xvf ../$JAR >/dev/null 2>&1
|
||||||
|
cp -R META-INF BOOT-INF/classes
|
||||||
|
|
||||||
|
LIBPATH=`find BOOT-INF/lib | tr '\n' ':'`
|
||||||
|
CP=BOOT-INF/classes:$LIBPATH:$FEATURE
|
||||||
|
|
||||||
|
if [ ! -f "$FEATURE" ]; then
|
||||||
|
printf "${RED}FAILURE${NC}: $FEATURE does not exist, please build the root project before building this sample.\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
GRAALVM_VERSION=`native-image --version`
|
||||||
|
echo "Compiling $ARTIFACT with $GRAALVM_VERSION"
|
||||||
|
{ time native-image \
|
||||||
|
--verbose \
|
||||||
|
--no-server \
|
||||||
|
--no-fallback \
|
||||||
|
--initialize-at-build-time \
|
||||||
|
-H:+PrintMethodHistogram \
|
||||||
|
-H:+TraceClassInitialization \
|
||||||
|
-H:Name=$ARTIFACT \
|
||||||
|
-H:+ReportExceptionStackTraces \
|
||||||
|
-Dspring.graal.remove-unused-autoconfig=true \
|
||||||
|
-Dspring.graal.remove-yaml-support=true \
|
||||||
|
-cp $CP $MAINCLASS >> output.txt ; } 2>> output.txt
|
||||||
|
|
||||||
|
if [[ -f $ARTIFACT ]]
|
||||||
|
then
|
||||||
|
printf "${GREEN}SUCCESS${NC}\n"
|
||||||
|
mv ./$ARTIFACT ..
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
cat output.txt
|
||||||
|
printf "${RED}FAILURE${NC}: an error occurred when compiling the native-image.\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.3.0.M4</version>
|
||||||
|
<relativePath />
|
||||||
|
</parent>
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>function-sample-aws-supplier-exporter</artifactId>
|
||||||
|
<version>1.0.0.RELEASE</version>
|
||||||
|
<name>function-sample-aws-supplier-exporter</name>
|
||||||
|
<description>Demo project for Spring Boot</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<spring-cloud-function.version>3.1.0.BUILD-SNAPSHOT</spring-cloud-function.version>
|
||||||
|
<reactor-bom.version>Dysprosium-SR6</reactor-bom.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-transport-native-epoll</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>io.netty</groupId>
|
||||||
|
<artifactId>netty-codec-http2</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-function-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-function-adapter-aws</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-function-dependencies</artifactId>
|
||||||
|
<version>${spring-cloud-function.version}</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>central</id>
|
||||||
|
<url>https://repo.maven.apache.org/maven2</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</pluginRepository>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>spring-release</id>
|
||||||
|
<name>Spring release</name>
|
||||||
|
<url>https://repo.spring.io/release</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</pluginRepository>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>spring-snapshot</id>
|
||||||
|
<name>Spring Snapshots</name>
|
||||||
|
<url>https://repo.spring.io/snapshot</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</pluginRepository>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>spring-milestone</id>
|
||||||
|
<name>Spring Milestone</name>
|
||||||
|
<url>https://repo.spring.io/milestone</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>central</id>
|
||||||
|
<url>https://repo.maven.apache.org/maven2</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>spring-release</id>
|
||||||
|
<name>Spring release</name>
|
||||||
|
<url>https://repo.spring.io/release</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>spring-snapshot</id>
|
||||||
|
<name>Spring Snapshots</name>
|
||||||
|
<url>https://repo.spring.io/snapshot</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>spring-milestone</id>
|
||||||
|
<name>Spring Milestone</name>
|
||||||
|
<url>https://repo.spring.io/milestone</url>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package com.example.demo;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringBootConfiguration;
|
||||||
|
import org.springframework.cloud.function.context.FunctionRegistration;
|
||||||
|
import org.springframework.cloud.function.context.FunctionType;
|
||||||
|
import org.springframework.cloud.function.context.FunctionalSpringApplication;
|
||||||
|
import org.springframework.context.ApplicationContextInitializer;
|
||||||
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
|
|
||||||
|
@SpringBootConfiguration(proxyBeanMethods = false)
|
||||||
|
public class DemoApplication
|
||||||
|
implements ApplicationContextInitializer<GenericApplicationContext> {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
FunctionalSpringApplication.run(DemoApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(GenericApplicationContext context) {
|
||||||
|
context.registerBean("foobar", FunctionRegistration.class,
|
||||||
|
() -> new FunctionRegistration<>(new Foobar())
|
||||||
|
.type(FunctionType.from(Foo.class).to(Foo.class)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Foo(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Foo() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foobar implements Function<Foo, Foo> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Foo apply(Foo input) {
|
||||||
|
System.err.println("HI: " + input.getName());
|
||||||
|
return new Foo("hi " + input.getName() + "!");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "com.example.demo.Foo",
|
||||||
|
"allDeclaredConstructors": true,
|
||||||
|
"allDeclaredMethods": true
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
spring.cloud.function.web.export.enabled=true
|
||||||
|
spring.cloud.function.web.export.debug=true
|
||||||
|
spring.main.web-application-type=none
|
||||||
|
logging.level.org.springframework.cloud=DEBUG
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package com.example.demo;
|
||||||
|
|
||||||
|
import com.example.test.TestServer;
|
||||||
|
import org.junit.jupiter.api.AfterAll;
|
||||||
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.cloud.function.context.test.FunctionalSpringBootTest;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.util.SocketUtils;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@FunctionalSpringBootTest({"spring.cloud.function.web.export.source.url=http://localhost:${export.port}/home",
|
||||||
|
"spring.cloud.function.web.export.sink.url=http://localhost:${export.port}/echo",
|
||||||
|
"logging.level.reactor=OFF",
|
||||||
|
"logging.level.io.netty=OFF"})
|
||||||
|
public class DemoApplicationTests {
|
||||||
|
|
||||||
|
static ConfigurableApplicationContext context;
|
||||||
|
|
||||||
|
@Value("${export.port}")
|
||||||
|
private int port;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebClient.Builder builder;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void contextLoads() throws Exception {
|
||||||
|
WebClient client = builder.baseUrl("http://localhost:" + port).build();
|
||||||
|
client.post().uri("/add").bodyValue("{\"name\":\"Fred\"}").exchange().block();
|
||||||
|
Thread.sleep(1000L);
|
||||||
|
String response = client.get().uri("/take").exchange().block().bodyToMono(String.class).block();
|
||||||
|
assertThat(response).isEqualTo("{\"name\":\"hi Fred!\"}");
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
static void after() {
|
||||||
|
if (context != null) {
|
||||||
|
context.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
static void before() {
|
||||||
|
int port = SocketUtils.findAvailableTcpPort();
|
||||||
|
System.setProperty("export.port", "" + port);
|
||||||
|
context = SpringApplication.run(TestServer.class, "--server.port="+port, "--spring.cloud.function.web.export.enabled=false", "--spring.main.web-application-type=reactive");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package com.example.test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.cloud.function.json.JsonMapper;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
import reactor.core.publisher.MonoProcessor;
|
||||||
|
|
||||||
|
@SpringBootApplication(proxyBeanMethods = false)
|
||||||
|
public class TestServer {
|
||||||
|
|
||||||
|
private MonoProcessor<String> output = MonoProcessor.<String>create();
|
||||||
|
|
||||||
|
private String response = "";
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Set<String> list = new LinkedHashSet<>(Arrays.asList(args));
|
||||||
|
list.addAll(Arrays.asList("--server.port=8000", "--spring.cloud.function.web.export.enabled=false", "--spring.main.web-application-type=reactive"));
|
||||||
|
SpringApplication.run(TestServer.class, list.toArray(new String[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Supplier<Mono<String>> home() {
|
||||||
|
return () -> output;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Bean
|
||||||
|
// public Function<String, String> echo(JsonMapper mapper) {
|
||||||
|
// return input -> {
|
||||||
|
// response = input;
|
||||||
|
// return "Echo: " + response;
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Function<Foo, String> echo(JsonMapper mapper) {
|
||||||
|
return input -> {
|
||||||
|
System.out.println("===> POJO " + input);
|
||||||
|
response = new String(mapper.toJson(input));
|
||||||
|
return "Echo: " + response;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Function<String, String> add() {
|
||||||
|
return input -> {
|
||||||
|
System.err.println("Add: " + input);
|
||||||
|
output.onNext(input);
|
||||||
|
output = MonoProcessor.<String>create();
|
||||||
|
return "Added: " + input;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Supplier<String> take() {
|
||||||
|
return () -> response;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Foo(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Foo() {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
curl -s localhost:8000/add -d '{"name":"world"}' -H "Content-Type: text/plain"
|
||||||
|
echo
|
||||||
|
echo Waiting...
|
||||||
|
sleep 1
|
||||||
|
RESPONSE=`curl -s localhost:8000/take`
|
||||||
|
echo Got response: $RESPONSE
|
||||||
|
if [[ "$RESPONSE" == '{"name":"hi world!"}' ]]; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
<module>function-sample-pojo</module>
|
<module>function-sample-pojo</module>
|
||||||
<module>function-sample-aws</module>
|
<module>function-sample-aws</module>
|
||||||
<module>function-sample-aws-custom</module>
|
<module>function-sample-aws-custom</module>
|
||||||
|
<module>function-sample-supplier-exporter</module>
|
||||||
<module>function-sample-azure</module>
|
<module>function-sample-azure</module>
|
||||||
<!--><module>function-sample-spring-integration</module>-->
|
<!--><module>function-sample-spring-integration</module>-->
|
||||||
<module>function-sample-gcp</module>
|
<module>function-sample-gcp</module>
|
||||||
|
|||||||
Reference in New Issue
Block a user