From 29708de88fbf95fca54ece03cbdb8555364e15b6 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Fri, 8 Sep 2023 15:45:30 +0200 Subject: [PATCH] Insert explicit ids for headers --- docs/modules/ROOT/pages/README.adoc | 4 ++ .../ROOT/pages/adapters/aws-intro.adoc | 12 ++++++ docs/modules/ROOT/pages/adapters/aws.adoc | 6 +++ .../ROOT/pages/adapters/azure-intro.adoc | 17 +++++++- .../ROOT/pages/adapters/gcp-intro.adoc | 9 ++++ docs/modules/ROOT/pages/functional.adoc | 5 +++ docs/modules/ROOT/pages/index.adoc | 1 + .../ROOT/pages/spring-cloud-function.adoc | 41 +++++++++++++++++++ 8 files changed, 94 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/README.adoc b/docs/modules/ROOT/pages/README.adoc index 6d0f4cf8d..3e3adfa2e 100644 --- a/docs/modules/ROOT/pages/README.adoc +++ b/docs/modules/ROOT/pages/README.adoc @@ -2,18 +2,22 @@ image::https://travis-ci.org/spring-cloud/spring-cloud-function.svg?branch={branch}[Build Status, link=https://travis-ci.org/spring-cloud/spring-cloud-function] +[[introduction]] == Introduction include::_intro.adoc[] +[[getting-started]] == Getting Started include::getting-started.adoc[] +[[building]] == Building include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/building.adoc[] +[[contributing]] == Contributing include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/contributing.adoc[] diff --git a/docs/modules/ROOT/pages/adapters/aws-intro.adoc b/docs/modules/ROOT/pages/adapters/aws-intro.adoc index 8bd82bb2f..14a3d7de9 100644 --- a/docs/modules/ROOT/pages/adapters/aws-intro.adoc +++ b/docs/modules/ROOT/pages/adapters/aws-intro.adoc @@ -1,5 +1,6 @@ :branch: master +[[aws-lambda]] === AWS Lambda The https://aws.amazon.com/[AWS] adapter takes a Spring Cloud Function app and converts it to a form that can run in AWS Lambda. @@ -7,6 +8,7 @@ The https://aws.amazon.com/[AWS] adapter takes a Spring Cloud Function app and c The details of how to get stared with AWS Lambda is out of scope of this document, so the expectation is that user has some familiarity with AWS and AWS Lambda and wants to learn what additional value spring provides. +[[getting-started]] ==== Getting Started One of the goals of Spring Cloud Function framework is to provide necessary infrastructure elements to enable a _simple function application_ @@ -56,6 +58,7 @@ isolating you from the specifics of AWS Lambda API, for some cases you may want to use. The next section will explain you how you can accomplish just that. +[[aws-request-handlers]] ==== AWS Request Handlers The adapter has a couple of generic request handlers that you can use. The most generic is (and the one we used in the Getting Started section) @@ -69,6 +72,7 @@ property or environment variable. The functions are extracted from the Spring Cl the framework will attempt to find a default following the search order where it searches first for `Function` then `Consumer` and finally `Supplier`). +[[aws-function-routing]] ==== AWS Function Routing One of the core features of Spring Cloud Function is https://docs.spring.io/spring-cloud-function/docs/{project-version}/reference/html/spring-cloud-function.html#_function_routing_and_filtering[routing] @@ -90,10 +94,12 @@ Also, note that since AWS does not allow dots `.` and/or hyphens`-` in the name dots with underscores and hyphens with camel case. So for example `spring.cloud.function.definition` becomes `spring_cloud_function_definition` and `spring.cloud.function.routing-expression` becomes `spring_cloud_function_routingExpression`. +[[aws-function-routing-with-custom-runtime]] ===== AWS Function Routing with Custom Runtime When using <> Function Routing works the same way. All you need is to specify `functionRouter` as AWS Handler the same way you would use the name of the function as handler. +[[notes-on-jar-layout]] ==== Notes on JAR Layout You don't need the Spring Cloud Function Web or Stream adapter at runtime in Lambda, so you might @@ -158,12 +164,14 @@ then additional transformers must be configured as part of the maven-shade-plugi ---- +[[build-file-setup]] ==== Build file setup In order to run Spring Cloud Function applications on AWS Lambda, you can leverage Maven or Gradle plugins offered by the cloud platform provider. +[[maven]] ===== Maven In order to use the adapter plugin for Maven, add the plugin dependency to your `pom.xml` @@ -202,6 +210,7 @@ You can use the Spring Boot Maven Plugin to generate the <>. You can find the entire sample `pom.xml` file for deploying Spring Cloud Function applications to AWS Lambda with Maven https://github.com/spring-cloud/spring-cloud-function/blob/{branch}/spring-cloud-function-samples/function-sample-aws/pom.xml[here]. +[[gradle]] ===== Gradle In order to use the adapter plugin for Gradle, add the dependency to your `build.gradle` file: @@ -270,6 +279,7 @@ assemble.dependsOn = [thinJar] You can find the entire sample `build.gradle` file for deploying Spring Cloud Function applications to AWS Lambda with Gradle https://github.com/spring-cloud/spring-cloud-function/blob/{branch}/spring-cloud-function-samples/function-sample-aws/build.gradle[here]. +[[upload]] ==== Upload Build the sample under `spring-cloud-function-samples/function-sample-aws` and upload the `-aws` jar file to Lambda. The handler can be `example.Handler` or `org.springframework.cloud.function.adapter.aws.SpringBootStreamHandler` (FQN of the class, _not_ a method reference, although Lambda does accept method references). @@ -295,6 +305,7 @@ The input type for the function in the AWS sample is a Foo with a single propert NOTE: The AWS sample app is written in the "functional" style (as an `ApplicationContextInitializer`). This is much faster on startup in Lambda than the traditional `@Bean` style, so if you don't need `@Beans` (or `@EnableAutoConfiguration`) it's a good choice. Warm starts are not affected. +[[type-conversion]] ==== Type Conversion Spring Cloud Function will attempt to transparently handle type conversion between the raw @@ -306,6 +317,7 @@ incoming stream event to an instance of `Foo`. In the event type is not known or can not be determined (e.g., `Function`) we will attempt to convert an incoming stream event to a generic `Map`. +[[raw-input]] ====== Raw Input There are times when you may want to have access to a raw input. In this case all you need is to declare your diff --git a/docs/modules/ROOT/pages/adapters/aws.adoc b/docs/modules/ROOT/pages/adapters/aws.adoc index 0912ded38..31b25b7b3 100644 --- a/docs/modules/ROOT/pages/adapters/aws.adoc +++ b/docs/modules/ROOT/pages/adapters/aws.adoc @@ -3,10 +3,12 @@ The https://aws.amazon.com/[AWS] adapter takes a Spring Cloud Function app and converts it to a form that can run in AWS Lambda. +[[introduction]] == Introduction include::adapters/aws-intro.adoc[] +[[functional-bean-definitions]] == Functional Bean Definitions Your functions will start much quicker if you can use functional bean definitions instead of `@Bean`. To do this make your main class @@ -37,6 +39,7 @@ public class FuncApplication implements ApplicationContextInitializer` as an input parameter to your function and then access `aws-context` from message headers. For convenience we provide AWSLambdaUtils.AWS_CONTEXT constant. +[[platform-specific-features]] == Platform Specific Features +[[http-and-api-gateway]] === HTTP and API Gateway AWS has some platform-specific data types, including batching of messages, which is much more efficient than processing each one individually. To make use of these types you can write a function that depends on those types. Or you can rely on Spring to extract the data from the AWS types and convert it to a Spring `Message`. To do this you tell AWS that the function is of a specific generic handler type (depending on the AWS service) and provide a bean of type `Function,Message>`, where `S` and `T` are your business data types. If there is more than one bean of type `Function` you may also need to configure the Spring Boot property `function.name` to be the name of the target bean (e.g. use `FUNCTION_NAME` as an environment variable). @@ -62,6 +67,7 @@ The supported AWS services and generic handler types are listed below: For example, to deploy behind an API Gateway, use `--handler org.springframework.cloud.function.adapter.aws.SpringBootApiGatewayRequestHandler` in your AWS command line (in via the UI) and define a `@Bean` of type `Function,Message>` where `Foo` and `Bar` are POJO types (the data will be marshalled and unmarshalled by AWS using Jackson). +[[custom-runtime]] == Custom Runtime You can also benefit from https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html[AWS Lambda custom runtime] feature of AWS Lambda diff --git a/docs/modules/ROOT/pages/adapters/azure-intro.adoc b/docs/modules/ROOT/pages/adapters/azure-intro.adoc index 59ceca215..f5e58c5a8 100644 --- a/docs/modules/ROOT/pages/adapters/azure-intro.adoc +++ b/docs/modules/ROOT/pages/adapters/azure-intro.adoc @@ -1,5 +1,6 @@ :branch: master +[[microsoft-azure-functions]] == Microsoft Azure Functions :sectnums: @@ -19,10 +20,12 @@ With the Azure Web Adapter you can deploy any Spring Web application as an Azure This adapter hides the Azure annotations complexity and uses the familiar https://docs.spring.io/spring-boot/docs/current/reference/html/web.html[Spring Web] programming model instead. For further information follow the <> section below. +[[azure-adapter]] == Azure Adapter Provides `Spring` & `Spring Cloud Function` integration for Azure Functions. +[[dependencies]] === Dependencies In order to enable the Azure Function integration add the azure adapter dependency to your `pom.xml` or `build.gradle` @@ -127,6 +130,7 @@ public class HttpTriggerDemoApplication { <1> The `@SpringBootApplication` annotated class is used as a `Main-Class` as explained in <>. <2> Functions auto-wired and used in the Azure function handlers. +[[function-catalog]] ==== Function Catalog The Spring Cloud Function supports a range of type signatures for user-defined functions, while providing a consistent execution model. @@ -137,6 +141,7 @@ But those are treated as plain Java class instances, not as a canonical Spring C To leverage Spring Cloud Function and have access to the canonical function representations, you need to auto-wire the `FunctionCatalog` and use it in your handler, like the `functionCatalog` instance the `springCloudFunction()` handler above. +[[accessing-azure-executioncontext]] ==== Accessing Azure ExecutionContext Some time there is a need to access the target execution context provided by the Azure runtime in the form of `com.microsoft.azure.functions.ExecutionContext`. @@ -186,6 +191,7 @@ Usually the Azure Maven (or Gradle) plugins are used to generate the necessary c IMPORTANT: The Azure https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-java?tabs=bash%2Cconsumption#folder-structure[packaging format] is not compatible with the default Spring Boot packaging (e.g. `uber jar`). The <> section below explains how to handle this. +[[azure-maven/gradle-plugins]] ==== Azure Maven/Gradle Plugins Azure provides https://github.com/microsoft/azure-maven-plugins/tree/develop/azure-functions-maven-plugin[Maven] and https://github.com/microsoft/azure-gradle-plugins/tree/master/azure-functions-gradle-plugin[Gradle] plugins to process the annotated classes, generate the necessary configurations and produce the expected package layout. @@ -327,6 +333,7 @@ For local runs, add the `MAIN_CLASS` variable to your `local.settings.json` file IMPORTANT: If the `MAIN_CLASS` variable is not set, the Azure adapter lookups the `MANIFEST/META-INFO` attributes from the jars found on the classpath and selects the first `Main-Class:` annotated with either a `@SpringBootApplication` or `@SpringBootConfiguration` annotation. +[[metadata-configuration]] ==== Metadata Configuration You can use a shared https://learn.microsoft.com/en-us/azure/azure-functions/functions-host-json[host.json] file to configure the function app. @@ -346,6 +353,7 @@ The host.json metadata file contains configuration options that affect all funct TIP: If the file is not in the project top folder you need to configure your plugins accordingly (like `hostJson` maven attribute). +[[samples]] === Samples Here is a list of various Spring Cloud Function Azure Adapter samples you can explore: @@ -389,6 +397,7 @@ dependencies { The same <> and <> instructions apply to the `Azure Web Adapter` as well. +[[samples]] === Samples For further information, explore the following, Azure Web Adapter, sample: @@ -400,6 +409,7 @@ For further information, explore the following, Azure Web Adapter, sample: Common instructions for building and deploying both, `Azure Adapter` and `Azure Web Adapter` type of applications. +[[build]] === Build ==== @@ -416,6 +426,7 @@ Common instructions for building and deploying both, `Azure Adapter` and `Azure ---- ==== +[[running-locally]] === Running locally To run locally on top of `Azure Functions`, and to deploy to your live Azure environment, you will need `Azure Functions Core Tools` installed along with the Azure CLI (see https://docs.microsoft.com/en-us/azure/azure-functions/create-first-function-cli-java?tabs=bash%2Cazure-cli%2Cbrowser#configure-your-local-environment[here]). @@ -437,6 +448,7 @@ Then run the sample: ---- ==== +[[running-on-azure]] === Running on Azure Make sure you are logged in your Azure account. @@ -461,6 +473,7 @@ and deploy ---- ==== +[[debug-locally]] === Debug locally Run the function in debug mode. @@ -516,12 +529,14 @@ Here is snippet for a `VSCode` remote debugging configuration: } ---- +[[functioninvoker-deprecated]] == FunctionInvoker (deprecated) WARNING: The legacy `FunctionInvoker` programming model is deprecated and will not be supported going forward. For additional documentation and samples about the Function Integration approach follow the https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-samples/function-sample-azure/[azure-sample] README and code. +[[relevant-links]] == Relevant Links - https://learn.microsoft.com/en-us/azure/developer/java/spring-framework/getting-started-with-spring-cloud-function-in-azure[Spring Cloud Function in Azure] @@ -530,4 +545,4 @@ For additional documentation and samples about the Function Integration approach - https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-java?tabs=bash%2Cconsumption[Azure Functions Java developer guide] - https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference?tabs=blob[Azure Functions developer guide] -:sectnums!: \ No newline at end of file +:sectnums!: diff --git a/docs/modules/ROOT/pages/adapters/gcp-intro.adoc b/docs/modules/ROOT/pages/adapters/gcp-intro.adoc index 1f72b19ed..4826d6d58 100644 --- a/docs/modules/ROOT/pages/adapters/gcp-intro.adoc +++ b/docs/modules/ROOT/pages/adapters/gcp-intro.adoc @@ -1,10 +1,12 @@ :branch: master +[[google-cloud-functions]] === Google Cloud Functions The Google Cloud Functions adapter enables Spring Cloud Function apps to run on the https://cloud.google.com/functions[Google Cloud Functions] serverless platform. You can either run the function locally using the open source https://github.com/GoogleCloudPlatform/functions-framework-java[Google Functions Framework for Java] or on GCP. +[[project-dependencies]] ==== Project Dependencies Start by adding the `spring-cloud-function-adapter-gcp` dependency to your project. @@ -62,10 +64,12 @@ NOTE: The function target should always be set to `org.springframework.cloud.fun A full example of a working `pom.xml` can be found in the https://github.com/spring-cloud/spring-cloud-function/blob/master/spring-cloud-function-samples/function-sample-gcp-http/pom.xml[Spring Cloud Functions GCP sample]. +[[http-functions]] ==== HTTP Functions Google Cloud Functions supports deploying https://cloud.google.com/functions/docs/writing/http[HTTP Functions], which are functions that are invoked by HTTP request. The sections below describe instructions for deploying a Spring Cloud Function as an HTTP Function. +[[getting-started]] ===== Getting Started Let’s start with a simple Spring Cloud Function example: @@ -106,6 +110,7 @@ Invoke the HTTP function: curl http://localhost:8080/ -d "hello" ---- +[[deploy-to-gcp]] ===== Deploy to GCP Start by packaging your application. @@ -158,6 +163,7 @@ public Function> function() { +[[background-functions]] ==== Background Functions Google Cloud Functions also supports deploying https://cloud.google.com/functions/docs/writing/background[Background Functions] which are invoked indirectly in response to an event, such as a message on a https://cloud.google.com/pubsub[Cloud Pub/Sub] topic, a change in a https://cloud.google.com/storage[Cloud Storage] bucket, or a https://firebase.google.com/[Firebase] event. @@ -167,6 +173,7 @@ The `spring-cloud-function-adapter-gcp` allows for functions to be deployed as b The sections below describe the process for writing a Cloud Pub/Sub topic background function. However, there are a number of different event types that can trigger a background function to execute which are not discussed here; these are described in the https://cloud.google.com/functions/docs/calling[Background Function triggers documentation]. +[[getting-started]] ===== Getting Started Let’s start with a simple Spring Cloud Function which will run as a GCF background function: @@ -259,6 +266,7 @@ curl localhost:8080 -H "Content-Type: application/json" -d '{"data":"hello"}' Verify that the function was invoked by viewing the logs. +[[deploy-to-gcp]] ===== Deploy to GCP In order to deploy your background function to GCP, first package your application. @@ -287,6 +295,7 @@ Google Cloud Function will now invoke the function every time a message is publi For a walkthrough on testing and verifying your background function, see the instructions for running the https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-samples/function-sample-gcp-background/[GCF Background Function sample]. +[[sample-functions]] ==== Sample Functions The project provides the following sample functions as reference: diff --git a/docs/modules/ROOT/pages/functional.adoc b/docs/modules/ROOT/pages/functional.adoc index a12f520ac..7e4e89736 100644 --- a/docs/modules/ROOT/pages/functional.adoc +++ b/docs/modules/ROOT/pages/functional.adoc @@ -1,5 +1,6 @@ Spring Cloud Function supports a "functional" style of bean declarations for small apps where you need fast startup. The functional style of bean declaration was a feature of Spring Framework 5.0 with significant enhancements in 5.1. +[[comparing-functional-with-traditional-bean-definitions]] == Comparing Functional with Traditional Bean Definitions Here's a vanilla Spring Cloud Function application from with the @@ -113,6 +114,7 @@ public void initialize(GenericApplicationContext context) { } ---- +[[limitations-of-functional-bean-declaration]] == Limitations of Functional Bean Declaration Most Spring Cloud Function apps have a relatively small scope compared to the whole of Spring Boot, @@ -128,6 +130,7 @@ functional mode" using `spring.functional.enabled=false` so that Spring Boot can Spring Cloud Function supports visualization of functions available in `FunctionCatalog` through Actuator endpoints as well as programmatic way. +[[programmatic-way]] ==== Programmatic way To see function available within your application context programmatically all you need is access to `FunctionCatalog`. There you can @@ -143,6 +146,7 @@ Set names = functionCatalog.getNames(null); will list the names of all t . . . ---- +[[actuator]] ==== Actuator Since actuator and web are optional, you must first add one of the web dependencies as well as add the actuator dependency manually. The following example shows how to add the dependency for the Web framework: @@ -198,6 +202,7 @@ Your output should look something like this: {"type":"SUPPLIER","output-type":"string"}. . . ---- +[[testing-functional-applications]] = Testing Functional Applications Spring Cloud Function also has some utilities for integration testing that will be very familiar to Spring Boot users. diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index ebc517b8a..cc9d0d1dd 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -1,3 +1,4 @@ +[[spring-cloud-function-reference-documentation]] = Spring Cloud Function Reference Documentation Mark Fisher, Dave Syer, Oleg Zhurakousky, Anshul Mehra, Dan Dobrin, Chris Bono, Artem Bilan diff --git a/docs/modules/ROOT/pages/spring-cloud-function.adoc b/docs/modules/ROOT/pages/spring-cloud-function.adoc index 7eea6e5fc..9cff8a176 100644 --- a/docs/modules/ROOT/pages/spring-cloud-function.adoc +++ b/docs/modules/ROOT/pages/spring-cloud-function.adoc @@ -1,3 +1,4 @@ +[[spring-cloud-function]] = Spring Cloud Function Mark Fisher, Dave Syer, Oleg Zhurakousky, Anshul Mehra, Dan Dobrin @@ -12,20 +13,24 @@ Mark Fisher, Dave Syer, Oleg Zhurakousky, Anshul Mehra, Dan Dobrin :nofooter: :branch: master +[[introduction]] == Introduction include::_intro.adoc[] include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/contributing-docs.adoc[] +[[getting-started]] == Getting Started include::getting-started.adoc[] +[[programming-model]] == Programming model [[function.catalog]] +[[function-catalog-and-flexible-function-signatures]] === Function Catalog and Flexible Function Signatures One of the main features of Spring Cloud Function is to adapt and support a range of type signatures for user-defined functions, @@ -42,6 +47,7 @@ your function implementation. Reactive programming model also enables functional support for features that would be otherwise difficult to impossible to implement using imperative programming style. For more on this please read <> section. +[[java-8-function-support]] === Java 8 function support Spring Cloud Function embraces and builds on top of the 3 core functional interfaces defined by Java @@ -80,6 +86,7 @@ adapters as well as other frameworks using Spring Cloud Function as the core pro So in summary Spring Cloud Function instruments java functions with additional features to be utilised in variety of execution contexts. +[[function-definition]] ==== Function definition While the previous example shows you how to lookup function in FunctionCatalog programmatically, in a typical integration case where Spring Cloud Function used as programming model by another framework (e.fg. Spring Cloud Stream), you declare which functions to use via `spring.cloud.function.definition` property. Knowing that it is important to understand some default behaviour when it comes to discovering functions in `FunctionCatalog`. For example, if you only have one Functional bean in your `ApplicationContext`, the `spring.cloud.function.definition` property typically will not be required, since a single function in `FunctionCatalog` can be looked up by an empty name or any name. For example, assuming that `uppercase` is the only function in your catalog, it can be looked up as `catalog.lookup(null)`, `catalog.lookup(“”)`, `catalog.lookup(“foo”)` That said, for cases where you are using framework such as Spring Cloud Stream which uses `spring.cloud.function.definition` it is best practice and recommended to always use `spring.cloud.function.definition` property. @@ -91,6 +98,7 @@ For example, spring.cloud.function.definition=uppercase ---- +[[filtering-ineligible-functions]] ==== Filtering ineligible functions A typical Application Context may include beans that are valid java functions, but not intended to be candidates to be registered with `FunctionCatalog`. Such beans could be auto-configurations from other projects or any other beans that qualify to be Java functions. @@ -105,6 +113,7 @@ For example, spring.cloud.function.ineligible-definitions=foo,bar ---- +[[supplier]] ==== Supplier Supplier can be _reactive_ - `Supplier>` or _imperative_ - `Supplier`. From the invocation standpoint this should make no difference @@ -138,23 +147,27 @@ public Supplier> someSupplier() { } ---- +[[function]] ==== Function Function can also be written in imperative or reactive way, yet unlike Supplier and Consumer there are no special considerations for the implementor other then understanding that when used within frameworks such as https://spring.io/projects/spring-cloud-stream[Spring Cloud Stream] and others, reactive function is invoked only once to pass a reference to the stream (Flux or Mono) and imperative is invoked once per event. +[[consumer]] ==== Consumer Consumer is a little bit special because it has a `void` return type, which implies blocking, at least potentially. Most likely you will not need to write `Consumer>`, but if you do need to do that, remember to subscribe to the input flux. +[[function-composition]] === Function Composition Function Composition is a feature that allows one to compose several functions into one. The core support is based on function composition feature available with https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html#andThen-java.util.function.Function-[Function.andThen(..)] support available since Java 8. However on top of it, we provide few additional features. +[[declarative-function-composition]] ==== Declarative Function Composition This feature allows you to provide composition instruction in a declarative way using `|` (pipe) or `,` (comma) delimiter @@ -169,6 +182,7 @@ function `uppercase` and function `reverse`. In fact that is one of the reasons since the definition of a function can be a composition of several named functions. And as mentioned you can use `,` instead of pipe (such as `...definition=uppercase,reverse`). +[[composing-non-functions]] ==== Composing non-Functions Spring Cloud Function also supports composing Supplier with `Consumer` or `Function` as well as `Function` with `Consumer`. What's important here is to understand the end product of such definitions. @@ -178,6 +192,7 @@ Following the same logic composing Function with Consumer will result in Consume And of course you can't compose uncomposable such as Consumer and Function, Consumer and Supplier etc. +[[function-routing-and-filtering]] === Function Routing and Filtering Since version 2.2 Spring Cloud Function provides routing feature allowing @@ -199,6 +214,7 @@ public class RoutingFunction implements Function { The routing instructions could be communicated in several ways. We support providing instructions via Message headers, System properties as well as pluggable strategy. So let's look at some of the details +[[messageroutingcallback]] ==== MessageRoutingCallback The `MessageRoutingCallback` is a strategy to assist with determining the name of the route-to function definition. @@ -299,6 +315,7 @@ public DefaultMessageRoutingHandler defaultRoutingHandler() { } ---- +[[function-filtering]] ==== Function Filtering Filtering is the type of routing where there are only two paths - 'go' or 'discard'. In terms of functions it mean you only want to invoke a certain function if some condition returns 'true', otherwise you want to discard input. @@ -329,6 +346,7 @@ due to the nature of the reactive functions which are invoked only once to pass is handled by the reactor, hence we can not access and/or rely on the routing instructions communicated via individual values (e.g., Message). +[[multiple-routers]] ==== Multiple Routers By default the framework will always have a single routing function configured as described in previous sections. However, there are times when you may need more than one routing function. @@ -381,6 +399,7 @@ public void testMultipleRouters() { } ---- +[[input/output-enrichment]] === Input/Output Enrichment There are often times when you need to modify or refine an incoming or outgoing Message and to keep your code clean of non-functional concerns. You don’t want to do it inside of your business logic. @@ -461,6 +480,7 @@ In the event you are dealing with functions that have multiple inputs (next sect --spring.cloud.function.configuration.echo.input-header-mapping-expression[1].key2='hello2' ---- +[[function-arity]] === Function Arity There are times when a stream of data needs to be categorized and organized. For example, @@ -496,6 +516,7 @@ IMPORTANT: IMPORTANT: At the moment, function arity is *only* supported for reac where evaluation and computation on confluence of events typically requires view into a stream of events rather than single event. +[[input-header-propagation]] === Input Header propagation In a typical scenario input Message headers are not propagated to output and rightfully so, since the output of a function may be an input to something else requiring it's own set of Message headers. @@ -531,6 +552,7 @@ Message result = uppercase.apply(MessageBuilder.withPayload("bob").setHe assertThat(result.getHeaders()).containsKey("foo"); ---- +[[type-conversion-content-type-negotiation]] === Type conversion (Content-Type negotiation) Content-Type negotiation is one of the core features of Spring Cloud Function as it allows to not only transform the incoming data to the types declared @@ -569,6 +591,7 @@ For example, HTTP POST request will have its content-type HTTP header copied to For cases when such header does not exist framework relies on the default content type as `application/json`. +[[content-type-versus-argument-type]] ==== Content Type versus Argument Type As mentioned earlier, for the framework to select the appropriate `MessageConverter`, it requires argument type and, optionally, content type information. @@ -586,6 +609,7 @@ NOTE: Do not expect `Message` to be converted into some other type based only on Remember that the `contentType` is complementary to the target type. It is a hint, which `MessageConverter` may or may not take into consideration. +[[message-converters]] ==== Message Converters `MessageConverters` define two methods: @@ -604,6 +628,7 @@ The payload of the `Message` could be any type, and it is up to the actual implementation of the `MessageConverter` to support multiple types. +[[provided-messageconverters]] ==== Provided MessageConverters As mentioned earlier, the framework already provides a stack of `MessageConverters` to handle most common use cases. @@ -662,6 +687,7 @@ public class MyCustomMessageConverter extends AbstractMessageConverter { } ---- +[[note-on-json-options]] ==== Note on JSON options In Spring Cloud Function we support Jackson and Gson mechanisms to deal with JSON. @@ -677,6 +703,7 @@ That said, the type conversion is usually transparent to the developer, however you can easily inject it into your code if needed. +[[kotlin-lambda-support]] === Kotlin Lambda support We also provide support for Kotlin lambdas (since v2.0). @@ -708,12 +735,14 @@ same rules for signature transformation outlined in "Java 8 function support" se To enable Kotlin support all you need is to add Kotlin SDK libraries on the classpath which will trigger appropriate autoconfiguration and supporting classes. +[[function-component-scan]] === Function Component Scan Spring Cloud Function will scan for implementations of `Function`, `Consumer` and `Supplier` in a package called `functions` if it exists. Using this feature you can write functions that have no dependencies on Spring - not even the `@Component` annotation is needed. If you want to use a different package, you can set `spring.cloud.function.scan.packages`. You can also use `spring.cloud.function.scan.enabled=false` to switch off the scan completely. +[[standalone-web-applications]] == Standalone Web Applications Functions could be automatically exported as HTTP endpoints. @@ -756,6 +785,7 @@ When POSTing text the response format might be different with Spring Boot 2.0 an See <> to see the details and example on how to test such application. +[[http-request-parameters]] ==== HTTP Request Parameters As you have noticed from the previous table, you can pass an argument to a function as path variable (i.e., `/{function}/{item}`). For example, `http://localhost:8080/uppercase/foo` will result in calling `uppercase` function with its input parameter being `foo`. @@ -764,6 +794,7 @@ While this is the recommended approach and the one that fits most use cases case The framework will treat HTTP request parameters similar to the HTTP headers by storing them in the `Message` headers under the header key `http_request_param` with its value being a `Map` of request parameters, so in order to access them your function input signature should accept `Message` type (e.g., `Function, String>`). For convenience we provide `HeaderUtils.HTTP_REQUEST_PARAM` constant. +[[function-mapping-rules]] === Function Mapping rules If there is only a single function (consumer etc.) in the catalog, the name in the path is optional. @@ -790,6 +821,7 @@ However there are function `foo` and `bar`. So, in this case `localhost:8080/upp This could be useful especially for cases when URL is used to communicate certain information since there will be Message header called `uri` with the value of the actual URL, giving user ability to use it for evaluation and computation. +[[function-filtering-rules]] === Function Filtering rules In situations where there are more than one function in catalog there may be a need to only export certain functions or function compositions. In that case you can use @@ -810,6 +842,7 @@ This will only export function `foo` and function `bar` regardless how many func This will only export function composition `foo|bar` and function `baz` regardless how many functions are available in catalog (e.g., `localhost:8080/foo,bar`). +[[crud-rest-with-spring-cloud-function]] === CRUD REST with Spring Cloud Function By now it should be clear that functions are exported as REST endpoints and can be invoked using various HTTP methods. In other words a single @@ -829,11 +862,13 @@ spring.cloud.function.http.DELETE=deleteById As you can see, here we’re mapping functions to various HTTP methods using the same rules as `spring.cloud.function.definition` property where “;” allows us to define several functions and “|” signifies function composition. +[[standalone-streaming-applications]] == Standalone Streaming Applications To send or receive messages from a broker (such as RabbitMQ or Kafka) you can leverage `spring-cloud-stream` project and it's integration with Spring Cloud Function. Please refer to https://cloud.spring.io/spring-cloud-static/spring-cloud-stream/current/reference/html/spring-cloud-stream.html#spring_cloud_function[Spring Cloud Function] section of the https://spring.io/projects/spring-cloud-stream[Spring Cloud Stream] reference manual for more details and examples. +[[deploying-a-packaged-function]] == Deploying a Packaged Function Spring Cloud Function provides a "deployer" library that allows you to launch a jar file (or exploded archive, or set of jar files) with an isolated class loader and expose the functions defined in it. This is quite a powerful tool that would allow you to, for instance, adapt a function to a range of different input-output adapters without changing the target jar file. Serverless platforms often have this kind of feature built in, so you could see it as a building block for a function invoker in such a platform (indeed the https://projectriff.io[Riff] Java function invoker uses this library). @@ -907,10 +942,12 @@ public MavenProperties mavenProperties() { } ``` +[[supported-packaging-scenarios]] === Supported Packaging Scenarios Currently Spring Cloud Function supports several packaging scenarios to give you the most flexibility when it comes to deploying functions. +[[simple-jar]] ==== Simple JAR This packaging option implies no dependency on anything related to Spring. @@ -954,6 +991,7 @@ package named `functions`, you can omit `spring.cloud.function.function-class` p Keep in mind the naming convention to follow when doing function lookup. For example function class `functions.UpperCaseFunction` will be available in `FunctionCatalog` under the name `upperCaseFunction`. +[[spring-boot-jar]] ==== Spring Boot JAR This packaging option implies there is a dependency on Spring Boot and that the JAR was generated as Spring Boot JAR. That said, given that the deployed JAR @@ -978,6 +1016,7 @@ As before all you need to do is specify `location` and `function-class` properti For more details please reference the complete sample available https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-deployer/src/it/bootjar[here]. You can also find a corresponding test in https://github.com/spring-cloud/spring-cloud-function/blob/master/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/FunctionDeployerTests.java#L50[FunctionDeployerTests]. +[[spring-boot-application]] ==== Spring Boot Application This packaging option implies your JAR is complete stand alone Spring Boot application with functions as managed Spring beans. @@ -1012,10 +1051,12 @@ You can also find a corresponding test in https://github.com/spring-cloud/spring NOTE: This particular deployment option may or may not have Spring Cloud Function on it's classpath. From the deployer perspective this doesn't matter. +[[functional-bean-definitions]] == Functional Bean Definitions include::functional.adoc[leveloffset=+1] +[[serverless-platform-adapters]] == Serverless Platform Adapters As well as being able to run as a standalone process, a Spring Cloud