66 lines
14 KiB
HTML
66 lines
14 KiB
HTML
<html><head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
|
<title>Spring Cloud Function</title><link rel="stylesheet" type="text/css" href="css/manual-singlepage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div lang="en" class="book"><div class="titlepage"><div><div><h1 class="title"><a name="d0e3"></a>Spring Cloud Function</h1></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="preface"><a href="#d0e9"></a></span></dt><dt><span class="chapter"><a href="#_introduction">1. Introduction</a></span></dt><dt><span class="chapter"><a href="#_getting_started">2. Getting Started</a></span></dt><dt><span class="chapter"><a href="#_building_and_running_a_function">3. Building and Running a Function</a></span></dt><dt><span class="chapter"><a href="#_deploying_a_packaged_function">4. Deploying a Packaged Function</a></span></dt><dt><span class="chapter"><a href="#_dynamic_compilation">5. Dynamic Compilation</a></span></dt><dd><dl><dt><span class="section"><a href="#_start_the_function_registry_service">5.1. Start the Function Registry Service:</a></span></dt><dt><span class="section"><a href="#_register_a_function">5.2. Register a Function:</a></span></dt><dt><span class="section"><a href="#_run_a_rest_microservice_using_that_function">5.3. Run a REST Microservice using that Function:</a></span></dt><dt><span class="section"><a href="#_register_a_supplier">5.4. Register a Supplier:</a></span></dt><dt><span class="section"><a href="#_run_a_rest_microservice_using_that_supplier">5.5. Run a REST Microservice using that Supplier:</a></span></dt><dt><span class="section"><a href="#_register_a_consumer">5.6. Register a Consumer:</a></span></dt><dt><span class="section"><a href="#_run_a_rest_microservice_using_that_consumer">5.7. Run a REST Microservice using that Consumer:</a></span></dt><dt><span class="section"><a href="#_run_stream_processing_microservices">5.8. Run Stream Processing Microservices:</a></span></dt></dl></dd></dl></div><div class="preface"><div class="titlepage"><div><div><h1 class="title"><a name="d0e9" href="#d0e9"></a></h1></div></div></div><p>Mark Fisher, Dave Syer</p><p></p></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_introduction" href="#_introduction"></a>1. Introduction</h1></div></div></div><p>Spring Cloud Function is a project with the following high-level goals:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><span class="emphasis"><em>Promote the implementation of business logic via functions.</em></span></li><li class="listitem"><span class="emphasis"><em>Decouple the development lifecycle of business logic from any specific runtime target so that the same code can run as a web endpoint, a stream processor, or a task.</em></span></li><li class="listitem"><span class="emphasis"><em>Support a uniform programming model across serverless providers, as well as the ability to run standalone (locally or in a PaaS).</em></span></li><li class="listitem"><span class="emphasis"><em>Enable Spring Boot features (auto-configuration, dependency injection, metrics) on serverless providers.</em></span></li></ul></div><p>It abstracts away all of the transport details and
|
|
infrastructure, allowing the developer to keep all the familiar tools
|
|
and processes, and focus firmly on business logic.</p><p>Here’s a complete, executable, testable Spring Boot application
|
|
(implementing a simple string manipulation):</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
|
|
|
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Function<Flux<String>, Flux<String>> uppercase() {
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> flux -> flux.map(value -> value.toUpperCase());
|
|
}
|
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
|
SpringApplication.run(Application.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
|
}
|
|
}</pre><p>It’s just a Spring Boot application, so it can be built, run and
|
|
tested, locally and in a CI build, the same way as any other Spring
|
|
Boot application. The <code class="literal">Function</code> is from <code class="literal">java.util</code> and <code class="literal">Flux</code> is a
|
|
<a class="link" href="http://www.reactive-streams.org/" target="_top">Reactive Streams</a> <code class="literal">Publisher</code> from
|
|
<a class="link" href="https://projectreactor.io/" target="_top">Project Reactor</a>. The function can be
|
|
accessed over HTTP or messaging.</p><p>Spring Cloud Function has 4 main features:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">Wrappers for <code class="literal">@Beans</code> of type <code class="literal">Function</code>, <code class="literal">Consumer</code> and
|
|
<code class="literal">Supplier</code>, exposing them to the outside world as either HTTP
|
|
endpoints and/or message stream listeners/publishers with RabbitMQ, Kafka etc.</li><li class="listitem">Compiling strings which are Java function bodies into bytecode, and
|
|
then turning them into <code class="literal">@Beans</code> that can be wrapped as above.</li><li class="listitem">Deploying a JAR file containing such an application context with an
|
|
isolated classloader, so that you can pack them together in a single
|
|
JVM.</li><li class="listitem">Adapters for <a class="link" href="https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-adapters/spring-cloud-function-adapter-aws" target="_top">AWS Lambda</a>, <a class="link" href="https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk" target="_top">Apache OpenWhisk</a> and possibly other "serverless" service providers.</li></ol></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Spring Cloud is released under the non-restrictive Apache 2.0 license. If you would like to contribute to this section of the documentation or if you find an error, please find the source code and issue trackers in the project at <a class="link" href="https://github.com/spring-cloud/spring-cloud-function/tree/master/docs/src/main/asciidoc" target="_top">github</a>.</p></td></tr></table></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_getting_started" href="#_getting_started"></a>2. Getting Started</h1></div></div></div><p>Build from the command line (and "install" the samples):</p><pre class="screen">$ ./mvnw clean install</pre><p>(If you like to YOLO add <code class="literal">-DskipTests</code>.)</p><p>Run one of the samples, e.g.</p><pre class="screen">$ java -jar spring-cloud-function-samples/spring-cloud-function-sample/target/*.jar</pre><p>This runs the app and exposes its functions over HTTP, so you can
|
|
convert a string to uppercase, like this:</p><pre class="screen">$ curl -H "Content-Type: text/plain" localhost:8080/uppercase -d Hello
|
|
HELLO</pre><p>You can convert multiple strings (a <code class="literal">Flux<String></code>) by separating them
|
|
with new lines</p><pre class="screen">$ curl -H "Content-Type: text/plain" localhost:8080/uppercase -d 'Hello
|
|
> World'
|
|
HELLOWORLD</pre><p>(You can use <code class="literal"><sup>Q</sup>J</code> in a terminal to insert a new line in a literal
|
|
string like that.)</p></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_building_and_running_a_function" href="#_building_and_running_a_function"></a>3. Building and Running a Function</h1></div></div></div><p>The sample <code class="literal">@SpringBootApplication</code> above has a function that can be
|
|
decorated at runtime by Spring Cloud Function to be an HTTP endpoint,
|
|
or a Stream processor, for instance with RabbitMQ, Apache Kafka or
|
|
JMS.</p><p>The <code class="literal">@Beans</code> can be <code class="literal">Function</code>, <code class="literal">Consumer</code> or <code class="literal">Supplier</code> (all from
|
|
<code class="literal">java.util</code>), and their parametric types can be String or POJO. A
|
|
<code class="literal">Function</code> is exposed as an HTTP POST if <code class="literal">spring-cloud-function-web</code>
|
|
is on the classpath, and as a Spring Cloud Stream <code class="literal">Processor</code> if
|
|
<code class="literal">spring-cloud-function-stream</code> is on the classpath and a
|
|
<code class="literal">spring.cloud.function.stream.endpoint</code> property is configured in the Spring
|
|
environment. A <code class="literal">Consumer</code> is also exposed as an HTTP POST, or as a Stream
|
|
<code class="literal">Sink</code>. A <code class="literal">Supplier</code> translates to an HTTP GET, or a Stream <code class="literal">Source</code>.</p><p>Functions can be of <code class="literal">Flux<String></code> or <code class="literal">Flux<Pojo></code> and Spring Cloud
|
|
Function takes care of converting the data to and from the desired
|
|
types, as long as it comes in as plain text or (in the case of the
|
|
POJO) JSON. TBD: support for <code class="literal">Flux<Message<Pojo>></code> and maybe plain
|
|
<code class="literal">Pojo</code> types (Fluxes implied and implemented by the framework).</p><p>Functions can be grouped together in a single application, or deployed
|
|
one-per-jar. It’s up to the developer to choose. An app with multiple
|
|
functions can be deployed multiple times in different "personalities",
|
|
exposing different functions over different physical transports.</p></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_deploying_a_packaged_function" href="#_deploying_a_packaged_function"></a>4. Deploying a Packaged Function</h1></div></div></div><p>TBD: describe the deployer app.</p></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_dynamic_compilation" href="#_dynamic_compilation"></a>5. Dynamic Compilation</h1></div></div></div><p>To run these examples, change into the <code class="literal">scripts</code> directory:</p><pre class="screen">cd scripts</pre><p>Also, start a RabbitMQ server locally (e.g. execute <code class="literal">rabbitmq-server</code>).</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_start_the_function_registry_service" href="#_start_the_function_registry_service"></a>5.1 Start the Function Registry Service:</h2></div></div></div><pre class="screen">./function-registry.sh</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_register_a_function" href="#_register_a_function"></a>5.2 Register a Function:</h2></div></div></div><pre class="screen">./registerFunction.sh -n uppercase -f "f->f.map(s->s.toString().toUpperCase())"</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_run_a_rest_microservice_using_that_function" href="#_run_a_rest_microservice_using_that_function"></a>5.3 Run a REST Microservice using that Function:</h2></div></div></div><pre class="screen">./web.sh -f uppercase -p 9000
|
|
curl -H "Content-Type: text/plain" -H "Accept: text/plain" localhost:9000/uppercase -d foo</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_register_a_supplier" href="#_register_a_supplier"></a>5.4 Register a Supplier:</h2></div></div></div><pre class="screen">./registerSupplier.sh -n words -f "()->Flux.just(\"foo\",\"bar\")"</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_run_a_rest_microservice_using_that_supplier" href="#_run_a_rest_microservice_using_that_supplier"></a>5.5 Run a REST Microservice using that Supplier:</h2></div></div></div><pre class="screen">./web.sh -s words -p 9001
|
|
curl -H "Accept: application/json" localhost:9001/words</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_register_a_consumer" href="#_register_a_consumer"></a>5.6 Register a Consumer:</h2></div></div></div><pre class="screen">./registerConsumer.sh -n print -t String -f "System.out::println"</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_run_a_rest_microservice_using_that_consumer" href="#_run_a_rest_microservice_using_that_consumer"></a>5.7 Run a REST Microservice using that Consumer:</h2></div></div></div><pre class="screen">./web.sh -c print -p 9002
|
|
curl -X POST -H "Content-Type: text/plain" -d foo localhost:9002/print</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_run_stream_processing_microservices" href="#_run_stream_processing_microservices"></a>5.8 Run Stream Processing Microservices:</h2></div></div></div><p>First register a streaming words supplier:</p><pre class="screen">./registerSupplier.sh -n wordstream -f "()->Flux.intervalMillis(1000).map(i->\"message-\"+i)"</pre><p>Then start the source (supplier), processor (function), and sink (consumer) apps
|
|
(in reverse order):</p><pre class="screen">./stream.sh -p 9103 -i uppercaseWords -c print
|
|
./stream.sh -p 9102 -i words -f uppercase -o uppercaseWords
|
|
./stream.sh -p 9101 -s wordstream -o words</pre><p>The output will appear in the console of the sink app (one message per second, converted to uppercase):</p><pre class="screen">MESSAGE-0
|
|
MESSAGE-1
|
|
MESSAGE-2
|
|
MESSAGE-3
|
|
MESSAGE-4
|
|
MESSAGE-5
|
|
MESSAGE-6
|
|
MESSAGE-7
|
|
MESSAGE-8
|
|
MESSAGE-9
|
|
...</pre></div></div></div></body></html> |