From a1b190fddcd2abc29d14bbb57bd05e46654dffbc Mon Sep 17 00:00:00 2001 From: buildmaster Date: Thu, 13 Dec 2018 20:19:12 +0000 Subject: [PATCH] Sync docs from v2.1.0.RC3 to gh-pages --- .../2.1.0.RC3/css/highlight.css | 35 + .../2.1.0.RC3/css/manual-multipage.css | 9 + .../2.1.0.RC3/css/manual-singlepage.css | 6 + spring-cloud-stream/2.1.0.RC3/css/manual.css | 344 ++ spring-cloud-stream/2.1.0.RC3/ghpages.sh | 330 ++ .../2.1.0.RC3/images/SCSt-groups.png | Bin 0 -> 17392 bytes .../2.1.0.RC3/images/SCSt-overview.png | Bin 0 -> 96212 bytes .../2.1.0.RC3/images/SCSt-partitioning.png | Bin 0 -> 18068 bytes .../2.1.0.RC3/images/SCSt-sensors.png | Bin 0 -> 16910 bytes .../2.1.0.RC3/images/SCSt-with-binder.png | Bin 0 -> 18899 bytes .../2.1.0.RC3/images/background.png | Bin 0 -> 18255 bytes .../2.1.0.RC3/images/callouts/1.png | Bin 0 -> 329 bytes .../2.1.0.RC3/images/callouts/2.png | Bin 0 -> 353 bytes .../2.1.0.RC3/images/callouts/3.png | Bin 0 -> 350 bytes .../2.1.0.RC3/images/caution.png | Bin 0 -> 2099 bytes .../custom_vs_global_error_channels.png | Bin 0 -> 48392 bytes .../2.1.0.RC3/images/important.png | Bin 0 -> 2085 bytes spring-cloud-stream/2.1.0.RC3/images/logo.png | Bin 0 -> 4387 bytes spring-cloud-stream/2.1.0.RC3/images/note.png | Bin 0 -> 2257 bytes .../2.1.0.RC3/images/producers-consumers.png | Bin 0 -> 15947 bytes .../2.1.0.RC3/images/redis-binder.png | Bin 0 -> 13731 bytes .../2.1.0.RC3/images/registration.png | Bin 0 -> 22405 bytes .../2.1.0.RC3/images/schema_reading.png | Bin 0 -> 45621 bytes .../2.1.0.RC3/images/schema_resolution.png | Bin 0 -> 27718 bytes .../2.1.0.RC3/images/spring-initializr.png | Bin 0 -> 82106 bytes spring-cloud-stream/2.1.0.RC3/images/tip.png | Bin 0 -> 931 bytes .../2.1.0.RC3/images/warning.png | Bin 0 -> 2130 bytes spring-cloud-stream/2.1.0.RC3/index.html | 117 + .../2.1.0.RC3/multi/css/highlight.css | 35 + .../2.1.0.RC3/multi/css/manual-multipage.css | 9 + .../2.1.0.RC3/multi/css/manual-singlepage.css | 6 + .../2.1.0.RC3/multi/css/manual.css | 344 ++ .../2.1.0.RC3/multi/images/background.png | Bin 0 -> 18255 bytes .../2.1.0.RC3/multi/images/callouts/1.png | Bin 0 -> 329 bytes .../2.1.0.RC3/multi/images/callouts/2.png | Bin 0 -> 353 bytes .../2.1.0.RC3/multi/images/callouts/3.png | Bin 0 -> 350 bytes .../2.1.0.RC3/multi/images/caution.png | Bin 0 -> 2099 bytes .../2.1.0.RC3/multi/images/important.png | Bin 0 -> 2085 bytes .../2.1.0.RC3/multi/images/logo.png | Bin 0 -> 4387 bytes .../2.1.0.RC3/multi/images/note.png | Bin 0 -> 2257 bytes .../2.1.0.RC3/multi/images/tip.png | Bin 0 -> 931 bytes .../2.1.0.RC3/multi/images/warning.png | Bin 0 -> 2130 bytes ...y_of_springs_data_integration_journey.html | 9 + .../multi/multi__binder_implementations.html | 3 + .../multi/multi__configuration_options.html | 127 + .../multi/multi__health_indicator.html | 12 + ...ulti__inter_application_communication.html | 37 + .../2.1.0.RC3/multi/multi__main_concepts.html | 35 + .../2.1.0.RC3/multi/multi__preface.html | 3 + .../multi/multi__programming_model.html | 396 +++ .../2.1.0.RC3/multi/multi__quick_start.html | 53 + .../2.1.0.RC3/multi/multi__samples.html | 3 + .../2.1.0.RC3/multi/multi__testing.html | 56 + .../multi/multi__whats_new_in_2_0.html | 32 + .../multi/multi_content-type-management.html | 78 + .../multi/multi_schema-evolution.html | 88 + ..._spring-cloud-stream-overview-binders.html | 76 + ...ing-cloud-stream-overview-introducing.html | 42 + ...cloud-stream-overview-metrics-emitter.html | 50 + .../multi/multi_spring-cloud-stream.html | 3 + .../2.1.0.RC3/single/css/highlight.css | 35 + .../2.1.0.RC3/single/css/manual-multipage.css | 9 + .../single/css/manual-singlepage.css | 6 + .../2.1.0.RC3/single/css/manual.css | 344 ++ .../2.1.0.RC3/single/images/background.png | Bin 0 -> 18255 bytes .../2.1.0.RC3/single/images/callouts/1.png | Bin 0 -> 329 bytes .../2.1.0.RC3/single/images/callouts/2.png | Bin 0 -> 353 bytes .../2.1.0.RC3/single/images/callouts/3.png | Bin 0 -> 350 bytes .../2.1.0.RC3/single/images/caution.png | Bin 0 -> 2099 bytes .../2.1.0.RC3/single/images/important.png | Bin 0 -> 2085 bytes .../2.1.0.RC3/single/images/logo.png | Bin 0 -> 4387 bytes .../2.1.0.RC3/single/images/note.png | Bin 0 -> 2257 bytes .../2.1.0.RC3/single/images/tip.png | Bin 0 -> 931 bytes .../2.1.0.RC3/single/images/warning.png | Bin 0 -> 2130 bytes .../2.1.0.RC3/single/spring-cloud-stream.html | 1052 ++++++ .../2.1.0.RC3/spring-cloud-stream.xml | 2900 +++++++++++++++++ 76 files changed, 6684 insertions(+) create mode 100644 spring-cloud-stream/2.1.0.RC3/css/highlight.css create mode 100644 spring-cloud-stream/2.1.0.RC3/css/manual-multipage.css create mode 100644 spring-cloud-stream/2.1.0.RC3/css/manual-singlepage.css create mode 100644 spring-cloud-stream/2.1.0.RC3/css/manual.css create mode 100644 spring-cloud-stream/2.1.0.RC3/ghpages.sh create mode 100644 spring-cloud-stream/2.1.0.RC3/images/SCSt-groups.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/SCSt-overview.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/SCSt-partitioning.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/SCSt-sensors.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/SCSt-with-binder.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/background.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/callouts/1.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/callouts/2.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/callouts/3.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/caution.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/custom_vs_global_error_channels.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/important.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/logo.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/note.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/producers-consumers.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/redis-binder.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/registration.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/schema_reading.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/schema_resolution.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/spring-initializr.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/tip.png create mode 100644 spring-cloud-stream/2.1.0.RC3/images/warning.png create mode 100644 spring-cloud-stream/2.1.0.RC3/index.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/css/highlight.css create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/css/manual-multipage.css create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/css/manual-singlepage.css create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/css/manual.css create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/images/background.png create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/images/callouts/1.png create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/images/callouts/2.png create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/images/callouts/3.png create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/images/caution.png create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/images/important.png create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/images/logo.png create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/images/note.png create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/images/tip.png create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/images/warning.png create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi__a_brief_history_of_springs_data_integration_journey.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi__binder_implementations.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi__configuration_options.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi__health_indicator.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi__inter_application_communication.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi__main_concepts.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi__preface.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi__programming_model.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi__quick_start.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi__samples.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi__testing.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi__whats_new_in_2_0.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi_content-type-management.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi_schema-evolution.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream-overview-binders.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream-overview-introducing.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream-overview-metrics-emitter.html create mode 100644 spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream.html create mode 100644 spring-cloud-stream/2.1.0.RC3/single/css/highlight.css create mode 100644 spring-cloud-stream/2.1.0.RC3/single/css/manual-multipage.css create mode 100644 spring-cloud-stream/2.1.0.RC3/single/css/manual-singlepage.css create mode 100644 spring-cloud-stream/2.1.0.RC3/single/css/manual.css create mode 100644 spring-cloud-stream/2.1.0.RC3/single/images/background.png create mode 100644 spring-cloud-stream/2.1.0.RC3/single/images/callouts/1.png create mode 100644 spring-cloud-stream/2.1.0.RC3/single/images/callouts/2.png create mode 100644 spring-cloud-stream/2.1.0.RC3/single/images/callouts/3.png create mode 100644 spring-cloud-stream/2.1.0.RC3/single/images/caution.png create mode 100644 spring-cloud-stream/2.1.0.RC3/single/images/important.png create mode 100644 spring-cloud-stream/2.1.0.RC3/single/images/logo.png create mode 100644 spring-cloud-stream/2.1.0.RC3/single/images/note.png create mode 100644 spring-cloud-stream/2.1.0.RC3/single/images/tip.png create mode 100644 spring-cloud-stream/2.1.0.RC3/single/images/warning.png create mode 100644 spring-cloud-stream/2.1.0.RC3/single/spring-cloud-stream.html create mode 100644 spring-cloud-stream/2.1.0.RC3/spring-cloud-stream.xml diff --git a/spring-cloud-stream/2.1.0.RC3/css/highlight.css b/spring-cloud-stream/2.1.0.RC3/css/highlight.css new file mode 100644 index 00000000..ffefef72 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/css/highlight.css @@ -0,0 +1,35 @@ +/* + code highlight CSS resemblign the Eclipse IDE default color schema + @author Costin Leau +*/ + +.hl-keyword { + color: #7F0055; + font-weight: bold; +} + +.hl-comment { + color: #3F5F5F; + font-style: italic; +} + +.hl-multiline-comment { + color: #3F5FBF; + font-style: italic; +} + +.hl-tag { + color: #3F7F7F; +} + +.hl-attribute { + color: #7F007F; +} + +.hl-value { + color: #2A00FF; +} + +.hl-string { + color: #2A00FF; +} \ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/css/manual-multipage.css b/spring-cloud-stream/2.1.0.RC3/css/manual-multipage.css new file mode 100644 index 00000000..0c484531 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/css/manual-multipage.css @@ -0,0 +1,9 @@ +@IMPORT url("manual.css"); + +body.firstpage { + background: url("../images/background.png") no-repeat center top; +} + +div.part h1 { + border-top: none; +} diff --git a/spring-cloud-stream/2.1.0.RC3/css/manual-singlepage.css b/spring-cloud-stream/2.1.0.RC3/css/manual-singlepage.css new file mode 100644 index 00000000..4a7fd140 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/css/manual-singlepage.css @@ -0,0 +1,6 @@ +@IMPORT url("manual.css"); + +body { + background: url("../images/background.png") no-repeat center top; +} + diff --git a/spring-cloud-stream/2.1.0.RC3/css/manual.css b/spring-cloud-stream/2.1.0.RC3/css/manual.css new file mode 100644 index 00000000..0ecbe2e8 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/css/manual.css @@ -0,0 +1,344 @@ +@IMPORT url("highlight.css"); + +html { + padding: 0pt; + margin: 0pt; +} + +body { + color: #333333; + margin: 15px 30px; + font-family: Helvetica, Arial, Freesans, Clean, Sans-serif; + line-height: 1.6; + -webkit-font-smoothing: antialiased; +} + +code { + font-size: 16px; + font-family: Consolas, "Liberation Mono", Courier, monospace; +} + +:not(a)>code { + color: #6D180B; +} + +:not(pre)>code { + background-color: #F2F2F2; + border: 1px solid #CCCCCC; + border-radius: 4px; + padding: 1px 3px 0; + text-shadow: none; + white-space: nowrap; +} + +body>*:first-child { + margin-top: 0 !important; +} + +div { + margin: 0pt; +} + +hr { + border: 1px solid #CCCCCC; + background: #CCCCCC; +} + +h1,h2,h3,h4,h5,h6 { + color: #000000; + cursor: text; + font-weight: bold; + margin: 30px 0 10px; + padding: 0; +} + +h1,h2,h3 { + margin: 40px 0 10px; +} + +h1 { + margin: 70px 0 30px; + padding-top: 20px; +} + +div.part h1 { + border-top: 1px dotted #CCCCCC; +} + +h1,h1 code { + font-size: 32px; +} + +h2,h2 code { + font-size: 24px; +} + +h3,h3 code { + font-size: 20px; +} + +h4,h1 code,h5,h5 code,h6,h6 code { + font-size: 18px; +} + +div.book,div.chapter,div.appendix,div.part,div.preface { + min-width: 300px; + max-width: 1200px; + margin: 0 auto; +} + +p.releaseinfo { + font-weight: bold; + margin-bottom: 40px; + margin-top: 40px; +} + +div.authorgroup { + line-height: 1; +} + +p.copyright { + line-height: 1; + margin-bottom: -5px; +} + +.legalnotice p { + font-style: italic; + font-size: 14px; + line-height: 1; +} + +div.titlepage+p,div.titlepage+p { + margin-top: 0; +} + +pre { + line-height: 1.0; + color: black; +} + +a { + color: #4183C4; + text-decoration: none; +} + +p { + margin: 15px 0; + text-align: left; +} + +ul,ol { + padding-left: 30px; +} + +li p { + margin: 0; +} + +div.table { + margin: 1em; + padding: 0.5em; + text-align: center; +} + +div.table table,div.informaltable table { + display: table; + width: 100%; +} + +div.table td { + padding-left: 7px; + padding-right: 7px; +} + +.sidebar { + line-height: 1.4; + padding: 0 20px; + background-color: #F8F8F8; + border: 1px solid #CCCCCC; + border-radius: 3px 3px 3px 3px; +} + +.sidebar p.title { + color: #6D180B; +} + +pre.programlisting,pre.screen { + font-size: 15px; + padding: 6px 10px; + background-color: #F8F8F8; + border: 1px solid #CCCCCC; + border-radius: 3px 3px 3px 3px; + clear: both; + overflow: auto; + line-height: 1.4; + font-family: Consolas, "Liberation Mono", Courier, monospace; +} + +table { + border-collapse: collapse; + border-spacing: 0; + border: 1px solid #DDDDDD !important; + border-radius: 4px !important; + border-collapse: separate !important; + line-height: 1.6; +} + +table thead { + background: #F5F5F5; +} + +table tr { + border: none; + border-bottom: none; +} + +table th { + font-weight: bold; +} + +table th,table td { + border: none !important; + padding: 6px 13px; +} + +table tr:nth-child(2n) { + background-color: #F8F8F8; +} + +td p { + margin: 0 0 15px 0; +} + +div.table-contents td p { + margin: 0; +} + +div.important *,div.note *,div.tip *,div.warning *,div.navheader *,div.navfooter *,div.calloutlist * + { + border: none !important; + background: none !important; + margin: 0; +} + +div.important p,div.note p,div.tip p,div.warning p { + color: #6F6F6F; + line-height: 1.6; +} + +div.important code,div.note code,div.tip code,div.warning code { + background-color: #F2F2F2 !important; + border: 1px solid #CCCCCC !important; + border-radius: 4px !important; + padding: 1px 3px 0 !important; + text-shadow: none !important; + white-space: nowrap !important; +} + +.note th,.tip th,.warning th { + display: none; +} + +.note tr:first-child td,.tip tr:first-child td,.warning tr:first-child td + { + border-right: 1px solid #CCCCCC !important; + padding-top: 10px; +} + +div.calloutlist p,div.calloutlist td { + padding: 0; + margin: 0; +} + +div.calloutlist>table>tbody>tr>td:first-child { + padding-left: 10px; + width: 30px !important; +} + +div.important,div.note,div.tip,div.warning { + margin-left: 0px !important; + margin-right: 20px !important; + margin-top: 20px; + margin-bottom: 20px; + padding-top: 10px; + padding-bottom: 10px; +} + +div.toc { + line-height: 1.2; +} + +dl,dt { + margin-top: 1px; + margin-bottom: 0; +} + +div.toc>dl>dt { + font-size: 32px; + font-weight: bold; + margin: 30px 0 10px 0; + display: block; +} + +div.toc>dl>dd>dl>dt { + font-size: 24px; + font-weight: bold; + margin: 20px 0 10px 0; + display: block; +} + +div.toc>dl>dd>dl>dd>dl>dt { + font-weight: bold; + font-size: 20px; + margin: 10px 0 0 0; +} + +tbody.footnotes * { + border: none !important; +} + +div.footnote p { + margin: 0; + line-height: 1; +} + +div.footnote p sup { + margin-right: 6px; + vertical-align: middle; +} + +div.navheader { + border-bottom: 1px solid #CCCCCC; +} + +div.navfooter { + border-top: 1px solid #CCCCCC; +} + +.title { + margin-left: -1em; + padding-left: 1em; +} + +.title>a { + position: absolute; + visibility: hidden; + display: block; + font-size: 0.85em; + margin-top: 0.05em; + margin-left: -1em; + vertical-align: text-top; + color: black; +} + +.title>a:before { + content: "\00A7"; +} + +.title:hover>a,.title>a:hover,.title:hover>a:hover { + visibility: visible; +} + +.title:focus>a,.title>a:focus,.title:focus>a:focus { + outline: 0; +} diff --git a/spring-cloud-stream/2.1.0.RC3/ghpages.sh b/spring-cloud-stream/2.1.0.RC3/ghpages.sh new file mode 100644 index 00000000..6795216e --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/ghpages.sh @@ -0,0 +1,330 @@ +#!/bin/bash -x + +set -e + +# Set default props like MAVEN_PATH, ROOT_FOLDER etc. +function set_default_props() { + # The script should be executed from the root folder + ROOT_FOLDER=`pwd` + echo "Current folder is ${ROOT_FOLDER}" + + if [[ ! -e "${ROOT_FOLDER}/.git" ]]; then + echo "You're not in the root folder of the project!" + exit 1 + fi + + # Prop that will let commit the changes + COMMIT_CHANGES="no" + MAVEN_PATH=${MAVEN_PATH:-} + echo "Path to Maven is [${MAVEN_PATH}]" + REPO_NAME=${PWD##*/} + echo "Repo name is [${REPO_NAME}]" + SPRING_CLOUD_STATIC_REPO=${SPRING_CLOUD_STATIC_REPO:-git@github.com:spring-cloud/spring-cloud-static.git} + echo "Spring Cloud Static repo is [${SPRING_CLOUD_STATIC_REPO}" +} + +# Check if gh-pages exists and docs have been built +function check_if_anything_to_sync() { + git remote set-url --push origin `git config remote.origin.url | sed -e 's/^git:/https:/'` + + if ! (git remote set-branches --add origin gh-pages && git fetch -q); then + echo "No gh-pages, so not syncing" + exit 0 + fi + + if ! [ -d docs/target/generated-docs ] && ! [ "${BUILD}" == "yes" ]; then + echo "No gh-pages sources in docs/target/generated-docs, so not syncing" + exit 0 + fi +} + +function retrieve_current_branch() { + # Code getting the name of the current branch. For master we want to publish as we did until now + # http://stackoverflow.com/questions/1593051/how-to-programmatically-determine-the-current-checked-out-git-branch + # If there is a branch already passed will reuse it - otherwise will try to find it + CURRENT_BRANCH=${BRANCH} + if [[ -z "${CURRENT_BRANCH}" ]] ; then + CURRENT_BRANCH=$(git symbolic-ref -q HEAD) + CURRENT_BRANCH=${CURRENT_BRANCH##refs/heads/} + CURRENT_BRANCH=${CURRENT_BRANCH:-HEAD} + fi + echo "Current branch is [${CURRENT_BRANCH}]" + git checkout ${CURRENT_BRANCH} || echo "Failed to check the branch... continuing with the script" +} + +# Switches to the provided value of the release version. We always prefix it with `v` +function switch_to_tag() { + git checkout v${VERSION} +} + +# Build the docs if switch is on +function build_docs_if_applicable() { + if [[ "${BUILD}" == "yes" ]] ; then + ./mvnw clean install -P docs -pl docs -DskipTests + fi +} + +# Get the name of the `docs.main` property +# Get whitelisted branches - assumes that a `docs` module is available under `docs` profile +function retrieve_doc_properties() { + MAIN_ADOC_VALUE=$("${MAVEN_PATH}"mvn -q \ + -Dexec.executable="echo" \ + -Dexec.args='${docs.main}' \ + --non-recursive \ + org.codehaus.mojo:exec-maven-plugin:1.3.1:exec) + echo "Extracted 'main.adoc' from Maven build [${MAIN_ADOC_VALUE}]" + + + WHITELIST_PROPERTY=${WHITELIST_PROPERTY:-"docs.whitelisted.branches"} + WHITELISTED_BRANCHES_VALUE=$("${MAVEN_PATH}"mvn -q \ + -Dexec.executable="echo" \ + -Dexec.args="\${${WHITELIST_PROPERTY}}" \ + org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \ + -P docs \ + -pl docs) + echo "Extracted '${WHITELIST_PROPERTY}' from Maven build [${WHITELISTED_BRANCHES_VALUE}]" +} + +# Stash any outstanding changes +function stash_changes() { + git diff-index --quiet HEAD && dirty=$? || (echo "Failed to check if the current repo is dirty. Assuming that it is." && dirty="1") + if [ "$dirty" != "0" ]; then git stash; fi +} + +# Switch to gh-pages branch to sync it with current branch +function add_docs_from_target() { + local DESTINATION_REPO_FOLDER + if [[ -z "${DESTINATION}" && -z "${CLONE}" ]] ; then + DESTINATION_REPO_FOLDER=${ROOT_FOLDER} + elif [[ "${CLONE}" == "yes" ]]; then + mkdir -p ${ROOT_FOLDER}/target + local clonedStatic=${ROOT_FOLDER}/target/spring-cloud-static + if [[ ! -e "${clonedStatic}/.git" ]]; then + echo "Cloning Spring Cloud Static to target" + git clone ${SPRING_CLOUD_STATIC_REPO} ${clonedStatic} && git checkout gh-pages + else + echo "Spring Cloud Static already cloned - will pull changes" + cd ${clonedStatic} && git checkout gh-pages && git pull origin gh-pages + fi + DESTINATION_REPO_FOLDER=${clonedStatic}/${REPO_NAME} + mkdir -p ${DESTINATION_REPO_FOLDER} + else + if [[ ! -e "${DESTINATION}/.git" ]]; then + echo "[${DESTINATION}] is not a git repository" + exit 1 + fi + DESTINATION_REPO_FOLDER=${DESTINATION}/${REPO_NAME} + mkdir -p ${DESTINATION_REPO_FOLDER} + echo "Destination was provided [${DESTINATION}]" + fi + cd ${DESTINATION_REPO_FOLDER} + git checkout gh-pages + git pull origin gh-pages + + # Add git branches + ################################################################### + if [[ -z "${VERSION}" ]] ; then + copy_docs_for_current_version + else + copy_docs_for_provided_version + fi + commit_changes_if_applicable +} + + +# Copies the docs by using the retrieved properties from Maven build +function copy_docs_for_current_version() { + if [[ "${CURRENT_BRANCH}" == "master" ]] ; then + echo -e "Current branch is master - will copy the current docs only to the root folder" + for f in docs/target/generated-docs/*; do + file=${f#docs/target/generated-docs/*} + if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then + # Not ignored... + cp -rf $f ${ROOT_FOLDER}/ + git add -A ${ROOT_FOLDER}/$file + fi + done + COMMIT_CHANGES="yes" + else + echo -e "Current branch is [${CURRENT_BRANCH}]" + # http://stackoverflow.com/questions/29300806/a-bash-script-to-check-if-a-string-is-present-in-a-comma-separated-list-of-strin + if [[ ",${WHITELISTED_BRANCHES_VALUE}," = *",${CURRENT_BRANCH},"* ]] ; then + mkdir -p ${ROOT_FOLDER}/${CURRENT_BRANCH} + echo -e "Branch [${CURRENT_BRANCH}] is whitelisted! Will copy the current docs to the [${CURRENT_BRANCH}] folder" + for f in docs/target/generated-docs/*; do + file=${f#docs/target/generated-docs/*} + if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then + # Not ignored... + # We want users to access 2.0.0.BUILD-SNAPSHOT/ instead of 1.0.0.RELEASE/spring-cloud.sleuth.html + if [[ "${file}" == "${MAIN_ADOC_VALUE}.html" ]] ; then + # We don't want to copy the spring-cloud-sleuth.html + # we want it to be converted to index.html + cp -rf $f ${ROOT_FOLDER}/${CURRENT_BRANCH}/index.html + git add -A ${ROOT_FOLDER}/${CURRENT_BRANCH}/index.html + else + cp -rf $f ${ROOT_FOLDER}/${CURRENT_BRANCH} + git add -A ${ROOT_FOLDER}/${CURRENT_BRANCH}/$file + fi + fi + done + COMMIT_CHANGES="yes" + else + echo -e "Branch [${CURRENT_BRANCH}] is not on the white list! Check out the Maven [${WHITELIST_PROPERTY}] property in + [docs] module available under [docs] profile. Won't commit any changes to gh-pages for this branch." + fi + fi +} + +# Copies the docs by using the explicitly provided version +function copy_docs_for_provided_version() { + local FOLDER=${DESTINATION_REPO_FOLDER}/${VERSION} + mkdir -p ${FOLDER} + echo -e "Current tag is [v${VERSION}] Will copy the current docs to the [${FOLDER}] folder" + for f in ${ROOT_FOLDER}/docs/target/generated-docs/*; do + file=${f#${ROOT_FOLDER}/docs/target/generated-docs/*} + copy_docs_for_branch ${file} ${FOLDER} + done + COMMIT_CHANGES="yes" + CURRENT_BRANCH="v${VERSION}" +} + +# Copies the docs from target to the provided destination +# Params: +# $1 - file from target +# $2 - destination to which copy the files +function copy_docs_for_branch() { + local file=$1 + local destination=$2 + if ! git ls-files -i -o --exclude-standard --directory | grep -q ^${file}$; then + # Not ignored... + # We want users to access 2.0.0.BUILD-SNAPSHOT/ instead of 1.0.0.RELEASE/spring-cloud.sleuth.html + if [[ ("${file}" == "${MAIN_ADOC_VALUE}.html") || ("${file}" == "${REPO_NAME}.html") ]] ; then + # We don't want to copy the spring-cloud-sleuth.html + # we want it to be converted to index.html + cp -rf $f ${destination}/index.html + git add -A ${destination}/index.html + else + cp -rf $f ${destination} + git add -A ${destination}/$file + fi + fi +} + +function commit_changes_if_applicable() { + if [[ "${COMMIT_CHANGES}" == "yes" ]] ; then + COMMIT_SUCCESSFUL="no" + git commit -a -m "Sync docs from ${CURRENT_BRANCH} to gh-pages" && COMMIT_SUCCESSFUL="yes" || echo "Failed to commit changes" + + # Uncomment the following push if you want to auto push to + # the gh-pages branch whenever you commit to master locally. + # This is a little extreme. Use with care! + ################################################################### + if [[ "${COMMIT_SUCCESSFUL}" == "yes" ]] ; then + git push origin gh-pages + fi + fi +} + +# Switch back to the previous branch and exit block +function checkout_previous_branch() { + # If -version was provided we need to come back to root project + cd ${ROOT_FOLDER} + git checkout ${CURRENT_BRANCH} || echo "Failed to check the branch... continuing with the script" + if [ "$dirty" != "0" ]; then git stash pop; fi + exit 0 +} + +# Assert if properties have been properly passed +function assert_properties() { +echo "VERSION [${VERSION}], DESTINATION [${DESTINATION}], CLONE [${CLONE}]" +if [[ "${VERSION}" != "" && (-z "${DESTINATION}" && -z "${CLONE}") ]] ; then echo "Version was set but destination / clone was not!"; exit 1;fi +if [[ ("${DESTINATION}" != "" && "${CLONE}" != "") && -z "${VERSION}" ]] ; then echo "Destination / clone was set but version was not!"; exit 1;fi +if [[ "${DESTINATION}" != "" && "${CLONE}" == "yes" ]] ; then echo "Destination and clone was set. Pick one!"; exit 1;fi +} + +# Prints the usage +function print_usage() { +cat </` +- if the destination switch is passed (-d) then the script will check if the provided dir is a git repo and then will + switch to gh-pages of that repo and copy the generated docs to `docs//` + +USAGE: + +You can use the following options: + +-v|--version - the script will apply the whole procedure for a particular library version +-d|--destination - the root of destination folder where the docs should be copied. You have to use the full path. + E.g. point to spring-cloud-static folder. Can't be used with (-c) +-b|--build - will run the standard build process after checking out the branch +-c|--clone - will automatically clone the spring-cloud-static repo instead of providing the destination. + Obviously can't be used with (-d) + +EOF +} + + +# ========================================== +# ____ ____ _____ _____ _____ _______ +# / ____|/ ____| __ \|_ _| __ \__ __| +# | (___ | | | |__) | | | | |__) | | | +# \___ \| | | _ / | | | ___/ | | +# ____) | |____| | \ \ _| |_| | | | +# |_____/ \_____|_| \_\_____|_| |_| +# +# ========================================== + +while [[ $# > 0 ]] +do +key="$1" +case ${key} in + -v|--version) + VERSION="$2" + shift # past argument + ;; + -d|--destination) + DESTINATION="$2" + shift # past argument + ;; + -b|--build) + BUILD="yes" + ;; + -c|--clone) + CLONE="yes" + ;; + -h|--help) + print_usage + exit 0 + ;; + *) + echo "Invalid option: [$1]" + print_usage + exit 1 + ;; +esac +shift # past argument or value +done + +assert_properties +set_default_props +check_if_anything_to_sync +if [[ -z "${VERSION}" ]] ; then + retrieve_current_branch +else + switch_to_tag +fi +build_docs_if_applicable +retrieve_doc_properties +stash_changes +add_docs_from_target +checkout_previous_branch \ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/images/SCSt-groups.png b/spring-cloud-stream/2.1.0.RC3/images/SCSt-groups.png new file mode 100644 index 0000000000000000000000000000000000000000..931ac9727a6f7984d5f931a46a815034d1c83af6 GIT binary patch literal 17392 zcmchWuqT5xa(PvGF-aZnJzoy|VZ zZSWtwyOz8Z{NfNx5cmPrMM2*k4(=%~>>oT_W;P)x@ZDBN&qGgDMaaV0kdW z3QDlL`#5=+d9ymXQ~#%t|Faz#D|ZVwTNe*oXD13+yJqIjo*tr9RIrZz`_F&I>0t}~ zpProD|Le8D3$nwWuye9;u>W`4psEP$u8_2|ql=rByE|xKj927e$^Xl}|LNyH|Q*ZZKSAFbep~LO~Ib??!<@ z1^(6q2cL%whrn(}b|N55BQqhxZc`vUMNuFxC;9)Rf<%BBR)`jEI=}N;jaiReJejEN zbg`iO?r5HP$1LSs?7i%B;|ANA($9upj;D$Sg5eQ~`5g4P6}6>s6ePAnAy6e%*@JQ6 z-wxkDe(#OKMaCdLzx`GH_jH7vB%{Pc1z{b5cpt9$a>*XCz7#D2Cy4_gMuQEPfL6Bb z4T_Q9QKNJ?I+5@jhb%rvJNlRSN<-Iwww4?1`91b0LlBW)F`%I}^`qK+EAQuSemhje z?YEsEKb|dE?{l_`A1gNoS#5GOG<~x_S)iCi7jSp^Im3gIa)>hjkEGjaVX1j{Cj5*{ zyvQkv@lvLeUJ33QnDyT^J=?mDCp^^~~Q&VnFS15_=KczBsKGqetgHf8o?@ zc6GekW#}=4!vLFfL|RG?=xF*{yI-1&$Io}i-|mhb=9EN{;2Ff=4?;J&Q)EzT8k29F z3K*WicfS3Cmq^RK18E5SaEhSuaeKbnB(FU&hNVuS0zskH=n}%#v|!%xcxxX`#Be}M zNfDrdQ;8EzH~DIJ8Xs|km2{a$dCp%m)7`}OIXpI2h!7ZnCyONx?3xGngP4N*G4m13 z2sGp+Zu8^bslcv3KtUV$Ty|>1!03`JSa6wNxcU+F_s8GI=V#{!Gnk_1 zlep?4waRI1yF{LE&Dt;K+U`$BIDt|A1)a+hfiim)Ww}efzdny;Jw{73f~hILB+}^=zuAf?PD~npyY5|;$dr) zXD+7eQ?fb2o%Gi{+H+mf8uU!O`1w!)Z1nQ5n{qTq_-Z49T<+N~WEKAR#Jp%{k9WUK znk^NvLc*}XGAhV15X(}#OiCj2+RZXB92ds0p^5EU?+$OiZuebmJLEOD?A+`kFmy=B z<7uZwK&7Dw_|U1MnT$r|GOH=i>%1nyV7^de)-`ZHnj_>%Eb80P-ZrbHTr18iF6gTa z!BGb5UaMaeNgD$vtes{Ocw^b8Sc@G}h;u!|W3Nf8oc<3~BzUpGyp^tK8OZ`5%J%?^ ztu*i|@!t=bC@iPT&K)nc{qg6SC_A5#;D4UpNjXW4bIhc*_y4fFqPz63TwL(EBNf@;eO0H#K}?{-ih|Lb zbbsITukA0^?H&rYr*J7) zJ*J6FT_}^iMNnW4`4(^owv5+KiY^(ylTq87qv_}Zn}fh#pTA62OGi9=;xHAa^Z^9| zc0I&&P|pDY5&43&HL)|~D!ovYZZdS@X1j8pRDPWC|=*nri z^~3rJHN(V|*Vuz}`L;6-bamMOkPT<@n&N#+70*AI;sXHmKTkkA7FEn+M38a8y=?Rs zqR|p)s5TE2?=q@rtZ^obI2F=s4x^*z?r3ek~M<$XuXMkZHBQ2=-zdSjYM8Xm+O$h!b{%-{Ou!^AF z1M2+WnA2%{O0FpI?=hwF2bEw*tEB+m5jLoQuYdwx0ZfI`3;2Mb4^1SxzS6KU(mp%Bc@=S%G~vDa+E;D|9Mi3sg<^)Td2P4`}2&^PdUd#BWX z*b0cSQ)|0!`rk@UL3m8?#uUWNYsdB;ev@ zJc=OfNDM}y$&(m}BYjAi^-su){|AYnTYzYZGfHK!=hxuOyuKNH`R`a2=<}KDQD{pB{CfuKn8GEf-x$eo`0Xz6TXXxBGaC5dt?lCE;E_PEa z3cU|F8{@|myIyB)S||iZE`6@|W~F|8b_C2q{ytp&fMz+yiJT6C`CdC5c>f}zVX@vi z&!ro6+40M2Rok)e@Aj)q-1gJ@aUuJ=qc8GHz(Kkj<(?4GBo8>peguf6lszGGrouMM zQ+5bx)y>|>@mdqyjHHf~tA5=s7fZNt$f=Sma#LOuM@5|F{7q1?i5f0)!gYW&;@1u6 zbd+--{Vy_^w`q0zW%qK^veU@Lc%~AXd2&lLn2+cY?deDP^AA2o|GR)Vv>h)Hwf` zH`ytkDZ4ZSa4^?>T#)BBtdA$A<%idg0G<_a%nDu1YPXOPz5D|_+^w*>3=XsIKLg}H z>a0d2Lyyd}cRf5Z8J;pDT(9E0Sh7J`&sU9{AqSBvrnyP6LFM zIg_A(udXS}z_anc_^yjAouChiR-l->k(EVPFPxSRCOAt{7i-ze^=pn!%=)E?j(qq?~cEL6(y;K7r!S95XX+c`kdMPGVwd&Wn(Ye7!T+3{5eYw z_UWWFrm=JTg^RIcn zXGSeJLPVhV-k-q9**kn}N!PsU^<(w^>!1D?GLPW2kb^f3MUq;NCE^x%9Uhi1NEp-L z{DZ8lEY~-BKgYG7=#nZl<X6`e8F{h7gfy?^apzcSOrdi zWio`X9761xses-vqQWr6RY=IU?7)5Am1^h|MGn_c&s*_(p7X|OVvU|ZeJn4-JMNotF`W4xx>3Sghzp~C8Q6b*_sAiB zKA;I#ie95{TauEl(LH?*&zC9@CUUjneu);uzhH_;>}x(Ee!sZ4}n5sLV;?+M-6X|mZqMTUTpuSj39Z-KZh8ONq#Kj*m_X9 zVkP%URa!k}2*q@acmD84hj2$59!^{Wi)VP?UewW34 z)*OGpIZ|0S%ryQ2iA>XAydP&U3n|kQOQ8UN?tFB;R#Rhm+Fmqd1GBtgX*Piz%~TwqRwR&y18KzjQ-(%kj!0cqxMd|jhj!!J(f-)x(0_iy|b ztwZc68*;L&7##!_FG=WaF%_J%RVmLz6fj<+nWAB-~|;JFZlhGN{|G&Y>G`M^svd0 zOyph^_}2|T#0av#H$7ZmY1e)+A$A82SZHppADiHKE>iMk0#_^v)Gu2UDg3E`RpmaC zsAU#Wb$$||PfcvXhSF8`TI+i^u52oDePOeqklesYdRMv|y(K$H4_#na3hG{lJ~htU z?ixmFu}BNX+(7|Mu1E&Ys}eU{%#*|lr>lq z6RBZ8d{+g0LhG4&?LXSV9K>!61d2odyz`%Qpxo+B*@7^F!O4|uXj?Zxo;hZt*Z)`ps|>=^u8y=Q5SCKHR1GC zhYZ7JVx<@VH6>)l{UOLX<>FVRTaOk}v$Xz+_^iCi^VWGJ#haI#@!Y3PbzWbD(6E$(KbnvmxLBpd5gpgsH3C8bGR5G~UQ3t;= z_WX|a&ScKidNjRjLm7l0O!nnyDiAjq=i$WX#>gIG))Vg7vq|2jacO{#T$?)e2)j99cLd?68Nw5dAz=Ze|&BVOJxjrb%OVu++ zEf$b2!1;6;Am2&!k&iLj8y_^2AI)9eS~!k$A4e+Ox=brr5C*;d!IIS(!2UxVi##P5o2mcDCStb_aS|!b$pdm+dsZ2f3JX{mE&eYtx zNDB4U)I!6H^ThyO=+x ze!ttlbRoT{Nj2?GHF8s=OIQLNC;DO{C4wO6b6bWwq7W-z)6i?x^I%)Z*2rpYtf7kAy1VGw+Q&JkugDF?-75CSIkABSqP0r>iFvUQYxfl#u8 z*Jd&w1PUM$T{4RxO$;hiHRc+2+MM|cfHgUO7Q_#z;|+S239{EC73CsM-)?rT;^Poh zo&p!9VcSD?da+P82IhBLPvi>!{>mL~2Aq*f1)h&WlYnV<-RJkB&!^NV1kQ8y&uxZN zMSwpawpS`{n*)H?`~C%g)vYBB9sFiSdS&@kBu8}o-#aiU_Lgm&<8wXWb$P5Py-$tY zri-DH?<%_1L}85nGvas?@UfKU3tW|%nC5%(io>>+4}z5u+UCL}==4FSeNL6Q->&zV}UR?r+MQF|*Gr+y)m2=y1VEg7_aIN51e zfh?rg0zTjY#57iD>|Pun8Cw|rQD6ue zf#EulfaT8&TX;VcX1Hs#&3)|PvURo%L)zK6RT{f_I)Bd~l>sCmAJfH15rdfECpQ)+ zdZGJnIy$v-3$C7)v?WjSNWs0uZe2Tb_&W~JJF69Xkn`+#l;M z_Rc%w!=l>=EBn_IsVXNgXG$93KYE)X6O3_Uw>Dnlta-0a;Q6>#+xmEGwjv346B)x> z1|dfeVE8-?#j{X#p6HYjKt7Tce7)X`DN$3F-M(|zN8hrH&MPR3%skQC%c7z^mwy2Z zA|ixRy4*U0;oA=Dp2A~ejQ5IzFv$7a4RjU>`L)5m4q4nFW`A#XocN=+|C+~)D&XYP zxvif)#KFQ?la9c6(M!Ea_uA293#lPmRdn|R)TKKjqyV}ZqhzB%uraS8nK9&#Hxof` zj#mUT7+GmvJsJ`82sk{T7tzZ6B$3%Z-EtkiP$IcY-wFjl%*F72h`h>P{II5HluIX4 zkk@`LcB?J)H<@cMc5#VETd_#Kh*}pRTcse+&7uVhr;%O_+27pCa{(U+R6x^)h~LDu z4}S#EDge9EHw<3HlWCBZUE4mF7XS2i4s)4gd@PHjhgo9jlu0Xd+`w;0A;2UwY5f#pT|8H(_!n@!#4 zuY%ofBz@V+qz=!1E#qv02thTOPAxl9P$#l4n)dluQvZ`KU@-{aOFxwN`_Cf|Z{cZs zmw%bumXE{4q75$)+0yf^o8H2c=L$UT`1|O4@iPDf-sxWeAOI?PDaOO8`ECOcGVX5a zPh_o6u0cA49he0;LWnudA;WOafC3@8{PH944iJ_>gOm{s4vTIb50^bqU<94vMDv@E4eAxLxOgg?DMW-S0 z$3*~}_&xb`RbrF;(k3_x7DiWw>bDb>rz_7QMekTfb2|V-MZRZWpgDd+@wI2s7}clbRNXt&C9#L!Bvf7-<^??pmYgryS2w0}bc%uy^WXx;@GaEf zzuiC(e%Svie!E|EzDPu68lMq30hlx==g)u3AggHAI&;P*4c|ZIPcqS(;bSq`nSB6a{Juc3i5Ny#oE`|2 zr)Lq6WywuzeeaKNfZyGz=wf6U6K>kuxh?Rk2c6of{o>VE)`z>_z)6NiuCH}>rmu$} zlXXfIIbX)2rVE>Agd8LAmvD#Y&pT7w&Z5U)bav;}84?UiEG5isBB_XW9e$CT$D_n2 z`H5mmk2b|l9t}tl1yBhIoCh1Z6iAKYlXfBxRWkjhTxYLLU#z0J@^!_4BrE5`?8x;{ zIw|inCJ8)etn~Na14$`l^c^Zq?X~QksSqxIgZlCN+{GDw`ecwL5SMiRdp#h&-(fLv zh}~unf(23|?sIs_^P}Z?y2x_8eavsN>-fTD0jJwT$+VX&wXMO40>3Kj-}+@d6WXW9 zK8ZD7*JjsI;5Zi?^Q506u)>Dj+aVq}Pv*0`M5N_<@2Z%yFZaGjj};w z9HV`oi<~@AQLM=n?ZSy}er{PZz{pS_0~PyPmgS7$RYg&bGFntuE~oRSrxg9?lOL6w zDZLC~;kgA!^@@JSE%X-Ha@%UpayYi1e?syB8`j8D$y(v5beWJFkwkWcc9rh5EqnO8 zJ-<^TI`QzQSx?nP{y?J4t-4=Zz6-W}8UFk!GyS(9&e#d2v>2S}EXROQs=J zF_vrNovlRrse6a}WjDW#Lzm5JD{qp*yQk+0Fj)72(Dhar5Gs);7j=3^*9}yVaDK|= zfO!NvDtYw8WMyvs95-gLH%ZK^a_gT2C!i(gx#M?sYht|A|KyddK!B!`+9CBkBpU+K zDTv=B#s#uO%bW$nu(5hLm;{e-K4MY$ycW=+w@AP4d){ejWk?eAs` z`{muA=6;`c1G^+bU#_LCWQ~AMMrQv@srutWF(6fl+p|oPo;(GKl)X^J)Rt_1ZkJ;; zU8*yTXYn=&YF-;XBk1D1e;LBRr}yzR`(utaa;F)&p<3mV@3p$Gk(e0K6{u_DH!7l^ zvE874M=p*CFsS}^%Vg4~x3qw!+7_RKmlN8}E z(+)`N#-L|}jLg)j+wmuT9GXU}JW zsyUYr7n}nmTlel^y8WJ6yS=TlKm?TjkqS>_A;PwxF)AKM05#N1=m(#B71Ecrtgu+7 z11Xk9N%W_b*+v1K*?u_@EL;cujrw9vKO~Hh$apCP^2^E3T`v?4BUttJ5GVYWUIt)D0fVg%4DA%1(e1#Gq5 zv3>%c2NCEjT^zSLe&%u7jb%eu%$sT*xfCAEgdkC{IVEe&_rX5r3LhdR$MP%{cJS|9 z560#xvY1miAX>yhc>fLK*~w7+)|(7l-ugXu4HK;)er$mN8yv$|!+hvnpRwz6vM$G)gA!XH30kRz&ZK6b(gc zyo(U`YdCzZzA=4t#|orOsNCm+RUx^ZQE)>w?qsvjI;Ok1X#P{a52c7y&U) zM8XeyY4(SyXXK%{WlBgtSflmPpLV6&1av;|jUv=`;XUc}FE2@=wStNekxVutU%(ed zC}6!}UKkokQSbTz@|xr~PAR?se})C*KH*ukO>j{!8U3)F*X5Ay!QcY|rQ_rjxG&07 z`+03>0$+t}q~jxwmLy+rTUU~#(+&q)9PVGcXArk@mYUU@^oASyPRbFrnfh$|JDic1 zDTOPs^=hF%El307v4$A+du+Yu=i(_fuJ_ra|AIqPKg6dUJw`B&F(-pU#C)T5P_4gxs85mOM(GHfKa6-Z%z&90}Dezbui^Ar} zd3ehH^@BX|pY@as|HTgvLTTn&pma^DC=be7Az!28a_ZBe9LO6N4*ld>!QqzF0gCW< zE@};86lN+xh6f(*$^M0-P|Ba^FR9dqkNT{0eflqTUAT##i*ues{X0E1jU>l)sI^O6 zWnNa0b5<6{7Jc4ZQvN1Zlr&C2TFNgUO9(Qiev=YczklR)Pv8*$3~974cq-ao19!s{~?TZFUIZLc%v=bOCy-H{h4#N653iXoLwWX7RHVH5~c zWt?pE9C`8}`>BuRwgfI`Ce(JI;7@;i$$Sq|BKbEq z21=XV7YITJhgs`cb+KB*mDuiL4O7qwJn^SU=iYCtvofFwQ;2E$I3fAWmxmPQf7K_s zY)YH!);jed#&1P)HEE#FeBGh_ zU1Ut*;SUf~5MkORtdJ)lwWae6c3T2MfK|>L(D_Q|+3L%+UCCfpS`w0p0W|-efj_Av z#OV=O?OMhV9h1|+YT_zJ-V#iK)tGvQ>vX|*kvV3PtkDSNY+XcYHHj^Iy>VHrRARdP z+eDMyIX6|w`I{h$k)1A>qm8qe=e6dO9pKoq{7JVO=Uw6#Js3)_b?yA2@>>v8SRo}G z?{^f7++ki6kxALdhdqp*Cu%nTh(_DTT^^PTZC$IZD> zVMgv_yu2T>Pw7Lr?F7DrIxDf-Tr#>RwUx#W=V9-lYF^Mfk2e}?+sTkmX6(q5iC?dW z`nP9zLCY>>tG;c9A&ysjf!s+PyTxh|dZUcQ1?}&Z%A-sz>RXE6E8k<}@?E$3OEr#M zfy$ADo6Ps5E;0&;R%hR+R#aSU^E{t1FUirTP8|`rOo^HITCy!Ok4hoIF6Ttx)z{_` zE3efu&~R%mYXv0IN`&Wx=#@*Xm1Ny{9m*_Qh{0z@V)9w14CBFM*U;hJEa!2)&p`5~ zNW?-T;-iio0%jY?$;wIm5{FxcjiBB9$VLRcyHxS&g8wyw1R%p*tWp+En^ese$uLv^ znwUL@mc)0fc*mMZV2zim7@r&7KdHRlUmul;fn#ec0 z99Ih|l%9BaN8#~5Z00$hCT?#1XD_om*&5M=%eW}JMyd$b%vz5>P&T>2w(LM28z zz_XGuecew@n9^X2;EK-}xvU~2=;o-4B#

5}#RqxVs7h`ZB?z;F&XNYU8t1n(S>v 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/images/SCSt-overview.png b/spring-cloud-stream/2.1.0.RC3/images/SCSt-overview.png new file mode 100644 index 0000000000000000000000000000000000000000..46dd0c809e705714e5667946f7ac38c292adb402 GIT binary patch literal 96212 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�BUgAMG00cIrC8+4-QSzZYjb~M& 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

^=LG!>?=FNiA^M8YE|vLq^yK$zg6!v)&xG; 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°DGR+bsvb*2Ql|1)1Th9#fwhk@@7 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 EKU&lfD*ylh literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/images/callouts/1.png b/spring-cloud-stream/2.1.0.RC3/images/callouts/1.png new file mode 100644 index 0000000000000000000000000000000000000000..7d473430b7bec514f7de12f5769fe7c5859e8c5d GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQC}X^4DKU-G|w_t}fLBA)Suv#nrW z!^h2QnY_`l!BOq-UXEX{m2up>JTQkX)2m zTvF+fTUlI^nXH#utd~++ke^qgmzgTe~DWM4ffP81J literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/images/callouts/2.png b/spring-cloud-stream/2.1.0.RC3/images/callouts/2.png new file mode 100644 index 0000000000000000000000000000000000000000..5d09341b2f6d2ea2d1d5dad5d980f14b4b05dfd2 GIT binary patch literal 353 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 Puw?Hj-p-PI`sRNClkEZS literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/images/important.png b/spring-cloud-stream/2.1.0.RC3/images/important.png new file mode 100644 index 0000000000000000000000000000000000000000..ec54df65cee2de118b8865a16c1b5d757e33709d GIT binary patch literal 2085 zcmbVNdr%Yk9ZyB)kUM)fy*ZWlX7hkR9=mxg$&&EMiv$RUB!mDWS(1gskWEOIB!Cwl zf?{PTT2XP%yB;V#^%U9;pe+^T>{&UE>x@@VD|&aWW35hWduOkAqaC|ZvHiolKf1HK zzu)h>-_Pg!p50|ED_WP3lt81=*6DR>6SZ!PJ@IkW`;%iIE>KG%sj-n}UjrG&0ywSE z>8r;9y%%f5O*rOkZN7-hX|y<(+hQYahEmkw^YXEn4nN}cQ)n7Zo*(gJ4i8QO^?0M3 zP=NP-H46f6rvj{$7$AdRg}dCkwg7H!E3-J-JPw%?%+CYl5tJhE;v@z{yiG(9jVQp! zyePGgi3K3=ScUW`z$Z@G3`RiZ3*dl+FXA~M7zPl84~r!T0&@W&1PcWabt61jj7ktx zm;*e$K+0Oc*?^kV+NZXtlLB;+q#qRs!r?GKEaLkDjRIIElf^iMLLQ~T3$_v@7U2;= z#tMTP4>|&FKk4=nK#UQq_qC7;kn;3N2wuOz@Qj!UK1~#rGC>6M3t&DZ@Ooo$J=PAA zCj7r{JXbqtY4zg*6CU)n1RPX78W<~JDtF&)D5gkxgKi4AsiI&_YM-OUixZ??tpKSn ze5c!qLLw=Z#T+q|BZLqs3`%u1gPQQ^_OJRXsZqwOD&qLO2*a!%fyU`U&AilhSE!u zf#RfW8Nca8?LYcmzi;^J0$aTLuk(_I7B(1E%i{iHi|z|Ja9*KR}4%unPJ zFw4TowlS1#GO3H7Q31*c7>im^52SWUc{QwoqtQYKQqqoI_}z^Db(y?bEU3*;g(Uk< zbhQt9Q;Rl4_Xd*GuUR{_5VHeEE0C#yNL!dhWt>(;lnbF3j@_RUxGA zhlU&%fA8^*!l1Y?gk+ci-WE<{Z}q7&M>qEshlgBmoET)9!8{*KHv&6`TU&?mta6qd z7iwD&9iFFcM~&TiU^y@_(iItM%&Y+Q4fzTJHodO2br<#Qk8o=Fh6?xiG;t(<^tVlGN*YwHYbN*+ux#qerwpu9`;s z-h^IVXo>ux{&d`$r9Z!%mi_6zmY=<_(Aa4VWq+kPR9x~xOWlpzJxnYGn>;_NtFFtp z54GGsQk4p=t-Lq$;+whBb8|*17xjJKQ38{*G>h8VSmBGr5-Z@b}+_3*Xjg7`HBiDzyy{&6?adFeNk#BLg0d5b-3 z9p!F+xWNDCwRfkhhF=kO!^16Ky!0x2slrhor)q_mdPk(;+PiMET zz5h+ansg!r=$v-@J7+7{oa2j2pl#+KRU%es&<_a|W z!QKDvpGsto{Bi1?F{rbP{YmvHRmJgSd->g=lhdE>DT$9i&DZ~hSKGgD<3Nr~x0crR x@l@~8v%fudb7|Fs)}6WGzYSl#_Wjpr@eu7sVJhKCFm=a%+M#HR literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/images/logo.png b/spring-cloud-stream/2.1.0.RC3/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ade2ce6ed9d9e9f2f4d9c5729a252ee618a0a5a7 GIT binary patch literal 4387 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/images/redis-binder.png b/spring-cloud-stream/2.1.0.RC3/images/redis-binder.png new file mode 100644 index 0000000000000000000000000000000000000000..1832bd2e31af35537088abd41f7092e5c63e3b66 GIT binary patch literal 13731 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/images/registration.png b/spring-cloud-stream/2.1.0.RC3/images/registration.png new file mode 100644 index 0000000000000000000000000000000000000000..d2c044c1e62a9536f94362c8dc7ad89f0231f9b4 GIT binary patch literal 22405 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/images/spring-initializr.png b/spring-cloud-stream/2.1.0.RC3/images/spring-initializr.png new file mode 100644 index 0000000000000000000000000000000000000000..4d161baaea51d6b2c444037c80b07ad75b617d15 GIT binary patch literal 82106 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%0DWrw{4)0d%L`sgr=?rIAgdq^iVp2(^COnQHJh3 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

Vuy0QIj8*7*m`;G>Ncx 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 FV1jwin)(0$ literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/images/warning.png b/spring-cloud-stream/2.1.0.RC3/images/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..0d5b5244605adbb7ab05a1549746a9c35490f95b GIT binary patch literal 2130 zcmbVNYg7|w8V(4q($)50y>JmGlLW#g$xLn}Vd2Si)}#|ptPAQp3Bp-3!-lL0;i^LY?;i#f0m5s49g z3h?3rDQg~EDPlm?FKkgKIcWEK-3X6YU0uzs7H|nq84s39r2!5;pF?SI$QqXy^Ko1x zV~zpENvp@<_Bsd`5MabC#3rvCq&$5dg43yGR zAdy0-rWjC#a1N_+kzUMY#pmogD7!DP(9dEKr3c5ngvUq_6>}Y+w-a81v=eSXnIi_+ zI?U>D1q2C!0zHox#XXKH+@|&rPT*OF5yvY$5J|)WwLqnU)c-5;=UChSlQkaY3@^|g z|J5#YBB}=i+n3Ex9bS$P?xJSKLk)-HHII@;3qG#TG^!+aj>0QkO~7kB0+|yM;YrGB zF>Ge@isQ#73%Tp#k_(tInh3U$uJWY-+DND*o}L-CB5g@#9YWWw~pxZ!Obm>yN#ZHFvL0zA3vNCTJ=t?)~`2O1M{L6un=ml<2x zQEYfifmA?Pz0tqRs^2Utt1pU0BQB1eIY0U_I}c1Y#PP7Ci5s7#IJn}xK{G+{_v^Z+1V#$Erodv>d}ew>RP0wzw+GWkGCBlS1Oj5Z!5NK zUuSR6>pa}RSEZ;qE_w1l#`hQX4E67U6NeP zHZ`T&wj0_H)t|Y1thUqnhub?%e)Y07;a^Tq%FO&iQkR&`qG!dh*2WfW(HuRQj*_DI zeCD1bUA|tMwjOb8E|FRIn$pzEU!2j_N}1Z2ig)vbr5xA0rjC70cmI6*%Uf->hWzaZ z{33HABO5q)vRhzDly2l691@+q3O{}NbSzx+I*k@|L4&3leK#$>u+T#TvTELfKb|IH zc23atf3vmfCa0&TWY@iuoA_Pm<0~ttEC*ut`isb^jXS>X^Sp=l?RXN_OJ*&usGXg$ zTlTv;Ch^vhLDf&+62jl64*&D+=+`sN_dap_1W%p|KQVYIdgPL5uRE9(c4On)DXndL zLNq?%!-u*zmMxyYc4m4Nr>>=A=s}PkJkqr&E^b9>5g+}c1%X}3|WKcg&spcJQ)05zI<<5LTBhNKRg$XRTi2{j)yl_ zj4~kKOvr+m(;vw~9zVh(zC-y9jqQnguz5r7FRq^MyKuXAENp(TAzUVtg&Ts+B_s7) zGn+fN0sG>9GjsPLKTRrvCd`71IZulJ1_1jO9KWbD&_@2UC+LTNpxxrdz#E|j|2nA9 zzB!UTyfAEJ&#%$pQ>QX#8vk@_a5iqukMF;8`wRKe{BI}5$H%OROs4J1#j)|?p|YSh z_SpR^e`VE#F52;WL{!+L(yZLRh40*KS;@box;9(-tE)`mcVp27O*>Z{_Lb*5T3cJA yr~0nPHtg2+UHi&&$8ha;`+hiaUmw&!n@8(?5PqF(KE5>Ym)EG)p&uyBP5%a8^# + + + + + + +spring-cloud-stream + + + + + + + +

+ + + + + + \ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/css/highlight.css b/spring-cloud-stream/2.1.0.RC3/multi/css/highlight.css new file mode 100644 index 00000000..ffefef72 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/css/highlight.css @@ -0,0 +1,35 @@ +/* + code highlight CSS resemblign the Eclipse IDE default color schema + @author Costin Leau +*/ + +.hl-keyword { + color: #7F0055; + font-weight: bold; +} + +.hl-comment { + color: #3F5F5F; + font-style: italic; +} + +.hl-multiline-comment { + color: #3F5FBF; + font-style: italic; +} + +.hl-tag { + color: #3F7F7F; +} + +.hl-attribute { + color: #7F007F; +} + +.hl-value { + color: #2A00FF; +} + +.hl-string { + color: #2A00FF; +} \ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/css/manual-multipage.css b/spring-cloud-stream/2.1.0.RC3/multi/css/manual-multipage.css new file mode 100644 index 00000000..0c484531 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/css/manual-multipage.css @@ -0,0 +1,9 @@ +@IMPORT url("manual.css"); + +body.firstpage { + background: url("../images/background.png") no-repeat center top; +} + +div.part h1 { + border-top: none; +} diff --git a/spring-cloud-stream/2.1.0.RC3/multi/css/manual-singlepage.css b/spring-cloud-stream/2.1.0.RC3/multi/css/manual-singlepage.css new file mode 100644 index 00000000..4a7fd140 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/css/manual-singlepage.css @@ -0,0 +1,6 @@ +@IMPORT url("manual.css"); + +body { + background: url("../images/background.png") no-repeat center top; +} + diff --git a/spring-cloud-stream/2.1.0.RC3/multi/css/manual.css b/spring-cloud-stream/2.1.0.RC3/multi/css/manual.css new file mode 100644 index 00000000..0ecbe2e8 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/css/manual.css @@ -0,0 +1,344 @@ +@IMPORT url("highlight.css"); + +html { + padding: 0pt; + margin: 0pt; +} + +body { + color: #333333; + margin: 15px 30px; + font-family: Helvetica, Arial, Freesans, Clean, Sans-serif; + line-height: 1.6; + -webkit-font-smoothing: antialiased; +} + +code { + font-size: 16px; + font-family: Consolas, "Liberation Mono", Courier, monospace; +} + +:not(a)>code { + color: #6D180B; +} + +:not(pre)>code { + background-color: #F2F2F2; + border: 1px solid #CCCCCC; + border-radius: 4px; + padding: 1px 3px 0; + text-shadow: none; + white-space: nowrap; +} + +body>*:first-child { + margin-top: 0 !important; +} + +div { + margin: 0pt; +} + +hr { + border: 1px solid #CCCCCC; + background: #CCCCCC; +} + +h1,h2,h3,h4,h5,h6 { + color: #000000; + cursor: text; + font-weight: bold; + margin: 30px 0 10px; + padding: 0; +} + +h1,h2,h3 { + margin: 40px 0 10px; +} + +h1 { + margin: 70px 0 30px; + padding-top: 20px; +} + +div.part h1 { + border-top: 1px dotted #CCCCCC; +} + +h1,h1 code { + font-size: 32px; +} + +h2,h2 code { + font-size: 24px; +} + +h3,h3 code { + font-size: 20px; +} + +h4,h1 code,h5,h5 code,h6,h6 code { + font-size: 18px; +} + +div.book,div.chapter,div.appendix,div.part,div.preface { + min-width: 300px; + max-width: 1200px; + margin: 0 auto; +} + +p.releaseinfo { + font-weight: bold; + margin-bottom: 40px; + margin-top: 40px; +} + +div.authorgroup { + line-height: 1; +} + +p.copyright { + line-height: 1; + margin-bottom: -5px; +} + +.legalnotice p { + font-style: italic; + font-size: 14px; + line-height: 1; +} + +div.titlepage+p,div.titlepage+p { + margin-top: 0; +} + +pre { + line-height: 1.0; + color: black; +} + +a { + color: #4183C4; + text-decoration: none; +} + +p { + margin: 15px 0; + text-align: left; +} + +ul,ol { + padding-left: 30px; +} + +li p { + margin: 0; +} + +div.table { + margin: 1em; + padding: 0.5em; + text-align: center; +} + +div.table table,div.informaltable table { + display: table; + width: 100%; +} + +div.table td { + padding-left: 7px; + padding-right: 7px; +} + +.sidebar { + line-height: 1.4; + padding: 0 20px; + background-color: #F8F8F8; + border: 1px solid #CCCCCC; + border-radius: 3px 3px 3px 3px; +} + +.sidebar p.title { + color: #6D180B; +} + +pre.programlisting,pre.screen { + font-size: 15px; + padding: 6px 10px; + background-color: #F8F8F8; + border: 1px solid #CCCCCC; + border-radius: 3px 3px 3px 3px; + clear: both; + overflow: auto; + line-height: 1.4; + font-family: Consolas, "Liberation Mono", Courier, monospace; +} + +table { + border-collapse: collapse; + border-spacing: 0; + border: 1px solid #DDDDDD !important; + border-radius: 4px !important; + border-collapse: separate !important; + line-height: 1.6; +} + +table thead { + background: #F5F5F5; +} + +table tr { + border: none; + border-bottom: none; +} + +table th { + font-weight: bold; +} + +table th,table td { + border: none !important; + padding: 6px 13px; +} + +table tr:nth-child(2n) { + background-color: #F8F8F8; +} + +td p { + margin: 0 0 15px 0; +} + +div.table-contents td p { + margin: 0; +} + +div.important *,div.note *,div.tip *,div.warning *,div.navheader *,div.navfooter *,div.calloutlist * + { + border: none !important; + background: none !important; + margin: 0; +} + +div.important p,div.note p,div.tip p,div.warning p { + color: #6F6F6F; + line-height: 1.6; +} + +div.important code,div.note code,div.tip code,div.warning code { + background-color: #F2F2F2 !important; + border: 1px solid #CCCCCC !important; + border-radius: 4px !important; + padding: 1px 3px 0 !important; + text-shadow: none !important; + white-space: nowrap !important; +} + +.note th,.tip th,.warning th { + display: none; +} + +.note tr:first-child td,.tip tr:first-child td,.warning tr:first-child td + { + border-right: 1px solid #CCCCCC !important; + padding-top: 10px; +} + +div.calloutlist p,div.calloutlist td { + padding: 0; + margin: 0; +} + +div.calloutlist>table>tbody>tr>td:first-child { + padding-left: 10px; + width: 30px !important; +} + +div.important,div.note,div.tip,div.warning { + margin-left: 0px !important; + margin-right: 20px !important; + margin-top: 20px; + margin-bottom: 20px; + padding-top: 10px; + padding-bottom: 10px; +} + +div.toc { + line-height: 1.2; +} + +dl,dt { + margin-top: 1px; + margin-bottom: 0; +} + +div.toc>dl>dt { + font-size: 32px; + font-weight: bold; + margin: 30px 0 10px 0; + display: block; +} + +div.toc>dl>dd>dl>dt { + font-size: 24px; + font-weight: bold; + margin: 20px 0 10px 0; + display: block; +} + +div.toc>dl>dd>dl>dd>dl>dt { + font-weight: bold; + font-size: 20px; + margin: 10px 0 0 0; +} + +tbody.footnotes * { + border: none !important; +} + +div.footnote p { + margin: 0; + line-height: 1; +} + +div.footnote p sup { + margin-right: 6px; + vertical-align: middle; +} + +div.navheader { + border-bottom: 1px solid #CCCCCC; +} + +div.navfooter { + border-top: 1px solid #CCCCCC; +} + +.title { + margin-left: -1em; + padding-left: 1em; +} + +.title>a { + position: absolute; + visibility: hidden; + display: block; + font-size: 0.85em; + margin-top: 0.05em; + margin-left: -1em; + vertical-align: text-top; + color: black; +} + +.title>a:before { + content: "\00A7"; +} + +.title:hover>a,.title>a:hover,.title:hover>a:hover { + visibility: visible; +} + +.title:focus>a,.title>a:focus,.title:focus>a:focus { + outline: 0; +} diff --git a/spring-cloud-stream/2.1.0.RC3/multi/images/background.png b/spring-cloud-stream/2.1.0.RC3/multi/images/background.png new file mode 100644 index 0000000000000000000000000000000000000000..15dca6fbe2669fae3609605e49c69cc414f1b6ed GIT binary patch literal 18255 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 EKU&lfD*ylh literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/multi/images/callouts/1.png b/spring-cloud-stream/2.1.0.RC3/multi/images/callouts/1.png new file mode 100644 index 0000000000000000000000000000000000000000..7d473430b7bec514f7de12f5769fe7c5859e8c5d GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQC}X^4DKU-G|w_t}fLBA)Suv#nrW z!^h2QnY_`l!BOq-UXEX{m2up>JTQkX)2m zTvF+fTUlI^nXH#utd~++ke^qgmzgTe~DWM4ffP81J literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/multi/images/callouts/2.png b/spring-cloud-stream/2.1.0.RC3/multi/images/callouts/2.png new file mode 100644 index 0000000000000000000000000000000000000000..5d09341b2f6d2ea2d1d5dad5d980f14b4b05dfd2 GIT binary patch literal 353 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/multi/images/logo.png b/spring-cloud-stream/2.1.0.RC3/multi/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ade2ce6ed9d9e9f2f4d9c5729a252ee618a0a5a7 GIT binary patch literal 4387 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 FV1jwin)(0$ literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/multi/images/warning.png b/spring-cloud-stream/2.1.0.RC3/multi/images/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..0d5b5244605adbb7ab05a1549746a9c35490f95b GIT binary patch literal 2130 zcmbVNYg7|w8V(4q($)50y>JmGlLW#g$xLn}Vd2Si)}#|ptPAQp3Bp-3!-lL0;i^LY?;i#f0m5s49g z3h?3rDQg~EDPlm?FKkgKIcWEK-3X6YU0uzs7H|nq84s39r2!5;pF?SI$QqXy^Ko1x zV~zpENvp@<_Bsd`5MabC#3rvCq&$5dg43yGR zAdy0-rWjC#a1N_+kzUMY#pmogD7!DP(9dEKr3c5ngvUq_6>}Y+w-a81v=eSXnIi_+ zI?U>D1q2C!0zHox#XXKH+@|&rPT*OF5yvY$5J|)WwLqnU)c-5;=UChSlQkaY3@^|g z|J5#YBB}=i+n3Ex9bS$P?xJSKLk)-HHII@;3qG#TG^!+aj>0QkO~7kB0+|yM;YrGB zF>Ge@isQ#73%Tp#k_(tInh3U$uJWY-+DND*o}L-CB5g@#9YWWw~pxZ!Obm>yN#ZHFvL0zA3vNCTJ=t?)~`2O1M{L6un=ml<2x zQEYfifmA?Pz0tqRs^2Utt1pU0BQB1eIY0U_I}c1Y#PP7Ci5s7#IJn}xK{G+{_v^Z+1V#$Erodv>d}ew>RP0wzw+GWkGCBlS1Oj5Z!5NK zUuSR6>pa}RSEZ;qE_w1l#`hQX4E67U6NeP zHZ`T&wj0_H)t|Y1thUqnhub?%e)Y07;a^Tq%FO&iQkR&`qG!dh*2WfW(HuRQj*_DI zeCD1bUA|tMwjOb8E|FRIn$pzEU!2j_N}1Z2ig)vbr5xA0rjC70cmI6*%Uf->hWzaZ z{33HABO5q)vRhzDly2l691@+q3O{}NbSzx+I*k@|L4&3leK#$>u+T#TvTELfKb|IH zc23atf3vmfCa0&TWY@iuoA_Pm<0~ttEC*ut`isb^jXS>X^Sp=l?RXN_OJ*&usGXg$ zTlTv;Ch^vhLDf&+62jl64*&D+=+`sN_dap_1W%p|KQVYIdgPL5uRE9(c4On)DXndL zLNq?%!-u*zmMxyYc4m4Nr>>=A=s}PkJkqr&E^b9>5g+}c1%X}3|WKcg&spcJQ)05zI<<5LTBhNKRg$XRTi2{j)yl_ zj4~kKOvr+m(;vw~9zVh(zC-y9jqQnguz5r7FRq^MyKuXAENp(TAzUVtg&Ts+B_s7) zGn+fN0sG>9GjsPLKTRrvCd`71IZulJ1_1jO9KWbD&_@2UC+LTNpxxrdz#E|j|2nA9 zzB!UTyfAEJ&#%$pQ>QX#8vk@_a5iqukMF;8`wRKe{BI}5$H%OROs4J1#j)|?p|YSh z_SpR^e`VE#F52;WL{!+L(yZLRh40*KS;@box;9(-tE)`mcVp27O*>Z{_Lb*5T3cJA yr~0nPHtg2+UHi&&$8ha;`+hiaUmw&!n@8(?5PqF(KE5>Ym)EG)p&uyBP5%a8^# + + 1. A Brief History of Spring’s Data Integration Journey

1. A Brief History of Spring’s Data Integration Journey

Spring’s journey on Data Integration started with Spring Integration. With its programming model, it provided a consistent developer experience to build applications that can embrace Enterprise Integration Patterns to connect with external systems such as, databases, message brokers, and among others.

Fast forward to the cloud-era, where microservices have become prominent in the enterprise setting. Spring Boot transformed the way how developers built Applications. With Spring’s programming model and the runtime responsibilities handled by Spring Boot, it became seamless to develop stand-alone, production-grade Spring-based microservices.

To extend this to Data Integration workloads, Spring Integration and Spring Boot were put together into a new project. Spring Cloud Stream was born.

With Spring Cloud Stream, developers can: +* Build, test, iterate, and deploy data-centric applications in isolation. +* Apply modern microservices architecture patterns, including composition through messaging. +* Decouple application responsibilities with event-centric thinking. An event can represent something that has happened in time, to which the downstream consumer applications can react without knowing where it originated or the producer’s identity. +* Port the business logic onto message brokers (such as RabbitMQ, Apache Kafka, Amazon Kinesis). +* Interoperate between channel-based and non-channel-based application binding scenarios to support stateless and stateful computations by using Project Reactor’s Flux and Kafka Streams APIs. +* Rely on the framework’s automatic content-type support for common use-cases. Extending to different data conversion types is possible.

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi__binder_implementations.html b/spring-cloud-stream/2.1.0.RC3/multi/multi__binder_implementations.html new file mode 100644 index 00000000..034b0353 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi__binder_implementations.html @@ -0,0 +1,3 @@ + + + 16. Binder Implementations \ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi__configuration_options.html b/spring-cloud-stream/2.1.0.RC3/multi/multi__configuration_options.html new file mode 100644 index 00000000..578c9034 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi__configuration_options.html @@ -0,0 +1,127 @@ + + + 8. Configuration Options

8. Configuration Options

Spring Cloud Stream supports general configuration options as well as configuration for bindings and binders. +Some binders let additional binding properties support middleware-specific features.

Configuration options can be provided to Spring Cloud Stream applications through any mechanism supported by Spring Boot. +This includes application arguments, environment variables, and YAML or .properties files.

8.1 Binding Service Properties

These properties are exposed via org.springframework.cloud.stream.config.BindingServiceProperties

spring.cloud.stream.instanceCount

The number of deployed instances of an application. +Must be set for partitioning on the producer side. Must be set on the consumer side when using RabbitMQ and with Kafka if autoRebalanceEnabled=false.

Default: 1.

spring.cloud.stream.instanceIndex
The instance index of the application: A number from 0 to instanceCount - 1. +Used for partitioning with RabbitMQ and with Kafka if autoRebalanceEnabled=false. +Automatically set in Cloud Foundry to match the application’s instance index.
spring.cloud.stream.dynamicDestinations

A list of destinations that can be bound dynamically (for example, in a dynamic routing scenario). +If set, only listed destinations can be bound.

Default: empty (letting any destination be bound).

spring.cloud.stream.defaultBinder

The default binder to use, if multiple binders are configured. +See Multiple Binders on the Classpath.

Default: empty.

spring.cloud.stream.overrideCloudConnectors

This property is only applicable when the cloud profile is active and Spring Cloud Connectors are provided with the application. +If the property is false (the default), the binder detects a suitable bound service (for example, a RabbitMQ service bound in Cloud Foundry for the RabbitMQ binder) and uses it for creating connections (usually through Spring Cloud Connectors). +When set to true, this property instructs binders to completely ignore the bound services and rely on Spring Boot properties (for example, relying on the spring.rabbitmq.* properties provided in the environment for the RabbitMQ binder). +The typical usage of this property is to be nested in a customized environment when connecting to multiple systems.

Default: false.

spring.cloud.stream.bindingRetryInterval

The interval (in seconds) between retrying binding creation when, for example, the binder does not support late binding and the broker (for example, Apache Kafka) is down. +Set it to zero to treat such conditions as fatal, preventing the application from starting.

Default: 30

8.2 Binding Properties

Binding properties are supplied by using the format of spring.cloud.stream.bindings.<channelName>.<property>=<value>. +The <channelName> represents the name of the channel being configured (for example, output for a Source).

To avoid repetition, Spring Cloud Stream supports setting values for all channels, in the format of spring.cloud.stream.default.<property>=<value>.

When it comes to avoiding repetitions for extended binding properties, this format should be used - spring.cloud.stream.<binder-type>.default.<producer|consumer>.<property>=<value>.

In what follows, we indicate where we have omitted the spring.cloud.stream.bindings.<channelName>. prefix and focus just on the property name, with the understanding that the prefix ise included at runtime.

8.2.1 Common Binding Properties

These properties are exposed via org.springframework.cloud.stream.config.BindingProperties

The following binding properties are available for both input and output bindings and must be prefixed with spring.cloud.stream.bindings.<channelName>. (for example, spring.cloud.stream.bindings.input.destination=ticktock).

Default values can be set by using the spring.cloud.stream.default prefix (for example`spring.cloud.stream.default.contentType=application/json`).

destination
The target destination of a channel on the bound middleware (for example, the RabbitMQ exchange or Kafka topic). +If the channel is bound as a consumer, it could be bound to multiple destinations, and the destination names can be specified as comma-separated String values. +If not set, the channel name is used instead. +The default value of this property cannot be overridden.
group

The consumer group of the channel. +Applies only to inbound bindings. +See Consumer Groups.

Default: null (indicating an anonymous consumer).

contentType

The content type of the channel. +See Chapter 9, Content Type Negotiation.

Default: application/json.

binder

The binder used by this binding. +See Section 7.4, “Multiple Binders on the Classpath” for details.

Default: null (the default binder is used, if it exists).

8.2.2 Consumer Properties

These properties are exposed via org.springframework.cloud.stream.binder.ConsumerProperties

The following binding properties are available for input bindings only and must be prefixed with spring.cloud.stream.bindings.<channelName>.consumer. (for example, spring.cloud.stream.bindings.input.consumer.concurrency=3).

Default values can be set by using the spring.cloud.stream.default.consumer prefix (for example, spring.cloud.stream.default.consumer.headerMode=none).

concurrency

The concurrency of the inbound consumer.

Default: 1.

partitioned

Whether the consumer receives data from a partitioned producer.

Default: false.

headerMode

When set to none, disables header parsing on input. +Effective only for messaging middleware that does not support message headers natively and requires header embedding. +This option is useful when consuming data from non-Spring Cloud Stream applications when native headers are not supported. +When set to headers, it uses the middleware’s native header mechanism. +When set to embeddedHeaders, it embeds headers into the message payload.

Default: depends on the binder implementation.

maxAttempts

If processing fails, the number of attempts to process the message (including the first). +Set to 1 to disable retry.

Default: 3.

backOffInitialInterval

The backoff initial interval on retry.

Default: 1000.

backOffMaxInterval

The maximum backoff interval.

Default: 10000.

backOffMultiplier

The backoff multiplier.

Default: 2.0.

defaultRetryable

Whether exceptions thrown by the listener that are not listed in the retryableExceptions are retryable.

Default: true.

instanceIndex

When set to a value greater than equal to zero, it allows customizing the instance index of this consumer (if different from spring.cloud.stream.instanceIndex). +When set to a negative value, it defaults to spring.cloud.stream.instanceIndex. +See Section 11.2, “Instance Index and Instance Count” for more information.

Default: -1.

instanceCount

When set to a value greater than equal to zero, it allows customizing the instance count of this consumer (if different from spring.cloud.stream.instanceCount). +When set to a negative value, it defaults to spring.cloud.stream.instanceCount. +See Section 11.2, “Instance Index and Instance Count” for more information.

Default: -1.

retryableExceptions

A map of Throwable class names in the key and a boolean in the value. +Specify those exceptions (and subclasses) that will or won’t be retried. +Also see defaultRetriable. +Example: spring.cloud.stream.bindings.input.consumer.retryable-exceptions.java.lang.IllegalStateException=false.

Default: empty.

useNativeDecoding

When set to true, the inbound message is deserialized directly by the client library, which must be configured correspondingly (for example, setting an appropriate Kafka producer value deserializer). +When this configuration is being used, the inbound message unmarshalling is not based on the contentType of the binding. +When native decoding is used, it is the responsibility of the producer to use an appropriate encoder (for example, the Kafka producer value serializer) to serialize the outbound message. +Also, when native encoding and decoding is used, the headerMode=embeddedHeaders property is ignored and headers are not embedded in the message. +See the producer property useNativeEncoding.

Default: false.

8.2.3 Producer Properties

These properties are exposed via org.springframework.cloud.stream.binder.ProducerProperties

The following binding properties are available for output bindings only and must be prefixed with spring.cloud.stream.bindings.<channelName>.producer. (for example, spring.cloud.stream.bindings.input.producer.partitionKeyExpression=payload.id).

Default values can be set by using the prefix spring.cloud.stream.default.producer (for example, spring.cloud.stream.default.producer.partitionKeyExpression=payload.id).

partitionKeyExpression

A SpEL expression that determines how to partition outbound data. +If set, or if partitionKeyExtractorClass is set, outbound data on this channel is partitioned. partitionCount must be set to a value greater than 1 to be effective. +Mutually exclusive with partitionKeyExtractorClass. +See Section 5.6, “Partitioning Support”.

Default: null.

partitionKeyExtractorClass

A PartitionKeyExtractorStrategy implementation. +If set, or if partitionKeyExpression is set, outbound data on this channel is partitioned. partitionCount must be set to a value greater than 1 to be effective. +Mutually exclusive with partitionKeyExpression. +See Section 5.6, “Partitioning Support”.

Default: null.

partitionSelectorClass

A PartitionSelectorStrategy implementation. +Mutually exclusive with partitionSelectorExpression. +If neither is set, the partition is selected as the hashCode(key) % partitionCount, where key is computed through either partitionKeyExpression or partitionKeyExtractorClass.

Default: null.

partitionSelectorExpression

A SpEL expression for customizing partition selection. +Mutually exclusive with partitionSelectorClass. +If neither is set, the partition is selected as the hashCode(key) % partitionCount, where key is computed through either partitionKeyExpression or partitionKeyExtractorClass.

Default: null.

partitionCount

The number of target partitions for the data, if partitioning is enabled. +Must be set to a value greater than 1 if the producer is partitioned. +On Kafka, it is interpreted as a hint. The larger of this and the partition count of the target topic is used instead.

Default: 1.

requiredGroups
A comma-separated list of groups to which the producer must ensure message delivery even if they start after it has been created (for example, by pre-creating durable queues in RabbitMQ).
headerMode

When set to none, it disables header embedding on output. +It is effective only for messaging middleware that does not support message headers natively and requires header embedding. +This option is useful when producing data for non-Spring Cloud Stream applications when native headers are not supported. +When set to headers, it uses the middleware’s native header mechanism. +When set to embeddedHeaders, it embeds headers into the message payload.

Default: Depends on the binder implementation.

useNativeEncoding

When set to true, the outbound message is serialized directly by the client library, which must be configured correspondingly (for example, setting an appropriate Kafka producer value serializer). +When this configuration is being used, the outbound message marshalling is not based on the contentType of the binding. +When native encoding is used, it is the responsibility of the consumer to use an appropriate decoder (for example, the Kafka consumer value de-serializer) to deserialize the inbound message. +Also, when native encoding and decoding is used, the headerMode=embeddedHeaders property is ignored and headers are not embedded in the message. +See the consumer property useNativeDecoding.

Default: false.

errorChannelEnabled

When set to true, if the binder supports asynchroous send results, send failures are sent to an error channel for the destination. +See Section 6.4, “Error Handling” for more information.

Default: false.

8.3 Using Dynamically Bound Destinations

Besides the channels defined by using @EnableBinding, Spring Cloud Stream lets applications send messages to dynamically bound destinations. +This is useful, for example, when the target destination needs to be determined at runtime. +Applications can do so by using the BinderAwareChannelResolver bean, registered automatically by the @EnableBinding annotation.

The 'spring.cloud.stream.dynamicDestinations' property can be used for restricting the dynamic destination names to a known set (whitelisting). +If this property is not set, any destination can be bound dynamically.

The BinderAwareChannelResolver can be used directly, as shown in the following example of a REST controller using a path variable to decide the target channel:

@EnableBinding
+@Controller
+public class SourceWithDynamicDestination {
+
+    @Autowired
+    private BinderAwareChannelResolver resolver;
+
+    @RequestMapping(path = "/{target}", method = POST, consumes = "*/*")
+    @ResponseStatus(HttpStatus.ACCEPTED)
+    public void handleRequest(@RequestBody String body, @PathVariable("target") target,
+           @RequestHeader(HttpHeaders.CONTENT_TYPE) Object contentType) {
+        sendMessage(body, target, contentType);
+    }
+
+    private void sendMessage(String body, String target, Object contentType) {
+        resolver.resolveDestination(target).send(MessageBuilder.createMessage(body,
+                new MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, contentType))));
+    }
+}

Now consider what happens when we start the application on the default port (8080) and make the following requests with CURL:

curl -H "Content-Type: application/json" -X POST -d "customer-1" http://localhost:8080/customers
+
+curl -H "Content-Type: application/json" -X POST -d "order-1" http://localhost:8080/orders

The destinations, 'customers' and 'orders', are created in the broker (in the exchange for Rabbit or in the topic for Kafka) with names of 'customers' and 'orders', and the data is published to the appropriate destinations.

The BinderAwareChannelResolver is a general-purpose Spring Integration DestinationResolver and can be injected in other components — for example, in a router using a SpEL expression based on the target field of an incoming JSON message. The following example includes a router that reads SpEL expressions:

@EnableBinding
+@Controller
+public class SourceWithDynamicDestination {
+
+    @Autowired
+    private BinderAwareChannelResolver resolver;
+
+
+    @RequestMapping(path = "/", method = POST, consumes = "application/json")
+    @ResponseStatus(HttpStatus.ACCEPTED)
+    public void handleRequest(@RequestBody String body, @RequestHeader(HttpHeaders.CONTENT_TYPE) Object contentType) {
+        sendMessage(body, contentType);
+    }
+
+    private void sendMessage(Object body, Object contentType) {
+        routerChannel().send(MessageBuilder.createMessage(body,
+                new MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, contentType))));
+    }
+
+    @Bean(name = "routerChannel")
+    public MessageChannel routerChannel() {
+        return new DirectChannel();
+    }
+
+    @Bean
+    @ServiceActivator(inputChannel = "routerChannel")
+    public ExpressionEvaluatingRouter router() {
+        ExpressionEvaluatingRouter router =
+            new ExpressionEvaluatingRouter(new SpelExpressionParser().parseExpression("payload.target"));
+        router.setDefaultOutputChannelName("default-output");
+        router.setChannelResolver(resolver);
+        return router;
+    }
+}

The Router Sink Application uses this technique to create the destinations on-demand.

If the channel names are known in advance, you can configure the producer properties as with any other destination. +Alternatively, if you register a NewDestinationBindingCallback<> bean, it is invoked just before the binding is created. +The callback takes the generic type of the extended producer properties used by the binder. +It has one method:

void configure(String channelName, MessageChannel channel, ProducerProperties producerProperties,
+        T extendedProducerProperties);

The following example shows how to use the RabbitMQ binder:

@Bean
+public NewDestinationBindingCallback<RabbitProducerProperties> dynamicConfigurer() {
+    return (name, channel, props, extended) -> {
+        props.setRequiredGroups("bindThisQueue");
+        extended.setQueueNameGroupOnly(true);
+        extended.setAutoBindDlq(true);
+        extended.setDeadLetterQueueName("myDLQ");
+    };
+}
[Note]Note

If you need to support dynamic destinations with multiple binder types, use Object for the generic type and cast the extended argument as needed.

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi__health_indicator.html b/spring-cloud-stream/2.1.0.RC3/multi/multi__health_indicator.html new file mode 100644 index 00000000..10e45418 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi__health_indicator.html @@ -0,0 +1,12 @@ + + + 13. Health Indicator

13. Health Indicator

Spring Cloud Stream provides a health indicator for binders. +It is registered under the name binders and can be enabled or disabled by setting the management.health.binders.enabled property.

To enable health check you first need to enable both "web" and "actuator" by including its dependencies (see Section 3.2.1, “Both Actuator and Web Dependencies Are Now Optional”)

If management.health.binders.enabled is not set explicitly by the application, then management.health.defaults.enabled is matched as true and the binder health indicators are enabled. +If you want to disable health indicator completely, then you have to set management.health.binders.enabled to false.

You can use Spring Boot actuator health endpoint to access the health indicator - /actuator/health. +By default, you will only receive the top level application status when you hit the above endpoint. +In order to receive the full details from the binder specific health indicators, you need to include the property management.endpoint.health.show-details with the value ALWAYS in your application.

Health indicators are binder-specific and certain binder implementations may not necessarily provide a health indicator.

If you want to completely disable all health indicators available out of the box and instead provide your own health indicators, +you can do so by setting property management.health.binders.enabled to false and then provide your own HealthIndicator beans in your application. +In this case, the health indicator infrastructure from Spring Boot will still pick up these custom beans. +Even if you are not disabling the binder health indicators, you can still enhance the health checks by providing your own HealthIndicator beans in addition to the out of the box health checks.

When you have multiple binders in the same application, health indicators are enabled by default unless the application turns them off by setting management.health.binders.enabled to false. +In this case, if the user wants to disable health check for a subset of the binders, then that should be done by setting management.health.binders.enabled to false in the multi binder configurations’s environment. +See Connecting to Multiple Systems for details on how environment specific properties can be provided.

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi__inter_application_communication.html b/spring-cloud-stream/2.1.0.RC3/multi/multi__inter_application_communication.html new file mode 100644 index 00000000..75d74985 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi__inter_application_communication.html @@ -0,0 +1,37 @@ + + + 11. Inter-Application Communication

11. Inter-Application Communication

Spring Cloud Stream enables communication between applications. Inter-application communication is a complex issue spanning several concerns, as described in the following topics:

11.1 Connecting Multiple Application Instances

While Spring Cloud Stream makes it easy for individual Spring Boot applications to connect to messaging systems, the typical scenario for Spring Cloud Stream is the creation of multi-application pipelines, where microservice applications send data to each other. +You can achieve this scenario by correlating the input and output destinations of adjacent applications.

Suppose a design calls for the Time Source application to send data to the Log Sink application. You could use a common destination named ticktock for bindings within both applications.

Time Source (that has the channel name output) would set the following property:

spring.cloud.stream.bindings.output.destination=ticktock

Log Sink (that has the channel name input) would set the following property:

spring.cloud.stream.bindings.input.destination=ticktock

11.2 Instance Index and Instance Count

When scaling up Spring Cloud Stream applications, each instance can receive information about how many other instances of the same application exist and what its own instance index is. +Spring Cloud Stream does this through the spring.cloud.stream.instanceCount and spring.cloud.stream.instanceIndex properties. +For example, if there are three instances of a HDFS sink application, all three instances have spring.cloud.stream.instanceCount set to 3, and the individual applications have spring.cloud.stream.instanceIndex set to 0, 1, and 2, respectively.

When Spring Cloud Stream applications are deployed through Spring Cloud Data Flow, these properties are configured automatically; when Spring Cloud Stream applications are launched independently, these properties must be set correctly. +By default, spring.cloud.stream.instanceCount is 1, and spring.cloud.stream.instanceIndex is 0.

In a scaled-up scenario, correct configuration of these two properties is important for addressing partitioning behavior (see below) in general, and the two properties are always required by certain binders (for example, the Kafka binder) in order to ensure that data are split correctly across multiple consumer instances.

11.3 Partitioning

Partitioning in Spring Cloud Stream consists of two tasks:

11.3.1 Configuring Output Bindings for Partitioning

You can configure an output binding to send partitioned data by setting one and only one of its partitionKeyExpression or partitionKeyExtractorName properties, as well as its partitionCount property.

For example, the following is a valid and typical configuration:

spring.cloud.stream.bindings.output.producer.partitionKeyExpression=payload.id
+spring.cloud.stream.bindings.output.producer.partitionCount=5

Based on that example configuration, data is sent to the target partition by using the following logic.

A partition key’s value is calculated for each message sent to a partitioned output channel based on the partitionKeyExpression. +The partitionKeyExpression is a SpEL expression that is evaluated against the outbound message for extracting the partitioning key.

If a SpEL expression is not sufficient for your needs, you can instead calculate the partition key value by providing an implementation of org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy and configuring it as a bean (by using the @Bean annotation). +If you have more then one bean of type org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy available in the Application Context, you can further filter it by specifying its name with the partitionKeyExtractorName property, as shown in the following example:

--spring.cloud.stream.bindings.output.producer.partitionKeyExtractorName=customPartitionKeyExtractor
+--spring.cloud.stream.bindings.output.producer.partitionCount=5
+. . .
+@Bean
+public CustomPartitionKeyExtractorClass customPartitionKeyExtractor() {
+    return new CustomPartitionKeyExtractorClass();
+}
[Note]Note

In previous versions of Spring Cloud Stream, you could specify the implementation of org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy by setting the spring.cloud.stream.bindings.output.producer.partitionKeyExtractorClass property. +Since version 2.0, this property is deprecated, and support for it will be removed in a future version.

Once the message key is calculated, the partition selection process determines the target partition as a value between 0 and partitionCount - 1. +The default calculation, applicable in most scenarios, is based on the following formula: key.hashCode() % partitionCount. +This can be customized on the binding, either by setting a SpEL expression to be evaluated against the 'key' (through the partitionSelectorExpression property) or by configuring an implementation of org.springframework.cloud.stream.binder.PartitionSelectorStrategy as a bean (by using the @Bean annotation). +Similar to the PartitionKeyExtractorStrategy, you can further filter it by using the spring.cloud.stream.bindings.output.producer.partitionSelectorName property when more than one bean of this type is available in the Application Context, as shown in the following example:

--spring.cloud.stream.bindings.output.producer.partitionSelectorName=customPartitionSelector
+. . .
+@Bean
+public CustomPartitionSelectorClass customPartitionSelector() {
+    return new CustomPartitionSelectorClass();
+}
[Note]Note

In previous versions of Spring Cloud Stream you could specify the implementation of org.springframework.cloud.stream.binder.PartitionSelectorStrategy by setting the spring.cloud.stream.bindings.output.producer.partitionSelectorClass property. +Since version 2.0, this property is deprecated and support for it will be removed in a future version.

11.3.2 Configuring Input Bindings for Partitioning

An input binding (with the channel name input) is configured to receive partitioned data by setting its partitioned property, as well as the instanceIndex and instanceCount properties on the application itself, as shown in the following example:

spring.cloud.stream.bindings.input.consumer.partitioned=true
+spring.cloud.stream.instanceIndex=3
+spring.cloud.stream.instanceCount=5

The instanceCount value represents the total number of application instances between which the data should be partitioned. +The instanceIndex must be a unique value across the multiple instances, with a value between 0 and instanceCount - 1. +The instance index helps each application instance to identify the unique partition(s) from which it receives data. +It is required by binders using technology that does not support partitioning natively. +For example, with RabbitMQ, there is a queue for each partition, with the queue name containing the instance index. +With Kafka, if autoRebalanceEnabled is true (default), Kafka takes care of distributing partitions across instances, and these properties are not required. +If autoRebalanceEnabled is set to false, the instanceCount and instanceIndex are used by the binder to determine which partition(s) the instance subscribes to (you must have at least as many partitions as there are instances). +The binder allocates the partitions instead of Kafka. +This might be useful if you want messages for a particular partition to always go to the same instance. +When a binder configuration requires them, it is important to set both values correctly in order to ensure that all of the data is consumed and that the application instances receive mutually exclusive datasets.

While a scenario in which using multiple instances for partitioned data processing may be complex to set up in a standalone case, Spring Cloud Dataflow can simplify the process significantly by populating both the input and output values correctly and by letting you rely on the runtime infrastructure to provide information about the instance index and instance count.

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi__main_concepts.html b/spring-cloud-stream/2.1.0.RC3/multi/multi__main_concepts.html new file mode 100644 index 00000000..813d5d7e --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi__main_concepts.html @@ -0,0 +1,35 @@ + + + 5. Main Concepts

5. Main Concepts

Spring Cloud Stream provides a number of abstractions and primitives that simplify the writing of message-driven microservice applications. +This section gives an overview of the following:

5.1 Application Model

A Spring Cloud Stream application consists of a middleware-neutral core. +The application communicates with the outside world through input and output channels injected into it by Spring Cloud Stream. +Channels are connected to external brokers through middleware-specific Binder implementations.

Figure 5.1. Spring Cloud Stream Application

SCSt with binder

5.1.1 Fat JAR

Spring Cloud Stream applications can be run in stand-alone mode from your IDE for testing. +To run a Spring Cloud Stream application in production, you can create an executable (or fat) JAR by using the standard Spring Boot tooling provided for Maven or Gradle. See the Spring Boot Reference Guide for more details.

5.2 The Binder Abstraction

Spring Cloud Stream provides Binder implementations for Kafka and Rabbit MQ. +Spring Cloud Stream also includes a TestSupportBinder, which leaves a channel unmodified so that tests can interact with channels directly and reliably assert on what is received. +You can also use the extensible API to write your own Binder.

Spring Cloud Stream uses Spring Boot for configuration, and the Binder abstraction makes it possible for a Spring Cloud Stream application to be flexible in how it connects to middleware. +For example, deployers can dynamically choose, at runtime, the destinations (such as the Kafka topics or RabbitMQ exchanges) to which channels connect. +Such configuration can be provided through external configuration properties and in any form supported by Spring Boot (including application arguments, environment variables, and application.yml or application.properties files). +In the sink example from the Chapter 4, Introducing Spring Cloud Stream section, setting the spring.cloud.stream.bindings.input.destination application property to raw-sensor-data causes it to read from the raw-sensor-data Kafka topic or from a queue bound to the raw-sensor-data RabbitMQ exchange.

Spring Cloud Stream automatically detects and uses a binder found on the classpath. +You can use different types of middleware with the same code. +To do so, include a different binder at build time. +For more complex use cases, you can also package multiple binders with your application and have it choose the binder( and even whether to use different binders for different channels) at runtime.

5.3 Persistent Publish-Subscribe Support

Communication between applications follows a publish-subscribe model, where data is broadcast through shared topics. +This can be seen in the following figure, which shows a typical deployment for a set of interacting Spring Cloud Stream applications.

Figure 5.2. Spring Cloud Stream Publish-Subscribe

SCSt sensors

Data reported by sensors to an HTTP endpoint is sent to a common destination named raw-sensor-data. +From the destination, it is independently processed by a microservice application that computes time-windowed averages and by another microservice application that ingests the raw data into HDFS (Hadoop Distributed File System). +In order to process the data, both applications declare the topic as their input at runtime.

The publish-subscribe communication model reduces the complexity of both the producer and the consumer and lets new applications be added to the topology without disruption of the existing flow. +For example, downstream from the average-calculating application, you can add an application that calculates the highest temperature values for display and monitoring. +You can then add another application that interprets the same flow of averages for fault detection. +Doing all communication through shared topics rather than point-to-point queues reduces coupling between microservices.

While the concept of publish-subscribe messaging is not new, Spring Cloud Stream takes the extra step of making it an opinionated choice for its application model. +By using native middleware support, Spring Cloud Stream also simplifies use of the publish-subscribe model across different platforms.

5.4 Consumer Groups

While the publish-subscribe model makes it easy to connect applications through shared topics, the ability to scale up by creating multiple instances of a given application is equally important. +When doing so, different instances of an application are placed in a competing consumer relationship, where only one of the instances is expected to handle a given message.

Spring Cloud Stream models this behavior through the concept of a consumer group. +(Spring Cloud Stream consumer groups are similar to and inspired by Kafka consumer groups.) +Each consumer binding can use the spring.cloud.stream.bindings.<channelName>.group property to specify a group name. +For the consumers shown in the following figure, this property would be set as spring.cloud.stream.bindings.<channelName>.group=hdfsWrite or spring.cloud.stream.bindings.<channelName>.group=average.

Figure 5.3. Spring Cloud Stream Consumer Groups

SCSt groups

All groups that subscribe to a given destination receive a copy of published data, but only one member of each group receives a given message from that destination. +By default, when a group is not specified, Spring Cloud Stream assigns the application to an anonymous and independent single-member consumer group that is in a publish-subscribe relationship with all other consumer groups.

5.5 Consumer Types

Two types of consumer are supported:

  • Message-driven (sometimes referred to as Asynchronous)
  • Polled (sometimes referred to as Synchronous)

Prior to version 2.0, only asynchronous consumers were supported. A message is delivered as soon as it is available and a thread is available to process it.

When you wish to control the rate at which messages are processed, you might want to use a synchronous consumer.

5.5.1 Durability

Consistent with the opinionated application model of Spring Cloud Stream, consumer group subscriptions are durable. +That is, a binder implementation ensures that group subscriptions are persistent and that, once at least one subscription for a group has been created, the group receives messages, even if they are sent while all applications in the group are stopped.

[Note]Note

Anonymous subscriptions are non-durable by nature. +For some binder implementations (such as RabbitMQ), it is possible to have non-durable group subscriptions.

In general, it is preferable to always specify a consumer group when binding an application to a given destination. +When scaling up a Spring Cloud Stream application, you must specify a consumer group for each of its input bindings. +Doing so prevents the application’s instances from receiving duplicate messages (unless that behavior is desired, which is unusual).

5.6 Partitioning Support

Spring Cloud Stream provides support for partitioning data between multiple instances of a given application. +In a partitioned scenario, the physical communication medium (such as the broker topic) is viewed as being structured into multiple partitions. +One or more producer application instances send data to multiple consumer application instances and ensure that data identified by common characteristics are processed by the same consumer instance.

Spring Cloud Stream provides a common abstraction for implementing partitioned processing use cases in a uniform fashion. +Partitioning can thus be used whether the broker itself is naturally partitioned (for example, Kafka) or not (for example, RabbitMQ).

Figure 5.4. Spring Cloud Stream Partitioning

SCSt partitioning

Partitioning is a critical concept in stateful processing, where it is critical (for either performance or consistency reasons) to ensure that all related data is processed together. +For example, in the time-windowed average calculation example, it is important that all measurements from any given sensor are processed by the same application instance.

[Note]Note

To set up a partitioned processing scenario, you must configure both the data-producing and the data-consuming ends.

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi__preface.html b/spring-cloud-stream/2.1.0.RC3/multi/multi__preface.html new file mode 100644 index 00000000..2d76995a --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi__preface.html @@ -0,0 +1,3 @@ + + + Part I. Preface

Part I. Preface

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi__programming_model.html b/spring-cloud-stream/2.1.0.RC3/multi/multi__programming_model.html new file mode 100644 index 00000000..53f63eaa --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi__programming_model.html @@ -0,0 +1,396 @@ + + + 6. Programming Model

6. Programming Model

To understand the programming model, you should be familiar with the following core concepts:

  • Destination Binders: Components responsible to provide integration with the external messaging systems.
  • Destination Bindings: Bridge between the external messaging systems and application provided Producers and Consumers of messages (created by the Destination Binders).
  • Message: The canonical data structure used by producers and consumers to communicate with Destination Binders (and thus other applications via external messaging systems).
SCSt overview

6.1 Destination Binders

Destination Binders are extension components of Spring Cloud Stream responsible for providing the necessary configuration and implementation to facilitate +integration with external messaging systems. +This integration is responsible for connectivity, delegation, and routing of messages to and from producers and consumers, data type conversion, +invocation of the user code, and more.

Binders handle a lot of the boiler plate responsibilities that would otherwise fall on your shoulders. However, to accomplish that, the binder still needs +some help in the form of minimalistic yet required set of instructions from the user, which typically come in the form of some type of configuration.

While it is out of scope of this section to discuss all of the available binder and binding configuration options (the rest of the manual covers them extensively), +Destination Binding does require special attention. The next section discusses it in detail.

6.2 Destination Bindings

As stated earlier, Destination Bindings provide a bridge between the external messaging system and application-provided Producers and Consumers.

Applying the @EnableBinding annotation to one of the application’s configuration classes defines a destination binding. +The @EnableBinding annotation itself is meta-annotated with @Configuration and triggers the configuration of the Spring Cloud Stream infrastructure.

The following example shows a fully configured and functioning Spring Cloud Stream application that receives the payload of the message from the INPUT +destination as a String type (see Chapter 9, Content Type Negotiation section), logs it to the console and sends it to the OUTPUT destination after converting it to upper case.

@SpringBootApplication
+@EnableBinding(Processor.class)
+public class MyApplication {
+
+	public static void main(String[] args) {
+		SpringApplication.run(MyApplication.class, args);
+	}
+
+	@StreamListener(Processor.INPUT)
+	@SendTo(Processor.OUTPUT)
+	public String handle(String value) {
+		System.out.println("Received: " + value);
+		return value.toUpperCase();
+	}
+}

As you can see the @EnableBinding annotation can take one or more interface classes as parameters. The parameters are referred to as bindings, +and they contain methods representing bindable components. +These components are typically message channels (see Spring Messaging) +for channel-based binders (such as Rabbit, Kafka, and others). However other types of bindings can +provide support for the native features of the corresponding technology. For example Kafka Streams binder (formerly known as KStream) allows native bindings directly to Kafka Streams +(see Kafka Streams for more details).

Spring Cloud Stream already provides binding interfaces for typical message exchange contracts, which include:

  • Sink: Identifies the contract for the message consumer by providing the destination from which the message is consumed.
  • Source: Identifies the contract for the message producer by providing the destination to which the produced message is sent.
  • Processor: Encapsulates both the sink and the source contracts by exposing two destinations that allow consumption and production of messages.
public interface Sink {
+
+  String INPUT = "input";
+
+  @Input(Sink.INPUT)
+  SubscribableChannel input();
+}
public interface Source {
+
+  String OUTPUT = "output";
+
+  @Output(Source.OUTPUT)
+  MessageChannel output();
+}
public interface Processor extends Source, Sink {}

While the preceding example satisfies the majority of cases, you can also define your own contracts by defining your own bindings interfaces and use @Input and @Output +annotations to identify the actual bindable components.

For example:

public interface Barista {
+
+    @Input
+    SubscribableChannel orders();
+
+    @Output
+    MessageChannel hotDrinks();
+
+    @Output
+    MessageChannel coldDrinks();
+}

Using the interface shown in the preceding example as a parameter to @EnableBinding triggers the creation of the three bound channels named orders, hotDrinks, and coldDrinks, +respectively.

You can provide as many binding interfaces as you need, as arguments to the @EnableBinding annotation, as shown in the following example:

@EnableBinding(value = { Orders.class, Payment.class })

In Spring Cloud Stream, the bindable MessageChannel components are the Spring Messaging MessageChannel (for outbound) and its extension, SubscribableChannel, +(for inbound).

Pollable Destination Binding

While the previously described bindings support event-based message consumption, sometimes you need more control, such as rate of consumption.

Starting with version 2.0, you can now bind a pollable consumer:

The following example shows how to bind a pollable consumer:

public interface PolledBarista {
+
+    @Input
+    PollableMessageSource orders();
+	. . .
+}

In this case, an implementation of PollableMessageSource is bound to the orders “channel”. See Section 6.3.5, “Using Polled Consumers” for more details.

Customizing Channel Names

By using the @Input and @Output annotations, you can specify a customized channel name for the channel, as shown in the following example:

public interface Barista {
+    @Input("inboundOrders")
+    SubscribableChannel orders();
+}

In the preceding example, the created bound channel is named inboundOrders.

Normally, you need not access individual channels or bindings directly (other then configuring them via @EnableBinding annotation). However there may be +times, such as testing or other corner cases, when you do.

Aside from generating channels for each binding and registering them as Spring beans, for each bound interface, Spring Cloud Stream generates a bean that implements the interface. +That means you can have access to the interfaces representing the bindings or individual channels by auto-wiring either in your application, as shown in the following two examples:

Autowire Binding interface

@Autowire
+private Source source
+
+public void sayHello(String name) {
+    source.output().send(MessageBuilder.withPayload(name).build());
+}

Autowire individual channel

@Autowire
+private MessageChannel output;
+
+public void sayHello(String name) {
+    output.send(MessageBuilder.withPayload(name).build());
+}

You can also use standard Spring’s @Qualifier annotation for cases when channel names are customized or in multiple-channel scenarios that require specifically named channels.

The following example shows how to use the @Qualifier annotation in this way:

@Autowire
+@Qualifier("myChannel")
+private MessageChannel output;

6.3 Producing and Consuming Messages

You can write a Spring Cloud Stream application by using either Spring Integration annotations or Spring Cloud Stream native annotation.

6.3.1 Spring Integration Support

Spring Cloud Stream is built on the concepts and patterns defined by Enterprise Integration Patterns and relies +in its internal implementation on an already established and popular implementation of Enterprise Integration Patterns within the Spring portfolio of projects: +Spring Integration framework.

So its only natural for it to support the foundation, semantics, and configuration options that are already established by Spring Integration

For example, you can attach the output channel of a Source to a MessageSource and use the familiar @InboundChannelAdapter annotation, as follows:

@EnableBinding(Source.class)
+public class TimerSource {
+
+  @Bean
+  @InboundChannelAdapter(value = Source.OUTPUT, poller = @Poller(fixedDelay = "10", maxMessagesPerPoll = "1"))
+  public MessageSource<String> timerMessageSource() {
+    return () -> new GenericMessage<>("Hello Spring Cloud Stream");
+  }
+}

Similarly, you can use @Transformer or @ServiceActivator while providing an implementation of a message handler method for a Processor binding contract, as shown in the following example:

@EnableBinding(Processor.class)
+public class TransformProcessor {
+  @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
+  public Object transform(String message) {
+    return message.toUpperCase();
+  }
+}
[Note]Note

While this may be skipping ahead a bit, it is important to understand that, when you consume from the same binding using @StreamListener annotation, a pub-sub model is used. +Each method annotated with @StreamListener receives its own copy of a message, and each one has its own consumer group. +However, if you consume from the same binding by using one of the Spring Integration annotation (such as @Aggregator, @Transformer, or @ServiceActivator), those consume in a competing model. +No individual consumer group is created for each subscription.

6.3.2 Using @StreamListener Annotation

Complementary to its Spring Integration support, Spring Cloud Stream provides its own @StreamListener annotation, modeled after other Spring Messaging annotations +(@MessageMapping, @JmsListener, @RabbitListener, and others) and provides conviniences, such as content-based routing and others.

@EnableBinding(Sink.class)
+public class VoteHandler {
+
+  @Autowired
+  VotingService votingService;
+
+  @StreamListener(Sink.INPUT)
+  public void handle(Vote vote) {
+    votingService.record(vote);
+  }
+}

As with other Spring Messaging methods, method arguments can be annotated with @Payload, @Headers, and @Header.

For methods that return data, you must use the @SendTo annotation to specify the output binding destination for data returned by the method, as shown in the following example:

@EnableBinding(Processor.class)
+public class TransformProcessor {
+
+  @Autowired
+  VotingService votingService;
+
+  @StreamListener(Processor.INPUT)
+  @SendTo(Processor.OUTPUT)
+  public VoteResult handle(Vote vote) {
+    return votingService.record(vote);
+  }
+}

6.3.3 Using @StreamListener for Content-based routing

Spring Cloud Stream supports dispatching messages to multiple handler methods annotated with @StreamListener based on conditions.

In order to be eligible to support conditional dispatching, a method must satisfy the follow conditions:

  • It must not return a value.
  • It must be an individual message handling method (reactive API methods are not supported).

The condition is specified by a SpEL expression in the condition argument of the annotation and is evaluated for each message. +All the handlers that match the condition are invoked in the same thread, and no assumption must be made about the order in which the invocations take place.

In the following example of a @StreamListener with dispatching conditions, all the messages bearing a header type with the value bogey are dispatched to the +receiveBogey method, and all the messages bearing a header type with the value bacall are dispatched to the receiveBacall method.

@EnableBinding(Sink.class)
+@EnableAutoConfiguration
+public static class TestPojoWithAnnotatedArguments {
+
+    @StreamListener(target = Sink.INPUT, condition = "headers['type']=='bogey'")
+    public void receiveBogey(@Payload BogeyPojo bogeyPojo) {
+       // handle the message
+    }
+
+    @StreamListener(target = Sink.INPUT, condition = "headers['type']=='bacall'")
+    public void receiveBacall(@Payload BacallPojo bacallPojo) {
+       // handle the message
+    }
+}

Content Type Negotiation in the Context of condition

It is important to understand some of the mechanics behind content-based routing using the condition argument of @StreamListener, especially in the context of the type of the message as a whole. +It may also help if you familiarize yourself with the Chapter 9, Content Type Negotiation before you proceed.

Consider the following scenario:

@EnableBinding(Sink.class)
+@EnableAutoConfiguration
+public static class CatsAndDogs {
+
+    @StreamListener(target = Sink.INPUT, condition = "payload.class.simpleName=='Dog'")
+    public void bark(Dog dog) {
+       // handle the message
+    }
+
+    @StreamListener(target = Sink.INPUT, condition = "payload.class.simpleName=='Cat'")
+    public void purr(Cat cat) {
+       // handle the message
+    }
+}

The preceding code is perfectly valid. It compiles and deploys without any issues, yet it never produces the result you expect.

That is because you are testing something that does not yet exist in a state you expect. That is because the payload of the message is not yet converted from the +wire format (byte[]) to the desired type. +In other words, it has not yet gone through the type conversion process described in the Chapter 9, Content Type Negotiation.

So, unless you use a SPeL expression that evaluates raw data (for example, the value of the first byte in the byte array), use message header-based expressions +(such as condition = "headers['type']=='dog'").

[Note]Note

At the moment, dispatching through @StreamListener conditions is supported only for channel-based binders (not for reactive programming) +support.

6.3.4 Spring Cloud Function support

Since Spring Cloud Stream v2.1, another alternative for defining stream handlers and sources is to use build-in +support for Spring Cloud Function where they can be expressed as beans of + type java.util.function.[Supplier/Function/Consumer].

To specify which functional bean to bind to the external destination(s) exposed by the bindings, you must provide spring.cloud.stream.function.definition property.

Here is the example of the Processor application exposing message handler as java.util.function.Function

@SpringBootApplication
+@EnableBinding(Processor.class)
+public class MyFunctionBootApp {
+
+	public static void main(String[] args) {
+		SpringApplication.run(MyFunctionBootApp.class, "--spring.cloud.stream.function.definition=toUpperCase");
+	}
+
+	@Bean
+	public Function<String, String> toUpperCase() {
+		return s -> s.toUpperCase();
+	}
+}

In the above you we simply define a bean of type java.util.function.Function called toUpperCase and identify it as a bean to be used as message handler +whose 'input' and 'output' must be bound to the external destinations exposed by the Processor binding.

Below are the examples of simple functional applications to support Source, Processor and Sink.

Here is the example of a Source application defined as java.util.function.Supplier

@SpringBootApplication
+@EnableBinding(Source.class)
+public static class SourceFromSupplier {
+	public static void main(String[] args) {
+		SpringApplication.run(SourceFromSupplier.class, "--spring.cloud.stream.function.definition=date");
+	}
+	@Bean
+	public Supplier<Date> date() {
+		return () -> new Date(12345L);
+	}
+}

Here is the example of a Processor application defined as java.util.function.Function

@SpringBootApplication
+@EnableBinding(Processor.class)
+public static class ProcessorFromFunction {
+	public static void main(String[] args) {
+		SpringApplication.run(ProcessorFromFunction.class, "--spring.cloud.stream.function.definition=toUpperCase");
+	}
+	@Bean
+	public Function<String, String> toUpperCase() {
+		return s -> s.toUpperCase();
+	}
+}

Here is the example of a Sink application defined as java.util.function.Consumer

@EnableAutoConfiguration
+@EnableBinding(Sink.class)
+public static class SinkFromConsumer {
+	public static void main(String[] args) {
+		SpringApplication.run(SinkFromConsumer.class, "--spring.cloud.stream.function.definition=sink");
+	}
+	@Bean
+	public Consumer<String> sink() {
+		return System.out::println;
+	}
+}

Functional Composition

Using this programming model you can also benefit from functional composition where you can dynamically compose complex handlers from a set of simple functions. +As an example let’s add the following function bean to the application defined above

@Bean
+public Function<String, String> wrapInQuotes() {
+	return s -> "\"" + s + "\"";
+}

and modify the spring.cloud.stream.function.definition property to reflect your intention to compose a new function from both ‘toUpperCase’ and ‘wrapInQuotes’. +To do that Spring Cloud Function allows you to use | (pipe) symbol. So to finish our example our property will now look like this:

—spring.cloud.stream.function.definition=toUpperCase|wrapInQuotes

6.3.5 Using Polled Consumers

Overview

When using polled consumers, you poll the PollableMessageSource on demand. +Consider the following example of a polled consumer:

public interface PolledConsumer {
+
+    @Input
+    PollableMessageSource destIn();
+
+    @Output
+    MessageChannel destOut();
+
+}

Given the polled consumer in the preceding example, you might use it as follows:

@Bean
+public ApplicationRunner poller(PollableMessageSource destIn, MessageChannel destOut) {
+    return args -> {
+        while (someCondition()) {
+            try {
+                if (!destIn.poll(m -> {
+                    String newPayload = ((String) m.getPayload()).toUpperCase();
+                    destOut.send(new GenericMessage<>(newPayload));
+                })) {
+                    Thread.sleep(1000);
+                }
+            }
+            catch (Exception e) {
+                // handle failure
+            }
+        }
+    };
+}

The PollableMessageSource.poll() method takes a MessageHandler argument (often a lambda expression, as shown here). +It returns true if the message was received and successfully processed.

As with message-driven consumers, if the MessageHandler throws an exception, messages are published to error channels, +as discussed in Section 6.4, “Error Handling”.

Normally, the poll() method acknowledges the message when the MessageHandler exits. +If the method exits abnormally, the message is rejected (not re-queued), but see the section called “Handling Errors”. +You can override that behavior by taking responsibility for the acknowledgment, as shown in the following example:

@Bean
+public ApplicationRunner poller(PollableMessageSource dest1In, MessageChannel dest2Out) {
+    return args -> {
+        while (someCondition()) {
+            if (!dest1In.poll(m -> {
+                StaticMessageHeaderAccessor.getAcknowledgmentCallback(m).noAutoAck();
+                // e.g. hand off to another thread which can perform the ack
+                // or acknowledge(Status.REQUEUE)
+
+            })) {
+                Thread.sleep(1000);
+            }
+        }
+    };
+}
[Important]Important

You must ack (or nack) the message at some point, to avoid resource leaks.

[Important]Important

Some messaging systems (such as Apache Kafka) maintain a simple offset in a log. If a delivery fails and is re-queued with StaticMessageHeaderAccessor.getAcknowledgmentCallback(m).acknowledge(Status.REQUEUE);, any later successfully ack’d messages are redelivered.

There is also an overloaded poll method, for which the definition is as follows:

poll(MessageHandler handler, ParameterizedTypeReference<?> type)

The type is a conversion hint that allows the incoming message payload to be converted, as shown in the following example:

boolean result = pollableSource.poll(received -> {
+			Map<String, Foo> payload = (Map<String, Foo>) received.getPayload();
+            ...
+
+		}, new ParameterizedTypeReference<Map<String, Foo>>() {});

Handling Errors

By default, an error channel is configured for the pollable source; if the callback throws an exception, an ErrorMessage is sent to the error channel (<destination>.<group>.errors); this error channel is also bridged to the global Spring Integration errorChannel.

You can subscribe to either error channel with a @ServiceActivator to handle errors; without a subscription, the error will simply be logged and the message will be acknowledged as successful. +If the error channel service activator throws an exception, the message will be rejected (by default) and won’t be redelivered. +If the service activator throws a RequeueCurrentMessageException, the message will be requeued at the broker and will be again retrieved on a subsequent poll.

If the listener throws a RequeueCurrentMessageException directly, the message will be requeued, as discussed above, and will not be sent to the error channels.

6.4 Error Handling

Errors happen, and Spring Cloud Stream provides several flexible mechanisms to handle them. +The error handling comes in two flavors:

  • application: The error handling is done within the application (custom error handler).
  • system: The error handling is delegated to the binder (re-queue, DL, and others). Note that the techniques are dependent on binder implementation and the +capability of the underlying messaging middleware.

Spring Cloud Stream uses the Spring Retry library to facilitate successful message processing. See Section 6.4.3, “Retry Template” for more details. +However, when all fails, the exceptions thrown by the message handlers are propagated back to the binder. At that point, binder invokes custom error handler or communicates +the error back to the messaging system (re-queue, DLQ, and others).

6.4.1 Application Error Handling

There are two types of application-level error handling. Errors can be handled at each binding subscription or a global handler can handle all the binding subscription errors. Let’s review the details.

Figure 6.1. A Spring Cloud Stream Sink Application with Custom and Global Error Handlers

custom vs global error channels

For each input binding, Spring Cloud Stream creates a dedicated error channel with the following semantics <destinationName>.errors.

[Note]Note

The <destinationName> consists of the name of the binding (such as input) and the name of the group (such as myGroup).

Consider the following:

spring.cloud.stream.bindings.input.group=myGroup
@StreamListener(Sink.INPUT) // destination name 'input.myGroup'
+public void handle(Person value) {
+	throw new RuntimeException("BOOM!");
+}
+
+@ServiceActivator(inputChannel = Processor.INPUT + ".myGroup.errors") //channel name 'input.myGroup.errors'
+public void error(Message<?> message) {
+	System.out.println("Handling ERROR: " + message);
+}

In the preceding example the destination name is input.myGroup and the dedicated error channel name is input.myGroup.errors.

[Note]Note

The use of @StreamListener annotation is intended specifically to define bindings that bridge internal channels and external destinations. Given that the destination +specific error channel does NOT have an associated external destination, such channel is a prerogative of Spring Integration (SI). This means that the handler +for such destination must be defined using one of the SI handler annotations (i.e., @ServiceActivator, @Transformer etc.).

[Note]Note

If group is not specified anonymous group is used (something like input.anonymous.2K37rb06Q6m2r51-SPIDDQ), which is not suitable for error +handling scenarious, since you don’t know what it’s going to be until the destination is created.

Also, in the event you are binding to the existing destination such as:

spring.cloud.stream.bindings.input.destination=myFooDestination
+spring.cloud.stream.bindings.input.group=myGroup

the full destination name is myFooDestination.myGroup and then the dedicated error channel name is myFooDestination.myGroup.errors.

Back to the example…​

The handle(..) method, which subscribes to the channel named input, throws an exception. Given there is also a subscriber to the error channel input.myGroup.errors +all error messages are handled by this subscriber.

If you have multiple bindings, you may want to have a single error handler. Spring Cloud Stream automatically provides support for +a global error channel by bridging each individual error channel to the channel named errorChannel, allowing a single subscriber to handle all errors, +as shown in the following example:

@StreamListener("errorChannel")
+public void error(Message<?> message) {
+	System.out.println("Handling ERROR: " + message);
+}

This may be a convenient option if error handling logic is the same regardless of which handler produced the error.

6.4.2 System Error Handling

System-level error handling implies that the errors are communicated back to the messaging system and, given that not every messaging system +is the same, the capabilities may differ from binder to binder.

That said, in this section we explain the general idea behind system level error handling and use Rabbit binder as an example. NOTE: Kafka binder provides similar +support, although some configuration properties do differ. Also, for more details and configuration options, see the individual binder’s documentation.

If no internal error handlers are configured, the errors propagate to the binders, and the binders subsequently propagate those errors back to the messaging system. +Depending on the capabilities of the messaging system such a system may drop the message, re-queue the message for re-processing or send the failed message to DLQ. +Both Rabbit and Kafka support these concepts. However, other binders may not, so refer to your individual binder’s documentation for details on supported system-level +error-handling options.

Drop Failed Messages

By default, if no additional system-level configuration is provided, the messaging system drops the failed message. +While acceptable in some cases, for most cases, it is not, and we need some recovery mechanism to avoid message loss.

DLQ - Dead Letter Queue

DLQ allows failed messages to be sent to a special destination: - Dead Letter Queue.

When configured, failed messages are sent to this destination for subsequent re-processing or auditing and reconciliation.

For example, continuing on the previous example and to set up the DLQ with Rabbit binder, you need to set the following property:

spring.cloud.stream.rabbit.bindings.input.consumer.auto-bind-dlq=true

Keep in mind that, in the above property, input corresponds to the name of the input destination binding. +The consumer indicates that it is a consumer property and auto-bind-dlq instructs the binder to configure DLQ for input +destination, which results in an additional Rabbit queue named input.myGroup.dlq.

Once configured, all failed messages are routed to this queue with an error message similar to the following:

delivery_mode:	1
+headers:
+x-death:
+count:	1
+reason:	rejected
+queue:	input.hello
+time:	1522328151
+exchange:
+routing-keys:	input.myGroup
+Payload {"name”:"Bob"}

As you can see from the above, your original message is preserved for further actions.

However, one thing you may have noticed is that there is limited information on the original issue with the message processing. For example, you do not see a stack +trace corresponding to the original error. +To get more relevant information about the original error, you must set an additional property:

spring.cloud.stream.rabbit.bindings.input.consumer.republish-to-dlq=true

Doing so forces the internal error handler to intercept the error message and add additional information to it before publishing it to DLQ. +Once configured, you can see that the error message contains more information relevant to the original error, as follows:

delivery_mode:	2
+headers:
+x-original-exchange:
+x-exception-message:	has an error
+x-original-routingKey:	input.myGroup
+x-exception-stacktrace:	org.springframework.messaging.MessageHandlingException: nested exception is
+      org.springframework.messaging.MessagingException: has an error, failedMessage=GenericMessage [payload=byte[15],
+      headers={amqp_receivedDeliveryMode=NON_PERSISTENT, amqp_receivedRoutingKey=input.hello, amqp_deliveryTag=1,
+      deliveryAttempt=3, amqp_consumerQueue=input.hello, amqp_redelivered=false, id=a15231e6-3f80-677b-5ad7-d4b1e61e486e,
+      amqp_consumerTag=amq.ctag-skBFapilvtZhDsn0k3ZmQg, contentType=application/json, timestamp=1522327846136}]
+      at org.spring...integ...han...MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:107)
+      at. . . . .
+Payload {"name”:"Bob"}

This effectively combines application-level and system-level error handling to further assist with downstream troubleshooting mechanics.

Re-queue Failed Messages

As mentioned earlier, the currently supported binders (Rabbit and Kafka) rely on RetryTemplate to facilitate successful message processing. See Section 6.4.3, “Retry Template” for details. +However, for cases when max-attempts property is set to 1, internal reprocessing of the message is disabled. At this point, you can facilitate message re-processing (re-tries) +by instructing the messaging system to re-queue the failed message. Once re-queued, the failed message is sent back to the original handler, essentially creating a retry loop.

This option may be feasible for cases where the nature of the error is related to some sporadic yet short-term unavailability of some resource.

To accomplish that, you must set the following properties:

spring.cloud.stream.bindings.input.consumer.max-attempts=1
+spring.cloud.stream.rabbit.bindings.input.consumer.requeue-rejected=true

In the preceding example, the max-attempts set to 1 essentially disabling internal re-tries and requeue-rejected (short for requeue rejected messages) is set to true. +Once set, the failed message is resubmitted to the same handler and loops continuously or until the handler throws AmqpRejectAndDontRequeueException +essentially allowing you to build your own re-try logic within the handler itself.

6.4.3 Retry Template

The RetryTemplate is part of the Spring Retry library. +While it is out of scope of this document to cover all of the capabilities of the RetryTemplate, we will mention the following consumer properties that are specifically related to +the RetryTemplate:

maxAttempts

The number of attempts to process the message.

Default: 3.

backOffInitialInterval

The backoff initial interval on retry.

Default 1000 milliseconds.

backOffMaxInterval

The maximum backoff interval.

Default 10000 milliseconds.

backOffMultiplier

The backoff multiplier.

Default 2.0.

defaultRetryable

Whether exceptions thrown by the listener that are not listed in the retryableExceptions are retryable.

Default: true.

retryableExceptions

A map of Throwable class names in the key and a boolean in the value. +Specify those exceptions (and subclasses) that will or won’t be retried. +Also see defaultRetriable. +Example: spring.cloud.stream.bindings.input.consumer.retryable-exceptions.java.lang.IllegalStateException=false.

Default: empty.

While the preceding settings are sufficient for majority of the customization requirements, they may not satisfy certain complex requirements at, which +point you may want to provide your own instance of the RetryTemplate. To do so configure it as a bean in your application configuration. The application provided +instance will override the one provided by the framework. Also, to avoid conflicts you must qualify the instance of the RetryTemplate you want to be used by the binder +as @StreamRetryTemplate. For example,

@StreamRetryTemplate
+public RetryTemplate myRetryTemplate() {
+    return new RetryTemplate();
+}

As you can see from the above example you don’t need to annotate it with @Bean since @StreamRetryTemplate is a qualified @Bean.

6.5 Reactive Programming Support

Spring Cloud Stream also supports the use of reactive APIs where incoming and outgoing data is handled as continuous data flows. +Support for reactive APIs is available through spring-cloud-stream-reactive, which needs to be added explicitly to your project.

The programming model with reactive APIs is declarative. Instead of specifying how each individual message should be handled, you can use operators that describe functional transformations from inbound to outbound data flows.

At present Spring Cloud Stream supports the only the Reactor API. +In the future, we intend to support a more generic model based on Reactive Streams.

The reactive programming model also uses the @StreamListener annotation for setting up reactive handlers. +The differences are that:

  • The @StreamListener annotation must not specify an input or output, as they are provided as arguments and return values from the method.
  • The arguments of the method must be annotated with @Input and @Output, indicating which input or output the incoming and outgoing data flows connect to, respectively.
  • The return value of the method, if any, is annotated with @Output, indicating the input where data should be sent.
[Note]Note

Reactive programming support requires Java 1.8.

[Note]Note

As of Spring Cloud Stream 1.1.1 and later (starting with release train Brooklyn.SR2), reactive programming support requires the use of Reactor 3.0.4.RELEASE and higher. +Earlier Reactor versions (including 3.0.1.RELEASE, 3.0.2.RELEASE and 3.0.3.RELEASE) are not supported. +spring-cloud-stream-reactive transitively retrieves the proper version, but it is possible for the project structure to manage the version of the io.projectreactor:reactor-core to an earlier release, especially when using Maven. +This is the case for projects generated by using Spring Initializr with Spring Boot 1.x, which overrides the Reactor version to 2.0.8.RELEASE. +In such cases, you must ensure that the proper version of the artifact is released. +You can do so by adding a direct dependency on io.projectreactor:reactor-core with a version of 3.0.4.RELEASE or later to your project.

[Note]Note

The use of term, reactive, currently refers to the reactive APIs being used and not to the execution model being reactive (that is, the bound endpoints still use a 'push' rather than a 'pull' model). While some backpressure support is provided by the use of Reactor, we do intend, in a future release, to support entirely reactive pipelines by the use of native reactive clients for the connected middleware.

6.5.1 Reactor-based Handlers

A Reactor-based handler can have the following argument types:

  • For arguments annotated with @Input, it supports the Reactor Flux type. +The parameterization of the inbound Flux follows the same rules as in the case of individual message handling: It can be the entire Message, a POJO that can be the Message payload, or a POJO that is the result of a transformation based on the Message content-type header. Multiple inputs are provided.
  • For arguments annotated with Output, it supports the FluxSender type, which connects a Flux produced by the method with an output. Generally speaking, specifying outputs as arguments is only recommended when the method can have multiple outputs.

A Reactor-based handler supports a return type of Flux. In that case, it must be annotated with @Output. We recommend using the return value of the method when a single output Flux is available.

The following example shows a Reactor-based Processor:

@EnableBinding(Processor.class)
+@EnableAutoConfiguration
+public static class UppercaseTransformer {
+
+  @StreamListener
+  @Output(Processor.OUTPUT)
+  public Flux<String> receive(@Input(Processor.INPUT) Flux<String> input) {
+    return input.map(s -> s.toUpperCase());
+  }
+}

The same processor using output arguments looks like the following example:

@EnableBinding(Processor.class)
+@EnableAutoConfiguration
+public static class UppercaseTransformer {
+
+  @StreamListener
+  public void receive(@Input(Processor.INPUT) Flux<String> input,
+     @Output(Processor.OUTPUT) FluxSender output) {
+     output.send(input.map(s -> s.toUpperCase()));
+  }
+}

6.5.2 Reactive Sources

Spring Cloud Stream reactive support also provides the ability for creating reactive sources through the @StreamEmitter annotation. +By using the @StreamEmitter annotation, a regular source may be converted to a reactive one. +@StreamEmitter is a method level annotation that marks a method to be an emitter to outputs declared with @EnableBinding. +You cannot use the @Input annotation along with @StreamEmitter, as the methods marked with this annotation are not listening for any input. Rather, methods marked with @StreamEmitter generate output. +Following the same programming model used in @StreamListener, @StreamEmitter also allows flexible ways of using the @Output annotation, depending on whether the method has any arguments, a return type, and other considerations.

The remainder of this section contains examples of using the @StreamEmitter annotation in various styles.

The following example emits the Hello, World message every millisecond and publishes to a Reactor Flux:

@EnableBinding(Source.class)
+@EnableAutoConfiguration
+public static class HelloWorldEmitter {
+
+  @StreamEmitter
+  @Output(Source.OUTPUT)
+  public Flux<String> emit() {
+    return Flux.intervalMillis(1)
+            .map(l -> "Hello World");
+  }
+}

In the preceding example, the resulting messages in the Flux are sent to the output channel of the Source.

The next example is another flavor of an @StreamEmmitter that sends a Reactor Flux. +Instead of returning a Flux, the following method uses a FluxSender to programmatically send a Flux from a source:

@EnableBinding(Source.class)
+@EnableAutoConfiguration
+public static class HelloWorldEmitter {
+
+  @StreamEmitter
+  @Output(Source.OUTPUT)
+  public void emit(FluxSender output) {
+    output.send(Flux.intervalMillis(1)
+            .map(l -> "Hello World"));
+  }
+}

The next example is exactly same as the above snippet in functionality and style. +However, instead of using an explicit @Output annotation on the method, it uses the annotation on the method parameter.

@EnableBinding(Source.class)
+@EnableAutoConfiguration
+public static class HelloWorldEmitter {
+
+  @StreamEmitter
+  public void emit(@Output(Source.OUTPUT) FluxSender output) {
+    output.send(Flux.intervalMillis(1)
+            .map(l -> "Hello World"));
+  }
+}

The last example in this section is yet another flavor of writing reacting sources by using the Reactive Streams Publisher API and taking advantage of the support for it in Spring Integration Java DSL. +The Publisher in the following example still uses Reactor Flux under the hood, but, from an application perspective, that is transparent to the user and only needs Reactive Streams and Java DSL for Spring Integration:

@EnableBinding(Source.class)
+@EnableAutoConfiguration
+public static class HelloWorldEmitter {
+
+  @StreamEmitter
+  @Output(Source.OUTPUT)
+  @Bean
+  public Publisher<Message<String>> emit() {
+    return IntegrationFlows.from(() ->
+                new GenericMessage<>("Hello World"),
+        e -> e.poller(p -> p.fixedDelay(1)))
+        .toReactivePublisher();
+  }
+}
\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi__quick_start.html b/spring-cloud-stream/2.1.0.RC3/multi/multi__quick_start.html new file mode 100644 index 00000000..d887a8df --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi__quick_start.html @@ -0,0 +1,53 @@ + + + 2. Quick Start

2. Quick Start

You can try Spring Cloud Stream in less then 5 min even before you jump into any details by following this three-step guide.

We show you how to create a Spring Cloud Stream application that receives messages coming from the messaging middleware of your choice (more on this later) and logs received messages to the console. +We call it LoggingConsumer. +While not very practical, it provides a good introduction to some of the main concepts +and abstractions, making it easier to digest the rest of this user guide.

The three steps are as follows:

2.1 Creating a Sample Application by Using Spring Initializr

To get started, visit the Spring Initializr. From there, you can generate our LoggingConsumer application. To do so:

  1. In the Dependencies section, start typing stream. +When the Cloud Stream option should appears, select it.
  2. Start typing either 'kafka' or 'rabbit'.
  3. Select Kafka or RabbitMQ.

    Basically, you choose the messaging middleware to which your application binds. +We recommend using the one you have already installed or feel more comfortable with installing and running. +Also, as you can see from the Initilaizer screen, there are a few other options you can choose. +For example, you can choose Gradle as your build tool instead of Maven (the default).

  4. In the Artifact field, type 'logging-consumer'.

    The value of the Artifact field becomes the application name. +If you chose RabbitMQ for the middleware, your Spring Initializr should now be as follows:

spring initializr
  1. Click the Generate Project button.

    Doing so downloads the zipped version of the generated project to your hard drive.

  2. Unzip the file into the folder you want to use as your project directory.
[Tip]Tip

We encourage you to explore the many possibilities available in the Spring Initializr. +It lets you create many different kinds of Spring applications.

2.2 Importing the Project into Your IDE

Now you can import the project into your IDE. +Keep in mind that, depending on the IDE, you may need to follow a specific import procedure. +For example, depending on how the project was generated (Maven or Gradle), you may need to follow specific import procedure (for example, in Eclipse or STS, you need to use File → Import → Maven → Existing Maven Project).

Once imported, the project must have no errors of any kind. Also, src/main/java should contain com.example.loggingconsumer.LoggingConsumerApplication.

Technically, at this point, you can run the application’s main class. +It is already a valid Spring Boot application. +However, it does not do anything, so we want to add some code.

2.3 Adding a Message Handler, Building, and Running

Modify the com.example.loggingconsumer.LoggingConsumerApplication class to look as follows:

@SpringBootApplication
+@EnableBinding(Sink.class)
+public class LoggingConsumerApplication {
+
+	public static void main(String[] args) {
+		SpringApplication.run(LoggingConsumerApplication.class, args);
+	}
+
+	@StreamListener(Sink.INPUT)
+	public void handle(Person person) {
+		System.out.println("Received: " + person);
+	}
+
+	public static class Person {
+		private String name;
+		public String getName() {
+			return name;
+		}
+		public void setName(String name) {
+			this.name = name;
+		}
+		public String toString() {
+			return this.name;
+		}
+	}
+}

As you can see from the preceding listing:

  • We have enabled Sink binding (input-no-output) by using @EnableBinding(Sink.class). +Doing so signals to the framework to initiate binding to the messaging middleware, where it automatically creates the destination (that is, queue, topic, and others) that are bound to the Sink.INPUT channel.
  • We have added a handler method to receive incoming messages of type Person. +Doing so lets you see one of the core features of the framework: It tries to automatically convert incoming message payloads to type Person.

You now have a fully functional Spring Cloud Stream application that does listens for messages. +From here, for simplicity, we assume you selected RabbitMQ in step one. +Assuming you have RabbitMQ installed and running, you can start the application by running its main method in your IDE.

You should see following output:

	--- [ main] c.s.b.r.p.RabbitExchangeQueueProvisioner : declaring queue for inbound: input.anonymous.CbMIwdkJSBO1ZoPDOtHtCg, bound to: input
+	--- [ main] o.s.a.r.c.CachingConnectionFactory       : Attempting to connect to: [localhost:5672]
+	--- [ main] o.s.a.r.c.CachingConnectionFactory       : Created new connection: rabbitConnectionFactory#2a3a299:0/SimpleConnection@66c83fc8. . .
+	. . .
+	--- [ main] o.s.i.a.i.AmqpInboundChannelAdapter      : started inbound.input.anonymous.CbMIwdkJSBO1ZoPDOtHtCg
+	. . .
+	--- [ main] c.e.l.LoggingConsumerApplication         : Started LoggingConsumerApplication in 2.531 seconds (JVM running for 2.897)

Go to the RabbitMQ management console or any other RabbitMQ client and send a message to input.anonymous.CbMIwdkJSBO1ZoPDOtHtCg. +The anonymous.CbMIwdkJSBO1ZoPDOtHtCg part represents the group name and is generated, so it is bound to be different in your environment. +For something more predictable, you can use an explicit group name by setting spring.cloud.stream.bindings.input.group=hello (or whatever name you like).

The contents of the message should be a JSON representation of the Person class, as follows:

{"name":"Sam Spade"}

Then, in your console, you should see:

Received: Sam Spade

You can also build and package your application into a boot jar (by using ./mvnw clean install) and run the built JAR by using the java -jar command.

Now you have a working (albeit very basic) Spring Cloud Stream application.

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi__samples.html b/spring-cloud-stream/2.1.0.RC3/multi/multi__samples.html new file mode 100644 index 00000000..628cc954 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi__samples.html @@ -0,0 +1,3 @@ + + + 15. Samples

15. Samples

For Spring Cloud Stream samples, see the spring-cloud-stream-samples repository on GitHub.

15.1 Deploying Stream Applications on CloudFoundry

On CloudFoundry, services are usually exposed through a special environment variable called VCAP_SERVICES.

When configuring your binder connections, you can use the values from an environment variable as explained on the dataflow Cloud Foundry Server docs.

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi__testing.html b/spring-cloud-stream/2.1.0.RC3/multi/multi__testing.html new file mode 100644 index 00000000..7a456a38 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi__testing.html @@ -0,0 +1,56 @@ + + + 12. Testing

12. Testing

Spring Cloud Stream provides support for testing your microservice applications without connecting to a messaging system. +You can do that by using the TestSupportBinder provided by the spring-cloud-stream-test-support library, which can be added as a test dependency to the application, as shown in the following example:

   <dependency>
+       <groupId>org.springframework.cloud</groupId>
+       <artifactId>spring-cloud-stream-test-support</artifactId>
+       <scope>test</scope>
+   </dependency>
[Note]Note

The TestSupportBinder uses the Spring Boot autoconfiguration mechanism to supersede the other binders found on the classpath. +Therefore, when adding a binder as a dependency, you must make sure that the test scope is being used.

The TestSupportBinder lets you interact with the bound channels and inspect any messages sent and received by the application.

For outbound message channels, the TestSupportBinder registers a single subscriber and retains the messages emitted by the application in a MessageCollector. +They can be retrieved during tests and have assertions made against them.

You can also send messages to inbound message channels so that the consumer application can consume the messages. +The following example shows how to test both input and output channels on a processor:

@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class ExampleTest {
+
+  @Autowired
+  private Processor processor;
+
+  @Autowired
+  private MessageCollector messageCollector;
+
+  @Test
+  @SuppressWarnings("unchecked")
+  public void testWiring() {
+    Message<String> message = new GenericMessage<>("hello");
+    processor.input().send(message);
+    Message<String> received = (Message<String>) messageCollector.forChannel(processor.output()).poll();
+    assertThat(received.getPayload(), equalTo("hello world"));
+  }
+
+
+  @SpringBootApplication
+  @EnableBinding(Processor.class)
+  public static class MyProcessor {
+
+    @Autowired
+    private Processor channels;
+
+    @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
+    public String transform(String in) {
+      return in + " world";
+    }
+  }
+}

In the preceding example, we create an application that has an input channel and an output channel, both bound through the Processor interface. +The bound interface is injected into the test so that we can have access to both channels. +We send a message on the input channel, and we use the MessageCollector provided by Spring Cloud Stream’s test support to capture that the message has been sent to the output channel as a result. +Once we have received the message, we can validate that the component functions correctly.

12.1 Disabling the Test Binder Autoconfiguration

The intent behind the test binder superseding all the other binders on the classpath is to make it easy to test your applications without making changes to your production dependencies. +In some cases (for example, integration tests) it is useful to use the actual production binders instead, and that requires disabling the test binder autoconfiguration. +To do so, you can exclude the org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration class by using one of the Spring Boot autoconfiguration exclusion mechanisms, as shown in the following example:

    @SpringBootApplication(exclude = TestSupportBinderAutoConfiguration.class)
+    @EnableBinding(Processor.class)
+    public static class MyProcessor {
+
+        @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
+        public String transform(String in) {
+            return in + " world";
+        }
+    }

When autoconfiguration is disabled, the test binder is available on the classpath, and its defaultCandidate property is set to false so that it does not interfere with the regular user configuration. It can be referenced under the name, test, as shown in the following example:

spring.cloud.stream.defaultBinder=test

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi__whats_new_in_2_0.html b/spring-cloud-stream/2.1.0.RC3/multi/multi__whats_new_in_2_0.html new file mode 100644 index 00000000..36eff59a --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi__whats_new_in_2_0.html @@ -0,0 +1,32 @@ + + + 3. What’s New in 2.0?

3. What’s New in 2.0?

Spring Cloud Stream introduces a number of new features, enhancements, and changes. The following sections outline the most notable ones:

3.1 New Features and Components

  • Polling Consumers: Introduction of polled consumers, which lets the application control message processing rates. +See Section 6.3.5, “Using Polled Consumers” for more details. +You can also read this blog post for more details.
  • Micrometer Support: Metrics has been switched to use Micrometer. +MeterRegistry is also provided as a bean so that custom applications can autowire it to capture custom metrics. +See Chapter 14, Metrics Emitter for more details.
  • New Actuator Binding Controls: New actuator binding controls let you both visualize and control the Bindings lifecycle. +For more details, see Section 7.6, “Binding visualization and control”.
  • Configurable RetryTemplate: Aside from providing properties to configure RetryTemplate, we now let you provide your own template, effectively overriding the one provided by the framework. +To use it, configure it as a @Bean in your application.

3.2 Notable Enhancements

This version includes the following notable enhancements:

3.2.1 Both Actuator and Web Dependencies Are Now Optional

This change slims down the footprint of the deployed application in the event neither actuator nor web dependencies required. +It also lets you switch between the reactive and conventional web paradigms by manually adding one of the following dependencies.

The following listing shows how to add the conventional web framework:

<dependency>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-web</artifactId>
+</dependency>

The following listing shows how to add the reactive web framework:

<dependency>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-webflux</artifactId>
+</dependency>

The following list shows how to add the actuator dependency:

<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-actuator</artifactId>
+</dependency>

3.2.2 Content-type Negotiation Improvements

One of the core themes for verion 2.0 is improvements (in both consistency and performance) around content-type negotiation and message conversion. +The following summary outlines the notable changes and improvements in this area. +See the Chapter 9, Content Type Negotiation section for more details. +Also this blog post contains more detail.

  • All message conversion is now handled only by MessageConverter objects.
  • We introduced the @StreamMessageConverter annotation to provide custom MessageConverter objects.
  • We introduced the default Content Type as application/json, which needs to be taken into consideration when migrating 1.3 application or operating in the mixed mode (that is, 1.3 producer → 2.0 consumer).
  • Messages with textual payloads and a contentType of text/…​ or …​/json are no longer converted to Message<String> for cases where the argument type of the provided MessageHandler can not be determined (that is, public void handle(Message<?> message) or public void handle(Object payload)). +Furthermore, a strong argument type may not be enough to properly convert messages, so the contentType header may be used as a supplement by some MessageConverters.

3.3 Notable Deprecations

As of version 2.0, the following items have been deprecated:

3.3.1 Java Serialization (Java Native and Kryo)

JavaSerializationMessageConverter and KryoMessageConverter remain for now. However, we plan to move them out of the core packages and support in the future. +The main reason for this deprecation is to flag the issue that type-based, language-specific serialization could cause in distributed environments, where Producers and Consumers may depend on different JVM versions or have different versions of supporting libraries (that is, Kryo). +We also wanted to draw the attention to the fact that Consumers and Producers may not even be Java-based, so polyglot style serialization (i.e., JSON) is better suited.

3.3.2 Deprecated Classes and Methods

The following is a quick summary of notable deprecations. See the corresponding {spring-cloud-stream-javadoc-current}[javadoc] for more details.

  • SharedChannelRegistry. Use SharedBindingTargetRegistry.
  • Bindings. +Beans qualified by it are already uniquely identified by their type — for example, provided Source, Processor, or custom bindings:
public interface Sample {
+	String OUTPUT = "sampleOutput";
+
+	@Output(Sample.OUTPUT)
+	MessageChannel output();
+}
  • HeaderMode.raw. Use none, headers or embeddedHeaders
  • ProducerProperties.partitionKeyExtractorClass in favor of partitionKeyExtractorName and ProducerProperties.partitionSelectorClass in favor of partitionSelectorName. +This change ensures that both components are Spring configured and managed and are referenced in a Spring-friendly way.
  • BinderAwareRouterBeanPostProcessor. While the component remains, it is no longer a BeanPostProcessor and will be renamed in the future.
  • BinderProperties.setEnvironment(Properties environment). Use BinderProperties.setEnvironment(Map<String, Object> environment).
\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi_content-type-management.html b/spring-cloud-stream/2.1.0.RC3/multi/multi_content-type-management.html new file mode 100644 index 00000000..ebf9f031 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi_content-type-management.html @@ -0,0 +1,78 @@ + + + 9. Content Type Negotiation

9. Content Type Negotiation

Data transformation is one of the core features of any message-driven microservice architecture. Given that, in Spring Cloud Stream, such data +is represented as a Spring Message, a message may have to be transformed to a desired shape or size before reaching its destination. This is required for two reasons:

  1. To convert the contents of the incoming message to match the signature of the application-provided handler.
  2. To convert the contents of the outgoing message to the wire format.

The wire format is typically byte[] (that is true for the Kafka and Rabbit binders), but it is governed by the binder implementation.

In Spring Cloud Stream, message transformation is accomplished with an org.springframework.messaging.converter.MessageConverter.

[Note]Note

As a supplement to the details to follow, you may also want to read the following blog post.

9.1 Mechanics

To better understand the mechanics and the necessity behind content-type negotiation, we take a look at a very simple use case by using the following message handler as an example:

@StreamListener(Processor.INPUT)
+@SendTo(Processor.OUTPUT)
+public String handle(Person person) {..}
[Note]Note

For simplicity, we assume that this is the only handler in the application (we assume there is no internal pipeline).

The handler shown in the preceding example expects a Person object as an argument and produces a String type as an output. +In order for the framework to succeed in passing the incoming Message as an argument to this handler, it has to somehow transform the payload of the Message type from the wire format to a Person type. +In other words, the framework must locate and apply the appropriate MessageConverter. +To accomplish that, the framework needs some instructions from the user. +One of these instructions is already provided by the signature of the handler method itself (Person type). +Consequently, in theory, that should be (and, in some cases, is) enough. +However, for the majority of use cases, in order to select the appropriate MessageConverter, the framework needs an additional piece of information. +That missing piece is contentType.

Spring Cloud Stream provides three mechanisms to define contentType (in order of precedence):

  1. HEADER: The contentType can be communicated through the Message itself. By providing a contentType header, you declare the content type to use to locate and apply the appropriate MessageConverter.
  2. BINDING: The contentType can be set per destination binding by setting the spring.cloud.stream.bindings.input.content-type property.

    [Note]Note

    The input segment in the property name corresponds to the actual name of the destination (which is “input” in our case). This approach lets you declare, on a per-binding basis, the content type to use to locate and apply the appropriate MessageConverter.

  3. DEFAULT: If contentType is not present in the Message header or the binding, the default application/json content type is used to +locate and apply the appropriate MessageConverter.

As mentioned earlier, the preceding list also demonstrates the order of precedence in case of a tie. For example, a header-provided content type takes precedence over any other content type. +The same applies for a content type set on a per-binding basis, which essentially lets you override the default content type. +However, it also provides a sensible default (which was determined from community feedback).

Another reason for making application/json the default stems from the interoperability requirements driven by distributed microservices architectures, where producer and consumer not only run in different JVMs but can also run on different non-JVM platforms.

When the non-void handler method returns, if the the return value is already a Message, that Message becomes the payload. However, when the return value is not a Message, the new Message is constructed with the return value as the payload while inheriting +headers from the input Message minus the headers defined or filtered by SpringIntegrationProperties.messageHandlerNotPropagatedHeaders. +By default, there is only one header set there: contentType. This means that the new Message does not have contentType header set, thus ensuring that the contentType can evolve. +You can always opt out of returning a Message from the handler method where you can inject any header you wish.

If there is an internal pipeline, the Message is sent to the next handler by going through the same process of conversion. However, if there is no internal pipeline or you have reached the end of it, the Message is sent back to the output destination.

9.1.1 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. +The logic for selecting the appropriate MessageConverter resides with the argument resolvers (HandlerMethodArgumentResolvers), which trigger right before the invocation of the user-defined handler method (which is when the actual argument type is known to the framework). +If the argument type does not match the type of the current payload, the framework delegates to the stack of the +pre-configured MessageConverters to see if any one of them can convert the payload. +As you can see, the Object fromMessage(Message<?> message, Class<?> targetClass); +operation of the MessageConverter takes targetClass as one of its arguments. +The framework also ensures that the provided Message always contains a contentType header. +When no contentType header was already present, it injects either the per-binding contentType header or the default contentType header. +The combination of contentType argument type is the mechanism by which framework determines if message can be converted to a target type. +If no appropriate MessageConverter is found, an exception is thrown, which you can handle by adding a custom MessageConverter (see Section 9.3, “User-defined Message Converters”).

But what if the payload type matches the target type declared by the handler method? In this case, there is nothing to convert, and the +payload is passed unmodified. While this sounds pretty straightforward and logical, keep in mind handler methods that take a Message<?> or Object as an argument. +By declaring the target type to be Object (which is an instanceof everything in Java), you essentially forfeit the conversion process.

[Note]Note

Do not expect Message to be converted into some other type based only on the contentType. +Remember that the contentType is complementary to the target type. +If you wish, you can provide a hint, which MessageConverter may or may not take into consideration.

9.1.2 Message Converters

MessageConverters define two methods:

Object fromMessage(Message<?> message, Class<?> targetClass);
+
+Message<?> toMessage(Object payload, @Nullable MessageHeaders headers);

It is important to understand the contract of these methods and their usage, specifically in the context of Spring Cloud Stream.

The fromMessage method converts an incoming Message to an argument type. +The payload of the Message could be any type, and it is +up to the actual implementation of the MessageConverter to support multiple types. +For example, some JSON converter may support the payload type as byte[], String, and others. +This is important when the application contains an internal pipeline (that is, input → handler1 → handler2 →. . . → output) and the output of the upstream handler results in a Message which may not be in the initial wire format.

However, the toMessage method has a more strict contract and must always convert Message to the wire format: byte[].

So, for all intents and purposes (and especially when implementing your own converter) you regard the two methods as having the following signatures:

Object fromMessage(Message<?> message, Class<?> targetClass);
+
+Message<byte[]> toMessage(Object payload, @Nullable MessageHeaders headers);

9.2 Provided MessageConverters

As mentioned earlier, the framework already provides a stack of MessageConverters to handle most common use cases. +The following list describes the provided MessageConverters, in order of precedence (the first MessageConverter that works is used):

  1. ApplicationJsonMessageMarshallingConverter: Variation of the org.springframework.messaging.converter.MappingJackson2MessageConverter. Supports conversion of the payload of the Message to/from POJO for cases when contentType is application/json (DEFAULT).
  2. TupleJsonMessageConverter: DEPRECATED Supports conversion of the payload of the Message to/from org.springframework.tuple.Tuple.
  3. ByteArrayMessageConverter: Supports conversion of the payload of the Message from byte[] to byte[] for cases when contentType is application/octet-stream. It is essentially a pass through and exists primarily for backward compatibility.
  4. ObjectStringMessageConverter: Supports conversion of any type to a String when contentType is text/plain. +It invokes Object’s toString() method or, if the payload is byte[], a new String(byte[]).
  5. JavaSerializationMessageConverter: DEPRECATED Supports conversion based on java serialization when contentType is application/x-java-serialized-object.
  6. KryoMessageConverter: DEPRECATED Supports conversion based on Kryo serialization when contentType is application/x-java-object.
  7. JsonUnmarshallingConverter: Similar to the ApplicationJsonMessageMarshallingConverter. It supports conversion of any type when contentType is application/x-java-object. +It expects the actual type information to be embedded in the contentType as an attribute (for example, application/x-java-object;type=foo.bar.Cat).

When no appropriate converter is found, the framework throws an exception. When that happens, you should check your code and configuration and ensure you did not miss anything (that is, ensure that you provided a contentType by using a binding or a header). +However, most likely, you found some uncommon case (such as a custom contentType perhaps) and the current stack of provided MessageConverters +does not know how to convert. If that is the case, you can add custom MessageConverter. See Section 9.3, “User-defined Message Converters”.

9.3 User-defined Message Converters

Spring Cloud Stream exposes a mechanism to define and register additional MessageConverters. +To use it, implement org.springframework.messaging.converter.MessageConverter, configure it as a @Bean, and annotate it with @StreamMessageConverter. +It is then apended to the existing stack of `MessageConverter`s.

[Note]Note

It is important to understand that custom MessageConverter implementations are added to the head of the existing stack. +Consequently, custom MessageConverter implementations take precedence over the existing ones, which lets you override as well as add to the existing converters.

The following example shows how to create a message converter bean to support a new content type called application/bar:

@EnableBinding(Sink.class)
+@SpringBootApplication
+public static class SinkApplication {
+
+    ...
+
+    @Bean
+    @StreamMessageConverter
+    public MessageConverter customMessageConverter() {
+        return new MyCustomMessageConverter();
+    }
+}
+
+public class MyCustomMessageConverter extends AbstractMessageConverter {
+
+    public MyCustomMessageConverter() {
+        super(new MimeType("application", "bar"));
+    }
+
+    @Override
+    protected boolean supports(Class<?> clazz) {
+        return (Bar.class.equals(clazz));
+    }
+
+    @Override
+    protected Object convertFromInternal(Message<?> message, Class<?> targetClass, Object conversionHint) {
+        Object payload = message.getPayload();
+        return (payload instanceof Bar ? payload : new Bar((byte[]) payload));
+    }
+}

Spring Cloud Stream also provides support for Avro-based converters and schema evolution. +See Chapter 10, Schema Evolution Support for details.

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi_schema-evolution.html b/spring-cloud-stream/2.1.0.RC3/multi/multi_schema-evolution.html new file mode 100644 index 00000000..2daafb4e --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi_schema-evolution.html @@ -0,0 +1,88 @@ + + + 10. Schema Evolution Support

10. Schema Evolution Support

Spring Cloud Stream provides support for schema evolution so that the data can be evolved over time and still work with older or newer producers and consumers and vice versa. +Most serialization models, especially the ones that aim for portability across different platforms and languages, rely on a schema that describes how the data is serialized in the binary payload. +In order to serialize the data and then to interpret it, both the sending and receiving sides must have access to a schema that describes the binary format. +In certain cases, the schema can be inferred from the payload type on serialization or from the target type on deserialization. +However, many applications benefit from having access to an explicit schema that describes the binary data format. +A schema registry lets you store schema information in a textual format (typically JSON) and makes that information accessible to various applications that need it to receive and send data in binary format. +A schema is referenceable as a tuple consisting of:

  • A subject that is the logical name of the schema
  • The schema version
  • The schema format, which describes the binary format of the data

This following sections goes through the details of various components involved in schema evolution process.

10.1 Schema Registry Client

The client-side abstraction for interacting with schema registry servers is the SchemaRegistryClient interface, which has the following structure:

public interface SchemaRegistryClient {
+
+    SchemaRegistrationResponse register(String subject, String format, String schema);
+
+    String fetch(SchemaReference schemaReference);
+
+    String fetch(Integer id);
+
+}

Spring Cloud Stream provides out-of-the-box implementations for interacting with its own schema server and for interacting with the Confluent Schema Registry.

A client for the Spring Cloud Stream schema registry can be configured by using the @EnableSchemaRegistryClient, as follows:

  @EnableBinding(Sink.class)
+  @SpringBootApplication
+  @EnableSchemaRegistryClient
+  public static class AvroSinkApplication {
+    ...
+  }
[Note]Note

The default converter is optimized to cache not only the schemas from the remote server but also the parse() and toString() methods, which are quite expensive. +Because of this, it uses a DefaultSchemaRegistryClient that does not cache responses. +If you intend to change the default behavior, you can use the client directly on your code and override it to the desired outcome. +To do so, you have to add the property spring.cloud.stream.schemaRegistryClient.cached=true to your application properties.

10.1.1 Schema Registry Client Properties

The Schema Registry Client supports the following properties:

spring.cloud.stream.schemaRegistryClient.endpoint
The location of the schema-server. +When setting this, use a full URL, including protocol (http or https) , port, and context path.
Default
http://localhost:8990/
spring.cloud.stream.schemaRegistryClient.cached
Whether the client should cache schema server responses. +Normally set to false, as the caching happens in the message converter. +Clients using the schema registry client should set this to true.
Default
false

10.2 Avro Schema Registry Client Message Converters

For applications that have a SchemaRegistryClient bean registered with the application context, Spring Cloud Stream auto configures an Apache Avro message converter for schema management. +This eases schema evolution, as applications that receive messages can get easy access to a writer schema that can be reconciled with their own reader schema.

For outbound messages, if the content type of the channel is set to application/*+avro, the MessageConverter is activated, as shown in the following example:

spring.cloud.stream.bindings.output.contentType=application/*+avro

During the outbound conversion, the message converter tries to infer the schema of each outbound messages (based on its type) and register it to a subject (based on the payload type) by using the SchemaRegistryClient. +If an identical schema is already found, then a reference to it is retrieved. +If not, the schema is registered, and a new version number is provided. +The message is sent with a contentType header by using the following scheme: application/[prefix].[subject].v[version]+avro, where prefix is configurable and subject is deduced from the payload type.

For example, a message of the type User might be sent as a binary payload with a content type of application/vnd.user.v2+avro, where user is the subject and 2 is the version number.

When receiving messages, the converter infers the schema reference from the header of the incoming message and tries to retrieve it. The schema is used as the writer schema in the deserialization process.

10.2.1 Avro Schema Registry Message Converter Properties

If you have enabled Avro based schema registry client by setting spring.cloud.stream.bindings.output.contentType=application/*+avro, you can customize the behavior of the registration by setting the following properties.

spring.cloud.stream.schema.avro.dynamicSchemaGenerationEnabled

Enable if you want the converter to use reflection to infer a Schema from a POJO.

Default: false

spring.cloud.stream.schema.avro.readerSchema
Avro compares schema versions by looking at a writer schema (origin payload) and a reader schema (your application payload). See the Avro documentation for more information. If set, this overrides any lookups at the schema server and uses the local schema as the reader schema. +Default: null
spring.cloud.stream.schema.avro.schemaLocations

Registers any .avsc files listed in this property with the Schema Server.

Default: empty

spring.cloud.stream.schema.avro.prefix

The prefix to be used on the Content-Type header.

Default: vnd

10.3 Apache Avro Message Converters

Spring Cloud Stream provides support for schema-based message converters through its spring-cloud-stream-schema module. +Currently, the only serialization format supported out of the box for schema-based message converters is Apache Avro, with more formats to be added in future versions.

The spring-cloud-stream-schema module contains two types of message converters that can be used for Apache Avro serialization:

  • Converters that use the class information of the serialized or deserialized objects or a schema with a location known at startup.
  • Converters that use a schema registry. They locate the schemas at runtime and dynamically register new schemas as domain objects evolve.

10.4 Converters with Schema Support

The AvroSchemaMessageConverter supports serializing and deserializing messages either by using a predefined schema or by using the schema information available in the class (either reflectively or contained in the SpecificRecord). +If you provide a custom converter, then the default AvroSchemaMessageConverter bean is not created. The following example shows a custom converter:

To use custom converters, you can simply add it to the application context, optionally specifying one or more MimeTypes with which to associate it. +The default MimeType is application/avro.

If the target type of the conversion is a GenericRecord, a schema must be set.

The following example shows how to configure a converter in a sink application by registering the Apache Avro MessageConverter without a predefined schema. +In this example, note that the mime type value is avro/bytes, not the default application/avro.

@EnableBinding(Sink.class)
+@SpringBootApplication
+public static class SinkApplication {
+
+  ...
+
+  @Bean
+  public MessageConverter userMessageConverter() {
+      return new AvroSchemaMessageConverter(MimeType.valueOf("avro/bytes"));
+  }
+}

Conversely, the following application registers a converter with a predefined schema (found on the classpath):

@EnableBinding(Sink.class)
+@SpringBootApplication
+public static class SinkApplication {
+
+  ...
+
+  @Bean
+  public MessageConverter userMessageConverter() {
+      AvroSchemaMessageConverter converter = new AvroSchemaMessageConverter(MimeType.valueOf("avro/bytes"));
+      converter.setSchemaLocation(new ClassPathResource("schemas/User.avro"));
+      return converter;
+  }
+}

10.5 Schema Registry Server

Spring Cloud Stream provides a schema registry server implementation. +To use it, you can add the spring-cloud-stream-schema-server artifact to your project and use the @EnableSchemaRegistryServer annotation, which adds the schema registry server REST controller to your application. +This annotation is intended to be used with Spring Boot web applications, and the listening port of the server is controlled by the server.port property. +The spring.cloud.stream.schema.server.path property can be used to control the root path of the schema server (especially when it is embedded in other applications). +The spring.cloud.stream.schema.server.allowSchemaDeletion boolean property enables the deletion of a schema. By default, this is disabled.

The schema registry server uses a relational database to store the schemas. +By default, it uses an embedded database. +You can customize the schema storage by using the Spring Boot SQL database and JDBC configuration options.

The following example shows a Spring Boot application that enables the schema registry:

@SpringBootApplication
+@EnableSchemaRegistryServer
+public class SchemaRegistryServerApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(SchemaRegistryServerApplication.class, args);
+    }
+}

10.5.1 Schema Registry Server API

The Schema Registry Server API consists of the following operations:

Registering a New Schema

To register a new schema, send a POST request to the / endpoint.

The / accepts a JSON payload with the following fields:

  • subject: The schema subject
  • format: The schema format
  • definition: The schema definition

Its response is a schema object in JSON, with the following fields:

  • id: The schema ID
  • subject: The schema subject
  • format: The schema format
  • version: The schema version
  • definition: The schema definition

Retrieving an Existing Schema by Subject, Format, and Version

To retrieve an existing schema by subject, format, and version, send GET request to the /{subject}/{format}/{version} endpoint.

Its response is a schema object in JSON, with the following fields:

  • id: The schema ID
  • subject: The schema subject
  • format: The schema format
  • version: The schema version
  • definition: The schema definition

Retrieving an Existing Schema by Subject and Format

To retrieve an existing schema by subject and format, send a GET request to the /subject/format endpoint.

Its response is a list of schemas with each schema object in JSON, with the following fields:

  • id: The schema ID
  • subject: The schema subject
  • format: The schema format
  • version: The schema version
  • definition: The schema definition

Retrieving an Existing Schema by ID

To retrieve a schema by its ID, send a GET request to the /schemas/{id} endpoint.

Its response is a schema object in JSON, with the following fields:

  • id: The schema ID
  • subject: The schema subject
  • format: The schema format
  • version: The schema version
  • definition: The schema definition

Deleting a Schema by Subject, Format, and Version

To delete a schema identified by its subject, format, and version, send a DELETE request to the /{subject}/{format}/{version} endpoint.

Deleting a Schema by ID

To delete a schema by its ID, send a DELETE request to the /schemas/{id} endpoint.

Deleting a Schema by Subject

DELETE /{subject}

Delete existing schemas by their subject.

[Note]Note

This note applies to users of Spring Cloud Stream 1.1.0.RELEASE only. +Spring Cloud Stream 1.1.0.RELEASE used the table name, schema, for storing Schema objects. Schema is a keyword in a number of database implementations. +To avoid any conflicts in the future, starting with 1.1.1.RELEASE, we have opted for the name SCHEMA_REPOSITORY for the storage table. +Any Spring Cloud Stream 1.1.0.RELEASE users who upgrade should migrate their existing schemas to the new table before upgrading.

10.5.2 Using Confluent’s Schema Registry

The default configuration creates a DefaultSchemaRegistryClient bean. +If you want to use the Confluent schema registry, you need to create a bean of type ConfluentSchemaRegistryClient, which supersedes the one configured by default by the framework. The following example shows how to create such a bean:

@Bean
+public SchemaRegistryClient schemaRegistryClient(@Value("${spring.cloud.stream.schemaRegistryClient.endpoint}") String endpoint){
+  ConfluentSchemaRegistryClient client = new ConfluentSchemaRegistryClient();
+  client.setEndpoint(endpoint);
+  return client;
+}
[Note]Note

The ConfluentSchemaRegistryClient is tested against Confluent platform version 4.0.0.

10.6 Schema Registration and Resolution

To better understand how Spring Cloud Stream registers and resolves new schemas and its use of Avro schema comparison features, we provide two separate subsections:

10.6.1 Schema Registration Process (Serialization)

The first part of the registration process is extracting a schema from the payload that is being sent over a channel. +Avro types such as SpecificRecord or GenericRecord already contain a schema, which can be retrieved immediately from the instance. +In the case of POJOs, a schema is inferred if the spring.cloud.stream.schema.avro.dynamicSchemaGenerationEnabled property is set to true (the default).

Figure 10.1. Schema Writer Resolution Process

schema resolution

Ones a schema is obtained, the converter loads its metadata (version) from the remote server. +First, it queries a local cache. If no result is found, it submits the data to the server, which replies with versioning information. +The converter always caches the results to avoid the overhead of querying the Schema Server for every new message that needs to be serialized.

Figure 10.2. Schema Registration Process

registration

With the schema version information, the converter sets the contentType header of the message to carry the version information — for example: application/vnd.user.v1+avro.

10.6.2 Schema Resolution Process (Deserialization)

When reading messages that contain version information (that is, a contentType header with a scheme like the one described under Section 10.6.1, “Schema Registration Process (Serialization)”), the converter queries the Schema server to fetch the writer schema of the message. +Once it has found the correct schema of the incoming message, it retrieves the reader schema and, by using Avro’s schema resolution support, reads it into the reader definition (setting defaults and any missing properties).

Figure 10.3. Schema Reading Resolution Process

schema reading

[Note]Note

You should understand the difference between a writer schema (the application that wrote the message) and a reader schema (the receiving application). +We suggest taking a moment to read the Avro terminology and understand the process. +Spring Cloud Stream always fetches the writer schema to determine how to read a message. +If you want to get Avro’s schema evolution support working, you need to make sure that a readerSchema was properly set for your application.

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream-overview-binders.html b/spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream-overview-binders.html new file mode 100644 index 00000000..9d3be77a --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream-overview-binders.html @@ -0,0 +1,76 @@ + + + 7. Binders

7. Binders

Spring Cloud Stream provides a Binder abstraction for use in connecting to physical destinations at the external middleware. +This section provides information about the main concepts behind the Binder SPI, its main components, and implementation-specific details.

7.1 Producers and Consumers

The following image shows the general relationship of producers and consumers:

Figure 7.1. Producers and Consumers

producers consumers

A producer is any component that sends messages to a channel. +The channel can be bound to an external message broker with a Binder implementation for that broker. +When invoking the bindProducer() method, the first parameter is the name of the destination within the broker, the second parameter is the local channel instance to which the producer sends messages, and the third parameter contains properties (such as a partition key expression) to be used within the adapter that is created for that channel.

A consumer is any component that receives messages from a channel. +As with a producer, the consumer’s channel can be bound to an external message broker. +When invoking the bindConsumer() method, the first parameter is the destination name, and a second parameter provides the name of a logical group of consumers. +Each group that is represented by consumer bindings for a given destination receives a copy of each message that a producer sends to that destination (that is, it follows normal publish-subscribe semantics). +If there are multiple consumer instances bound with the same group name, then messages are load-balanced across those consumer instances so that each message sent by a producer is consumed by only a single consumer instance within each group (that is, it follows normal queueing semantics).

7.2 Binder SPI

The Binder SPI consists of a number of interfaces, out-of-the box utility classes, and discovery strategies that provide a pluggable mechanism for connecting to external middleware.

The key point of the SPI is the Binder interface, which is a strategy for connecting inputs and outputs to external middleware. The following listing shows the definnition of the Binder interface:

public interface Binder<T, C extends ConsumerProperties, P extends ProducerProperties> {
+    Binding<T> bindConsumer(String name, String group, T inboundBindTarget, C consumerProperties);
+
+    Binding<T> bindProducer(String name, T outboundBindTarget, P producerProperties);
+}

The interface is parameterized, offering a number of extension points:

  • Input and output bind targets. As of version 1.0, only MessageChannel is supported, but this is intended to be used as an extension point in the future.
  • Extended consumer and producer properties, allowing specific Binder implementations to add supplemental properties that can be supported in a type-safe manner.

A typical binder implementation consists of the following:

  • A class that implements the Binder interface;
  • A Spring @Configuration class that creates a bean of type Binder along with the middleware connection infrastructure.
  • A META-INF/spring.binders file found on the classpath containing one or more binder definitions, as shown in the following example:

    kafka:\
    +org.springframework.cloud.stream.binder.kafka.config.KafkaBinderConfiguration

7.3 Binder Detection

Spring Cloud Stream relies on implementations of the Binder SPI to perform the task of connecting channels to message brokers. +Each Binder implementation typically connects to one type of messaging system.

7.3.1 Classpath Detection

By default, Spring Cloud Stream relies on Spring Boot’s auto-configuration to configure the binding process. +If a single Binder implementation is found on the classpath, Spring Cloud Stream automatically uses it. +For example, a Spring Cloud Stream project that aims to bind only to RabbitMQ can add the following dependency:

<dependency>
+  <groupId>org.springframework.cloud</groupId>
+  <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
+</dependency>

For the specific Maven coordinates of other binder dependencies, see the documentation of that binder implementation.

7.4 Multiple Binders on the Classpath

When multiple binders are present on the classpath, the application must indicate which binder is to be used for each channel binding. +Each binder configuration contains a META-INF/spring.binders file, which is a simple properties file, as shown in the following example:

rabbit:\
+org.springframework.cloud.stream.binder.rabbit.config.RabbitServiceAutoConfiguration

Similar files exist for the other provided binder implementations (such as Kafka), and custom binder implementations are expected to provide them as well. +The key represents an identifying name for the binder implementation, whereas the value is a comma-separated list of configuration classes that each contain one and only one bean definition of type org.springframework.cloud.stream.binder.Binder.

Binder selection can either be performed globally, using the spring.cloud.stream.defaultBinder property (for example, spring.cloud.stream.defaultBinder=rabbit) or individually, by configuring the binder on each channel binding. +For instance, a processor application (that has channels named input and output for read and write respectively) that reads from Kafka and writes to RabbitMQ can specify the following configuration:

spring.cloud.stream.bindings.input.binder=kafka
+spring.cloud.stream.bindings.output.binder=rabbit

7.5 Connecting to Multiple Systems

By default, binders share the application’s Spring Boot auto-configuration, so that one instance of each binder found on the classpath is created. +If your application should connect to more than one broker of the same type, you can specify multiple binder configurations, each with different environment settings.

[Note]Note

Turning on explicit binder configuration disables the default binder configuration process altogether. +If you do so, all binders in use must be included in the configuration. +Frameworks that intend to use Spring Cloud Stream transparently may create binder configurations that can be referenced by name, but they do not affect the default binder configuration. +In order to do so, a binder configuration may have its defaultCandidate flag set to false (for example, spring.cloud.stream.binders.<configurationName>.defaultCandidate=false). +This denotes a configuration that exists independently of the default binder configuration process.

The following example shows a typical configuration for a processor application that connects to two RabbitMQ broker instances:

spring:
+  cloud:
+    stream:
+      bindings:
+        input:
+          destination: thing1
+          binder: rabbit1
+        output:
+          destination: thing2
+          binder: rabbit2
+      binders:
+        rabbit1:
+          type: rabbit
+          environment:
+            spring:
+              rabbitmq:
+                host: <host1>
+        rabbit2:
+          type: rabbit
+          environment:
+            spring:
+              rabbitmq:
+                host: <host2>

7.6 Binding visualization and control

Since version 2.0, Spring Cloud Stream supports visualization and control of the Bindings through Actuator endpoints.

Starting with version 2.0 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:

<dependency>
+     <groupId>org.springframework.boot</groupId>
+     <artifactId>spring-boot-starter-web</artifactId>
+</dependency>

The following example shows how to add the dependency for the WebFlux framework:

<dependency>
+       <groupId>org.springframework.boot</groupId>
+       <artifactId>spring-boot-starter-webflux</artifactId>
+</dependency>

You can add the Actuator dependency as follows:

<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-actuator</artifactId>
+</dependency>
[Note]Note

To run Spring Cloud Stream 2.0 apps in Cloud Foundry, you must add spring-boot-starter-web and spring-boot-starter-actuator to the classpath. Otherwise, the +application will not start due to health check failures.

You must also enable the bindings actuator endpoints by setting the following property: --management.endpoints.web.exposure.include=bindings.

Once those prerequisites are satisfied. you should see the following in the logs when application start:

: Mapped "{[/actuator/bindings/{name}],methods=[POST]. . .
+: Mapped "{[/actuator/bindings],methods=[GET]. . .
+: Mapped "{[/actuator/bindings/{name}],methods=[GET]. . .

To visualize the current bindings, access the following URL: +http://<host>:<port>/actuator/bindings

Alternative, to see a single binding, access one of the URLs similar to the following: +http://<host>:<port>/actuator/bindings/myBindingName

You can also stop, start, pause, and resume individual bindings by posting to the same URL while providing a state argument as JSON, as shown in the following examples:

curl -d '{"state":"STOPPED"}' -H "Content-Type: application/json" -X POST http://<host>:<port>/actuator/bindings/myBindingName +curl -d '{"state":"STARTED"}' -H "Content-Type: application/json" -X POST http://<host>:<port>/actuator/bindings/myBindingName +curl -d '{"state":"PAUSED"}' -H "Content-Type: application/json" -X POST http://<host>:<port>/actuator/bindings/myBindingName +curl -d '{"state":"RESUMED"}' -H "Content-Type: application/json" -X POST http://<host>:<port>/actuator/bindings/myBindingName

[Note]Note

PAUSED and RESUMED work only when the corresponding binder and its underlying technology supports it. Otherwise, you see the warning message in the logs. +Currently, only Kafka binder supports the PAUSED and RESUMED states.

7.7 Binder Configuration Properties

The following properties are available when customizing binder configurations. These properties exposed via org.springframework.cloud.stream.config.BinderProperties

They must be prefixed with spring.cloud.stream.binders.<configurationName>.

type

The binder type. +It typically references one of the binders found on the classpath — in particular, a key in a META-INF/spring.binders file.

By default, it has the same value as the configuration name.

inheritEnvironment

Whether the configuration inherits the environment of the application itself.

Default: true.

environment

Root for a set of properties that can be used to customize the environment of the binder. +When this property is set, the context in which the binder is being created is not a child of the application context. +This setting allows for complete separation between the binder components and the application components.

Default: empty.

defaultCandidate

Whether the binder configuration is a candidate for being considered a default binder or can be used only when explicitly referenced. +This setting allows adding binder configurations without interfering with the default processing.

Default: true.

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream-overview-introducing.html b/spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream-overview-introducing.html new file mode 100644 index 00000000..39651eea --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream-overview-introducing.html @@ -0,0 +1,42 @@ + + + 4. Introducing Spring Cloud Stream

4. Introducing Spring Cloud Stream

Spring Cloud Stream is a framework for building message-driven microservice applications. +Spring Cloud Stream builds upon Spring Boot to create standalone, production-grade Spring applications and uses Spring Integration to provide connectivity to message brokers. +It provides opinionated configuration of middleware from several vendors, introducing the concepts of persistent publish-subscribe semantics, consumer groups, and partitions.

You can add the @EnableBinding annotation to your application to get immediate connectivity to a message broker, and you can add @StreamListener to a method to cause it to receive events for stream processing. +The following example shows a sink application that receives external messages:

@SpringBootApplication
+@EnableBinding(Sink.class)
+public class VoteRecordingSinkApplication {
+
+  public static void main(String[] args) {
+    SpringApplication.run(VoteRecordingSinkApplication.class, args);
+  }
+
+  @StreamListener(Sink.INPUT)
+  public void processVote(Vote vote) {
+      votingService.recordVote(vote);
+  }
+}

The @EnableBinding annotation takes one or more interfaces as parameters (in this case, the parameter is a single Sink interface). +An interface declares input and output channels. +Spring Cloud Stream provides the Source, Sink, and Processor interfaces. You can also define your own interfaces.

The following listing shows the definition of the Sink interface:

public interface Sink {
+  String INPUT = "input";
+
+  @Input(Sink.INPUT)
+  SubscribableChannel input();
+}

The @Input annotation identifies an input channel, through which received messages enter the application. +The @Output annotation identifies an output channel, through which published messages leave the application. +The @Input and @Output annotations can take a channel name as a parameter. +If a name is not provided, the name of the annotated method is used.

Spring Cloud Stream creates an implementation of the interface for you. +You can use this in the application by autowiring it, as shown in the following example (from a test case):

@RunWith(SpringJUnit4ClassRunner.class)
+@SpringApplicationConfiguration(classes = VoteRecordingSinkApplication.class)
+@WebAppConfiguration
+@DirtiesContext
+public class StreamApplicationTests {
+
+  @Autowired
+  private Sink sink;
+
+  @Test
+  public void contextLoads() {
+    assertNotNull(this.sink.input());
+  }
+}
\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream-overview-metrics-emitter.html b/spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream-overview-metrics-emitter.html new file mode 100644 index 00000000..d8741ec4 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream-overview-metrics-emitter.html @@ -0,0 +1,50 @@ + + + 14. Metrics Emitter

14. Metrics Emitter

Spring Boot Actuator provides dependency management and auto-configuration for Micrometer, an application metrics +facade that supports numerous monitoring systems.

Spring Cloud Stream provides support for emitting any available micrometer-based metrics to a binding destination, allowing for periodic +collection of metric data from stream applications without relying on polling individual endpoints.

Metrics Emitter is activated by defining the spring.cloud.stream.bindings.applicationMetrics.destination property, +which specifies the name of the binding destination used by the current binder to publish metric messages.

For example:

spring.cloud.stream.bindings.applicationMetrics.destination=myMetricDestination

The preceding example instructs the binder to bind to myMetricDestination (that is, Rabbit exchange, Kafka topic, and others).

The following properties can be used for customizing the emission of metrics:

spring.cloud.stream.metrics.key

The name of the metric being emitted. Should be a unique value per application.

Default: ${spring.application.name:${vcap.application.name:${spring.config.name:application}}}

spring.cloud.stream.metrics.properties

Allows white listing application properties that are added to the metrics payload

Default: null.

spring.cloud.stream.metrics.meter-filter

Pattern to control the 'meters' one wants to capture. +For example, specifying spring.integration.* captures metric information for meters whose name starts with spring.integration.

Default: all 'meters' are captured.

spring.cloud.stream.metrics.schedule-interval

Interval to control the rate of publishing metric data.

Default: 1 min

Consider the following:

java -jar time-source.jar \
+    --spring.cloud.stream.bindings.applicationMetrics.destination=someMetrics \
+    --spring.cloud.stream.metrics.properties=spring.application** \
+    --spring.cloud.stream.metrics.meter-filter=spring.integration.*

The following example shows the payload of the data published to the binding destination as a result of the preceding command:

{
+	"name": "application",
+	"createdTime": "2018-03-23T14:48:12.700Z",
+	"properties": {
+	},
+	"metrics": [
+		{
+			"id": {
+				"name": "spring.integration.send",
+				"tags": [
+					{
+						"key": "exception",
+						"value": "none"
+					},
+					{
+						"key": "name",
+						"value": "input"
+					},
+					{
+						"key": "result",
+						"value": "success"
+					},
+					{
+						"key": "type",
+						"value": "channel"
+					}
+				],
+				"type": "TIMER",
+				"description": "Send processing time",
+				"baseUnit": "milliseconds"
+			},
+			"timestamp": "2018-03-23T14:48:12.697Z",
+			"sum": 130.340546,
+			"count": 6,
+			"mean": 21.72342433333333,
+			"upper": 116.176299,
+			"total": 130.340546
+		}
+	]
+}
[Note]Note

Given that the format of the Metric message has slightly changed after migrating to Micrometer, the published message will also have +a STREAM_CLOUD_STREAM_VERSION header set to 2.x to help distinguish between Metric messages from the older versions of the Spring Cloud Stream.

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream.html b/spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream.html new file mode 100644 index 00000000..39803068 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/multi/multi_spring-cloud-stream.html @@ -0,0 +1,3 @@ + + + Spring Cloud Stream Reference Guide

Spring Cloud Stream Reference Guide

Authors

Sabby Anandan, Marius Bogoevici, Eric Bottard, Mark Fisher, Ilayaperumal Gopinathan, Gunnar Hillert, Mark Pollack, Patrick Peralta, Glenn Renfro, Thomas Risberg, Dave Syer, David Turanski, Janne Valkealahti, Benjamin Klein, Vinicius Carvalho, Gary Russell, Oleg Zhurakousky, Jay Bryant

Table of Contents

I. Preface
1. A Brief History of Spring’s Data Integration Journey
2. Quick Start
2.1. Creating a Sample Application by Using Spring Initializr
2.2. Importing the Project into Your IDE
2.3. Adding a Message Handler, Building, and Running
3. What’s New in 2.0?
3.1. New Features and Components
3.2. Notable Enhancements
3.2.1. Both Actuator and Web Dependencies Are Now Optional
3.2.2. Content-type Negotiation Improvements
3.3. Notable Deprecations
3.3.1. Java Serialization (Java Native and Kryo)
3.3.2. Deprecated Classes and Methods
4. Introducing Spring Cloud Stream
5. Main Concepts
5.1. Application Model
5.1.1. Fat JAR
5.2. The Binder Abstraction
5.3. Persistent Publish-Subscribe Support
5.4. Consumer Groups
5.5. Consumer Types
5.5.1. Durability
5.6. Partitioning Support
6. Programming Model
6.1. Destination Binders
6.2. Destination Bindings
6.3. Producing and Consuming Messages
6.3.1. Spring Integration Support
6.3.2. Using @StreamListener Annotation
6.3.3. Using @StreamListener for Content-based routing
6.3.4. Spring Cloud Function support
Functional Composition
6.3.5. Using Polled Consumers
Overview
Handling Errors
6.4. Error Handling
6.4.1. Application Error Handling
6.4.2. System Error Handling
Drop Failed Messages
DLQ - Dead Letter Queue
Re-queue Failed Messages
6.4.3. Retry Template
6.5. Reactive Programming Support
6.5.1. Reactor-based Handlers
6.5.2. Reactive Sources
7. Binders
7.1. Producers and Consumers
7.2. Binder SPI
7.3. Binder Detection
7.3.1. Classpath Detection
7.4. Multiple Binders on the Classpath
7.5. Connecting to Multiple Systems
7.6. Binding visualization and control
7.7. Binder Configuration Properties
8. Configuration Options
8.1. Binding Service Properties
8.2. Binding Properties
8.2.1. Common Binding Properties
8.2.2. Consumer Properties
8.2.3. Producer Properties
8.3. Using Dynamically Bound Destinations
9. Content Type Negotiation
9.1. Mechanics
9.1.1. Content Type versus Argument Type
9.1.2. Message Converters
9.2. Provided MessageConverters
9.3. User-defined Message Converters
10. Schema Evolution Support
10.1. Schema Registry Client
10.1.1. Schema Registry Client Properties
10.2. Avro Schema Registry Client Message Converters
10.2.1. Avro Schema Registry Message Converter Properties
10.3. Apache Avro Message Converters
10.4. Converters with Schema Support
10.5. Schema Registry Server
10.5.1. Schema Registry Server API
Registering a New Schema
Retrieving an Existing Schema by Subject, Format, and Version
Retrieving an Existing Schema by Subject and Format
Retrieving an Existing Schema by ID
Deleting a Schema by Subject, Format, and Version
Deleting a Schema by ID
Deleting a Schema by Subject
10.5.2. Using Confluent’s Schema Registry
10.6. Schema Registration and Resolution
10.6.1. Schema Registration Process (Serialization)
10.6.2. Schema Resolution Process (Deserialization)
11. Inter-Application Communication
11.1. Connecting Multiple Application Instances
11.2. Instance Index and Instance Count
11.3. Partitioning
11.3.1. Configuring Output Bindings for Partitioning
11.3.2. Configuring Input Bindings for Partitioning
12. Testing
12.1. Disabling the Test Binder Autoconfiguration
13. Health Indicator
14. Metrics Emitter
15. Samples
15.1. Deploying Stream Applications on CloudFoundry
16. Binder Implementations
\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/single/css/highlight.css b/spring-cloud-stream/2.1.0.RC3/single/css/highlight.css new file mode 100644 index 00000000..ffefef72 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/single/css/highlight.css @@ -0,0 +1,35 @@ +/* + code highlight CSS resemblign the Eclipse IDE default color schema + @author Costin Leau +*/ + +.hl-keyword { + color: #7F0055; + font-weight: bold; +} + +.hl-comment { + color: #3F5F5F; + font-style: italic; +} + +.hl-multiline-comment { + color: #3F5FBF; + font-style: italic; +} + +.hl-tag { + color: #3F7F7F; +} + +.hl-attribute { + color: #7F007F; +} + +.hl-value { + color: #2A00FF; +} + +.hl-string { + color: #2A00FF; +} \ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/single/css/manual-multipage.css b/spring-cloud-stream/2.1.0.RC3/single/css/manual-multipage.css new file mode 100644 index 00000000..0c484531 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/single/css/manual-multipage.css @@ -0,0 +1,9 @@ +@IMPORT url("manual.css"); + +body.firstpage { + background: url("../images/background.png") no-repeat center top; +} + +div.part h1 { + border-top: none; +} diff --git a/spring-cloud-stream/2.1.0.RC3/single/css/manual-singlepage.css b/spring-cloud-stream/2.1.0.RC3/single/css/manual-singlepage.css new file mode 100644 index 00000000..4a7fd140 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/single/css/manual-singlepage.css @@ -0,0 +1,6 @@ +@IMPORT url("manual.css"); + +body { + background: url("../images/background.png") no-repeat center top; +} + diff --git a/spring-cloud-stream/2.1.0.RC3/single/css/manual.css b/spring-cloud-stream/2.1.0.RC3/single/css/manual.css new file mode 100644 index 00000000..0ecbe2e8 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/single/css/manual.css @@ -0,0 +1,344 @@ +@IMPORT url("highlight.css"); + +html { + padding: 0pt; + margin: 0pt; +} + +body { + color: #333333; + margin: 15px 30px; + font-family: Helvetica, Arial, Freesans, Clean, Sans-serif; + line-height: 1.6; + -webkit-font-smoothing: antialiased; +} + +code { + font-size: 16px; + font-family: Consolas, "Liberation Mono", Courier, monospace; +} + +:not(a)>code { + color: #6D180B; +} + +:not(pre)>code { + background-color: #F2F2F2; + border: 1px solid #CCCCCC; + border-radius: 4px; + padding: 1px 3px 0; + text-shadow: none; + white-space: nowrap; +} + +body>*:first-child { + margin-top: 0 !important; +} + +div { + margin: 0pt; +} + +hr { + border: 1px solid #CCCCCC; + background: #CCCCCC; +} + +h1,h2,h3,h4,h5,h6 { + color: #000000; + cursor: text; + font-weight: bold; + margin: 30px 0 10px; + padding: 0; +} + +h1,h2,h3 { + margin: 40px 0 10px; +} + +h1 { + margin: 70px 0 30px; + padding-top: 20px; +} + +div.part h1 { + border-top: 1px dotted #CCCCCC; +} + +h1,h1 code { + font-size: 32px; +} + +h2,h2 code { + font-size: 24px; +} + +h3,h3 code { + font-size: 20px; +} + +h4,h1 code,h5,h5 code,h6,h6 code { + font-size: 18px; +} + +div.book,div.chapter,div.appendix,div.part,div.preface { + min-width: 300px; + max-width: 1200px; + margin: 0 auto; +} + +p.releaseinfo { + font-weight: bold; + margin-bottom: 40px; + margin-top: 40px; +} + +div.authorgroup { + line-height: 1; +} + +p.copyright { + line-height: 1; + margin-bottom: -5px; +} + +.legalnotice p { + font-style: italic; + font-size: 14px; + line-height: 1; +} + +div.titlepage+p,div.titlepage+p { + margin-top: 0; +} + +pre { + line-height: 1.0; + color: black; +} + +a { + color: #4183C4; + text-decoration: none; +} + +p { + margin: 15px 0; + text-align: left; +} + +ul,ol { + padding-left: 30px; +} + +li p { + margin: 0; +} + +div.table { + margin: 1em; + padding: 0.5em; + text-align: center; +} + +div.table table,div.informaltable table { + display: table; + width: 100%; +} + +div.table td { + padding-left: 7px; + padding-right: 7px; +} + +.sidebar { + line-height: 1.4; + padding: 0 20px; + background-color: #F8F8F8; + border: 1px solid #CCCCCC; + border-radius: 3px 3px 3px 3px; +} + +.sidebar p.title { + color: #6D180B; +} + +pre.programlisting,pre.screen { + font-size: 15px; + padding: 6px 10px; + background-color: #F8F8F8; + border: 1px solid #CCCCCC; + border-radius: 3px 3px 3px 3px; + clear: both; + overflow: auto; + line-height: 1.4; + font-family: Consolas, "Liberation Mono", Courier, monospace; +} + +table { + border-collapse: collapse; + border-spacing: 0; + border: 1px solid #DDDDDD !important; + border-radius: 4px !important; + border-collapse: separate !important; + line-height: 1.6; +} + +table thead { + background: #F5F5F5; +} + +table tr { + border: none; + border-bottom: none; +} + +table th { + font-weight: bold; +} + +table th,table td { + border: none !important; + padding: 6px 13px; +} + +table tr:nth-child(2n) { + background-color: #F8F8F8; +} + +td p { + margin: 0 0 15px 0; +} + +div.table-contents td p { + margin: 0; +} + +div.important *,div.note *,div.tip *,div.warning *,div.navheader *,div.navfooter *,div.calloutlist * + { + border: none !important; + background: none !important; + margin: 0; +} + +div.important p,div.note p,div.tip p,div.warning p { + color: #6F6F6F; + line-height: 1.6; +} + +div.important code,div.note code,div.tip code,div.warning code { + background-color: #F2F2F2 !important; + border: 1px solid #CCCCCC !important; + border-radius: 4px !important; + padding: 1px 3px 0 !important; + text-shadow: none !important; + white-space: nowrap !important; +} + +.note th,.tip th,.warning th { + display: none; +} + +.note tr:first-child td,.tip tr:first-child td,.warning tr:first-child td + { + border-right: 1px solid #CCCCCC !important; + padding-top: 10px; +} + +div.calloutlist p,div.calloutlist td { + padding: 0; + margin: 0; +} + +div.calloutlist>table>tbody>tr>td:first-child { + padding-left: 10px; + width: 30px !important; +} + +div.important,div.note,div.tip,div.warning { + margin-left: 0px !important; + margin-right: 20px !important; + margin-top: 20px; + margin-bottom: 20px; + padding-top: 10px; + padding-bottom: 10px; +} + +div.toc { + line-height: 1.2; +} + +dl,dt { + margin-top: 1px; + margin-bottom: 0; +} + +div.toc>dl>dt { + font-size: 32px; + font-weight: bold; + margin: 30px 0 10px 0; + display: block; +} + +div.toc>dl>dd>dl>dt { + font-size: 24px; + font-weight: bold; + margin: 20px 0 10px 0; + display: block; +} + +div.toc>dl>dd>dl>dd>dl>dt { + font-weight: bold; + font-size: 20px; + margin: 10px 0 0 0; +} + +tbody.footnotes * { + border: none !important; +} + +div.footnote p { + margin: 0; + line-height: 1; +} + +div.footnote p sup { + margin-right: 6px; + vertical-align: middle; +} + +div.navheader { + border-bottom: 1px solid #CCCCCC; +} + +div.navfooter { + border-top: 1px solid #CCCCCC; +} + +.title { + margin-left: -1em; + padding-left: 1em; +} + +.title>a { + position: absolute; + visibility: hidden; + display: block; + font-size: 0.85em; + margin-top: 0.05em; + margin-left: -1em; + vertical-align: text-top; + color: black; +} + +.title>a:before { + content: "\00A7"; +} + +.title:hover>a,.title>a:hover,.title:hover>a:hover { + visibility: visible; +} + +.title:focus>a,.title>a:focus,.title:focus>a:focus { + outline: 0; +} diff --git a/spring-cloud-stream/2.1.0.RC3/single/images/background.png b/spring-cloud-stream/2.1.0.RC3/single/images/background.png new file mode 100644 index 0000000000000000000000000000000000000000..15dca6fbe2669fae3609605e49c69cc414f1b6ed GIT binary patch literal 18255 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 EKU&lfD*ylh literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/single/images/callouts/1.png b/spring-cloud-stream/2.1.0.RC3/single/images/callouts/1.png new file mode 100644 index 0000000000000000000000000000000000000000..7d473430b7bec514f7de12f5769fe7c5859e8c5d GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^JRr;gBp8b2n5}^nQC}X^4DKU-G|w_t}fLBA)Suv#nrW z!^h2QnY_`l!BOq-UXEX{m2up>JTQkX)2m zTvF+fTUlI^nXH#utd~++ke^qgmzgTe~DWM4ffP81J literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/single/images/callouts/2.png b/spring-cloud-stream/2.1.0.RC3/single/images/callouts/2.png new file mode 100644 index 0000000000000000000000000000000000000000..5d09341b2f6d2ea2d1d5dad5d980f14b4b05dfd2 GIT binary patch literal 353 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 literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/single/images/logo.png b/spring-cloud-stream/2.1.0.RC3/single/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ade2ce6ed9d9e9f2f4d9c5729a252ee618a0a5a7 GIT binary patch literal 4387 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 FV1jwin)(0$ literal 0 HcmV?d00001 diff --git a/spring-cloud-stream/2.1.0.RC3/single/images/warning.png b/spring-cloud-stream/2.1.0.RC3/single/images/warning.png new file mode 100644 index 0000000000000000000000000000000000000000..0d5b5244605adbb7ab05a1549746a9c35490f95b GIT binary patch literal 2130 zcmbVNYg7|w8V(4q($)50y>JmGlLW#g$xLn}Vd2Si)}#|ptPAQp3Bp-3!-lL0;i^LY?;i#f0m5s49g z3h?3rDQg~EDPlm?FKkgKIcWEK-3X6YU0uzs7H|nq84s39r2!5;pF?SI$QqXy^Ko1x zV~zpENvp@<_Bsd`5MabC#3rvCq&$5dg43yGR zAdy0-rWjC#a1N_+kzUMY#pmogD7!DP(9dEKr3c5ngvUq_6>}Y+w-a81v=eSXnIi_+ zI?U>D1q2C!0zHox#XXKH+@|&rPT*OF5yvY$5J|)WwLqnU)c-5;=UChSlQkaY3@^|g z|J5#YBB}=i+n3Ex9bS$P?xJSKLk)-HHII@;3qG#TG^!+aj>0QkO~7kB0+|yM;YrGB zF>Ge@isQ#73%Tp#k_(tInh3U$uJWY-+DND*o}L-CB5g@#9YWWw~pxZ!Obm>yN#ZHFvL0zA3vNCTJ=t?)~`2O1M{L6un=ml<2x zQEYfifmA?Pz0tqRs^2Utt1pU0BQB1eIY0U_I}c1Y#PP7Ci5s7#IJn}xK{G+{_v^Z+1V#$Erodv>d}ew>RP0wzw+GWkGCBlS1Oj5Z!5NK zUuSR6>pa}RSEZ;qE_w1l#`hQX4E67U6NeP zHZ`T&wj0_H)t|Y1thUqnhub?%e)Y07;a^Tq%FO&iQkR&`qG!dh*2WfW(HuRQj*_DI zeCD1bUA|tMwjOb8E|FRIn$pzEU!2j_N}1Z2ig)vbr5xA0rjC70cmI6*%Uf->hWzaZ z{33HABO5q)vRhzDly2l691@+q3O{}NbSzx+I*k@|L4&3leK#$>u+T#TvTELfKb|IH zc23atf3vmfCa0&TWY@iuoA_Pm<0~ttEC*ut`isb^jXS>X^Sp=l?RXN_OJ*&usGXg$ zTlTv;Ch^vhLDf&+62jl64*&D+=+`sN_dap_1W%p|KQVYIdgPL5uRE9(c4On)DXndL zLNq?%!-u*zmMxyYc4m4Nr>>=A=s}PkJkqr&E^b9>5g+}c1%X}3|WKcg&spcJQ)05zI<<5LTBhNKRg$XRTi2{j)yl_ zj4~kKOvr+m(;vw~9zVh(zC-y9jqQnguz5r7FRq^MyKuXAENp(TAzUVtg&Ts+B_s7) zGn+fN0sG>9GjsPLKTRrvCd`71IZulJ1_1jO9KWbD&_@2UC+LTNpxxrdz#E|j|2nA9 zzB!UTyfAEJ&#%$pQ>QX#8vk@_a5iqukMF;8`wRKe{BI}5$H%OROs4J1#j)|?p|YSh z_SpR^e`VE#F52;WL{!+L(yZLRh40*KS;@box;9(-tE)`mcVp27O*>Z{_Lb*5T3cJA yr~0nPHtg2+UHi&&$8ha;`+hiaUmw&!n@8(?5PqF(KE5>Ym)EG)p&uyBP5%a8^# + + Spring Cloud Stream Reference Guide

Spring Cloud Stream Reference Guide

Authors

Sabby Anandan, Marius Bogoevici, Eric Bottard, Mark Fisher, Ilayaperumal Gopinathan, Gunnar Hillert, Mark Pollack, Patrick Peralta, Glenn Renfro, Thomas Risberg, Dave Syer, David Turanski, Janne Valkealahti, Benjamin Klein, Vinicius Carvalho, Gary Russell, Oleg Zhurakousky, Jay Bryant

Table of Contents

I. Preface
1. A Brief History of Spring’s Data Integration Journey
2. Quick Start
2.1. Creating a Sample Application by Using Spring Initializr
2.2. Importing the Project into Your IDE
2.3. Adding a Message Handler, Building, and Running
3. What’s New in 2.0?
3.1. New Features and Components
3.2. Notable Enhancements
3.2.1. Both Actuator and Web Dependencies Are Now Optional
3.2.2. Content-type Negotiation Improvements
3.3. Notable Deprecations
3.3.1. Java Serialization (Java Native and Kryo)
3.3.2. Deprecated Classes and Methods
4. Introducing Spring Cloud Stream
5. Main Concepts
5.1. Application Model
5.1.1. Fat JAR
5.2. The Binder Abstraction
5.3. Persistent Publish-Subscribe Support
5.4. Consumer Groups
5.5. Consumer Types
5.5.1. Durability
5.6. Partitioning Support
6. Programming Model
6.1. Destination Binders
6.2. Destination Bindings
6.3. Producing and Consuming Messages
6.3.1. Spring Integration Support
6.3.2. Using @StreamListener Annotation
6.3.3. Using @StreamListener for Content-based routing
6.3.4. Spring Cloud Function support
Functional Composition
6.3.5. Using Polled Consumers
Overview
Handling Errors
6.4. Error Handling
6.4.1. Application Error Handling
6.4.2. System Error Handling
Drop Failed Messages
DLQ - Dead Letter Queue
Re-queue Failed Messages
6.4.3. Retry Template
6.5. Reactive Programming Support
6.5.1. Reactor-based Handlers
6.5.2. Reactive Sources
7. Binders
7.1. Producers and Consumers
7.2. Binder SPI
7.3. Binder Detection
7.3.1. Classpath Detection
7.4. Multiple Binders on the Classpath
7.5. Connecting to Multiple Systems
7.6. Binding visualization and control
7.7. Binder Configuration Properties
8. Configuration Options
8.1. Binding Service Properties
8.2. Binding Properties
8.2.1. Common Binding Properties
8.2.2. Consumer Properties
8.2.3. Producer Properties
8.3. Using Dynamically Bound Destinations
9. Content Type Negotiation
9.1. Mechanics
9.1.1. Content Type versus Argument Type
9.1.2. Message Converters
9.2. Provided MessageConverters
9.3. User-defined Message Converters
10. Schema Evolution Support
10.1. Schema Registry Client
10.1.1. Schema Registry Client Properties
10.2. Avro Schema Registry Client Message Converters
10.2.1. Avro Schema Registry Message Converter Properties
10.3. Apache Avro Message Converters
10.4. Converters with Schema Support
10.5. Schema Registry Server
10.5.1. Schema Registry Server API
Registering a New Schema
Retrieving an Existing Schema by Subject, Format, and Version
Retrieving an Existing Schema by Subject and Format
Retrieving an Existing Schema by ID
Deleting a Schema by Subject, Format, and Version
Deleting a Schema by ID
Deleting a Schema by Subject
10.5.2. Using Confluent’s Schema Registry
10.6. Schema Registration and Resolution
10.6.1. Schema Registration Process (Serialization)
10.6.2. Schema Resolution Process (Deserialization)
11. Inter-Application Communication
11.1. Connecting Multiple Application Instances
11.2. Instance Index and Instance Count
11.3. Partitioning
11.3.1. Configuring Output Bindings for Partitioning
11.3.2. Configuring Input Bindings for Partitioning
12. Testing
12.1. Disabling the Test Binder Autoconfiguration
13. Health Indicator
14. Metrics Emitter
15. Samples
15.1. Deploying Stream Applications on CloudFoundry
16. Binder Implementations

Part I. Preface

1. A Brief History of Spring’s Data Integration Journey

Spring’s journey on Data Integration started with Spring Integration. With its programming model, it provided a consistent developer experience to build applications that can embrace Enterprise Integration Patterns to connect with external systems such as, databases, message brokers, and among others.

Fast forward to the cloud-era, where microservices have become prominent in the enterprise setting. Spring Boot transformed the way how developers built Applications. With Spring’s programming model and the runtime responsibilities handled by Spring Boot, it became seamless to develop stand-alone, production-grade Spring-based microservices.

To extend this to Data Integration workloads, Spring Integration and Spring Boot were put together into a new project. Spring Cloud Stream was born.

With Spring Cloud Stream, developers can: +* Build, test, iterate, and deploy data-centric applications in isolation. +* Apply modern microservices architecture patterns, including composition through messaging. +* Decouple application responsibilities with event-centric thinking. An event can represent something that has happened in time, to which the downstream consumer applications can react without knowing where it originated or the producer’s identity. +* Port the business logic onto message brokers (such as RabbitMQ, Apache Kafka, Amazon Kinesis). +* Interoperate between channel-based and non-channel-based application binding scenarios to support stateless and stateful computations by using Project Reactor’s Flux and Kafka Streams APIs. +* Rely on the framework’s automatic content-type support for common use-cases. Extending to different data conversion types is possible.

2. Quick Start

You can try Spring Cloud Stream in less then 5 min even before you jump into any details by following this three-step guide.

We show you how to create a Spring Cloud Stream application that receives messages coming from the messaging middleware of your choice (more on this later) and logs received messages to the console. +We call it LoggingConsumer. +While not very practical, it provides a good introduction to some of the main concepts +and abstractions, making it easier to digest the rest of this user guide.

The three steps are as follows:

2.1 Creating a Sample Application by Using Spring Initializr

To get started, visit the Spring Initializr. From there, you can generate our LoggingConsumer application. To do so:

  1. In the Dependencies section, start typing stream. +When the Cloud Stream option should appears, select it.
  2. Start typing either 'kafka' or 'rabbit'.
  3. Select Kafka or RabbitMQ.

    Basically, you choose the messaging middleware to which your application binds. +We recommend using the one you have already installed or feel more comfortable with installing and running. +Also, as you can see from the Initilaizer screen, there are a few other options you can choose. +For example, you can choose Gradle as your build tool instead of Maven (the default).

  4. In the Artifact field, type 'logging-consumer'.

    The value of the Artifact field becomes the application name. +If you chose RabbitMQ for the middleware, your Spring Initializr should now be as follows:

spring initializr
  1. Click the Generate Project button.

    Doing so downloads the zipped version of the generated project to your hard drive.

  2. Unzip the file into the folder you want to use as your project directory.
[Tip]Tip

We encourage you to explore the many possibilities available in the Spring Initializr. +It lets you create many different kinds of Spring applications.

2.2 Importing the Project into Your IDE

Now you can import the project into your IDE. +Keep in mind that, depending on the IDE, you may need to follow a specific import procedure. +For example, depending on how the project was generated (Maven or Gradle), you may need to follow specific import procedure (for example, in Eclipse or STS, you need to use File → Import → Maven → Existing Maven Project).

Once imported, the project must have no errors of any kind. Also, src/main/java should contain com.example.loggingconsumer.LoggingConsumerApplication.

Technically, at this point, you can run the application’s main class. +It is already a valid Spring Boot application. +However, it does not do anything, so we want to add some code.

2.3 Adding a Message Handler, Building, and Running

Modify the com.example.loggingconsumer.LoggingConsumerApplication class to look as follows:

@SpringBootApplication
+@EnableBinding(Sink.class)
+public class LoggingConsumerApplication {
+
+	public static void main(String[] args) {
+		SpringApplication.run(LoggingConsumerApplication.class, args);
+	}
+
+	@StreamListener(Sink.INPUT)
+	public void handle(Person person) {
+		System.out.println("Received: " + person);
+	}
+
+	public static class Person {
+		private String name;
+		public String getName() {
+			return name;
+		}
+		public void setName(String name) {
+			this.name = name;
+		}
+		public String toString() {
+			return this.name;
+		}
+	}
+}

As you can see from the preceding listing:

  • We have enabled Sink binding (input-no-output) by using @EnableBinding(Sink.class). +Doing so signals to the framework to initiate binding to the messaging middleware, where it automatically creates the destination (that is, queue, topic, and others) that are bound to the Sink.INPUT channel.
  • We have added a handler method to receive incoming messages of type Person. +Doing so lets you see one of the core features of the framework: It tries to automatically convert incoming message payloads to type Person.

You now have a fully functional Spring Cloud Stream application that does listens for messages. +From here, for simplicity, we assume you selected RabbitMQ in step one. +Assuming you have RabbitMQ installed and running, you can start the application by running its main method in your IDE.

You should see following output:

	--- [ main] c.s.b.r.p.RabbitExchangeQueueProvisioner : declaring queue for inbound: input.anonymous.CbMIwdkJSBO1ZoPDOtHtCg, bound to: input
+	--- [ main] o.s.a.r.c.CachingConnectionFactory       : Attempting to connect to: [localhost:5672]
+	--- [ main] o.s.a.r.c.CachingConnectionFactory       : Created new connection: rabbitConnectionFactory#2a3a299:0/SimpleConnection@66c83fc8. . .
+	. . .
+	--- [ main] o.s.i.a.i.AmqpInboundChannelAdapter      : started inbound.input.anonymous.CbMIwdkJSBO1ZoPDOtHtCg
+	. . .
+	--- [ main] c.e.l.LoggingConsumerApplication         : Started LoggingConsumerApplication in 2.531 seconds (JVM running for 2.897)

Go to the RabbitMQ management console or any other RabbitMQ client and send a message to input.anonymous.CbMIwdkJSBO1ZoPDOtHtCg. +The anonymous.CbMIwdkJSBO1ZoPDOtHtCg part represents the group name and is generated, so it is bound to be different in your environment. +For something more predictable, you can use an explicit group name by setting spring.cloud.stream.bindings.input.group=hello (or whatever name you like).

The contents of the message should be a JSON representation of the Person class, as follows:

{"name":"Sam Spade"}

Then, in your console, you should see:

Received: Sam Spade

You can also build and package your application into a boot jar (by using ./mvnw clean install) and run the built JAR by using the java -jar command.

Now you have a working (albeit very basic) Spring Cloud Stream application.

3. What’s New in 2.0?

Spring Cloud Stream introduces a number of new features, enhancements, and changes. The following sections outline the most notable ones:

3.1 New Features and Components

  • Polling Consumers: Introduction of polled consumers, which lets the application control message processing rates. +See Section 6.3.5, “Using Polled Consumers” for more details. +You can also read this blog post for more details.
  • Micrometer Support: Metrics has been switched to use Micrometer. +MeterRegistry is also provided as a bean so that custom applications can autowire it to capture custom metrics. +See Chapter 14, Metrics Emitter for more details.
  • New Actuator Binding Controls: New actuator binding controls let you both visualize and control the Bindings lifecycle. +For more details, see Section 7.6, “Binding visualization and control”.
  • Configurable RetryTemplate: Aside from providing properties to configure RetryTemplate, we now let you provide your own template, effectively overriding the one provided by the framework. +To use it, configure it as a @Bean in your application.

3.2 Notable Enhancements

This version includes the following notable enhancements:

3.2.1 Both Actuator and Web Dependencies Are Now Optional

This change slims down the footprint of the deployed application in the event neither actuator nor web dependencies required. +It also lets you switch between the reactive and conventional web paradigms by manually adding one of the following dependencies.

The following listing shows how to add the conventional web framework:

<dependency>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-web</artifactId>
+</dependency>

The following listing shows how to add the reactive web framework:

<dependency>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-webflux</artifactId>
+</dependency>

The following list shows how to add the actuator dependency:

<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-actuator</artifactId>
+</dependency>

3.2.2 Content-type Negotiation Improvements

One of the core themes for verion 2.0 is improvements (in both consistency and performance) around content-type negotiation and message conversion. +The following summary outlines the notable changes and improvements in this area. +See the Chapter 9, Content Type Negotiation section for more details. +Also this blog post contains more detail.

  • All message conversion is now handled only by MessageConverter objects.
  • We introduced the @StreamMessageConverter annotation to provide custom MessageConverter objects.
  • We introduced the default Content Type as application/json, which needs to be taken into consideration when migrating 1.3 application or operating in the mixed mode (that is, 1.3 producer → 2.0 consumer).
  • Messages with textual payloads and a contentType of text/…​ or …​/json are no longer converted to Message<String> for cases where the argument type of the provided MessageHandler can not be determined (that is, public void handle(Message<?> message) or public void handle(Object payload)). +Furthermore, a strong argument type may not be enough to properly convert messages, so the contentType header may be used as a supplement by some MessageConverters.

3.3 Notable Deprecations

As of version 2.0, the following items have been deprecated:

3.3.1 Java Serialization (Java Native and Kryo)

JavaSerializationMessageConverter and KryoMessageConverter remain for now. However, we plan to move them out of the core packages and support in the future. +The main reason for this deprecation is to flag the issue that type-based, language-specific serialization could cause in distributed environments, where Producers and Consumers may depend on different JVM versions or have different versions of supporting libraries (that is, Kryo). +We also wanted to draw the attention to the fact that Consumers and Producers may not even be Java-based, so polyglot style serialization (i.e., JSON) is better suited.

3.3.2 Deprecated Classes and Methods

The following is a quick summary of notable deprecations. See the corresponding {spring-cloud-stream-javadoc-current}[javadoc] for more details.

  • SharedChannelRegistry. Use SharedBindingTargetRegistry.
  • Bindings. +Beans qualified by it are already uniquely identified by their type — for example, provided Source, Processor, or custom bindings:
public interface Sample {
+	String OUTPUT = "sampleOutput";
+
+	@Output(Sample.OUTPUT)
+	MessageChannel output();
+}
  • HeaderMode.raw. Use none, headers or embeddedHeaders
  • ProducerProperties.partitionKeyExtractorClass in favor of partitionKeyExtractorName and ProducerProperties.partitionSelectorClass in favor of partitionSelectorName. +This change ensures that both components are Spring configured and managed and are referenced in a Spring-friendly way.
  • BinderAwareRouterBeanPostProcessor. While the component remains, it is no longer a BeanPostProcessor and will be renamed in the future.
  • BinderProperties.setEnvironment(Properties environment). Use BinderProperties.setEnvironment(Map<String, Object> environment).

4. Introducing Spring Cloud Stream

Spring Cloud Stream is a framework for building message-driven microservice applications. +Spring Cloud Stream builds upon Spring Boot to create standalone, production-grade Spring applications and uses Spring Integration to provide connectivity to message brokers. +It provides opinionated configuration of middleware from several vendors, introducing the concepts of persistent publish-subscribe semantics, consumer groups, and partitions.

You can add the @EnableBinding annotation to your application to get immediate connectivity to a message broker, and you can add @StreamListener to a method to cause it to receive events for stream processing. +The following example shows a sink application that receives external messages:

@SpringBootApplication
+@EnableBinding(Sink.class)
+public class VoteRecordingSinkApplication {
+
+  public static void main(String[] args) {
+    SpringApplication.run(VoteRecordingSinkApplication.class, args);
+  }
+
+  @StreamListener(Sink.INPUT)
+  public void processVote(Vote vote) {
+      votingService.recordVote(vote);
+  }
+}

The @EnableBinding annotation takes one or more interfaces as parameters (in this case, the parameter is a single Sink interface). +An interface declares input and output channels. +Spring Cloud Stream provides the Source, Sink, and Processor interfaces. You can also define your own interfaces.

The following listing shows the definition of the Sink interface:

public interface Sink {
+  String INPUT = "input";
+
+  @Input(Sink.INPUT)
+  SubscribableChannel input();
+}

The @Input annotation identifies an input channel, through which received messages enter the application. +The @Output annotation identifies an output channel, through which published messages leave the application. +The @Input and @Output annotations can take a channel name as a parameter. +If a name is not provided, the name of the annotated method is used.

Spring Cloud Stream creates an implementation of the interface for you. +You can use this in the application by autowiring it, as shown in the following example (from a test case):

@RunWith(SpringJUnit4ClassRunner.class)
+@SpringApplicationConfiguration(classes = VoteRecordingSinkApplication.class)
+@WebAppConfiguration
+@DirtiesContext
+public class StreamApplicationTests {
+
+  @Autowired
+  private Sink sink;
+
+  @Test
+  public void contextLoads() {
+    assertNotNull(this.sink.input());
+  }
+}

5. Main Concepts

Spring Cloud Stream provides a number of abstractions and primitives that simplify the writing of message-driven microservice applications. +This section gives an overview of the following:

5.1 Application Model

A Spring Cloud Stream application consists of a middleware-neutral core. +The application communicates with the outside world through input and output channels injected into it by Spring Cloud Stream. +Channels are connected to external brokers through middleware-specific Binder implementations.

Figure 5.1. Spring Cloud Stream Application

SCSt with binder

5.1.1 Fat JAR

Spring Cloud Stream applications can be run in stand-alone mode from your IDE for testing. +To run a Spring Cloud Stream application in production, you can create an executable (or fat) JAR by using the standard Spring Boot tooling provided for Maven or Gradle. See the Spring Boot Reference Guide for more details.

5.2 The Binder Abstraction

Spring Cloud Stream provides Binder implementations for Kafka and Rabbit MQ. +Spring Cloud Stream also includes a TestSupportBinder, which leaves a channel unmodified so that tests can interact with channels directly and reliably assert on what is received. +You can also use the extensible API to write your own Binder.

Spring Cloud Stream uses Spring Boot for configuration, and the Binder abstraction makes it possible for a Spring Cloud Stream application to be flexible in how it connects to middleware. +For example, deployers can dynamically choose, at runtime, the destinations (such as the Kafka topics or RabbitMQ exchanges) to which channels connect. +Such configuration can be provided through external configuration properties and in any form supported by Spring Boot (including application arguments, environment variables, and application.yml or application.properties files). +In the sink example from the Chapter 4, Introducing Spring Cloud Stream section, setting the spring.cloud.stream.bindings.input.destination application property to raw-sensor-data causes it to read from the raw-sensor-data Kafka topic or from a queue bound to the raw-sensor-data RabbitMQ exchange.

Spring Cloud Stream automatically detects and uses a binder found on the classpath. +You can use different types of middleware with the same code. +To do so, include a different binder at build time. +For more complex use cases, you can also package multiple binders with your application and have it choose the binder( and even whether to use different binders for different channels) at runtime.

5.3 Persistent Publish-Subscribe Support

Communication between applications follows a publish-subscribe model, where data is broadcast through shared topics. +This can be seen in the following figure, which shows a typical deployment for a set of interacting Spring Cloud Stream applications.

Figure 5.2. Spring Cloud Stream Publish-Subscribe

SCSt sensors

Data reported by sensors to an HTTP endpoint is sent to a common destination named raw-sensor-data. +From the destination, it is independently processed by a microservice application that computes time-windowed averages and by another microservice application that ingests the raw data into HDFS (Hadoop Distributed File System). +In order to process the data, both applications declare the topic as their input at runtime.

The publish-subscribe communication model reduces the complexity of both the producer and the consumer and lets new applications be added to the topology without disruption of the existing flow. +For example, downstream from the average-calculating application, you can add an application that calculates the highest temperature values for display and monitoring. +You can then add another application that interprets the same flow of averages for fault detection. +Doing all communication through shared topics rather than point-to-point queues reduces coupling between microservices.

While the concept of publish-subscribe messaging is not new, Spring Cloud Stream takes the extra step of making it an opinionated choice for its application model. +By using native middleware support, Spring Cloud Stream also simplifies use of the publish-subscribe model across different platforms.

5.4 Consumer Groups

While the publish-subscribe model makes it easy to connect applications through shared topics, the ability to scale up by creating multiple instances of a given application is equally important. +When doing so, different instances of an application are placed in a competing consumer relationship, where only one of the instances is expected to handle a given message.

Spring Cloud Stream models this behavior through the concept of a consumer group. +(Spring Cloud Stream consumer groups are similar to and inspired by Kafka consumer groups.) +Each consumer binding can use the spring.cloud.stream.bindings.<channelName>.group property to specify a group name. +For the consumers shown in the following figure, this property would be set as spring.cloud.stream.bindings.<channelName>.group=hdfsWrite or spring.cloud.stream.bindings.<channelName>.group=average.

Figure 5.3. Spring Cloud Stream Consumer Groups

SCSt groups

All groups that subscribe to a given destination receive a copy of published data, but only one member of each group receives a given message from that destination. +By default, when a group is not specified, Spring Cloud Stream assigns the application to an anonymous and independent single-member consumer group that is in a publish-subscribe relationship with all other consumer groups.

5.5 Consumer Types

Two types of consumer are supported:

  • Message-driven (sometimes referred to as Asynchronous)
  • Polled (sometimes referred to as Synchronous)

Prior to version 2.0, only asynchronous consumers were supported. A message is delivered as soon as it is available and a thread is available to process it.

When you wish to control the rate at which messages are processed, you might want to use a synchronous consumer.

5.5.1 Durability

Consistent with the opinionated application model of Spring Cloud Stream, consumer group subscriptions are durable. +That is, a binder implementation ensures that group subscriptions are persistent and that, once at least one subscription for a group has been created, the group receives messages, even if they are sent while all applications in the group are stopped.

[Note]Note

Anonymous subscriptions are non-durable by nature. +For some binder implementations (such as RabbitMQ), it is possible to have non-durable group subscriptions.

In general, it is preferable to always specify a consumer group when binding an application to a given destination. +When scaling up a Spring Cloud Stream application, you must specify a consumer group for each of its input bindings. +Doing so prevents the application’s instances from receiving duplicate messages (unless that behavior is desired, which is unusual).

5.6 Partitioning Support

Spring Cloud Stream provides support for partitioning data between multiple instances of a given application. +In a partitioned scenario, the physical communication medium (such as the broker topic) is viewed as being structured into multiple partitions. +One or more producer application instances send data to multiple consumer application instances and ensure that data identified by common characteristics are processed by the same consumer instance.

Spring Cloud Stream provides a common abstraction for implementing partitioned processing use cases in a uniform fashion. +Partitioning can thus be used whether the broker itself is naturally partitioned (for example, Kafka) or not (for example, RabbitMQ).

Figure 5.4. Spring Cloud Stream Partitioning

SCSt partitioning

Partitioning is a critical concept in stateful processing, where it is critical (for either performance or consistency reasons) to ensure that all related data is processed together. +For example, in the time-windowed average calculation example, it is important that all measurements from any given sensor are processed by the same application instance.

[Note]Note

To set up a partitioned processing scenario, you must configure both the data-producing and the data-consuming ends.

6. Programming Model

To understand the programming model, you should be familiar with the following core concepts:

  • Destination Binders: Components responsible to provide integration with the external messaging systems.
  • Destination Bindings: Bridge between the external messaging systems and application provided Producers and Consumers of messages (created by the Destination Binders).
  • Message: The canonical data structure used by producers and consumers to communicate with Destination Binders (and thus other applications via external messaging systems).
SCSt overview

6.1 Destination Binders

Destination Binders are extension components of Spring Cloud Stream responsible for providing the necessary configuration and implementation to facilitate +integration with external messaging systems. +This integration is responsible for connectivity, delegation, and routing of messages to and from producers and consumers, data type conversion, +invocation of the user code, and more.

Binders handle a lot of the boiler plate responsibilities that would otherwise fall on your shoulders. However, to accomplish that, the binder still needs +some help in the form of minimalistic yet required set of instructions from the user, which typically come in the form of some type of configuration.

While it is out of scope of this section to discuss all of the available binder and binding configuration options (the rest of the manual covers them extensively), +Destination Binding does require special attention. The next section discusses it in detail.

6.2 Destination Bindings

As stated earlier, Destination Bindings provide a bridge between the external messaging system and application-provided Producers and Consumers.

Applying the @EnableBinding annotation to one of the application’s configuration classes defines a destination binding. +The @EnableBinding annotation itself is meta-annotated with @Configuration and triggers the configuration of the Spring Cloud Stream infrastructure.

The following example shows a fully configured and functioning Spring Cloud Stream application that receives the payload of the message from the INPUT +destination as a String type (see Chapter 9, Content Type Negotiation section), logs it to the console and sends it to the OUTPUT destination after converting it to upper case.

@SpringBootApplication
+@EnableBinding(Processor.class)
+public class MyApplication {
+
+	public static void main(String[] args) {
+		SpringApplication.run(MyApplication.class, args);
+	}
+
+	@StreamListener(Processor.INPUT)
+	@SendTo(Processor.OUTPUT)
+	public String handle(String value) {
+		System.out.println("Received: " + value);
+		return value.toUpperCase();
+	}
+}

As you can see the @EnableBinding annotation can take one or more interface classes as parameters. The parameters are referred to as bindings, +and they contain methods representing bindable components. +These components are typically message channels (see Spring Messaging) +for channel-based binders (such as Rabbit, Kafka, and others). However other types of bindings can +provide support for the native features of the corresponding technology. For example Kafka Streams binder (formerly known as KStream) allows native bindings directly to Kafka Streams +(see Kafka Streams for more details).

Spring Cloud Stream already provides binding interfaces for typical message exchange contracts, which include:

  • Sink: Identifies the contract for the message consumer by providing the destination from which the message is consumed.
  • Source: Identifies the contract for the message producer by providing the destination to which the produced message is sent.
  • Processor: Encapsulates both the sink and the source contracts by exposing two destinations that allow consumption and production of messages.
public interface Sink {
+
+  String INPUT = "input";
+
+  @Input(Sink.INPUT)
+  SubscribableChannel input();
+}
public interface Source {
+
+  String OUTPUT = "output";
+
+  @Output(Source.OUTPUT)
+  MessageChannel output();
+}
public interface Processor extends Source, Sink {}

While the preceding example satisfies the majority of cases, you can also define your own contracts by defining your own bindings interfaces and use @Input and @Output +annotations to identify the actual bindable components.

For example:

public interface Barista {
+
+    @Input
+    SubscribableChannel orders();
+
+    @Output
+    MessageChannel hotDrinks();
+
+    @Output
+    MessageChannel coldDrinks();
+}

Using the interface shown in the preceding example as a parameter to @EnableBinding triggers the creation of the three bound channels named orders, hotDrinks, and coldDrinks, +respectively.

You can provide as many binding interfaces as you need, as arguments to the @EnableBinding annotation, as shown in the following example:

@EnableBinding(value = { Orders.class, Payment.class })

In Spring Cloud Stream, the bindable MessageChannel components are the Spring Messaging MessageChannel (for outbound) and its extension, SubscribableChannel, +(for inbound).

Pollable Destination Binding

While the previously described bindings support event-based message consumption, sometimes you need more control, such as rate of consumption.

Starting with version 2.0, you can now bind a pollable consumer:

The following example shows how to bind a pollable consumer:

public interface PolledBarista {
+
+    @Input
+    PollableMessageSource orders();
+	. . .
+}

In this case, an implementation of PollableMessageSource is bound to the orders “channel”. See Section 6.3.5, “Using Polled Consumers” for more details.

Customizing Channel Names

By using the @Input and @Output annotations, you can specify a customized channel name for the channel, as shown in the following example:

public interface Barista {
+    @Input("inboundOrders")
+    SubscribableChannel orders();
+}

In the preceding example, the created bound channel is named inboundOrders.

Normally, you need not access individual channels or bindings directly (other then configuring them via @EnableBinding annotation). However there may be +times, such as testing or other corner cases, when you do.

Aside from generating channels for each binding and registering them as Spring beans, for each bound interface, Spring Cloud Stream generates a bean that implements the interface. +That means you can have access to the interfaces representing the bindings or individual channels by auto-wiring either in your application, as shown in the following two examples:

Autowire Binding interface

@Autowire
+private Source source
+
+public void sayHello(String name) {
+    source.output().send(MessageBuilder.withPayload(name).build());
+}

Autowire individual channel

@Autowire
+private MessageChannel output;
+
+public void sayHello(String name) {
+    output.send(MessageBuilder.withPayload(name).build());
+}

You can also use standard Spring’s @Qualifier annotation for cases when channel names are customized or in multiple-channel scenarios that require specifically named channels.

The following example shows how to use the @Qualifier annotation in this way:

@Autowire
+@Qualifier("myChannel")
+private MessageChannel output;

6.3 Producing and Consuming Messages

You can write a Spring Cloud Stream application by using either Spring Integration annotations or Spring Cloud Stream native annotation.

6.3.1 Spring Integration Support

Spring Cloud Stream is built on the concepts and patterns defined by Enterprise Integration Patterns and relies +in its internal implementation on an already established and popular implementation of Enterprise Integration Patterns within the Spring portfolio of projects: +Spring Integration framework.

So its only natural for it to support the foundation, semantics, and configuration options that are already established by Spring Integration

For example, you can attach the output channel of a Source to a MessageSource and use the familiar @InboundChannelAdapter annotation, as follows:

@EnableBinding(Source.class)
+public class TimerSource {
+
+  @Bean
+  @InboundChannelAdapter(value = Source.OUTPUT, poller = @Poller(fixedDelay = "10", maxMessagesPerPoll = "1"))
+  public MessageSource<String> timerMessageSource() {
+    return () -> new GenericMessage<>("Hello Spring Cloud Stream");
+  }
+}

Similarly, you can use @Transformer or @ServiceActivator while providing an implementation of a message handler method for a Processor binding contract, as shown in the following example:

@EnableBinding(Processor.class)
+public class TransformProcessor {
+  @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
+  public Object transform(String message) {
+    return message.toUpperCase();
+  }
+}
[Note]Note

While this may be skipping ahead a bit, it is important to understand that, when you consume from the same binding using @StreamListener annotation, a pub-sub model is used. +Each method annotated with @StreamListener receives its own copy of a message, and each one has its own consumer group. +However, if you consume from the same binding by using one of the Spring Integration annotation (such as @Aggregator, @Transformer, or @ServiceActivator), those consume in a competing model. +No individual consumer group is created for each subscription.

6.3.2 Using @StreamListener Annotation

Complementary to its Spring Integration support, Spring Cloud Stream provides its own @StreamListener annotation, modeled after other Spring Messaging annotations +(@MessageMapping, @JmsListener, @RabbitListener, and others) and provides conviniences, such as content-based routing and others.

@EnableBinding(Sink.class)
+public class VoteHandler {
+
+  @Autowired
+  VotingService votingService;
+
+  @StreamListener(Sink.INPUT)
+  public void handle(Vote vote) {
+    votingService.record(vote);
+  }
+}

As with other Spring Messaging methods, method arguments can be annotated with @Payload, @Headers, and @Header.

For methods that return data, you must use the @SendTo annotation to specify the output binding destination for data returned by the method, as shown in the following example:

@EnableBinding(Processor.class)
+public class TransformProcessor {
+
+  @Autowired
+  VotingService votingService;
+
+  @StreamListener(Processor.INPUT)
+  @SendTo(Processor.OUTPUT)
+  public VoteResult handle(Vote vote) {
+    return votingService.record(vote);
+  }
+}

6.3.3 Using @StreamListener for Content-based routing

Spring Cloud Stream supports dispatching messages to multiple handler methods annotated with @StreamListener based on conditions.

In order to be eligible to support conditional dispatching, a method must satisfy the follow conditions:

  • It must not return a value.
  • It must be an individual message handling method (reactive API methods are not supported).

The condition is specified by a SpEL expression in the condition argument of the annotation and is evaluated for each message. +All the handlers that match the condition are invoked in the same thread, and no assumption must be made about the order in which the invocations take place.

In the following example of a @StreamListener with dispatching conditions, all the messages bearing a header type with the value bogey are dispatched to the +receiveBogey method, and all the messages bearing a header type with the value bacall are dispatched to the receiveBacall method.

@EnableBinding(Sink.class)
+@EnableAutoConfiguration
+public static class TestPojoWithAnnotatedArguments {
+
+    @StreamListener(target = Sink.INPUT, condition = "headers['type']=='bogey'")
+    public void receiveBogey(@Payload BogeyPojo bogeyPojo) {
+       // handle the message
+    }
+
+    @StreamListener(target = Sink.INPUT, condition = "headers['type']=='bacall'")
+    public void receiveBacall(@Payload BacallPojo bacallPojo) {
+       // handle the message
+    }
+}

Content Type Negotiation in the Context of condition

It is important to understand some of the mechanics behind content-based routing using the condition argument of @StreamListener, especially in the context of the type of the message as a whole. +It may also help if you familiarize yourself with the Chapter 9, Content Type Negotiation before you proceed.

Consider the following scenario:

@EnableBinding(Sink.class)
+@EnableAutoConfiguration
+public static class CatsAndDogs {
+
+    @StreamListener(target = Sink.INPUT, condition = "payload.class.simpleName=='Dog'")
+    public void bark(Dog dog) {
+       // handle the message
+    }
+
+    @StreamListener(target = Sink.INPUT, condition = "payload.class.simpleName=='Cat'")
+    public void purr(Cat cat) {
+       // handle the message
+    }
+}

The preceding code is perfectly valid. It compiles and deploys without any issues, yet it never produces the result you expect.

That is because you are testing something that does not yet exist in a state you expect. That is because the payload of the message is not yet converted from the +wire format (byte[]) to the desired type. +In other words, it has not yet gone through the type conversion process described in the Chapter 9, Content Type Negotiation.

So, unless you use a SPeL expression that evaluates raw data (for example, the value of the first byte in the byte array), use message header-based expressions +(such as condition = "headers['type']=='dog'").

[Note]Note

At the moment, dispatching through @StreamListener conditions is supported only for channel-based binders (not for reactive programming) +support.

6.3.4 Spring Cloud Function support

Since Spring Cloud Stream v2.1, another alternative for defining stream handlers and sources is to use build-in +support for Spring Cloud Function where they can be expressed as beans of + type java.util.function.[Supplier/Function/Consumer].

To specify which functional bean to bind to the external destination(s) exposed by the bindings, you must provide spring.cloud.stream.function.definition property.

Here is the example of the Processor application exposing message handler as java.util.function.Function

@SpringBootApplication
+@EnableBinding(Processor.class)
+public class MyFunctionBootApp {
+
+	public static void main(String[] args) {
+		SpringApplication.run(MyFunctionBootApp.class, "--spring.cloud.stream.function.definition=toUpperCase");
+	}
+
+	@Bean
+	public Function<String, String> toUpperCase() {
+		return s -> s.toUpperCase();
+	}
+}

In the above you we simply define a bean of type java.util.function.Function called toUpperCase and identify it as a bean to be used as message handler +whose 'input' and 'output' must be bound to the external destinations exposed by the Processor binding.

Below are the examples of simple functional applications to support Source, Processor and Sink.

Here is the example of a Source application defined as java.util.function.Supplier

@SpringBootApplication
+@EnableBinding(Source.class)
+public static class SourceFromSupplier {
+	public static void main(String[] args) {
+		SpringApplication.run(SourceFromSupplier.class, "--spring.cloud.stream.function.definition=date");
+	}
+	@Bean
+	public Supplier<Date> date() {
+		return () -> new Date(12345L);
+	}
+}

Here is the example of a Processor application defined as java.util.function.Function

@SpringBootApplication
+@EnableBinding(Processor.class)
+public static class ProcessorFromFunction {
+	public static void main(String[] args) {
+		SpringApplication.run(ProcessorFromFunction.class, "--spring.cloud.stream.function.definition=toUpperCase");
+	}
+	@Bean
+	public Function<String, String> toUpperCase() {
+		return s -> s.toUpperCase();
+	}
+}

Here is the example of a Sink application defined as java.util.function.Consumer

@EnableAutoConfiguration
+@EnableBinding(Sink.class)
+public static class SinkFromConsumer {
+	public static void main(String[] args) {
+		SpringApplication.run(SinkFromConsumer.class, "--spring.cloud.stream.function.definition=sink");
+	}
+	@Bean
+	public Consumer<String> sink() {
+		return System.out::println;
+	}
+}

Functional Composition

Using this programming model you can also benefit from functional composition where you can dynamically compose complex handlers from a set of simple functions. +As an example let’s add the following function bean to the application defined above

@Bean
+public Function<String, String> wrapInQuotes() {
+	return s -> "\"" + s + "\"";
+}

and modify the spring.cloud.stream.function.definition property to reflect your intention to compose a new function from both ‘toUpperCase’ and ‘wrapInQuotes’. +To do that Spring Cloud Function allows you to use | (pipe) symbol. So to finish our example our property will now look like this:

—spring.cloud.stream.function.definition=toUpperCase|wrapInQuotes

6.3.5 Using Polled Consumers

Overview

When using polled consumers, you poll the PollableMessageSource on demand. +Consider the following example of a polled consumer:

public interface PolledConsumer {
+
+    @Input
+    PollableMessageSource destIn();
+
+    @Output
+    MessageChannel destOut();
+
+}

Given the polled consumer in the preceding example, you might use it as follows:

@Bean
+public ApplicationRunner poller(PollableMessageSource destIn, MessageChannel destOut) {
+    return args -> {
+        while (someCondition()) {
+            try {
+                if (!destIn.poll(m -> {
+                    String newPayload = ((String) m.getPayload()).toUpperCase();
+                    destOut.send(new GenericMessage<>(newPayload));
+                })) {
+                    Thread.sleep(1000);
+                }
+            }
+            catch (Exception e) {
+                // handle failure
+            }
+        }
+    };
+}

The PollableMessageSource.poll() method takes a MessageHandler argument (often a lambda expression, as shown here). +It returns true if the message was received and successfully processed.

As with message-driven consumers, if the MessageHandler throws an exception, messages are published to error channels, +as discussed in Section 6.4, “Error Handling”.

Normally, the poll() method acknowledges the message when the MessageHandler exits. +If the method exits abnormally, the message is rejected (not re-queued), but see the section called “Handling Errors”. +You can override that behavior by taking responsibility for the acknowledgment, as shown in the following example:

@Bean
+public ApplicationRunner poller(PollableMessageSource dest1In, MessageChannel dest2Out) {
+    return args -> {
+        while (someCondition()) {
+            if (!dest1In.poll(m -> {
+                StaticMessageHeaderAccessor.getAcknowledgmentCallback(m).noAutoAck();
+                // e.g. hand off to another thread which can perform the ack
+                // or acknowledge(Status.REQUEUE)
+
+            })) {
+                Thread.sleep(1000);
+            }
+        }
+    };
+}
[Important]Important

You must ack (or nack) the message at some point, to avoid resource leaks.

[Important]Important

Some messaging systems (such as Apache Kafka) maintain a simple offset in a log. If a delivery fails and is re-queued with StaticMessageHeaderAccessor.getAcknowledgmentCallback(m).acknowledge(Status.REQUEUE);, any later successfully ack’d messages are redelivered.

There is also an overloaded poll method, for which the definition is as follows:

poll(MessageHandler handler, ParameterizedTypeReference<?> type)

The type is a conversion hint that allows the incoming message payload to be converted, as shown in the following example:

boolean result = pollableSource.poll(received -> {
+			Map<String, Foo> payload = (Map<String, Foo>) received.getPayload();
+            ...
+
+		}, new ParameterizedTypeReference<Map<String, Foo>>() {});

Handling Errors

By default, an error channel is configured for the pollable source; if the callback throws an exception, an ErrorMessage is sent to the error channel (<destination>.<group>.errors); this error channel is also bridged to the global Spring Integration errorChannel.

You can subscribe to either error channel with a @ServiceActivator to handle errors; without a subscription, the error will simply be logged and the message will be acknowledged as successful. +If the error channel service activator throws an exception, the message will be rejected (by default) and won’t be redelivered. +If the service activator throws a RequeueCurrentMessageException, the message will be requeued at the broker and will be again retrieved on a subsequent poll.

If the listener throws a RequeueCurrentMessageException directly, the message will be requeued, as discussed above, and will not be sent to the error channels.

6.4 Error Handling

Errors happen, and Spring Cloud Stream provides several flexible mechanisms to handle them. +The error handling comes in two flavors:

  • application: The error handling is done within the application (custom error handler).
  • system: The error handling is delegated to the binder (re-queue, DL, and others). Note that the techniques are dependent on binder implementation and the +capability of the underlying messaging middleware.

Spring Cloud Stream uses the Spring Retry library to facilitate successful message processing. See Section 6.4.3, “Retry Template” for more details. +However, when all fails, the exceptions thrown by the message handlers are propagated back to the binder. At that point, binder invokes custom error handler or communicates +the error back to the messaging system (re-queue, DLQ, and others).

6.4.1 Application Error Handling

There are two types of application-level error handling. Errors can be handled at each binding subscription or a global handler can handle all the binding subscription errors. Let’s review the details.

Figure 6.1. A Spring Cloud Stream Sink Application with Custom and Global Error Handlers

custom vs global error channels

For each input binding, Spring Cloud Stream creates a dedicated error channel with the following semantics <destinationName>.errors.

[Note]Note

The <destinationName> consists of the name of the binding (such as input) and the name of the group (such as myGroup).

Consider the following:

spring.cloud.stream.bindings.input.group=myGroup
@StreamListener(Sink.INPUT) // destination name 'input.myGroup'
+public void handle(Person value) {
+	throw new RuntimeException("BOOM!");
+}
+
+@ServiceActivator(inputChannel = Processor.INPUT + ".myGroup.errors") //channel name 'input.myGroup.errors'
+public void error(Message<?> message) {
+	System.out.println("Handling ERROR: " + message);
+}

In the preceding example the destination name is input.myGroup and the dedicated error channel name is input.myGroup.errors.

[Note]Note

The use of @StreamListener annotation is intended specifically to define bindings that bridge internal channels and external destinations. Given that the destination +specific error channel does NOT have an associated external destination, such channel is a prerogative of Spring Integration (SI). This means that the handler +for such destination must be defined using one of the SI handler annotations (i.e., @ServiceActivator, @Transformer etc.).

[Note]Note

If group is not specified anonymous group is used (something like input.anonymous.2K37rb06Q6m2r51-SPIDDQ), which is not suitable for error +handling scenarious, since you don’t know what it’s going to be until the destination is created.

Also, in the event you are binding to the existing destination such as:

spring.cloud.stream.bindings.input.destination=myFooDestination
+spring.cloud.stream.bindings.input.group=myGroup

the full destination name is myFooDestination.myGroup and then the dedicated error channel name is myFooDestination.myGroup.errors.

Back to the example…​

The handle(..) method, which subscribes to the channel named input, throws an exception. Given there is also a subscriber to the error channel input.myGroup.errors +all error messages are handled by this subscriber.

If you have multiple bindings, you may want to have a single error handler. Spring Cloud Stream automatically provides support for +a global error channel by bridging each individual error channel to the channel named errorChannel, allowing a single subscriber to handle all errors, +as shown in the following example:

@StreamListener("errorChannel")
+public void error(Message<?> message) {
+	System.out.println("Handling ERROR: " + message);
+}

This may be a convenient option if error handling logic is the same regardless of which handler produced the error.

6.4.2 System Error Handling

System-level error handling implies that the errors are communicated back to the messaging system and, given that not every messaging system +is the same, the capabilities may differ from binder to binder.

That said, in this section we explain the general idea behind system level error handling and use Rabbit binder as an example. NOTE: Kafka binder provides similar +support, although some configuration properties do differ. Also, for more details and configuration options, see the individual binder’s documentation.

If no internal error handlers are configured, the errors propagate to the binders, and the binders subsequently propagate those errors back to the messaging system. +Depending on the capabilities of the messaging system such a system may drop the message, re-queue the message for re-processing or send the failed message to DLQ. +Both Rabbit and Kafka support these concepts. However, other binders may not, so refer to your individual binder’s documentation for details on supported system-level +error-handling options.

Drop Failed Messages

By default, if no additional system-level configuration is provided, the messaging system drops the failed message. +While acceptable in some cases, for most cases, it is not, and we need some recovery mechanism to avoid message loss.

DLQ - Dead Letter Queue

DLQ allows failed messages to be sent to a special destination: - Dead Letter Queue.

When configured, failed messages are sent to this destination for subsequent re-processing or auditing and reconciliation.

For example, continuing on the previous example and to set up the DLQ with Rabbit binder, you need to set the following property:

spring.cloud.stream.rabbit.bindings.input.consumer.auto-bind-dlq=true

Keep in mind that, in the above property, input corresponds to the name of the input destination binding. +The consumer indicates that it is a consumer property and auto-bind-dlq instructs the binder to configure DLQ for input +destination, which results in an additional Rabbit queue named input.myGroup.dlq.

Once configured, all failed messages are routed to this queue with an error message similar to the following:

delivery_mode:	1
+headers:
+x-death:
+count:	1
+reason:	rejected
+queue:	input.hello
+time:	1522328151
+exchange:
+routing-keys:	input.myGroup
+Payload {"name”:"Bob"}

As you can see from the above, your original message is preserved for further actions.

However, one thing you may have noticed is that there is limited information on the original issue with the message processing. For example, you do not see a stack +trace corresponding to the original error. +To get more relevant information about the original error, you must set an additional property:

spring.cloud.stream.rabbit.bindings.input.consumer.republish-to-dlq=true

Doing so forces the internal error handler to intercept the error message and add additional information to it before publishing it to DLQ. +Once configured, you can see that the error message contains more information relevant to the original error, as follows:

delivery_mode:	2
+headers:
+x-original-exchange:
+x-exception-message:	has an error
+x-original-routingKey:	input.myGroup
+x-exception-stacktrace:	org.springframework.messaging.MessageHandlingException: nested exception is
+      org.springframework.messaging.MessagingException: has an error, failedMessage=GenericMessage [payload=byte[15],
+      headers={amqp_receivedDeliveryMode=NON_PERSISTENT, amqp_receivedRoutingKey=input.hello, amqp_deliveryTag=1,
+      deliveryAttempt=3, amqp_consumerQueue=input.hello, amqp_redelivered=false, id=a15231e6-3f80-677b-5ad7-d4b1e61e486e,
+      amqp_consumerTag=amq.ctag-skBFapilvtZhDsn0k3ZmQg, contentType=application/json, timestamp=1522327846136}]
+      at org.spring...integ...han...MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:107)
+      at. . . . .
+Payload {"name”:"Bob"}

This effectively combines application-level and system-level error handling to further assist with downstream troubleshooting mechanics.

Re-queue Failed Messages

As mentioned earlier, the currently supported binders (Rabbit and Kafka) rely on RetryTemplate to facilitate successful message processing. See Section 6.4.3, “Retry Template” for details. +However, for cases when max-attempts property is set to 1, internal reprocessing of the message is disabled. At this point, you can facilitate message re-processing (re-tries) +by instructing the messaging system to re-queue the failed message. Once re-queued, the failed message is sent back to the original handler, essentially creating a retry loop.

This option may be feasible for cases where the nature of the error is related to some sporadic yet short-term unavailability of some resource.

To accomplish that, you must set the following properties:

spring.cloud.stream.bindings.input.consumer.max-attempts=1
+spring.cloud.stream.rabbit.bindings.input.consumer.requeue-rejected=true

In the preceding example, the max-attempts set to 1 essentially disabling internal re-tries and requeue-rejected (short for requeue rejected messages) is set to true. +Once set, the failed message is resubmitted to the same handler and loops continuously or until the handler throws AmqpRejectAndDontRequeueException +essentially allowing you to build your own re-try logic within the handler itself.

6.4.3 Retry Template

The RetryTemplate is part of the Spring Retry library. +While it is out of scope of this document to cover all of the capabilities of the RetryTemplate, we will mention the following consumer properties that are specifically related to +the RetryTemplate:

maxAttempts

The number of attempts to process the message.

Default: 3.

backOffInitialInterval

The backoff initial interval on retry.

Default 1000 milliseconds.

backOffMaxInterval

The maximum backoff interval.

Default 10000 milliseconds.

backOffMultiplier

The backoff multiplier.

Default 2.0.

defaultRetryable

Whether exceptions thrown by the listener that are not listed in the retryableExceptions are retryable.

Default: true.

retryableExceptions

A map of Throwable class names in the key and a boolean in the value. +Specify those exceptions (and subclasses) that will or won’t be retried. +Also see defaultRetriable. +Example: spring.cloud.stream.bindings.input.consumer.retryable-exceptions.java.lang.IllegalStateException=false.

Default: empty.

While the preceding settings are sufficient for majority of the customization requirements, they may not satisfy certain complex requirements at, which +point you may want to provide your own instance of the RetryTemplate. To do so configure it as a bean in your application configuration. The application provided +instance will override the one provided by the framework. Also, to avoid conflicts you must qualify the instance of the RetryTemplate you want to be used by the binder +as @StreamRetryTemplate. For example,

@StreamRetryTemplate
+public RetryTemplate myRetryTemplate() {
+    return new RetryTemplate();
+}

As you can see from the above example you don’t need to annotate it with @Bean since @StreamRetryTemplate is a qualified @Bean.

6.5 Reactive Programming Support

Spring Cloud Stream also supports the use of reactive APIs where incoming and outgoing data is handled as continuous data flows. +Support for reactive APIs is available through spring-cloud-stream-reactive, which needs to be added explicitly to your project.

The programming model with reactive APIs is declarative. Instead of specifying how each individual message should be handled, you can use operators that describe functional transformations from inbound to outbound data flows.

At present Spring Cloud Stream supports the only the Reactor API. +In the future, we intend to support a more generic model based on Reactive Streams.

The reactive programming model also uses the @StreamListener annotation for setting up reactive handlers. +The differences are that:

  • The @StreamListener annotation must not specify an input or output, as they are provided as arguments and return values from the method.
  • The arguments of the method must be annotated with @Input and @Output, indicating which input or output the incoming and outgoing data flows connect to, respectively.
  • The return value of the method, if any, is annotated with @Output, indicating the input where data should be sent.
[Note]Note

Reactive programming support requires Java 1.8.

[Note]Note

As of Spring Cloud Stream 1.1.1 and later (starting with release train Brooklyn.SR2), reactive programming support requires the use of Reactor 3.0.4.RELEASE and higher. +Earlier Reactor versions (including 3.0.1.RELEASE, 3.0.2.RELEASE and 3.0.3.RELEASE) are not supported. +spring-cloud-stream-reactive transitively retrieves the proper version, but it is possible for the project structure to manage the version of the io.projectreactor:reactor-core to an earlier release, especially when using Maven. +This is the case for projects generated by using Spring Initializr with Spring Boot 1.x, which overrides the Reactor version to 2.0.8.RELEASE. +In such cases, you must ensure that the proper version of the artifact is released. +You can do so by adding a direct dependency on io.projectreactor:reactor-core with a version of 3.0.4.RELEASE or later to your project.

[Note]Note

The use of term, reactive, currently refers to the reactive APIs being used and not to the execution model being reactive (that is, the bound endpoints still use a 'push' rather than a 'pull' model). While some backpressure support is provided by the use of Reactor, we do intend, in a future release, to support entirely reactive pipelines by the use of native reactive clients for the connected middleware.

6.5.1 Reactor-based Handlers

A Reactor-based handler can have the following argument types:

  • For arguments annotated with @Input, it supports the Reactor Flux type. +The parameterization of the inbound Flux follows the same rules as in the case of individual message handling: It can be the entire Message, a POJO that can be the Message payload, or a POJO that is the result of a transformation based on the Message content-type header. Multiple inputs are provided.
  • For arguments annotated with Output, it supports the FluxSender type, which connects a Flux produced by the method with an output. Generally speaking, specifying outputs as arguments is only recommended when the method can have multiple outputs.

A Reactor-based handler supports a return type of Flux. In that case, it must be annotated with @Output. We recommend using the return value of the method when a single output Flux is available.

The following example shows a Reactor-based Processor:

@EnableBinding(Processor.class)
+@EnableAutoConfiguration
+public static class UppercaseTransformer {
+
+  @StreamListener
+  @Output(Processor.OUTPUT)
+  public Flux<String> receive(@Input(Processor.INPUT) Flux<String> input) {
+    return input.map(s -> s.toUpperCase());
+  }
+}

The same processor using output arguments looks like the following example:

@EnableBinding(Processor.class)
+@EnableAutoConfiguration
+public static class UppercaseTransformer {
+
+  @StreamListener
+  public void receive(@Input(Processor.INPUT) Flux<String> input,
+     @Output(Processor.OUTPUT) FluxSender output) {
+     output.send(input.map(s -> s.toUpperCase()));
+  }
+}

6.5.2 Reactive Sources

Spring Cloud Stream reactive support also provides the ability for creating reactive sources through the @StreamEmitter annotation. +By using the @StreamEmitter annotation, a regular source may be converted to a reactive one. +@StreamEmitter is a method level annotation that marks a method to be an emitter to outputs declared with @EnableBinding. +You cannot use the @Input annotation along with @StreamEmitter, as the methods marked with this annotation are not listening for any input. Rather, methods marked with @StreamEmitter generate output. +Following the same programming model used in @StreamListener, @StreamEmitter also allows flexible ways of using the @Output annotation, depending on whether the method has any arguments, a return type, and other considerations.

The remainder of this section contains examples of using the @StreamEmitter annotation in various styles.

The following example emits the Hello, World message every millisecond and publishes to a Reactor Flux:

@EnableBinding(Source.class)
+@EnableAutoConfiguration
+public static class HelloWorldEmitter {
+
+  @StreamEmitter
+  @Output(Source.OUTPUT)
+  public Flux<String> emit() {
+    return Flux.intervalMillis(1)
+            .map(l -> "Hello World");
+  }
+}

In the preceding example, the resulting messages in the Flux are sent to the output channel of the Source.

The next example is another flavor of an @StreamEmmitter that sends a Reactor Flux. +Instead of returning a Flux, the following method uses a FluxSender to programmatically send a Flux from a source:

@EnableBinding(Source.class)
+@EnableAutoConfiguration
+public static class HelloWorldEmitter {
+
+  @StreamEmitter
+  @Output(Source.OUTPUT)
+  public void emit(FluxSender output) {
+    output.send(Flux.intervalMillis(1)
+            .map(l -> "Hello World"));
+  }
+}

The next example is exactly same as the above snippet in functionality and style. +However, instead of using an explicit @Output annotation on the method, it uses the annotation on the method parameter.

@EnableBinding(Source.class)
+@EnableAutoConfiguration
+public static class HelloWorldEmitter {
+
+  @StreamEmitter
+  public void emit(@Output(Source.OUTPUT) FluxSender output) {
+    output.send(Flux.intervalMillis(1)
+            .map(l -> "Hello World"));
+  }
+}

The last example in this section is yet another flavor of writing reacting sources by using the Reactive Streams Publisher API and taking advantage of the support for it in Spring Integration Java DSL. +The Publisher in the following example still uses Reactor Flux under the hood, but, from an application perspective, that is transparent to the user and only needs Reactive Streams and Java DSL for Spring Integration:

@EnableBinding(Source.class)
+@EnableAutoConfiguration
+public static class HelloWorldEmitter {
+
+  @StreamEmitter
+  @Output(Source.OUTPUT)
+  @Bean
+  public Publisher<Message<String>> emit() {
+    return IntegrationFlows.from(() ->
+                new GenericMessage<>("Hello World"),
+        e -> e.poller(p -> p.fixedDelay(1)))
+        .toReactivePublisher();
+  }
+}

7. Binders

Spring Cloud Stream provides a Binder abstraction for use in connecting to physical destinations at the external middleware. +This section provides information about the main concepts behind the Binder SPI, its main components, and implementation-specific details.

7.1 Producers and Consumers

The following image shows the general relationship of producers and consumers:

Figure 7.1. Producers and Consumers

producers consumers

A producer is any component that sends messages to a channel. +The channel can be bound to an external message broker with a Binder implementation for that broker. +When invoking the bindProducer() method, the first parameter is the name of the destination within the broker, the second parameter is the local channel instance to which the producer sends messages, and the third parameter contains properties (such as a partition key expression) to be used within the adapter that is created for that channel.

A consumer is any component that receives messages from a channel. +As with a producer, the consumer’s channel can be bound to an external message broker. +When invoking the bindConsumer() method, the first parameter is the destination name, and a second parameter provides the name of a logical group of consumers. +Each group that is represented by consumer bindings for a given destination receives a copy of each message that a producer sends to that destination (that is, it follows normal publish-subscribe semantics). +If there are multiple consumer instances bound with the same group name, then messages are load-balanced across those consumer instances so that each message sent by a producer is consumed by only a single consumer instance within each group (that is, it follows normal queueing semantics).

7.2 Binder SPI

The Binder SPI consists of a number of interfaces, out-of-the box utility classes, and discovery strategies that provide a pluggable mechanism for connecting to external middleware.

The key point of the SPI is the Binder interface, which is a strategy for connecting inputs and outputs to external middleware. The following listing shows the definnition of the Binder interface:

public interface Binder<T, C extends ConsumerProperties, P extends ProducerProperties> {
+    Binding<T> bindConsumer(String name, String group, T inboundBindTarget, C consumerProperties);
+
+    Binding<T> bindProducer(String name, T outboundBindTarget, P producerProperties);
+}

The interface is parameterized, offering a number of extension points:

  • Input and output bind targets. As of version 1.0, only MessageChannel is supported, but this is intended to be used as an extension point in the future.
  • Extended consumer and producer properties, allowing specific Binder implementations to add supplemental properties that can be supported in a type-safe manner.

A typical binder implementation consists of the following:

  • A class that implements the Binder interface;
  • A Spring @Configuration class that creates a bean of type Binder along with the middleware connection infrastructure.
  • A META-INF/spring.binders file found on the classpath containing one or more binder definitions, as shown in the following example:

    kafka:\
    +org.springframework.cloud.stream.binder.kafka.config.KafkaBinderConfiguration

7.3 Binder Detection

Spring Cloud Stream relies on implementations of the Binder SPI to perform the task of connecting channels to message brokers. +Each Binder implementation typically connects to one type of messaging system.

7.3.1 Classpath Detection

By default, Spring Cloud Stream relies on Spring Boot’s auto-configuration to configure the binding process. +If a single Binder implementation is found on the classpath, Spring Cloud Stream automatically uses it. +For example, a Spring Cloud Stream project that aims to bind only to RabbitMQ can add the following dependency:

<dependency>
+  <groupId>org.springframework.cloud</groupId>
+  <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
+</dependency>

For the specific Maven coordinates of other binder dependencies, see the documentation of that binder implementation.

7.4 Multiple Binders on the Classpath

When multiple binders are present on the classpath, the application must indicate which binder is to be used for each channel binding. +Each binder configuration contains a META-INF/spring.binders file, which is a simple properties file, as shown in the following example:

rabbit:\
+org.springframework.cloud.stream.binder.rabbit.config.RabbitServiceAutoConfiguration

Similar files exist for the other provided binder implementations (such as Kafka), and custom binder implementations are expected to provide them as well. +The key represents an identifying name for the binder implementation, whereas the value is a comma-separated list of configuration classes that each contain one and only one bean definition of type org.springframework.cloud.stream.binder.Binder.

Binder selection can either be performed globally, using the spring.cloud.stream.defaultBinder property (for example, spring.cloud.stream.defaultBinder=rabbit) or individually, by configuring the binder on each channel binding. +For instance, a processor application (that has channels named input and output for read and write respectively) that reads from Kafka and writes to RabbitMQ can specify the following configuration:

spring.cloud.stream.bindings.input.binder=kafka
+spring.cloud.stream.bindings.output.binder=rabbit

7.5 Connecting to Multiple Systems

By default, binders share the application’s Spring Boot auto-configuration, so that one instance of each binder found on the classpath is created. +If your application should connect to more than one broker of the same type, you can specify multiple binder configurations, each with different environment settings.

[Note]Note

Turning on explicit binder configuration disables the default binder configuration process altogether. +If you do so, all binders in use must be included in the configuration. +Frameworks that intend to use Spring Cloud Stream transparently may create binder configurations that can be referenced by name, but they do not affect the default binder configuration. +In order to do so, a binder configuration may have its defaultCandidate flag set to false (for example, spring.cloud.stream.binders.<configurationName>.defaultCandidate=false). +This denotes a configuration that exists independently of the default binder configuration process.

The following example shows a typical configuration for a processor application that connects to two RabbitMQ broker instances:

spring:
+  cloud:
+    stream:
+      bindings:
+        input:
+          destination: thing1
+          binder: rabbit1
+        output:
+          destination: thing2
+          binder: rabbit2
+      binders:
+        rabbit1:
+          type: rabbit
+          environment:
+            spring:
+              rabbitmq:
+                host: <host1>
+        rabbit2:
+          type: rabbit
+          environment:
+            spring:
+              rabbitmq:
+                host: <host2>

7.6 Binding visualization and control

Since version 2.0, Spring Cloud Stream supports visualization and control of the Bindings through Actuator endpoints.

Starting with version 2.0 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:

<dependency>
+     <groupId>org.springframework.boot</groupId>
+     <artifactId>spring-boot-starter-web</artifactId>
+</dependency>

The following example shows how to add the dependency for the WebFlux framework:

<dependency>
+       <groupId>org.springframework.boot</groupId>
+       <artifactId>spring-boot-starter-webflux</artifactId>
+</dependency>

You can add the Actuator dependency as follows:

<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-actuator</artifactId>
+</dependency>
[Note]Note

To run Spring Cloud Stream 2.0 apps in Cloud Foundry, you must add spring-boot-starter-web and spring-boot-starter-actuator to the classpath. Otherwise, the +application will not start due to health check failures.

You must also enable the bindings actuator endpoints by setting the following property: --management.endpoints.web.exposure.include=bindings.

Once those prerequisites are satisfied. you should see the following in the logs when application start:

: Mapped "{[/actuator/bindings/{name}],methods=[POST]. . .
+: Mapped "{[/actuator/bindings],methods=[GET]. . .
+: Mapped "{[/actuator/bindings/{name}],methods=[GET]. . .

To visualize the current bindings, access the following URL: +http://<host>:<port>/actuator/bindings

Alternative, to see a single binding, access one of the URLs similar to the following: +http://<host>:<port>/actuator/bindings/myBindingName

You can also stop, start, pause, and resume individual bindings by posting to the same URL while providing a state argument as JSON, as shown in the following examples:

curl -d '{"state":"STOPPED"}' -H "Content-Type: application/json" -X POST http://<host>:<port>/actuator/bindings/myBindingName +curl -d '{"state":"STARTED"}' -H "Content-Type: application/json" -X POST http://<host>:<port>/actuator/bindings/myBindingName +curl -d '{"state":"PAUSED"}' -H "Content-Type: application/json" -X POST http://<host>:<port>/actuator/bindings/myBindingName +curl -d '{"state":"RESUMED"}' -H "Content-Type: application/json" -X POST http://<host>:<port>/actuator/bindings/myBindingName

[Note]Note

PAUSED and RESUMED work only when the corresponding binder and its underlying technology supports it. Otherwise, you see the warning message in the logs. +Currently, only Kafka binder supports the PAUSED and RESUMED states.

7.7 Binder Configuration Properties

The following properties are available when customizing binder configurations. These properties exposed via org.springframework.cloud.stream.config.BinderProperties

They must be prefixed with spring.cloud.stream.binders.<configurationName>.

type

The binder type. +It typically references one of the binders found on the classpath — in particular, a key in a META-INF/spring.binders file.

By default, it has the same value as the configuration name.

inheritEnvironment

Whether the configuration inherits the environment of the application itself.

Default: true.

environment

Root for a set of properties that can be used to customize the environment of the binder. +When this property is set, the context in which the binder is being created is not a child of the application context. +This setting allows for complete separation between the binder components and the application components.

Default: empty.

defaultCandidate

Whether the binder configuration is a candidate for being considered a default binder or can be used only when explicitly referenced. +This setting allows adding binder configurations without interfering with the default processing.

Default: true.

8. Configuration Options

Spring Cloud Stream supports general configuration options as well as configuration for bindings and binders. +Some binders let additional binding properties support middleware-specific features.

Configuration options can be provided to Spring Cloud Stream applications through any mechanism supported by Spring Boot. +This includes application arguments, environment variables, and YAML or .properties files.

8.1 Binding Service Properties

These properties are exposed via org.springframework.cloud.stream.config.BindingServiceProperties

spring.cloud.stream.instanceCount

The number of deployed instances of an application. +Must be set for partitioning on the producer side. Must be set on the consumer side when using RabbitMQ and with Kafka if autoRebalanceEnabled=false.

Default: 1.

spring.cloud.stream.instanceIndex
The instance index of the application: A number from 0 to instanceCount - 1. +Used for partitioning with RabbitMQ and with Kafka if autoRebalanceEnabled=false. +Automatically set in Cloud Foundry to match the application’s instance index.
spring.cloud.stream.dynamicDestinations

A list of destinations that can be bound dynamically (for example, in a dynamic routing scenario). +If set, only listed destinations can be bound.

Default: empty (letting any destination be bound).

spring.cloud.stream.defaultBinder

The default binder to use, if multiple binders are configured. +See Multiple Binders on the Classpath.

Default: empty.

spring.cloud.stream.overrideCloudConnectors

This property is only applicable when the cloud profile is active and Spring Cloud Connectors are provided with the application. +If the property is false (the default), the binder detects a suitable bound service (for example, a RabbitMQ service bound in Cloud Foundry for the RabbitMQ binder) and uses it for creating connections (usually through Spring Cloud Connectors). +When set to true, this property instructs binders to completely ignore the bound services and rely on Spring Boot properties (for example, relying on the spring.rabbitmq.* properties provided in the environment for the RabbitMQ binder). +The typical usage of this property is to be nested in a customized environment when connecting to multiple systems.

Default: false.

spring.cloud.stream.bindingRetryInterval

The interval (in seconds) between retrying binding creation when, for example, the binder does not support late binding and the broker (for example, Apache Kafka) is down. +Set it to zero to treat such conditions as fatal, preventing the application from starting.

Default: 30

8.2 Binding Properties

Binding properties are supplied by using the format of spring.cloud.stream.bindings.<channelName>.<property>=<value>. +The <channelName> represents the name of the channel being configured (for example, output for a Source).

To avoid repetition, Spring Cloud Stream supports setting values for all channels, in the format of spring.cloud.stream.default.<property>=<value>.

When it comes to avoiding repetitions for extended binding properties, this format should be used - spring.cloud.stream.<binder-type>.default.<producer|consumer>.<property>=<value>.

In what follows, we indicate where we have omitted the spring.cloud.stream.bindings.<channelName>. prefix and focus just on the property name, with the understanding that the prefix ise included at runtime.

8.2.1 Common Binding Properties

These properties are exposed via org.springframework.cloud.stream.config.BindingProperties

The following binding properties are available for both input and output bindings and must be prefixed with spring.cloud.stream.bindings.<channelName>. (for example, spring.cloud.stream.bindings.input.destination=ticktock).

Default values can be set by using the spring.cloud.stream.default prefix (for example`spring.cloud.stream.default.contentType=application/json`).

destination
The target destination of a channel on the bound middleware (for example, the RabbitMQ exchange or Kafka topic). +If the channel is bound as a consumer, it could be bound to multiple destinations, and the destination names can be specified as comma-separated String values. +If not set, the channel name is used instead. +The default value of this property cannot be overridden.
group

The consumer group of the channel. +Applies only to inbound bindings. +See Consumer Groups.

Default: null (indicating an anonymous consumer).

contentType

The content type of the channel. +See Chapter 9, Content Type Negotiation.

Default: application/json.

binder

The binder used by this binding. +See Section 7.4, “Multiple Binders on the Classpath” for details.

Default: null (the default binder is used, if it exists).

8.2.2 Consumer Properties

These properties are exposed via org.springframework.cloud.stream.binder.ConsumerProperties

The following binding properties are available for input bindings only and must be prefixed with spring.cloud.stream.bindings.<channelName>.consumer. (for example, spring.cloud.stream.bindings.input.consumer.concurrency=3).

Default values can be set by using the spring.cloud.stream.default.consumer prefix (for example, spring.cloud.stream.default.consumer.headerMode=none).

concurrency

The concurrency of the inbound consumer.

Default: 1.

partitioned

Whether the consumer receives data from a partitioned producer.

Default: false.

headerMode

When set to none, disables header parsing on input. +Effective only for messaging middleware that does not support message headers natively and requires header embedding. +This option is useful when consuming data from non-Spring Cloud Stream applications when native headers are not supported. +When set to headers, it uses the middleware’s native header mechanism. +When set to embeddedHeaders, it embeds headers into the message payload.

Default: depends on the binder implementation.

maxAttempts

If processing fails, the number of attempts to process the message (including the first). +Set to 1 to disable retry.

Default: 3.

backOffInitialInterval

The backoff initial interval on retry.

Default: 1000.

backOffMaxInterval

The maximum backoff interval.

Default: 10000.

backOffMultiplier

The backoff multiplier.

Default: 2.0.

defaultRetryable

Whether exceptions thrown by the listener that are not listed in the retryableExceptions are retryable.

Default: true.

instanceIndex

When set to a value greater than equal to zero, it allows customizing the instance index of this consumer (if different from spring.cloud.stream.instanceIndex). +When set to a negative value, it defaults to spring.cloud.stream.instanceIndex. +See Section 11.2, “Instance Index and Instance Count” for more information.

Default: -1.

instanceCount

When set to a value greater than equal to zero, it allows customizing the instance count of this consumer (if different from spring.cloud.stream.instanceCount). +When set to a negative value, it defaults to spring.cloud.stream.instanceCount. +See Section 11.2, “Instance Index and Instance Count” for more information.

Default: -1.

retryableExceptions

A map of Throwable class names in the key and a boolean in the value. +Specify those exceptions (and subclasses) that will or won’t be retried. +Also see defaultRetriable. +Example: spring.cloud.stream.bindings.input.consumer.retryable-exceptions.java.lang.IllegalStateException=false.

Default: empty.

useNativeDecoding

When set to true, the inbound message is deserialized directly by the client library, which must be configured correspondingly (for example, setting an appropriate Kafka producer value deserializer). +When this configuration is being used, the inbound message unmarshalling is not based on the contentType of the binding. +When native decoding is used, it is the responsibility of the producer to use an appropriate encoder (for example, the Kafka producer value serializer) to serialize the outbound message. +Also, when native encoding and decoding is used, the headerMode=embeddedHeaders property is ignored and headers are not embedded in the message. +See the producer property useNativeEncoding.

Default: false.

8.2.3 Producer Properties

These properties are exposed via org.springframework.cloud.stream.binder.ProducerProperties

The following binding properties are available for output bindings only and must be prefixed with spring.cloud.stream.bindings.<channelName>.producer. (for example, spring.cloud.stream.bindings.input.producer.partitionKeyExpression=payload.id).

Default values can be set by using the prefix spring.cloud.stream.default.producer (for example, spring.cloud.stream.default.producer.partitionKeyExpression=payload.id).

partitionKeyExpression

A SpEL expression that determines how to partition outbound data. +If set, or if partitionKeyExtractorClass is set, outbound data on this channel is partitioned. partitionCount must be set to a value greater than 1 to be effective. +Mutually exclusive with partitionKeyExtractorClass. +See Section 5.6, “Partitioning Support”.

Default: null.

partitionKeyExtractorClass

A PartitionKeyExtractorStrategy implementation. +If set, or if partitionKeyExpression is set, outbound data on this channel is partitioned. partitionCount must be set to a value greater than 1 to be effective. +Mutually exclusive with partitionKeyExpression. +See Section 5.6, “Partitioning Support”.

Default: null.

partitionSelectorClass

A PartitionSelectorStrategy implementation. +Mutually exclusive with partitionSelectorExpression. +If neither is set, the partition is selected as the hashCode(key) % partitionCount, where key is computed through either partitionKeyExpression or partitionKeyExtractorClass.

Default: null.

partitionSelectorExpression

A SpEL expression for customizing partition selection. +Mutually exclusive with partitionSelectorClass. +If neither is set, the partition is selected as the hashCode(key) % partitionCount, where key is computed through either partitionKeyExpression or partitionKeyExtractorClass.

Default: null.

partitionCount

The number of target partitions for the data, if partitioning is enabled. +Must be set to a value greater than 1 if the producer is partitioned. +On Kafka, it is interpreted as a hint. The larger of this and the partition count of the target topic is used instead.

Default: 1.

requiredGroups
A comma-separated list of groups to which the producer must ensure message delivery even if they start after it has been created (for example, by pre-creating durable queues in RabbitMQ).
headerMode

When set to none, it disables header embedding on output. +It is effective only for messaging middleware that does not support message headers natively and requires header embedding. +This option is useful when producing data for non-Spring Cloud Stream applications when native headers are not supported. +When set to headers, it uses the middleware’s native header mechanism. +When set to embeddedHeaders, it embeds headers into the message payload.

Default: Depends on the binder implementation.

useNativeEncoding

When set to true, the outbound message is serialized directly by the client library, which must be configured correspondingly (for example, setting an appropriate Kafka producer value serializer). +When this configuration is being used, the outbound message marshalling is not based on the contentType of the binding. +When native encoding is used, it is the responsibility of the consumer to use an appropriate decoder (for example, the Kafka consumer value de-serializer) to deserialize the inbound message. +Also, when native encoding and decoding is used, the headerMode=embeddedHeaders property is ignored and headers are not embedded in the message. +See the consumer property useNativeDecoding.

Default: false.

errorChannelEnabled

When set to true, if the binder supports asynchroous send results, send failures are sent to an error channel for the destination. +See Section 6.4, “Error Handling” for more information.

Default: false.

8.3 Using Dynamically Bound Destinations

Besides the channels defined by using @EnableBinding, Spring Cloud Stream lets applications send messages to dynamically bound destinations. +This is useful, for example, when the target destination needs to be determined at runtime. +Applications can do so by using the BinderAwareChannelResolver bean, registered automatically by the @EnableBinding annotation.

The 'spring.cloud.stream.dynamicDestinations' property can be used for restricting the dynamic destination names to a known set (whitelisting). +If this property is not set, any destination can be bound dynamically.

The BinderAwareChannelResolver can be used directly, as shown in the following example of a REST controller using a path variable to decide the target channel:

@EnableBinding
+@Controller
+public class SourceWithDynamicDestination {
+
+    @Autowired
+    private BinderAwareChannelResolver resolver;
+
+    @RequestMapping(path = "/{target}", method = POST, consumes = "*/*")
+    @ResponseStatus(HttpStatus.ACCEPTED)
+    public void handleRequest(@RequestBody String body, @PathVariable("target") target,
+           @RequestHeader(HttpHeaders.CONTENT_TYPE) Object contentType) {
+        sendMessage(body, target, contentType);
+    }
+
+    private void sendMessage(String body, String target, Object contentType) {
+        resolver.resolveDestination(target).send(MessageBuilder.createMessage(body,
+                new MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, contentType))));
+    }
+}

Now consider what happens when we start the application on the default port (8080) and make the following requests with CURL:

curl -H "Content-Type: application/json" -X POST -d "customer-1" http://localhost:8080/customers
+
+curl -H "Content-Type: application/json" -X POST -d "order-1" http://localhost:8080/orders

The destinations, 'customers' and 'orders', are created in the broker (in the exchange for Rabbit or in the topic for Kafka) with names of 'customers' and 'orders', and the data is published to the appropriate destinations.

The BinderAwareChannelResolver is a general-purpose Spring Integration DestinationResolver and can be injected in other components — for example, in a router using a SpEL expression based on the target field of an incoming JSON message. The following example includes a router that reads SpEL expressions:

@EnableBinding
+@Controller
+public class SourceWithDynamicDestination {
+
+    @Autowired
+    private BinderAwareChannelResolver resolver;
+
+
+    @RequestMapping(path = "/", method = POST, consumes = "application/json")
+    @ResponseStatus(HttpStatus.ACCEPTED)
+    public void handleRequest(@RequestBody String body, @RequestHeader(HttpHeaders.CONTENT_TYPE) Object contentType) {
+        sendMessage(body, contentType);
+    }
+
+    private void sendMessage(Object body, Object contentType) {
+        routerChannel().send(MessageBuilder.createMessage(body,
+                new MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, contentType))));
+    }
+
+    @Bean(name = "routerChannel")
+    public MessageChannel routerChannel() {
+        return new DirectChannel();
+    }
+
+    @Bean
+    @ServiceActivator(inputChannel = "routerChannel")
+    public ExpressionEvaluatingRouter router() {
+        ExpressionEvaluatingRouter router =
+            new ExpressionEvaluatingRouter(new SpelExpressionParser().parseExpression("payload.target"));
+        router.setDefaultOutputChannelName("default-output");
+        router.setChannelResolver(resolver);
+        return router;
+    }
+}

The Router Sink Application uses this technique to create the destinations on-demand.

If the channel names are known in advance, you can configure the producer properties as with any other destination. +Alternatively, if you register a NewDestinationBindingCallback<> bean, it is invoked just before the binding is created. +The callback takes the generic type of the extended producer properties used by the binder. +It has one method:

void configure(String channelName, MessageChannel channel, ProducerProperties producerProperties,
+        T extendedProducerProperties);

The following example shows how to use the RabbitMQ binder:

@Bean
+public NewDestinationBindingCallback<RabbitProducerProperties> dynamicConfigurer() {
+    return (name, channel, props, extended) -> {
+        props.setRequiredGroups("bindThisQueue");
+        extended.setQueueNameGroupOnly(true);
+        extended.setAutoBindDlq(true);
+        extended.setDeadLetterQueueName("myDLQ");
+    };
+}
[Note]Note

If you need to support dynamic destinations with multiple binder types, use Object for the generic type and cast the extended argument as needed.

9. Content Type Negotiation

Data transformation is one of the core features of any message-driven microservice architecture. Given that, in Spring Cloud Stream, such data +is represented as a Spring Message, a message may have to be transformed to a desired shape or size before reaching its destination. This is required for two reasons:

  1. To convert the contents of the incoming message to match the signature of the application-provided handler.
  2. To convert the contents of the outgoing message to the wire format.

The wire format is typically byte[] (that is true for the Kafka and Rabbit binders), but it is governed by the binder implementation.

In Spring Cloud Stream, message transformation is accomplished with an org.springframework.messaging.converter.MessageConverter.

[Note]Note

As a supplement to the details to follow, you may also want to read the following blog post.

9.1 Mechanics

To better understand the mechanics and the necessity behind content-type negotiation, we take a look at a very simple use case by using the following message handler as an example:

@StreamListener(Processor.INPUT)
+@SendTo(Processor.OUTPUT)
+public String handle(Person person) {..}
[Note]Note

For simplicity, we assume that this is the only handler in the application (we assume there is no internal pipeline).

The handler shown in the preceding example expects a Person object as an argument and produces a String type as an output. +In order for the framework to succeed in passing the incoming Message as an argument to this handler, it has to somehow transform the payload of the Message type from the wire format to a Person type. +In other words, the framework must locate and apply the appropriate MessageConverter. +To accomplish that, the framework needs some instructions from the user. +One of these instructions is already provided by the signature of the handler method itself (Person type). +Consequently, in theory, that should be (and, in some cases, is) enough. +However, for the majority of use cases, in order to select the appropriate MessageConverter, the framework needs an additional piece of information. +That missing piece is contentType.

Spring Cloud Stream provides three mechanisms to define contentType (in order of precedence):

  1. HEADER: The contentType can be communicated through the Message itself. By providing a contentType header, you declare the content type to use to locate and apply the appropriate MessageConverter.
  2. BINDING: The contentType can be set per destination binding by setting the spring.cloud.stream.bindings.input.content-type property.

    [Note]Note

    The input segment in the property name corresponds to the actual name of the destination (which is “input” in our case). This approach lets you declare, on a per-binding basis, the content type to use to locate and apply the appropriate MessageConverter.

  3. DEFAULT: If contentType is not present in the Message header or the binding, the default application/json content type is used to +locate and apply the appropriate MessageConverter.

As mentioned earlier, the preceding list also demonstrates the order of precedence in case of a tie. For example, a header-provided content type takes precedence over any other content type. +The same applies for a content type set on a per-binding basis, which essentially lets you override the default content type. +However, it also provides a sensible default (which was determined from community feedback).

Another reason for making application/json the default stems from the interoperability requirements driven by distributed microservices architectures, where producer and consumer not only run in different JVMs but can also run on different non-JVM platforms.

When the non-void handler method returns, if the the return value is already a Message, that Message becomes the payload. However, when the return value is not a Message, the new Message is constructed with the return value as the payload while inheriting +headers from the input Message minus the headers defined or filtered by SpringIntegrationProperties.messageHandlerNotPropagatedHeaders. +By default, there is only one header set there: contentType. This means that the new Message does not have contentType header set, thus ensuring that the contentType can evolve. +You can always opt out of returning a Message from the handler method where you can inject any header you wish.

If there is an internal pipeline, the Message is sent to the next handler by going through the same process of conversion. However, if there is no internal pipeline or you have reached the end of it, the Message is sent back to the output destination.

9.1.1 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. +The logic for selecting the appropriate MessageConverter resides with the argument resolvers (HandlerMethodArgumentResolvers), which trigger right before the invocation of the user-defined handler method (which is when the actual argument type is known to the framework). +If the argument type does not match the type of the current payload, the framework delegates to the stack of the +pre-configured MessageConverters to see if any one of them can convert the payload. +As you can see, the Object fromMessage(Message<?> message, Class<?> targetClass); +operation of the MessageConverter takes targetClass as one of its arguments. +The framework also ensures that the provided Message always contains a contentType header. +When no contentType header was already present, it injects either the per-binding contentType header or the default contentType header. +The combination of contentType argument type is the mechanism by which framework determines if message can be converted to a target type. +If no appropriate MessageConverter is found, an exception is thrown, which you can handle by adding a custom MessageConverter (see Section 9.3, “User-defined Message Converters”).

But what if the payload type matches the target type declared by the handler method? In this case, there is nothing to convert, and the +payload is passed unmodified. While this sounds pretty straightforward and logical, keep in mind handler methods that take a Message<?> or Object as an argument. +By declaring the target type to be Object (which is an instanceof everything in Java), you essentially forfeit the conversion process.

[Note]Note

Do not expect Message to be converted into some other type based only on the contentType. +Remember that the contentType is complementary to the target type. +If you wish, you can provide a hint, which MessageConverter may or may not take into consideration.

9.1.2 Message Converters

MessageConverters define two methods:

Object fromMessage(Message<?> message, Class<?> targetClass);
+
+Message<?> toMessage(Object payload, @Nullable MessageHeaders headers);

It is important to understand the contract of these methods and their usage, specifically in the context of Spring Cloud Stream.

The fromMessage method converts an incoming Message to an argument type. +The payload of the Message could be any type, and it is +up to the actual implementation of the MessageConverter to support multiple types. +For example, some JSON converter may support the payload type as byte[], String, and others. +This is important when the application contains an internal pipeline (that is, input → handler1 → handler2 →. . . → output) and the output of the upstream handler results in a Message which may not be in the initial wire format.

However, the toMessage method has a more strict contract and must always convert Message to the wire format: byte[].

So, for all intents and purposes (and especially when implementing your own converter) you regard the two methods as having the following signatures:

Object fromMessage(Message<?> message, Class<?> targetClass);
+
+Message<byte[]> toMessage(Object payload, @Nullable MessageHeaders headers);

9.2 Provided MessageConverters

As mentioned earlier, the framework already provides a stack of MessageConverters to handle most common use cases. +The following list describes the provided MessageConverters, in order of precedence (the first MessageConverter that works is used):

  1. ApplicationJsonMessageMarshallingConverter: Variation of the org.springframework.messaging.converter.MappingJackson2MessageConverter. Supports conversion of the payload of the Message to/from POJO for cases when contentType is application/json (DEFAULT).
  2. TupleJsonMessageConverter: DEPRECATED Supports conversion of the payload of the Message to/from org.springframework.tuple.Tuple.
  3. ByteArrayMessageConverter: Supports conversion of the payload of the Message from byte[] to byte[] for cases when contentType is application/octet-stream. It is essentially a pass through and exists primarily for backward compatibility.
  4. ObjectStringMessageConverter: Supports conversion of any type to a String when contentType is text/plain. +It invokes Object’s toString() method or, if the payload is byte[], a new String(byte[]).
  5. JavaSerializationMessageConverter: DEPRECATED Supports conversion based on java serialization when contentType is application/x-java-serialized-object.
  6. KryoMessageConverter: DEPRECATED Supports conversion based on Kryo serialization when contentType is application/x-java-object.
  7. JsonUnmarshallingConverter: Similar to the ApplicationJsonMessageMarshallingConverter. It supports conversion of any type when contentType is application/x-java-object. +It expects the actual type information to be embedded in the contentType as an attribute (for example, application/x-java-object;type=foo.bar.Cat).

When no appropriate converter is found, the framework throws an exception. When that happens, you should check your code and configuration and ensure you did not miss anything (that is, ensure that you provided a contentType by using a binding or a header). +However, most likely, you found some uncommon case (such as a custom contentType perhaps) and the current stack of provided MessageConverters +does not know how to convert. If that is the case, you can add custom MessageConverter. See Section 9.3, “User-defined Message Converters”.

9.3 User-defined Message Converters

Spring Cloud Stream exposes a mechanism to define and register additional MessageConverters. +To use it, implement org.springframework.messaging.converter.MessageConverter, configure it as a @Bean, and annotate it with @StreamMessageConverter. +It is then apended to the existing stack of `MessageConverter`s.

[Note]Note

It is important to understand that custom MessageConverter implementations are added to the head of the existing stack. +Consequently, custom MessageConverter implementations take precedence over the existing ones, which lets you override as well as add to the existing converters.

The following example shows how to create a message converter bean to support a new content type called application/bar:

@EnableBinding(Sink.class)
+@SpringBootApplication
+public static class SinkApplication {
+
+    ...
+
+    @Bean
+    @StreamMessageConverter
+    public MessageConverter customMessageConverter() {
+        return new MyCustomMessageConverter();
+    }
+}
+
+public class MyCustomMessageConverter extends AbstractMessageConverter {
+
+    public MyCustomMessageConverter() {
+        super(new MimeType("application", "bar"));
+    }
+
+    @Override
+    protected boolean supports(Class<?> clazz) {
+        return (Bar.class.equals(clazz));
+    }
+
+    @Override
+    protected Object convertFromInternal(Message<?> message, Class<?> targetClass, Object conversionHint) {
+        Object payload = message.getPayload();
+        return (payload instanceof Bar ? payload : new Bar((byte[]) payload));
+    }
+}

Spring Cloud Stream also provides support for Avro-based converters and schema evolution. +See Chapter 10, Schema Evolution Support for details.

10. Schema Evolution Support

Spring Cloud Stream provides support for schema evolution so that the data can be evolved over time and still work with older or newer producers and consumers and vice versa. +Most serialization models, especially the ones that aim for portability across different platforms and languages, rely on a schema that describes how the data is serialized in the binary payload. +In order to serialize the data and then to interpret it, both the sending and receiving sides must have access to a schema that describes the binary format. +In certain cases, the schema can be inferred from the payload type on serialization or from the target type on deserialization. +However, many applications benefit from having access to an explicit schema that describes the binary data format. +A schema registry lets you store schema information in a textual format (typically JSON) and makes that information accessible to various applications that need it to receive and send data in binary format. +A schema is referenceable as a tuple consisting of:

  • A subject that is the logical name of the schema
  • The schema version
  • The schema format, which describes the binary format of the data

This following sections goes through the details of various components involved in schema evolution process.

10.1 Schema Registry Client

The client-side abstraction for interacting with schema registry servers is the SchemaRegistryClient interface, which has the following structure:

public interface SchemaRegistryClient {
+
+    SchemaRegistrationResponse register(String subject, String format, String schema);
+
+    String fetch(SchemaReference schemaReference);
+
+    String fetch(Integer id);
+
+}

Spring Cloud Stream provides out-of-the-box implementations for interacting with its own schema server and for interacting with the Confluent Schema Registry.

A client for the Spring Cloud Stream schema registry can be configured by using the @EnableSchemaRegistryClient, as follows:

  @EnableBinding(Sink.class)
+  @SpringBootApplication
+  @EnableSchemaRegistryClient
+  public static class AvroSinkApplication {
+    ...
+  }
[Note]Note

The default converter is optimized to cache not only the schemas from the remote server but also the parse() and toString() methods, which are quite expensive. +Because of this, it uses a DefaultSchemaRegistryClient that does not cache responses. +If you intend to change the default behavior, you can use the client directly on your code and override it to the desired outcome. +To do so, you have to add the property spring.cloud.stream.schemaRegistryClient.cached=true to your application properties.

10.1.1 Schema Registry Client Properties

The Schema Registry Client supports the following properties:

spring.cloud.stream.schemaRegistryClient.endpoint
The location of the schema-server. +When setting this, use a full URL, including protocol (http or https) , port, and context path.
Default
http://localhost:8990/
spring.cloud.stream.schemaRegistryClient.cached
Whether the client should cache schema server responses. +Normally set to false, as the caching happens in the message converter. +Clients using the schema registry client should set this to true.
Default
false

10.2 Avro Schema Registry Client Message Converters

For applications that have a SchemaRegistryClient bean registered with the application context, Spring Cloud Stream auto configures an Apache Avro message converter for schema management. +This eases schema evolution, as applications that receive messages can get easy access to a writer schema that can be reconciled with their own reader schema.

For outbound messages, if the content type of the channel is set to application/*+avro, the MessageConverter is activated, as shown in the following example:

spring.cloud.stream.bindings.output.contentType=application/*+avro

During the outbound conversion, the message converter tries to infer the schema of each outbound messages (based on its type) and register it to a subject (based on the payload type) by using the SchemaRegistryClient. +If an identical schema is already found, then a reference to it is retrieved. +If not, the schema is registered, and a new version number is provided. +The message is sent with a contentType header by using the following scheme: application/[prefix].[subject].v[version]+avro, where prefix is configurable and subject is deduced from the payload type.

For example, a message of the type User might be sent as a binary payload with a content type of application/vnd.user.v2+avro, where user is the subject and 2 is the version number.

When receiving messages, the converter infers the schema reference from the header of the incoming message and tries to retrieve it. The schema is used as the writer schema in the deserialization process.

10.2.1 Avro Schema Registry Message Converter Properties

If you have enabled Avro based schema registry client by setting spring.cloud.stream.bindings.output.contentType=application/*+avro, you can customize the behavior of the registration by setting the following properties.

spring.cloud.stream.schema.avro.dynamicSchemaGenerationEnabled

Enable if you want the converter to use reflection to infer a Schema from a POJO.

Default: false

spring.cloud.stream.schema.avro.readerSchema
Avro compares schema versions by looking at a writer schema (origin payload) and a reader schema (your application payload). See the Avro documentation for more information. If set, this overrides any lookups at the schema server and uses the local schema as the reader schema. +Default: null
spring.cloud.stream.schema.avro.schemaLocations

Registers any .avsc files listed in this property with the Schema Server.

Default: empty

spring.cloud.stream.schema.avro.prefix

The prefix to be used on the Content-Type header.

Default: vnd

10.3 Apache Avro Message Converters

Spring Cloud Stream provides support for schema-based message converters through its spring-cloud-stream-schema module. +Currently, the only serialization format supported out of the box for schema-based message converters is Apache Avro, with more formats to be added in future versions.

The spring-cloud-stream-schema module contains two types of message converters that can be used for Apache Avro serialization:

  • Converters that use the class information of the serialized or deserialized objects or a schema with a location known at startup.
  • Converters that use a schema registry. They locate the schemas at runtime and dynamically register new schemas as domain objects evolve.

10.4 Converters with Schema Support

The AvroSchemaMessageConverter supports serializing and deserializing messages either by using a predefined schema or by using the schema information available in the class (either reflectively or contained in the SpecificRecord). +If you provide a custom converter, then the default AvroSchemaMessageConverter bean is not created. The following example shows a custom converter:

To use custom converters, you can simply add it to the application context, optionally specifying one or more MimeTypes with which to associate it. +The default MimeType is application/avro.

If the target type of the conversion is a GenericRecord, a schema must be set.

The following example shows how to configure a converter in a sink application by registering the Apache Avro MessageConverter without a predefined schema. +In this example, note that the mime type value is avro/bytes, not the default application/avro.

@EnableBinding(Sink.class)
+@SpringBootApplication
+public static class SinkApplication {
+
+  ...
+
+  @Bean
+  public MessageConverter userMessageConverter() {
+      return new AvroSchemaMessageConverter(MimeType.valueOf("avro/bytes"));
+  }
+}

Conversely, the following application registers a converter with a predefined schema (found on the classpath):

@EnableBinding(Sink.class)
+@SpringBootApplication
+public static class SinkApplication {
+
+  ...
+
+  @Bean
+  public MessageConverter userMessageConverter() {
+      AvroSchemaMessageConverter converter = new AvroSchemaMessageConverter(MimeType.valueOf("avro/bytes"));
+      converter.setSchemaLocation(new ClassPathResource("schemas/User.avro"));
+      return converter;
+  }
+}

10.5 Schema Registry Server

Spring Cloud Stream provides a schema registry server implementation. +To use it, you can add the spring-cloud-stream-schema-server artifact to your project and use the @EnableSchemaRegistryServer annotation, which adds the schema registry server REST controller to your application. +This annotation is intended to be used with Spring Boot web applications, and the listening port of the server is controlled by the server.port property. +The spring.cloud.stream.schema.server.path property can be used to control the root path of the schema server (especially when it is embedded in other applications). +The spring.cloud.stream.schema.server.allowSchemaDeletion boolean property enables the deletion of a schema. By default, this is disabled.

The schema registry server uses a relational database to store the schemas. +By default, it uses an embedded database. +You can customize the schema storage by using the Spring Boot SQL database and JDBC configuration options.

The following example shows a Spring Boot application that enables the schema registry:

@SpringBootApplication
+@EnableSchemaRegistryServer
+public class SchemaRegistryServerApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(SchemaRegistryServerApplication.class, args);
+    }
+}

10.5.1 Schema Registry Server API

The Schema Registry Server API consists of the following operations:

Registering a New Schema

To register a new schema, send a POST request to the / endpoint.

The / accepts a JSON payload with the following fields:

  • subject: The schema subject
  • format: The schema format
  • definition: The schema definition

Its response is a schema object in JSON, with the following fields:

  • id: The schema ID
  • subject: The schema subject
  • format: The schema format
  • version: The schema version
  • definition: The schema definition

Retrieving an Existing Schema by Subject, Format, and Version

To retrieve an existing schema by subject, format, and version, send GET request to the /{subject}/{format}/{version} endpoint.

Its response is a schema object in JSON, with the following fields:

  • id: The schema ID
  • subject: The schema subject
  • format: The schema format
  • version: The schema version
  • definition: The schema definition

Retrieving an Existing Schema by Subject and Format

To retrieve an existing schema by subject and format, send a GET request to the /subject/format endpoint.

Its response is a list of schemas with each schema object in JSON, with the following fields:

  • id: The schema ID
  • subject: The schema subject
  • format: The schema format
  • version: The schema version
  • definition: The schema definition

Retrieving an Existing Schema by ID

To retrieve a schema by its ID, send a GET request to the /schemas/{id} endpoint.

Its response is a schema object in JSON, with the following fields:

  • id: The schema ID
  • subject: The schema subject
  • format: The schema format
  • version: The schema version
  • definition: The schema definition

Deleting a Schema by Subject, Format, and Version

To delete a schema identified by its subject, format, and version, send a DELETE request to the /{subject}/{format}/{version} endpoint.

Deleting a Schema by ID

To delete a schema by its ID, send a DELETE request to the /schemas/{id} endpoint.

Deleting a Schema by Subject

DELETE /{subject}

Delete existing schemas by their subject.

[Note]Note

This note applies to users of Spring Cloud Stream 1.1.0.RELEASE only. +Spring Cloud Stream 1.1.0.RELEASE used the table name, schema, for storing Schema objects. Schema is a keyword in a number of database implementations. +To avoid any conflicts in the future, starting with 1.1.1.RELEASE, we have opted for the name SCHEMA_REPOSITORY for the storage table. +Any Spring Cloud Stream 1.1.0.RELEASE users who upgrade should migrate their existing schemas to the new table before upgrading.

10.5.2 Using Confluent’s Schema Registry

The default configuration creates a DefaultSchemaRegistryClient bean. +If you want to use the Confluent schema registry, you need to create a bean of type ConfluentSchemaRegistryClient, which supersedes the one configured by default by the framework. The following example shows how to create such a bean:

@Bean
+public SchemaRegistryClient schemaRegistryClient(@Value("${spring.cloud.stream.schemaRegistryClient.endpoint}") String endpoint){
+  ConfluentSchemaRegistryClient client = new ConfluentSchemaRegistryClient();
+  client.setEndpoint(endpoint);
+  return client;
+}
[Note]Note

The ConfluentSchemaRegistryClient is tested against Confluent platform version 4.0.0.

10.6 Schema Registration and Resolution

To better understand how Spring Cloud Stream registers and resolves new schemas and its use of Avro schema comparison features, we provide two separate subsections:

10.6.1 Schema Registration Process (Serialization)

The first part of the registration process is extracting a schema from the payload that is being sent over a channel. +Avro types such as SpecificRecord or GenericRecord already contain a schema, which can be retrieved immediately from the instance. +In the case of POJOs, a schema is inferred if the spring.cloud.stream.schema.avro.dynamicSchemaGenerationEnabled property is set to true (the default).

Figure 10.1. Schema Writer Resolution Process

schema resolution

Ones a schema is obtained, the converter loads its metadata (version) from the remote server. +First, it queries a local cache. If no result is found, it submits the data to the server, which replies with versioning information. +The converter always caches the results to avoid the overhead of querying the Schema Server for every new message that needs to be serialized.

Figure 10.2. Schema Registration Process

registration

With the schema version information, the converter sets the contentType header of the message to carry the version information — for example: application/vnd.user.v1+avro.

10.6.2 Schema Resolution Process (Deserialization)

When reading messages that contain version information (that is, a contentType header with a scheme like the one described under Section 10.6.1, “Schema Registration Process (Serialization)”), the converter queries the Schema server to fetch the writer schema of the message. +Once it has found the correct schema of the incoming message, it retrieves the reader schema and, by using Avro’s schema resolution support, reads it into the reader definition (setting defaults and any missing properties).

Figure 10.3. Schema Reading Resolution Process

schema reading

[Note]Note

You should understand the difference between a writer schema (the application that wrote the message) and a reader schema (the receiving application). +We suggest taking a moment to read the Avro terminology and understand the process. +Spring Cloud Stream always fetches the writer schema to determine how to read a message. +If you want to get Avro’s schema evolution support working, you need to make sure that a readerSchema was properly set for your application.

11. Inter-Application Communication

Spring Cloud Stream enables communication between applications. Inter-application communication is a complex issue spanning several concerns, as described in the following topics:

11.1 Connecting Multiple Application Instances

While Spring Cloud Stream makes it easy for individual Spring Boot applications to connect to messaging systems, the typical scenario for Spring Cloud Stream is the creation of multi-application pipelines, where microservice applications send data to each other. +You can achieve this scenario by correlating the input and output destinations of adjacent applications.

Suppose a design calls for the Time Source application to send data to the Log Sink application. You could use a common destination named ticktock for bindings within both applications.

Time Source (that has the channel name output) would set the following property:

spring.cloud.stream.bindings.output.destination=ticktock

Log Sink (that has the channel name input) would set the following property:

spring.cloud.stream.bindings.input.destination=ticktock

11.2 Instance Index and Instance Count

When scaling up Spring Cloud Stream applications, each instance can receive information about how many other instances of the same application exist and what its own instance index is. +Spring Cloud Stream does this through the spring.cloud.stream.instanceCount and spring.cloud.stream.instanceIndex properties. +For example, if there are three instances of a HDFS sink application, all three instances have spring.cloud.stream.instanceCount set to 3, and the individual applications have spring.cloud.stream.instanceIndex set to 0, 1, and 2, respectively.

When Spring Cloud Stream applications are deployed through Spring Cloud Data Flow, these properties are configured automatically; when Spring Cloud Stream applications are launched independently, these properties must be set correctly. +By default, spring.cloud.stream.instanceCount is 1, and spring.cloud.stream.instanceIndex is 0.

In a scaled-up scenario, correct configuration of these two properties is important for addressing partitioning behavior (see below) in general, and the two properties are always required by certain binders (for example, the Kafka binder) in order to ensure that data are split correctly across multiple consumer instances.

11.3 Partitioning

Partitioning in Spring Cloud Stream consists of two tasks:

11.3.1 Configuring Output Bindings for Partitioning

You can configure an output binding to send partitioned data by setting one and only one of its partitionKeyExpression or partitionKeyExtractorName properties, as well as its partitionCount property.

For example, the following is a valid and typical configuration:

spring.cloud.stream.bindings.output.producer.partitionKeyExpression=payload.id
+spring.cloud.stream.bindings.output.producer.partitionCount=5

Based on that example configuration, data is sent to the target partition by using the following logic.

A partition key’s value is calculated for each message sent to a partitioned output channel based on the partitionKeyExpression. +The partitionKeyExpression is a SpEL expression that is evaluated against the outbound message for extracting the partitioning key.

If a SpEL expression is not sufficient for your needs, you can instead calculate the partition key value by providing an implementation of org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy and configuring it as a bean (by using the @Bean annotation). +If you have more then one bean of type org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy available in the Application Context, you can further filter it by specifying its name with the partitionKeyExtractorName property, as shown in the following example:

--spring.cloud.stream.bindings.output.producer.partitionKeyExtractorName=customPartitionKeyExtractor
+--spring.cloud.stream.bindings.output.producer.partitionCount=5
+. . .
+@Bean
+public CustomPartitionKeyExtractorClass customPartitionKeyExtractor() {
+    return new CustomPartitionKeyExtractorClass();
+}
[Note]Note

In previous versions of Spring Cloud Stream, you could specify the implementation of org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy by setting the spring.cloud.stream.bindings.output.producer.partitionKeyExtractorClass property. +Since version 2.0, this property is deprecated, and support for it will be removed in a future version.

Once the message key is calculated, the partition selection process determines the target partition as a value between 0 and partitionCount - 1. +The default calculation, applicable in most scenarios, is based on the following formula: key.hashCode() % partitionCount. +This can be customized on the binding, either by setting a SpEL expression to be evaluated against the 'key' (through the partitionSelectorExpression property) or by configuring an implementation of org.springframework.cloud.stream.binder.PartitionSelectorStrategy as a bean (by using the @Bean annotation). +Similar to the PartitionKeyExtractorStrategy, you can further filter it by using the spring.cloud.stream.bindings.output.producer.partitionSelectorName property when more than one bean of this type is available in the Application Context, as shown in the following example:

--spring.cloud.stream.bindings.output.producer.partitionSelectorName=customPartitionSelector
+. . .
+@Bean
+public CustomPartitionSelectorClass customPartitionSelector() {
+    return new CustomPartitionSelectorClass();
+}
[Note]Note

In previous versions of Spring Cloud Stream you could specify the implementation of org.springframework.cloud.stream.binder.PartitionSelectorStrategy by setting the spring.cloud.stream.bindings.output.producer.partitionSelectorClass property. +Since version 2.0, this property is deprecated and support for it will be removed in a future version.

11.3.2 Configuring Input Bindings for Partitioning

An input binding (with the channel name input) is configured to receive partitioned data by setting its partitioned property, as well as the instanceIndex and instanceCount properties on the application itself, as shown in the following example:

spring.cloud.stream.bindings.input.consumer.partitioned=true
+spring.cloud.stream.instanceIndex=3
+spring.cloud.stream.instanceCount=5

The instanceCount value represents the total number of application instances between which the data should be partitioned. +The instanceIndex must be a unique value across the multiple instances, with a value between 0 and instanceCount - 1. +The instance index helps each application instance to identify the unique partition(s) from which it receives data. +It is required by binders using technology that does not support partitioning natively. +For example, with RabbitMQ, there is a queue for each partition, with the queue name containing the instance index. +With Kafka, if autoRebalanceEnabled is true (default), Kafka takes care of distributing partitions across instances, and these properties are not required. +If autoRebalanceEnabled is set to false, the instanceCount and instanceIndex are used by the binder to determine which partition(s) the instance subscribes to (you must have at least as many partitions as there are instances). +The binder allocates the partitions instead of Kafka. +This might be useful if you want messages for a particular partition to always go to the same instance. +When a binder configuration requires them, it is important to set both values correctly in order to ensure that all of the data is consumed and that the application instances receive mutually exclusive datasets.

While a scenario in which using multiple instances for partitioned data processing may be complex to set up in a standalone case, Spring Cloud Dataflow can simplify the process significantly by populating both the input and output values correctly and by letting you rely on the runtime infrastructure to provide information about the instance index and instance count.

12. Testing

Spring Cloud Stream provides support for testing your microservice applications without connecting to a messaging system. +You can do that by using the TestSupportBinder provided by the spring-cloud-stream-test-support library, which can be added as a test dependency to the application, as shown in the following example:

   <dependency>
+       <groupId>org.springframework.cloud</groupId>
+       <artifactId>spring-cloud-stream-test-support</artifactId>
+       <scope>test</scope>
+   </dependency>
[Note]Note

The TestSupportBinder uses the Spring Boot autoconfiguration mechanism to supersede the other binders found on the classpath. +Therefore, when adding a binder as a dependency, you must make sure that the test scope is being used.

The TestSupportBinder lets you interact with the bound channels and inspect any messages sent and received by the application.

For outbound message channels, the TestSupportBinder registers a single subscriber and retains the messages emitted by the application in a MessageCollector. +They can be retrieved during tests and have assertions made against them.

You can also send messages to inbound message channels so that the consumer application can consume the messages. +The following example shows how to test both input and output channels on a processor:

@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class ExampleTest {
+
+  @Autowired
+  private Processor processor;
+
+  @Autowired
+  private MessageCollector messageCollector;
+
+  @Test
+  @SuppressWarnings("unchecked")
+  public void testWiring() {
+    Message<String> message = new GenericMessage<>("hello");
+    processor.input().send(message);
+    Message<String> received = (Message<String>) messageCollector.forChannel(processor.output()).poll();
+    assertThat(received.getPayload(), equalTo("hello world"));
+  }
+
+
+  @SpringBootApplication
+  @EnableBinding(Processor.class)
+  public static class MyProcessor {
+
+    @Autowired
+    private Processor channels;
+
+    @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
+    public String transform(String in) {
+      return in + " world";
+    }
+  }
+}

In the preceding example, we create an application that has an input channel and an output channel, both bound through the Processor interface. +The bound interface is injected into the test so that we can have access to both channels. +We send a message on the input channel, and we use the MessageCollector provided by Spring Cloud Stream’s test support to capture that the message has been sent to the output channel as a result. +Once we have received the message, we can validate that the component functions correctly.

12.1 Disabling the Test Binder Autoconfiguration

The intent behind the test binder superseding all the other binders on the classpath is to make it easy to test your applications without making changes to your production dependencies. +In some cases (for example, integration tests) it is useful to use the actual production binders instead, and that requires disabling the test binder autoconfiguration. +To do so, you can exclude the org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration class by using one of the Spring Boot autoconfiguration exclusion mechanisms, as shown in the following example:

    @SpringBootApplication(exclude = TestSupportBinderAutoConfiguration.class)
+    @EnableBinding(Processor.class)
+    public static class MyProcessor {
+
+        @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
+        public String transform(String in) {
+            return in + " world";
+        }
+    }

When autoconfiguration is disabled, the test binder is available on the classpath, and its defaultCandidate property is set to false so that it does not interfere with the regular user configuration. It can be referenced under the name, test, as shown in the following example:

spring.cloud.stream.defaultBinder=test

13. Health Indicator

Spring Cloud Stream provides a health indicator for binders. +It is registered under the name binders and can be enabled or disabled by setting the management.health.binders.enabled property.

To enable health check you first need to enable both "web" and "actuator" by including its dependencies (see Section 3.2.1, “Both Actuator and Web Dependencies Are Now Optional”)

If management.health.binders.enabled is not set explicitly by the application, then management.health.defaults.enabled is matched as true and the binder health indicators are enabled. +If you want to disable health indicator completely, then you have to set management.health.binders.enabled to false.

You can use Spring Boot actuator health endpoint to access the health indicator - /actuator/health. +By default, you will only receive the top level application status when you hit the above endpoint. +In order to receive the full details from the binder specific health indicators, you need to include the property management.endpoint.health.show-details with the value ALWAYS in your application.

Health indicators are binder-specific and certain binder implementations may not necessarily provide a health indicator.

If you want to completely disable all health indicators available out of the box and instead provide your own health indicators, +you can do so by setting property management.health.binders.enabled to false and then provide your own HealthIndicator beans in your application. +In this case, the health indicator infrastructure from Spring Boot will still pick up these custom beans. +Even if you are not disabling the binder health indicators, you can still enhance the health checks by providing your own HealthIndicator beans in addition to the out of the box health checks.

When you have multiple binders in the same application, health indicators are enabled by default unless the application turns them off by setting management.health.binders.enabled to false. +In this case, if the user wants to disable health check for a subset of the binders, then that should be done by setting management.health.binders.enabled to false in the multi binder configurations’s environment. +See Connecting to Multiple Systems for details on how environment specific properties can be provided.

14. Metrics Emitter

Spring Boot Actuator provides dependency management and auto-configuration for Micrometer, an application metrics +facade that supports numerous monitoring systems.

Spring Cloud Stream provides support for emitting any available micrometer-based metrics to a binding destination, allowing for periodic +collection of metric data from stream applications without relying on polling individual endpoints.

Metrics Emitter is activated by defining the spring.cloud.stream.bindings.applicationMetrics.destination property, +which specifies the name of the binding destination used by the current binder to publish metric messages.

For example:

spring.cloud.stream.bindings.applicationMetrics.destination=myMetricDestination

The preceding example instructs the binder to bind to myMetricDestination (that is, Rabbit exchange, Kafka topic, and others).

The following properties can be used for customizing the emission of metrics:

spring.cloud.stream.metrics.key

The name of the metric being emitted. Should be a unique value per application.

Default: ${spring.application.name:${vcap.application.name:${spring.config.name:application}}}

spring.cloud.stream.metrics.properties

Allows white listing application properties that are added to the metrics payload

Default: null.

spring.cloud.stream.metrics.meter-filter

Pattern to control the 'meters' one wants to capture. +For example, specifying spring.integration.* captures metric information for meters whose name starts with spring.integration.

Default: all 'meters' are captured.

spring.cloud.stream.metrics.schedule-interval

Interval to control the rate of publishing metric data.

Default: 1 min

Consider the following:

java -jar time-source.jar \
+    --spring.cloud.stream.bindings.applicationMetrics.destination=someMetrics \
+    --spring.cloud.stream.metrics.properties=spring.application** \
+    --spring.cloud.stream.metrics.meter-filter=spring.integration.*

The following example shows the payload of the data published to the binding destination as a result of the preceding command:

{
+	"name": "application",
+	"createdTime": "2018-03-23T14:48:12.700Z",
+	"properties": {
+	},
+	"metrics": [
+		{
+			"id": {
+				"name": "spring.integration.send",
+				"tags": [
+					{
+						"key": "exception",
+						"value": "none"
+					},
+					{
+						"key": "name",
+						"value": "input"
+					},
+					{
+						"key": "result",
+						"value": "success"
+					},
+					{
+						"key": "type",
+						"value": "channel"
+					}
+				],
+				"type": "TIMER",
+				"description": "Send processing time",
+				"baseUnit": "milliseconds"
+			},
+			"timestamp": "2018-03-23T14:48:12.697Z",
+			"sum": 130.340546,
+			"count": 6,
+			"mean": 21.72342433333333,
+			"upper": 116.176299,
+			"total": 130.340546
+		}
+	]
+}
[Note]Note

Given that the format of the Metric message has slightly changed after migrating to Micrometer, the published message will also have +a STREAM_CLOUD_STREAM_VERSION header set to 2.x to help distinguish between Metric messages from the older versions of the Spring Cloud Stream.

15. Samples

For Spring Cloud Stream samples, see the spring-cloud-stream-samples repository on GitHub.

15.1 Deploying Stream Applications on CloudFoundry

On CloudFoundry, services are usually exposed through a special environment variable called VCAP_SERVICES.

When configuring your binder connections, you can use the values from an environment variable as explained on the dataflow Cloud Foundry Server docs.

\ No newline at end of file diff --git a/spring-cloud-stream/2.1.0.RC3/spring-cloud-stream.xml b/spring-cloud-stream/2.1.0.RC3/spring-cloud-stream.xml new file mode 100644 index 00000000..b3e7c992 --- /dev/null +++ b/spring-cloud-stream/2.1.0.RC3/spring-cloud-stream.xml @@ -0,0 +1,2900 @@ + + + + + +Spring Cloud Stream Reference Guide +2018-12-13 + + + +Sabby +Anandan + + + + +Marius +Bogoevici + + + + +Eric +Bottard + + + + +Mark +Fisher + + + + +Ilayaperumal +Gopinathan + + + + +Gunnar +Hillert + + + + +Mark +Pollack + + + + +Patrick +Peralta + + + + +Glenn +Renfro + + + + +Thomas +Risberg + + + + +Dave +Syer + + + + +David +Turanski + + + + +Janne +Valkealahti + + + + +Benjamin +Klein + + + + +Vinicius +Carvalho + + + + +Gary +Russell + + + + +Oleg +Zhurakousky + + + + +Jay +Bryant + + + + + +Preface + +A Brief History of Spring’s Data Integration Journey +Spring’s journey on Data Integration started with Spring Integration. With its programming model, it provided a consistent developer experience to build applications that can embrace Enterprise Integration Patterns to connect with external systems such as, databases, message brokers, and among others. +Fast forward to the cloud-era, where microservices have become prominent in the enterprise setting. Spring Boot transformed the way how developers built Applications. With Spring’s programming model and the runtime responsibilities handled by Spring Boot, it became seamless to develop stand-alone, production-grade Spring-based microservices. +To extend this to Data Integration workloads, Spring Integration and Spring Boot were put together into a new project. Spring Cloud Stream was born. +With Spring Cloud Stream, developers can: +* Build, test, iterate, and deploy data-centric applications in isolation. +* Apply modern microservices architecture patterns, including composition through messaging. +* Decouple application responsibilities with event-centric thinking. An event can represent something that has happened in time, to which the downstream consumer applications can react without knowing where it originated or the producer’s identity. +* Port the business logic onto message brokers (such as RabbitMQ, Apache Kafka, Amazon Kinesis). +* Interoperate between channel-based and non-channel-based application binding scenarios to support stateless and stateful computations by using Project Reactor’s Flux and Kafka Streams APIs. +* Rely on the framework’s automatic content-type support for common use-cases. Extending to different data conversion types is possible. + + +Quick Start +You can try Spring Cloud Stream in less then 5 min even before you jump into any details by following this three-step guide. +We show you how to create a Spring Cloud Stream application that receives messages coming from the messaging middleware of your choice (more on this later) and logs received messages to the console. +We call it LoggingConsumer. +While not very practical, it provides a good introduction to some of the main concepts +and abstractions, making it easier to digest the rest of this user guide. +The three steps are as follows: + + + + + + + + + + + +
+Creating a Sample Application by Using Spring Initializr +To get started, visit the Spring Initializr. From there, you can generate our LoggingConsumer application. To do so: + + +In the Dependencies section, start typing stream. +When the Cloud Stream option should appears, select it. + + +Start typing either 'kafka' or 'rabbit'. + + +Select Kafka or RabbitMQ. +Basically, you choose the messaging middleware to which your application binds. +We recommend using the one you have already installed or feel more comfortable with installing and running. +Also, as you can see from the Initilaizer screen, there are a few other options you can choose. +For example, you can choose Gradle as your build tool instead of Maven (the default). + + +In the Artifact field, type 'logging-consumer'. +The value of the Artifact field becomes the application name. +If you chose RabbitMQ for the middleware, your Spring Initializr should now be as follows: + + + + + + + +spring initializr + + + + +Click the Generate Project button. +Doing so downloads the zipped version of the generated project to your hard drive. + + +Unzip the file into the folder you want to use as your project directory. + + + +We encourage you to explore the many possibilities available in the Spring Initializr. +It lets you create many different kinds of Spring applications. + +
+
+Importing the Project into Your IDE +Now you can import the project into your IDE. +Keep in mind that, depending on the IDE, you may need to follow a specific import procedure. +For example, depending on how the project was generated (Maven or Gradle), you may need to follow specific import procedure (for example, in Eclipse or STS, you need to use File → Import → Maven → Existing Maven Project). +Once imported, the project must have no errors of any kind. Also, src/main/java should contain com.example.loggingconsumer.LoggingConsumerApplication. +Technically, at this point, you can run the application’s main class. +It is already a valid Spring Boot application. +However, it does not do anything, so we want to add some code. +
+
+Adding a Message Handler, Building, and Running +Modify the com.example.loggingconsumer.LoggingConsumerApplication class to look as follows: +@SpringBootApplication +@EnableBinding(Sink.class) +public class LoggingConsumerApplication { + + public static void main(String[] args) { + SpringApplication.run(LoggingConsumerApplication.class, args); + } + + @StreamListener(Sink.INPUT) + public void handle(Person person) { + System.out.println("Received: " + person); + } + + public static class Person { + private String name; + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String toString() { + return this.name; + } + } +} +As you can see from the preceding listing: + + +We have enabled Sink binding (input-no-output) by using @EnableBinding(Sink.class). +Doing so signals to the framework to initiate binding to the messaging middleware, where it automatically creates the destination (that is, queue, topic, and others) that are bound to the Sink.INPUT channel. + + +We have added a handler method to receive incoming messages of type Person. +Doing so lets you see one of the core features of the framework: It tries to automatically convert incoming message payloads to type Person. + + +You now have a fully functional Spring Cloud Stream application that does listens for messages. +From here, for simplicity, we assume you selected RabbitMQ in step one. +Assuming you have RabbitMQ installed and running, you can start the application by running its main method in your IDE. +You should see following output: + --- [ main] c.s.b.r.p.RabbitExchangeQueueProvisioner : declaring queue for inbound: input.anonymous.CbMIwdkJSBO1ZoPDOtHtCg, bound to: input + --- [ main] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: [localhost:5672] + --- [ main] o.s.a.r.c.CachingConnectionFactory : Created new connection: rabbitConnectionFactory#2a3a299:0/SimpleConnection@66c83fc8. . . + . . . + --- [ main] o.s.i.a.i.AmqpInboundChannelAdapter : started inbound.input.anonymous.CbMIwdkJSBO1ZoPDOtHtCg + . . . + --- [ main] c.e.l.LoggingConsumerApplication : Started LoggingConsumerApplication in 2.531 seconds (JVM running for 2.897) +Go to the RabbitMQ management console or any other RabbitMQ client and send a message to input.anonymous.CbMIwdkJSBO1ZoPDOtHtCg. +The anonymous.CbMIwdkJSBO1ZoPDOtHtCg part represents the group name and is generated, so it is bound to be different in your environment. +For something more predictable, you can use an explicit group name by setting spring.cloud.stream.bindings.input.group=hello (or whatever name you like). +The contents of the message should be a JSON representation of the Person class, as follows: +{"name":"Sam Spade"} +Then, in your console, you should see: +Received: Sam Spade +You can also build and package your application into a boot jar (by using ./mvnw clean install) and run the built JAR by using the java -jar command. +Now you have a working (albeit very basic) Spring Cloud Stream application. +
+
+ +What’s New in 2.0? +Spring Cloud Stream introduces a number of new features, enhancements, and changes. The following sections outline the most notable ones: + + + + + + + + +
+New Features and Components + + +Polling Consumers: Introduction of polled consumers, which lets the application control message processing rates. +See for more details. +You can also read this blog post for more details. + + +Micrometer Support: Metrics has been switched to use Micrometer. +MeterRegistry is also provided as a bean so that custom applications can autowire it to capture custom metrics. +See for more details. + + +New Actuator Binding Controls: New actuator binding controls let you both visualize and control the Bindings lifecycle. +For more details, see . + + +Configurable RetryTemplate: Aside from providing properties to configure RetryTemplate, we now let you provide your own template, effectively overriding the one provided by the framework. +To use it, configure it as a @Bean in your application. + + +
+
+Notable Enhancements +This version includes the following notable enhancements: + + + + + + + + + + + +
+Both Actuator and Web Dependencies Are Now Optional +This change slims down the footprint of the deployed application in the event neither actuator nor web dependencies required. +It also lets you switch between the reactive and conventional web paradigms by manually adding one of the following dependencies. +The following listing shows how to add the conventional web framework: +<dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> +</dependency> +The following listing shows how to add the reactive web framework: +<dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-webflux</artifactId> +</dependency> +The following list shows how to add the actuator dependency: +<dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> +</dependency> +
+
+Content-type Negotiation Improvements +One of the core themes for verion 2.0 is improvements (in both consistency and performance) around content-type negotiation and message conversion. +The following summary outlines the notable changes and improvements in this area. +See the section for more details. +Also this blog post contains more detail. + + +All message conversion is now handled only by MessageConverter objects. + + +We introduced the @StreamMessageConverter annotation to provide custom MessageConverter objects. + + +We introduced the default Content Type as application/json, which needs to be taken into consideration when migrating 1.3 application or operating in the mixed mode (that is, 1.3 producer → 2.0 consumer). + + +Messages with textual payloads and a contentType of text/…​ or …​/json are no longer converted to Message<String> for cases where the argument type of the provided MessageHandler can not be determined (that is, public void handle(Message<?> message) or public void handle(Object payload)). +Furthermore, a strong argument type may not be enough to properly convert messages, so the contentType header may be used as a supplement by some MessageConverters. + + +
+
+
+Notable Deprecations +As of version 2.0, the following items have been deprecated: + + + + + + + + +
+Java Serialization (Java Native and Kryo) +JavaSerializationMessageConverter and KryoMessageConverter remain for now. However, we plan to move them out of the core packages and support in the future. +The main reason for this deprecation is to flag the issue that type-based, language-specific serialization could cause in distributed environments, where Producers and Consumers may depend on different JVM versions or have different versions of supporting libraries (that is, Kryo). +We also wanted to draw the attention to the fact that Consumers and Producers may not even be Java-based, so polyglot style serialization (i.e., JSON) is better suited. +
+
+Deprecated Classes and Methods +The following is a quick summary of notable deprecations. See the corresponding {spring-cloud-stream-javadoc-current}[javadoc] for more details. + + +SharedChannelRegistry. Use SharedBindingTargetRegistry. + + +Bindings. +Beans qualified by it are already uniquely identified by their type — for example, provided Source, Processor, or custom bindings: + + +public interface Sample { + String OUTPUT = "sampleOutput"; + + @Output(Sample.OUTPUT) + MessageChannel output(); +} + + +HeaderMode.raw. Use none, headers or embeddedHeaders + + +ProducerProperties.partitionKeyExtractorClass in favor of partitionKeyExtractorName and ProducerProperties.partitionSelectorClass in favor of partitionSelectorName. +This change ensures that both components are Spring configured and managed and are referenced in a Spring-friendly way. + + +BinderAwareRouterBeanPostProcessor. While the component remains, it is no longer a BeanPostProcessor and will be renamed in the future. + + +BinderProperties.setEnvironment(Properties environment). Use BinderProperties.setEnvironment(Map<String, Object> environment). + + + +
+
+
+ +Introducing Spring Cloud Stream +Spring Cloud Stream is a framework for building message-driven microservice applications. +Spring Cloud Stream builds upon Spring Boot to create standalone, production-grade Spring applications and uses Spring Integration to provide connectivity to message brokers. +It provides opinionated configuration of middleware from several vendors, introducing the concepts of persistent publish-subscribe semantics, consumer groups, and partitions. +You can add the @EnableBinding annotation to your application to get immediate connectivity to a message broker, and you can add @StreamListener to a method to cause it to receive events for stream processing. +The following example shows a sink application that receives external messages: +@SpringBootApplication +@EnableBinding(Sink.class) +public class VoteRecordingSinkApplication { + + public static void main(String[] args) { + SpringApplication.run(VoteRecordingSinkApplication.class, args); + } + + @StreamListener(Sink.INPUT) + public void processVote(Vote vote) { + votingService.recordVote(vote); + } +} +The @EnableBinding annotation takes one or more interfaces as parameters (in this case, the parameter is a single Sink interface). +An interface declares input and output channels. +Spring Cloud Stream provides the Source, Sink, and Processor interfaces. You can also define your own interfaces. +The following listing shows the definition of the Sink interface: +public interface Sink { + String INPUT = "input"; + + @Input(Sink.INPUT) + SubscribableChannel input(); +} +The @Input annotation identifies an input channel, through which received messages enter the application. +The @Output annotation identifies an output channel, through which published messages leave the application. +The @Input and @Output annotations can take a channel name as a parameter. +If a name is not provided, the name of the annotated method is used. +Spring Cloud Stream creates an implementation of the interface for you. +You can use this in the application by autowiring it, as shown in the following example (from a test case): +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = VoteRecordingSinkApplication.class) +@WebAppConfiguration +@DirtiesContext +public class StreamApplicationTests { + + @Autowired + private Sink sink; + + @Test + public void contextLoads() { + assertNotNull(this.sink.input()); + } +} + + +Main Concepts +Spring Cloud Stream provides a number of abstractions and primitives that simplify the writing of message-driven microservice applications. +This section gives an overview of the following: + + +Spring Cloud Stream’s application model + + + + + +Persistent publish-subscribe support + + +Consumer group support + + +Partitioning support + + +A pluggable Binder SPI + + +
+Application Model +A Spring Cloud Stream application consists of a middleware-neutral core. +The application communicates with the outside world through input and output channels injected into it by Spring Cloud Stream. +Channels are connected to external brokers through middleware-specific Binder implementations. +
+Spring Cloud Stream Application + + + + +SCSt with binder + +
+
+Fat JAR +Spring Cloud Stream applications can be run in stand-alone mode from your IDE for testing. +To run a Spring Cloud Stream application in production, you can create an executable (or fat) JAR by using the standard Spring Boot tooling provided for Maven or Gradle. See the Spring Boot Reference Guide for more details. +
+
+
+The Binder Abstraction +Spring Cloud Stream provides Binder implementations for Kafka and Rabbit MQ. +Spring Cloud Stream also includes a TestSupportBinder, which leaves a channel unmodified so that tests can interact with channels directly and reliably assert on what is received. +You can also use the extensible API to write your own Binder. +Spring Cloud Stream uses Spring Boot for configuration, and the Binder abstraction makes it possible for a Spring Cloud Stream application to be flexible in how it connects to middleware. +For example, deployers can dynamically choose, at runtime, the destinations (such as the Kafka topics or RabbitMQ exchanges) to which channels connect. +Such configuration can be provided through external configuration properties and in any form supported by Spring Boot (including application arguments, environment variables, and application.yml or application.properties files). +In the sink example from the section, setting the spring.cloud.stream.bindings.input.destination application property to raw-sensor-data causes it to read from the raw-sensor-data Kafka topic or from a queue bound to the raw-sensor-data RabbitMQ exchange. +Spring Cloud Stream automatically detects and uses a binder found on the classpath. +You can use different types of middleware with the same code. +To do so, include a different binder at build time. +For more complex use cases, you can also package multiple binders with your application and have it choose the binder( and even whether to use different binders for different channels) at runtime. +
+
+Persistent Publish-Subscribe Support +Communication between applications follows a publish-subscribe model, where data is broadcast through shared topics. +This can be seen in the following figure, which shows a typical deployment for a set of interacting Spring Cloud Stream applications. +
+Spring Cloud Stream Publish-Subscribe + + + + +SCSt sensors + +
+Data reported by sensors to an HTTP endpoint is sent to a common destination named raw-sensor-data. +From the destination, it is independently processed by a microservice application that computes time-windowed averages and by another microservice application that ingests the raw data into HDFS (Hadoop Distributed File System). +In order to process the data, both applications declare the topic as their input at runtime. +The publish-subscribe communication model reduces the complexity of both the producer and the consumer and lets new applications be added to the topology without disruption of the existing flow. +For example, downstream from the average-calculating application, you can add an application that calculates the highest temperature values for display and monitoring. +You can then add another application that interprets the same flow of averages for fault detection. +Doing all communication through shared topics rather than point-to-point queues reduces coupling between microservices. +While the concept of publish-subscribe messaging is not new, Spring Cloud Stream takes the extra step of making it an opinionated choice for its application model. +By using native middleware support, Spring Cloud Stream also simplifies use of the publish-subscribe model across different platforms. +
+
+Consumer Groups +While the publish-subscribe model makes it easy to connect applications through shared topics, the ability to scale up by creating multiple instances of a given application is equally important. +When doing so, different instances of an application are placed in a competing consumer relationship, where only one of the instances is expected to handle a given message. +Spring Cloud Stream models this behavior through the concept of a consumer group. +(Spring Cloud Stream consumer groups are similar to and inspired by Kafka consumer groups.) +Each consumer binding can use the spring.cloud.stream.bindings.<channelName>.group property to specify a group name. +For the consumers shown in the following figure, this property would be set as spring.cloud.stream.bindings.<channelName>.group=hdfsWrite or spring.cloud.stream.bindings.<channelName>.group=average. +
+Spring Cloud Stream Consumer Groups + + + + +SCSt groups + +
+All groups that subscribe to a given destination receive a copy of published data, but only one member of each group receives a given message from that destination. +By default, when a group is not specified, Spring Cloud Stream assigns the application to an anonymous and independent single-member consumer group that is in a publish-subscribe relationship with all other consumer groups. +
+
+Consumer Types +Two types of consumer are supported: + + +Message-driven (sometimes referred to as Asynchronous) + + +Polled (sometimes referred to as Synchronous) + + +Prior to version 2.0, only asynchronous consumers were supported. A message is delivered as soon as it is available and a thread is available to process it. +When you wish to control the rate at which messages are processed, you might want to use a synchronous consumer. +
+Durability +Consistent with the opinionated application model of Spring Cloud Stream, consumer group subscriptions are durable. +That is, a binder implementation ensures that group subscriptions are persistent and that, once at least one subscription for a group has been created, the group receives messages, even if they are sent while all applications in the group are stopped. + +Anonymous subscriptions are non-durable by nature. +For some binder implementations (such as RabbitMQ), it is possible to have non-durable group subscriptions. + +In general, it is preferable to always specify a consumer group when binding an application to a given destination. +When scaling up a Spring Cloud Stream application, you must specify a consumer group for each of its input bindings. +Doing so prevents the application’s instances from receiving duplicate messages (unless that behavior is desired, which is unusual). +
+
+
+Partitioning Support +Spring Cloud Stream provides support for partitioning data between multiple instances of a given application. +In a partitioned scenario, the physical communication medium (such as the broker topic) is viewed as being structured into multiple partitions. +One or more producer application instances send data to multiple consumer application instances and ensure that data identified by common characteristics are processed by the same consumer instance. +Spring Cloud Stream provides a common abstraction for implementing partitioned processing use cases in a uniform fashion. +Partitioning can thus be used whether the broker itself is naturally partitioned (for example, Kafka) or not (for example, RabbitMQ). +
+Spring Cloud Stream Partitioning + + + + +SCSt partitioning + +
+Partitioning is a critical concept in stateful processing, where it is critical (for either performance or consistency reasons) to ensure that all related data is processed together. +For example, in the time-windowed average calculation example, it is important that all measurements from any given sensor are processed by the same application instance. + +To set up a partitioned processing scenario, you must configure both the data-producing and the data-consuming ends. + +
+
+ +Programming Model +To understand the programming model, you should be familiar with the following core concepts: + + +Destination Binders: Components responsible to provide integration with the external messaging systems. + + +Destination Bindings: Bridge between the external messaging systems and application provided Producers and Consumers of messages (created by the Destination Binders). + + +Message: The canonical data structure used by producers and consumers to communicate with Destination Binders (and thus other applications via external messaging systems). + + + + + + + +SCSt overview + + +
+Destination Binders +Destination Binders are extension components of Spring Cloud Stream responsible for providing the necessary configuration and implementation to facilitate +integration with external messaging systems. +This integration is responsible for connectivity, delegation, and routing of messages to and from producers and consumers, data type conversion, +invocation of the user code, and more. +Binders handle a lot of the boiler plate responsibilities that would otherwise fall on your shoulders. However, to accomplish that, the binder still needs +some help in the form of minimalistic yet required set of instructions from the user, which typically come in the form of some type of configuration. +While it is out of scope of this section to discuss all of the available binder and binding configuration options (the rest of the manual covers them extensively), +Destination Binding does require special attention. The next section discusses it in detail. +
+
+Destination Bindings +As stated earlier, Destination Bindings provide a bridge between the external messaging system and application-provided Producers and Consumers. +Applying the @EnableBinding annotation to one of the application’s configuration classes defines a destination binding. +The @EnableBinding annotation itself is meta-annotated with @Configuration and triggers the configuration of the Spring Cloud Stream infrastructure. +The following example shows a fully configured and functioning Spring Cloud Stream application that receives the payload of the message from the INPUT +destination as a String type (see section), logs it to the console and sends it to the OUTPUT destination after converting it to upper case. +@SpringBootApplication +@EnableBinding(Processor.class) +public class MyApplication { + + public static void main(String[] args) { + SpringApplication.run(MyApplication.class, args); + } + + @StreamListener(Processor.INPUT) + @SendTo(Processor.OUTPUT) + public String handle(String value) { + System.out.println("Received: " + value); + return value.toUpperCase(); + } +} +As you can see the @EnableBinding annotation can take one or more interface classes as parameters. The parameters are referred to as bindings, +and they contain methods representing bindable components. +These components are typically message channels (see Spring Messaging) +for channel-based binders (such as Rabbit, Kafka, and others). However other types of bindings can +provide support for the native features of the corresponding technology. For example Kafka Streams binder (formerly known as KStream) allows native bindings directly to Kafka Streams +(see Kafka Streams for more details). +Spring Cloud Stream already provides binding interfaces for typical message exchange contracts, which include: + + +Sink: Identifies the contract for the message consumer by providing the destination from which the message is consumed. + + +Source: Identifies the contract for the message producer by providing the destination to which the produced message is sent. + + +Processor: Encapsulates both the sink and the source contracts by exposing two destinations that allow consumption and production of messages. + + +public interface Sink { + + String INPUT = "input"; + + @Input(Sink.INPUT) + SubscribableChannel input(); +} +public interface Source { + + String OUTPUT = "output"; + + @Output(Source.OUTPUT) + MessageChannel output(); +} +public interface Processor extends Source, Sink {} +While the preceding example satisfies the majority of cases, you can also define your own contracts by defining your own bindings interfaces and use @Input and @Output +annotations to identify the actual bindable components. +For example: +public interface Barista { + + @Input + SubscribableChannel orders(); + + @Output + MessageChannel hotDrinks(); + + @Output + MessageChannel coldDrinks(); +} +Using the interface shown in the preceding example as a parameter to @EnableBinding triggers the creation of the three bound channels named orders, hotDrinks, and coldDrinks, +respectively. +You can provide as many binding interfaces as you need, as arguments to the @EnableBinding annotation, as shown in the following example: +@EnableBinding(value = { Orders.class, Payment.class }) +In Spring Cloud Stream, the bindable MessageChannel components are the Spring Messaging MessageChannel (for outbound) and its extension, SubscribableChannel, +(for inbound). +Pollable Destination Binding +While the previously described bindings support event-based message consumption, sometimes you need more control, such as rate of consumption. +Starting with version 2.0, you can now bind a pollable consumer: +The following example shows how to bind a pollable consumer: +public interface PolledBarista { + + @Input + PollableMessageSource orders(); + . . . +} +In this case, an implementation of PollableMessageSource is bound to the orders “channel”. See for more details. +Customizing Channel Names +By using the @Input and @Output annotations, you can specify a customized channel name for the channel, as shown in the following example: +public interface Barista { + @Input("inboundOrders") + SubscribableChannel orders(); +} +In the preceding example, the created bound channel is named inboundOrders. +Normally, you need not access individual channels or bindings directly (other then configuring them via @EnableBinding annotation). However there may be +times, such as testing or other corner cases, when you do. +Aside from generating channels for each binding and registering them as Spring beans, for each bound interface, Spring Cloud Stream generates a bean that implements the interface. +That means you can have access to the interfaces representing the bindings or individual channels by auto-wiring either in your application, as shown in the following two examples: +Autowire Binding interface +@Autowire +private Source source + +public void sayHello(String name) { + source.output().send(MessageBuilder.withPayload(name).build()); +} +Autowire individual channel +@Autowire +private MessageChannel output; + +public void sayHello(String name) { + output.send(MessageBuilder.withPayload(name).build()); +} +You can also use standard Spring’s @Qualifier annotation for cases when channel names are customized or in multiple-channel scenarios that require specifically named channels. +The following example shows how to use the @Qualifier annotation in this way: +@Autowire +@Qualifier("myChannel") +private MessageChannel output; +
+
+Producing and Consuming Messages +You can write a Spring Cloud Stream application by using either Spring Integration annotations or Spring Cloud Stream native annotation. +
+Spring Integration Support +Spring Cloud Stream is built on the concepts and patterns defined by Enterprise Integration Patterns and relies +in its internal implementation on an already established and popular implementation of Enterprise Integration Patterns within the Spring portfolio of projects: +Spring Integration framework. +So its only natural for it to support the foundation, semantics, and configuration options that are already established by Spring Integration +For example, you can attach the output channel of a Source to a MessageSource and use the familiar @InboundChannelAdapter annotation, as follows: +@EnableBinding(Source.class) +public class TimerSource { + + @Bean + @InboundChannelAdapter(value = Source.OUTPUT, poller = @Poller(fixedDelay = "10", maxMessagesPerPoll = "1")) + public MessageSource<String> timerMessageSource() { + return () -> new GenericMessage<>("Hello Spring Cloud Stream"); + } +} +Similarly, you can use @Transformer or @ServiceActivator while providing an implementation of a message handler method for a Processor binding contract, as shown in the following example: +@EnableBinding(Processor.class) +public class TransformProcessor { + @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) + public Object transform(String message) { + return message.toUpperCase(); + } +} + +While this may be skipping ahead a bit, it is important to understand that, when you consume from the same binding using @StreamListener annotation, a pub-sub model is used. +Each method annotated with @StreamListener receives its own copy of a message, and each one has its own consumer group. +However, if you consume from the same binding by using one of the Spring Integration annotation (such as @Aggregator, @Transformer, or @ServiceActivator), those consume in a competing model. +No individual consumer group is created for each subscription. + +
+
+Using @StreamListener Annotation +Complementary to its Spring Integration support, Spring Cloud Stream provides its own @StreamListener annotation, modeled after other Spring Messaging annotations +(@MessageMapping, @JmsListener, @RabbitListener, and others) and provides conviniences, such as content-based routing and others. +@EnableBinding(Sink.class) +public class VoteHandler { + + @Autowired + VotingService votingService; + + @StreamListener(Sink.INPUT) + public void handle(Vote vote) { + votingService.record(vote); + } +} +As with other Spring Messaging methods, method arguments can be annotated with @Payload, @Headers, and @Header. +For methods that return data, you must use the @SendTo annotation to specify the output binding destination for data returned by the method, as shown in the following example: +@EnableBinding(Processor.class) +public class TransformProcessor { + + @Autowired + VotingService votingService; + + @StreamListener(Processor.INPUT) + @SendTo(Processor.OUTPUT) + public VoteResult handle(Vote vote) { + return votingService.record(vote); + } +} +
+
+Using @StreamListener for Content-based routing +Spring Cloud Stream supports dispatching messages to multiple handler methods annotated with @StreamListener based on conditions. +In order to be eligible to support conditional dispatching, a method must satisfy the follow conditions: + + +It must not return a value. + + +It must be an individual message handling method (reactive API methods are not supported). + + +The condition is specified by a SpEL expression in the condition argument of the annotation and is evaluated for each message. +All the handlers that match the condition are invoked in the same thread, and no assumption must be made about the order in which the invocations take place. +In the following example of a @StreamListener with dispatching conditions, all the messages bearing a header type with the value bogey are dispatched to the +receiveBogey method, and all the messages bearing a header type with the value bacall are dispatched to the receiveBacall method. +@EnableBinding(Sink.class) +@EnableAutoConfiguration +public static class TestPojoWithAnnotatedArguments { + + @StreamListener(target = Sink.INPUT, condition = "headers['type']=='bogey'") + public void receiveBogey(@Payload BogeyPojo bogeyPojo) { + // handle the message + } + + @StreamListener(target = Sink.INPUT, condition = "headers['type']=='bacall'") + public void receiveBacall(@Payload BacallPojo bacallPojo) { + // handle the message + } +} +Content Type Negotiation in the Context of condition +It is important to understand some of the mechanics behind content-based routing using the condition argument of @StreamListener, especially in the context of the type of the message as a whole. +It may also help if you familiarize yourself with the before you proceed. +Consider the following scenario: +@EnableBinding(Sink.class) +@EnableAutoConfiguration +public static class CatsAndDogs { + + @StreamListener(target = Sink.INPUT, condition = "payload.class.simpleName=='Dog'") + public void bark(Dog dog) { + // handle the message + } + + @StreamListener(target = Sink.INPUT, condition = "payload.class.simpleName=='Cat'") + public void purr(Cat cat) { + // handle the message + } +} +The preceding code is perfectly valid. It compiles and deploys without any issues, yet it never produces the result you expect. +That is because you are testing something that does not yet exist in a state you expect. That is because the payload of the message is not yet converted from the +wire format (byte[]) to the desired type. +In other words, it has not yet gone through the type conversion process described in the . +So, unless you use a SPeL expression that evaluates raw data (for example, the value of the first byte in the byte array), use message header-based expressions +(such as condition = "headers['type']=='dog'"). + +At the moment, dispatching through @StreamListener conditions is supported only for channel-based binders (not for reactive programming) +support. + +
+
+Spring Cloud Function support +Since Spring Cloud Stream v2.1, another alternative for defining stream handlers and sources is to use build-in +support for Spring Cloud Function where they can be expressed as beans of + type java.util.function.[Supplier/Function/Consumer]. +To specify which functional bean to bind to the external destination(s) exposed by the bindings, you must provide spring.cloud.stream.function.definition property. +Here is the example of the Processor application exposing message handler as java.util.function.Function +@SpringBootApplication +@EnableBinding(Processor.class) +public class MyFunctionBootApp { + + public static void main(String[] args) { + SpringApplication.run(MyFunctionBootApp.class, "--spring.cloud.stream.function.definition=toUpperCase"); + } + + @Bean + public Function<String, String> toUpperCase() { + return s -> s.toUpperCase(); + } +} +In the above you we simply define a bean of type java.util.function.Function called toUpperCase and identify it as a bean to be used as message handler +whose 'input' and 'output' must be bound to the external destinations exposed by the Processor binding. +Below are the examples of simple functional applications to support Source, Processor and Sink. +Here is the example of a Source application defined as java.util.function.Supplier +@SpringBootApplication +@EnableBinding(Source.class) +public static class SourceFromSupplier { + public static void main(String[] args) { + SpringApplication.run(SourceFromSupplier.class, "--spring.cloud.stream.function.definition=date"); + } + @Bean + public Supplier<Date> date() { + return () -> new Date(12345L); + } +} +Here is the example of a Processor application defined as java.util.function.Function +@SpringBootApplication +@EnableBinding(Processor.class) +public static class ProcessorFromFunction { + public static void main(String[] args) { + SpringApplication.run(ProcessorFromFunction.class, "--spring.cloud.stream.function.definition=toUpperCase"); + } + @Bean + public Function<String, String> toUpperCase() { + return s -> s.toUpperCase(); + } +} +Here is the example of a Sink application defined as java.util.function.Consumer +@EnableAutoConfiguration +@EnableBinding(Sink.class) +public static class SinkFromConsumer { + public static void main(String[] args) { + SpringApplication.run(SinkFromConsumer.class, "--spring.cloud.stream.function.definition=sink"); + } + @Bean + public Consumer<String> sink() { + return System.out::println; + } +} +
+Functional Composition +Using this programming model you can also benefit from functional composition where you can dynamically compose complex handlers from a set of simple functions. +As an example let’s add the following function bean to the application defined above +@Bean +public Function<String, String> wrapInQuotes() { + return s -> "\"" + s + "\""; +} +and modify the spring.cloud.stream.function.definition property to reflect your intention to compose a new function from both ‘toUpperCase’ and ‘wrapInQuotes’. +To do that Spring Cloud Function allows you to use | (pipe) symbol. So to finish our example our property will now look like this: +—spring.cloud.stream.function.definition=toUpperCase|wrapInQuotes +
+
+
+Using Polled Consumers +
+Overview +When using polled consumers, you poll the PollableMessageSource on demand. +Consider the following example of a polled consumer: +public interface PolledConsumer { + + @Input + PollableMessageSource destIn(); + + @Output + MessageChannel destOut(); + +} +Given the polled consumer in the preceding example, you might use it as follows: +@Bean +public ApplicationRunner poller(PollableMessageSource destIn, MessageChannel destOut) { + return args -> { + while (someCondition()) { + try { + if (!destIn.poll(m -> { + String newPayload = ((String) m.getPayload()).toUpperCase(); + destOut.send(new GenericMessage<>(newPayload)); + })) { + Thread.sleep(1000); + } + } + catch (Exception e) { + // handle failure + } + } + }; +} +The PollableMessageSource.poll() method takes a MessageHandler argument (often a lambda expression, as shown here). +It returns true if the message was received and successfully processed. +As with message-driven consumers, if the MessageHandler throws an exception, messages are published to error channels, +as discussed in . +Normally, the poll() method acknowledges the message when the MessageHandler exits. +If the method exits abnormally, the message is rejected (not re-queued), but see . +You can override that behavior by taking responsibility for the acknowledgment, as shown in the following example: +@Bean +public ApplicationRunner poller(PollableMessageSource dest1In, MessageChannel dest2Out) { + return args -> { + while (someCondition()) { + if (!dest1In.poll(m -> { + StaticMessageHeaderAccessor.getAcknowledgmentCallback(m).noAutoAck(); + // e.g. hand off to another thread which can perform the ack + // or acknowledge(Status.REQUEUE) + + })) { + Thread.sleep(1000); + } + } + }; +} + +You must ack (or nack) the message at some point, to avoid resource leaks. + + +Some messaging systems (such as Apache Kafka) maintain a simple offset in a log. If a delivery fails and is re-queued with StaticMessageHeaderAccessor.getAcknowledgmentCallback(m).acknowledge(Status.REQUEUE);, any later successfully ack’d messages are redelivered. + +There is also an overloaded poll method, for which the definition is as follows: +poll(MessageHandler handler, ParameterizedTypeReference<?> type) +The type is a conversion hint that allows the incoming message payload to be converted, as shown in the following example: +boolean result = pollableSource.poll(received -> { + Map<String, Foo> payload = (Map<String, Foo>) received.getPayload(); + ... + + }, new ParameterizedTypeReference<Map<String, Foo>>() {}); +
+
+Handling Errors +By default, an error channel is configured for the pollable source; if the callback throws an exception, an ErrorMessage is sent to the error channel (<destination>.<group>.errors); this error channel is also bridged to the global Spring Integration errorChannel. +You can subscribe to either error channel with a @ServiceActivator to handle errors; without a subscription, the error will simply be logged and the message will be acknowledged as successful. +If the error channel service activator throws an exception, the message will be rejected (by default) and won’t be redelivered. +If the service activator throws a RequeueCurrentMessageException, the message will be requeued at the broker and will be again retrieved on a subsequent poll. +If the listener throws a RequeueCurrentMessageException directly, the message will be requeued, as discussed above, and will not be sent to the error channels. +
+
+
+
+Error Handling +Errors happen, and Spring Cloud Stream provides several flexible mechanisms to handle them. +The error handling comes in two flavors: + + +application: The error handling is done within the application (custom error handler). + + +system: The error handling is delegated to the binder (re-queue, DL, and others). Note that the techniques are dependent on binder implementation and the +capability of the underlying messaging middleware. + + +Spring Cloud Stream uses the Spring Retry library to facilitate successful message processing. See for more details. +However, when all fails, the exceptions thrown by the message handlers are propagated back to the binder. At that point, binder invokes custom error handler or communicates +the error back to the messaging system (re-queue, DLQ, and others). +
+Application Error Handling +There are two types of application-level error handling. Errors can be handled at each binding subscription or a global handler can handle all the binding subscription errors. Let’s review the details. +
+A Spring Cloud Stream Sink Application with Custom and Global Error Handlers + + + + +custom vs global error channels + +
+For each input binding, Spring Cloud Stream creates a dedicated error channel with the following semantics <destinationName>.errors. + +The <destinationName> consists of the name of the binding (such as input) and the name of the group (such as myGroup). + +Consider the following: +spring.cloud.stream.bindings.input.group=myGroup +@StreamListener(Sink.INPUT) // destination name 'input.myGroup' +public void handle(Person value) { + throw new RuntimeException("BOOM!"); +} + +@ServiceActivator(inputChannel = Processor.INPUT + ".myGroup.errors") //channel name 'input.myGroup.errors' +public void error(Message<?> message) { + System.out.println("Handling ERROR: " + message); +} +In the preceding example the destination name is input.myGroup and the dedicated error channel name is input.myGroup.errors. + +The use of @StreamListener annotation is intended specifically to define bindings that bridge internal channels and external destinations. Given that the destination +specific error channel does NOT have an associated external destination, such channel is a prerogative of Spring Integration (SI). This means that the handler +for such destination must be defined using one of the SI handler annotations (i.e., @ServiceActivator, @Transformer etc.). + + +If group is not specified anonymous group is used (something like input.anonymous.2K37rb06Q6m2r51-SPIDDQ), which is not suitable for error +handling scenarious, since you don’t know what it’s going to be until the destination is created. + +Also, in the event you are binding to the existing destination such as: +spring.cloud.stream.bindings.input.destination=myFooDestination +spring.cloud.stream.bindings.input.group=myGroup +the full destination name is myFooDestination.myGroup and then the dedicated error channel name is myFooDestination.myGroup.errors. +Back to the example…​ +The handle(..) method, which subscribes to the channel named input, throws an exception. Given there is also a subscriber to the error channel input.myGroup.errors +all error messages are handled by this subscriber. +If you have multiple bindings, you may want to have a single error handler. Spring Cloud Stream automatically provides support for +a global error channel by bridging each individual error channel to the channel named errorChannel, allowing a single subscriber to handle all errors, +as shown in the following example: +@StreamListener("errorChannel") +public void error(Message<?> message) { + System.out.println("Handling ERROR: " + message); +} +This may be a convenient option if error handling logic is the same regardless of which handler produced the error. +
+
+System Error Handling +System-level error handling implies that the errors are communicated back to the messaging system and, given that not every messaging system +is the same, the capabilities may differ from binder to binder. +That said, in this section we explain the general idea behind system level error handling and use Rabbit binder as an example. NOTE: Kafka binder provides similar +support, although some configuration properties do differ. Also, for more details and configuration options, see the individual binder’s documentation. +If no internal error handlers are configured, the errors propagate to the binders, and the binders subsequently propagate those errors back to the messaging system. +Depending on the capabilities of the messaging system such a system may drop the message, re-queue the message for re-processing or send the failed message to DLQ. +Both Rabbit and Kafka support these concepts. However, other binders may not, so refer to your individual binder’s documentation for details on supported system-level +error-handling options. +
+Drop Failed Messages +By default, if no additional system-level configuration is provided, the messaging system drops the failed message. +While acceptable in some cases, for most cases, it is not, and we need some recovery mechanism to avoid message loss. +
+
+DLQ - Dead Letter Queue +DLQ allows failed messages to be sent to a special destination: - Dead Letter Queue. +When configured, failed messages are sent to this destination for subsequent re-processing or auditing and reconciliation. +For example, continuing on the previous example and to set up the DLQ with Rabbit binder, you need to set the following property: +spring.cloud.stream.rabbit.bindings.input.consumer.auto-bind-dlq=true +Keep in mind that, in the above property, input corresponds to the name of the input destination binding. +The consumer indicates that it is a consumer property and auto-bind-dlq instructs the binder to configure DLQ for input +destination, which results in an additional Rabbit queue named input.myGroup.dlq. +Once configured, all failed messages are routed to this queue with an error message similar to the following: +delivery_mode: 1 +headers: +x-death: +count: 1 +reason: rejected +queue: input.hello +time: 1522328151 +exchange: +routing-keys: input.myGroup +Payload {"name”:"Bob"} +As you can see from the above, your original message is preserved for further actions. +However, one thing you may have noticed is that there is limited information on the original issue with the message processing. For example, you do not see a stack +trace corresponding to the original error. +To get more relevant information about the original error, you must set an additional property: +spring.cloud.stream.rabbit.bindings.input.consumer.republish-to-dlq=true +Doing so forces the internal error handler to intercept the error message and add additional information to it before publishing it to DLQ. +Once configured, you can see that the error message contains more information relevant to the original error, as follows: +delivery_mode: 2 +headers: +x-original-exchange: +x-exception-message: has an error +x-original-routingKey: input.myGroup +x-exception-stacktrace: org.springframework.messaging.MessageHandlingException: nested exception is + org.springframework.messaging.MessagingException: has an error, failedMessage=GenericMessage [payload=byte[15], + headers={amqp_receivedDeliveryMode=NON_PERSISTENT, amqp_receivedRoutingKey=input.hello, amqp_deliveryTag=1, + deliveryAttempt=3, amqp_consumerQueue=input.hello, amqp_redelivered=false, id=a15231e6-3f80-677b-5ad7-d4b1e61e486e, + amqp_consumerTag=amq.ctag-skBFapilvtZhDsn0k3ZmQg, contentType=application/json, timestamp=1522327846136}] + at org.spring...integ...han...MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:107) + at. . . . . +Payload {"name”:"Bob"} +This effectively combines application-level and system-level error handling to further assist with downstream troubleshooting mechanics. +
+
+Re-queue Failed Messages +As mentioned earlier, the currently supported binders (Rabbit and Kafka) rely on RetryTemplate to facilitate successful message processing. See for details. +However, for cases when max-attempts property is set to 1, internal reprocessing of the message is disabled. At this point, you can facilitate message re-processing (re-tries) +by instructing the messaging system to re-queue the failed message. Once re-queued, the failed message is sent back to the original handler, essentially creating a retry loop. +This option may be feasible for cases where the nature of the error is related to some sporadic yet short-term unavailability of some resource. +To accomplish that, you must set the following properties: +spring.cloud.stream.bindings.input.consumer.max-attempts=1 +spring.cloud.stream.rabbit.bindings.input.consumer.requeue-rejected=true +In the preceding example, the max-attempts set to 1 essentially disabling internal re-tries and requeue-rejected (short for requeue rejected messages) is set to true. +Once set, the failed message is resubmitted to the same handler and loops continuously or until the handler throws AmqpRejectAndDontRequeueException +essentially allowing you to build your own re-try logic within the handler itself. +
+
+
+Retry Template +The RetryTemplate is part of the Spring Retry library. +While it is out of scope of this document to cover all of the capabilities of the RetryTemplate, we will mention the following consumer properties that are specifically related to +the RetryTemplate: + + +maxAttempts + +The number of attempts to process the message. +Default: 3. + + + +backOffInitialInterval + +The backoff initial interval on retry. +Default 1000 milliseconds. + + + +backOffMaxInterval + +The maximum backoff interval. +Default 10000 milliseconds. + + + +backOffMultiplier + +The backoff multiplier. +Default 2.0. + + + +defaultRetryable + +Whether exceptions thrown by the listener that are not listed in the retryableExceptions are retryable. +Default: true. + + + +retryableExceptions + +A map of Throwable class names in the key and a boolean in the value. +Specify those exceptions (and subclasses) that will or won’t be retried. +Also see defaultRetriable. +Example: spring.cloud.stream.bindings.input.consumer.retryable-exceptions.java.lang.IllegalStateException=false. +Default: empty. + + + +While the preceding settings are sufficient for majority of the customization requirements, they may not satisfy certain complex requirements at, which +point you may want to provide your own instance of the RetryTemplate. To do so configure it as a bean in your application configuration. The application provided +instance will override the one provided by the framework. Also, to avoid conflicts you must qualify the instance of the RetryTemplate you want to be used by the binder +as @StreamRetryTemplate. For example, +@StreamRetryTemplate +public RetryTemplate myRetryTemplate() { + return new RetryTemplate(); +} +As you can see from the above example you don’t need to annotate it with @Bean since @StreamRetryTemplate is a qualified @Bean. +
+
+
+Reactive Programming Support +Spring Cloud Stream also supports the use of reactive APIs where incoming and outgoing data is handled as continuous data flows. +Support for reactive APIs is available through spring-cloud-stream-reactive, which needs to be added explicitly to your project. +The programming model with reactive APIs is declarative. Instead of specifying how each individual message should be handled, you can use operators that describe functional transformations from inbound to outbound data flows. +At present Spring Cloud Stream supports the only the Reactor API. +In the future, we intend to support a more generic model based on Reactive Streams. +The reactive programming model also uses the @StreamListener annotation for setting up reactive handlers. +The differences are that: + + +The @StreamListener annotation must not specify an input or output, as they are provided as arguments and return values from the method. + + +The arguments of the method must be annotated with @Input and @Output, indicating which input or output the incoming and outgoing data flows connect to, respectively. + + +The return value of the method, if any, is annotated with @Output, indicating the input where data should be sent. + + + +Reactive programming support requires Java 1.8. + + +As of Spring Cloud Stream 1.1.1 and later (starting with release train Brooklyn.SR2), reactive programming support requires the use of Reactor 3.0.4.RELEASE and higher. +Earlier Reactor versions (including 3.0.1.RELEASE, 3.0.2.RELEASE and 3.0.3.RELEASE) are not supported. +spring-cloud-stream-reactive transitively retrieves the proper version, but it is possible for the project structure to manage the version of the io.projectreactor:reactor-core to an earlier release, especially when using Maven. +This is the case for projects generated by using Spring Initializr with Spring Boot 1.x, which overrides the Reactor version to 2.0.8.RELEASE. +In such cases, you must ensure that the proper version of the artifact is released. +You can do so by adding a direct dependency on io.projectreactor:reactor-core with a version of 3.0.4.RELEASE or later to your project. + + +The use of term, reactive, currently refers to the reactive APIs being used and not to the execution model being reactive (that is, the bound endpoints still use a 'push' rather than a 'pull' model). While some backpressure support is provided by the use of Reactor, we do intend, in a future release, to support entirely reactive pipelines by the use of native reactive clients for the connected middleware. + +
+Reactor-based Handlers +A Reactor-based handler can have the following argument types: + + +For arguments annotated with @Input, it supports the Reactor Flux type. +The parameterization of the inbound Flux follows the same rules as in the case of individual message handling: It can be the entire Message, a POJO that can be the Message payload, or a POJO that is the result of a transformation based on the Message content-type header. Multiple inputs are provided. + + +For arguments annotated with Output, it supports the FluxSender type, which connects a Flux produced by the method with an output. Generally speaking, specifying outputs as arguments is only recommended when the method can have multiple outputs. + + +A Reactor-based handler supports a return type of Flux. In that case, it must be annotated with @Output. We recommend using the return value of the method when a single output Flux is available. +The following example shows a Reactor-based Processor: +@EnableBinding(Processor.class) +@EnableAutoConfiguration +public static class UppercaseTransformer { + + @StreamListener + @Output(Processor.OUTPUT) + public Flux<String> receive(@Input(Processor.INPUT) Flux<String> input) { + return input.map(s -> s.toUpperCase()); + } +} +The same processor using output arguments looks like the following example: +@EnableBinding(Processor.class) +@EnableAutoConfiguration +public static class UppercaseTransformer { + + @StreamListener + public void receive(@Input(Processor.INPUT) Flux<String> input, + @Output(Processor.OUTPUT) FluxSender output) { + output.send(input.map(s -> s.toUpperCase())); + } +} +
+
+Reactive Sources +Spring Cloud Stream reactive support also provides the ability for creating reactive sources through the @StreamEmitter annotation. +By using the @StreamEmitter annotation, a regular source may be converted to a reactive one. +@StreamEmitter is a method level annotation that marks a method to be an emitter to outputs declared with @EnableBinding. +You cannot use the @Input annotation along with @StreamEmitter, as the methods marked with this annotation are not listening for any input. Rather, methods marked with @StreamEmitter generate output. +Following the same programming model used in @StreamListener, @StreamEmitter also allows flexible ways of using the @Output annotation, depending on whether the method has any arguments, a return type, and other considerations. +The remainder of this section contains examples of using the @StreamEmitter annotation in various styles. +The following example emits the Hello, World message every millisecond and publishes to a Reactor Flux: +@EnableBinding(Source.class) +@EnableAutoConfiguration +public static class HelloWorldEmitter { + + @StreamEmitter + @Output(Source.OUTPUT) + public Flux<String> emit() { + return Flux.intervalMillis(1) + .map(l -> "Hello World"); + } +} +In the preceding example, the resulting messages in the Flux are sent to the output channel of the Source. +The next example is another flavor of an @StreamEmmitter that sends a Reactor Flux. +Instead of returning a Flux, the following method uses a FluxSender to programmatically send a Flux from a source: +@EnableBinding(Source.class) +@EnableAutoConfiguration +public static class HelloWorldEmitter { + + @StreamEmitter + @Output(Source.OUTPUT) + public void emit(FluxSender output) { + output.send(Flux.intervalMillis(1) + .map(l -> "Hello World")); + } +} +The next example is exactly same as the above snippet in functionality and style. +However, instead of using an explicit @Output annotation on the method, it uses the annotation on the method parameter. +@EnableBinding(Source.class) +@EnableAutoConfiguration +public static class HelloWorldEmitter { + + @StreamEmitter + public void emit(@Output(Source.OUTPUT) FluxSender output) { + output.send(Flux.intervalMillis(1) + .map(l -> "Hello World")); + } +} +The last example in this section is yet another flavor of writing reacting sources by using the Reactive Streams Publisher API and taking advantage of the support for it in Spring Integration Java DSL. +The Publisher in the following example still uses Reactor Flux under the hood, but, from an application perspective, that is transparent to the user and only needs Reactive Streams and Java DSL for Spring Integration: +@EnableBinding(Source.class) +@EnableAutoConfiguration +public static class HelloWorldEmitter { + + @StreamEmitter + @Output(Source.OUTPUT) + @Bean + public Publisher<Message<String>> emit() { + return IntegrationFlows.from(() -> + new GenericMessage<>("Hello World"), + e -> e.poller(p -> p.fixedDelay(1))) + .toReactivePublisher(); + } +} +
+
+
+ +Binders +Spring Cloud Stream provides a Binder abstraction for use in connecting to physical destinations at the external middleware. +This section provides information about the main concepts behind the Binder SPI, its main components, and implementation-specific details. +
+Producers and Consumers +The following image shows the general relationship of producers and consumers: +
+Producers and Consumers + + + + +producers consumers + +
+A producer is any component that sends messages to a channel. +The channel can be bound to an external message broker with a Binder implementation for that broker. +When invoking the bindProducer() method, the first parameter is the name of the destination within the broker, the second parameter is the local channel instance to which the producer sends messages, and the third parameter contains properties (such as a partition key expression) to be used within the adapter that is created for that channel. +A consumer is any component that receives messages from a channel. +As with a producer, the consumer’s channel can be bound to an external message broker. +When invoking the bindConsumer() method, the first parameter is the destination name, and a second parameter provides the name of a logical group of consumers. +Each group that is represented by consumer bindings for a given destination receives a copy of each message that a producer sends to that destination (that is, it follows normal publish-subscribe semantics). +If there are multiple consumer instances bound with the same group name, then messages are load-balanced across those consumer instances so that each message sent by a producer is consumed by only a single consumer instance within each group (that is, it follows normal queueing semantics). +
+
+Binder SPI +The Binder SPI consists of a number of interfaces, out-of-the box utility classes, and discovery strategies that provide a pluggable mechanism for connecting to external middleware. +The key point of the SPI is the Binder interface, which is a strategy for connecting inputs and outputs to external middleware. The following listing shows the definnition of the Binder interface: +public interface Binder<T, C extends ConsumerProperties, P extends ProducerProperties> { + Binding<T> bindConsumer(String name, String group, T inboundBindTarget, C consumerProperties); + + Binding<T> bindProducer(String name, T outboundBindTarget, P producerProperties); +} +The interface is parameterized, offering a number of extension points: + + +Input and output bind targets. As of version 1.0, only MessageChannel is supported, but this is intended to be used as an extension point in the future. + + +Extended consumer and producer properties, allowing specific Binder implementations to add supplemental properties that can be supported in a type-safe manner. + + +A typical binder implementation consists of the following: + + +A class that implements the Binder interface; + + +A Spring @Configuration class that creates a bean of type Binder along with the middleware connection infrastructure. + + +A META-INF/spring.binders file found on the classpath containing one or more binder definitions, as shown in the following example: +kafka:\ +org.springframework.cloud.stream.binder.kafka.config.KafkaBinderConfiguration + + +
+
+Binder Detection +Spring Cloud Stream relies on implementations of the Binder SPI to perform the task of connecting channels to message brokers. +Each Binder implementation typically connects to one type of messaging system. +
+Classpath Detection +By default, Spring Cloud Stream relies on Spring Boot’s auto-configuration to configure the binding process. +If a single Binder implementation is found on the classpath, Spring Cloud Stream automatically uses it. +For example, a Spring Cloud Stream project that aims to bind only to RabbitMQ can add the following dependency: +<dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-stream-binder-rabbit</artifactId> +</dependency> +For the specific Maven coordinates of other binder dependencies, see the documentation of that binder implementation. +
+
+
+Multiple Binders on the Classpath +When multiple binders are present on the classpath, the application must indicate which binder is to be used for each channel binding. +Each binder configuration contains a META-INF/spring.binders file, which is a simple properties file, as shown in the following example: +rabbit:\ +org.springframework.cloud.stream.binder.rabbit.config.RabbitServiceAutoConfiguration +Similar files exist for the other provided binder implementations (such as Kafka), and custom binder implementations are expected to provide them as well. +The key represents an identifying name for the binder implementation, whereas the value is a comma-separated list of configuration classes that each contain one and only one bean definition of type org.springframework.cloud.stream.binder.Binder. +Binder selection can either be performed globally, using the spring.cloud.stream.defaultBinder property (for example, spring.cloud.stream.defaultBinder=rabbit) or individually, by configuring the binder on each channel binding. +For instance, a processor application (that has channels named input and output for read and write respectively) that reads from Kafka and writes to RabbitMQ can specify the following configuration: +spring.cloud.stream.bindings.input.binder=kafka +spring.cloud.stream.bindings.output.binder=rabbit +
+
+Connecting to Multiple Systems +By default, binders share the application’s Spring Boot auto-configuration, so that one instance of each binder found on the classpath is created. +If your application should connect to more than one broker of the same type, you can specify multiple binder configurations, each with different environment settings. + +Turning on explicit binder configuration disables the default binder configuration process altogether. +If you do so, all binders in use must be included in the configuration. +Frameworks that intend to use Spring Cloud Stream transparently may create binder configurations that can be referenced by name, but they do not affect the default binder configuration. +In order to do so, a binder configuration may have its defaultCandidate flag set to false (for example, spring.cloud.stream.binders.<configurationName>.defaultCandidate=false). +This denotes a configuration that exists independently of the default binder configuration process. + +The following example shows a typical configuration for a processor application that connects to two RabbitMQ broker instances: +spring: + cloud: + stream: + bindings: + input: + destination: thing1 + binder: rabbit1 + output: + destination: thing2 + binder: rabbit2 + binders: + rabbit1: + type: rabbit + environment: + spring: + rabbitmq: + host: <host1> + rabbit2: + type: rabbit + environment: + spring: + rabbitmq: + host: <host2> +
+
+Binding visualization and control +Since version 2.0, Spring Cloud Stream supports visualization and control of the Bindings through Actuator endpoints. +Starting with version 2.0 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: +<dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> +</dependency> +The following example shows how to add the dependency for the WebFlux framework: +<dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-webflux</artifactId> +</dependency> +You can add the Actuator dependency as follows: +<dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> +</dependency> + +To run Spring Cloud Stream 2.0 apps in Cloud Foundry, you must add spring-boot-starter-web and spring-boot-starter-actuator to the classpath. Otherwise, the +application will not start due to health check failures. + +You must also enable the bindings actuator endpoints by setting the following property: --management.endpoints.web.exposure.include=bindings. +Once those prerequisites are satisfied. you should see the following in the logs when application start: +: Mapped "{[/actuator/bindings/{name}],methods=[POST]. . . +: Mapped "{[/actuator/bindings],methods=[GET]. . . +: Mapped "{[/actuator/bindings/{name}],methods=[GET]. . . +To visualize the current bindings, access the following URL: +http://<host>:<port>/actuator/bindings +Alternative, to see a single binding, access one of the URLs similar to the following: +http://<host>:<port>/actuator/bindings/myBindingName +You can also stop, start, pause, and resume individual bindings by posting to the same URL while providing a state argument as JSON, as shown in the following examples: +curl -d '{"state":"STOPPED"}' -H "Content-Type: application/json" -X POST http://<host>:<port>/actuator/bindings/myBindingName +curl -d '{"state":"STARTED"}' -H "Content-Type: application/json" -X POST http://<host>:<port>/actuator/bindings/myBindingName +curl -d '{"state":"PAUSED"}' -H "Content-Type: application/json" -X POST http://<host>:<port>/actuator/bindings/myBindingName +curl -d '{"state":"RESUMED"}' -H "Content-Type: application/json" -X POST http://<host>:<port>/actuator/bindings/myBindingName + +PAUSED and RESUMED work only when the corresponding binder and its underlying technology supports it. Otherwise, you see the warning message in the logs. +Currently, only Kafka binder supports the PAUSED and RESUMED states. + +
+
+Binder Configuration Properties +The following properties are available when customizing binder configurations. These properties exposed via org.springframework.cloud.stream.config.BinderProperties +They must be prefixed with spring.cloud.stream.binders.<configurationName>. + + +type + +The binder type. +It typically references one of the binders found on the classpath — in particular, a key in a META-INF/spring.binders file. +By default, it has the same value as the configuration name. + + + +inheritEnvironment + +Whether the configuration inherits the environment of the application itself. +Default: true. + + + +environment + +Root for a set of properties that can be used to customize the environment of the binder. +When this property is set, the context in which the binder is being created is not a child of the application context. +This setting allows for complete separation between the binder components and the application components. +Default: empty. + + + +defaultCandidate + +Whether the binder configuration is a candidate for being considered a default binder or can be used only when explicitly referenced. +This setting allows adding binder configurations without interfering with the default processing. +Default: true. + + + +
+
+ +Configuration Options +Spring Cloud Stream supports general configuration options as well as configuration for bindings and binders. +Some binders let additional binding properties support middleware-specific features. +Configuration options can be provided to Spring Cloud Stream applications through any mechanism supported by Spring Boot. +This includes application arguments, environment variables, and YAML or .properties files. +
+Binding Service Properties +These properties are exposed via org.springframework.cloud.stream.config.BindingServiceProperties + + +spring.cloud.stream.instanceCount + +The number of deployed instances of an application. +Must be set for partitioning on the producer side. Must be set on the consumer side when using RabbitMQ and with Kafka if autoRebalanceEnabled=false. +Default: 1. + + + +spring.cloud.stream.instanceIndex + +The instance index of the application: A number from 0 to instanceCount - 1. +Used for partitioning with RabbitMQ and with Kafka if autoRebalanceEnabled=false. +Automatically set in Cloud Foundry to match the application’s instance index. + + + +spring.cloud.stream.dynamicDestinations + +A list of destinations that can be bound dynamically (for example, in a dynamic routing scenario). +If set, only listed destinations can be bound. +Default: empty (letting any destination be bound). + + + +spring.cloud.stream.defaultBinder + +The default binder to use, if multiple binders are configured. +See Multiple Binders on the Classpath. +Default: empty. + + + +spring.cloud.stream.overrideCloudConnectors + +This property is only applicable when the cloud profile is active and Spring Cloud Connectors are provided with the application. +If the property is false (the default), the binder detects a suitable bound service (for example, a RabbitMQ service bound in Cloud Foundry for the RabbitMQ binder) and uses it for creating connections (usually through Spring Cloud Connectors). +When set to true, this property instructs binders to completely ignore the bound services and rely on Spring Boot properties (for example, relying on the spring.rabbitmq.* properties provided in the environment for the RabbitMQ binder). +The typical usage of this property is to be nested in a customized environment when connecting to multiple systems. +Default: false. + + + +spring.cloud.stream.bindingRetryInterval + +The interval (in seconds) between retrying binding creation when, for example, the binder does not support late binding and the broker (for example, Apache Kafka) is down. +Set it to zero to treat such conditions as fatal, preventing the application from starting. +Default: 30 + + + +
+
+Binding Properties +Binding properties are supplied by using the format of spring.cloud.stream.bindings.<channelName>.<property>=<value>. +The <channelName> represents the name of the channel being configured (for example, output for a Source). +To avoid repetition, Spring Cloud Stream supports setting values for all channels, in the format of spring.cloud.stream.default.<property>=<value>. +When it comes to avoiding repetitions for extended binding properties, this format should be used - spring.cloud.stream.<binder-type>.default.<producer|consumer>.<property>=<value>. +In what follows, we indicate where we have omitted the spring.cloud.stream.bindings.<channelName>. prefix and focus just on the property name, with the understanding that the prefix ise included at runtime. +
+Common Binding Properties +These properties are exposed via org.springframework.cloud.stream.config.BindingProperties +The following binding properties are available for both input and output bindings and must be prefixed with spring.cloud.stream.bindings.<channelName>. (for example, spring.cloud.stream.bindings.input.destination=ticktock). +Default values can be set by using the spring.cloud.stream.default prefix (for example`spring.cloud.stream.default.contentType=application/json`). + + +destination + +The target destination of a channel on the bound middleware (for example, the RabbitMQ exchange or Kafka topic). +If the channel is bound as a consumer, it could be bound to multiple destinations, and the destination names can be specified as comma-separated String values. +If not set, the channel name is used instead. +The default value of this property cannot be overridden. + + + +group + +The consumer group of the channel. +Applies only to inbound bindings. +See Consumer Groups. +Default: null (indicating an anonymous consumer). + + + +contentType + +The content type of the channel. +See . +Default: application/json. + + + +binder + +The binder used by this binding. +See for details. +Default: null (the default binder is used, if it exists). + + + +
+
+Consumer Properties +These properties are exposed via org.springframework.cloud.stream.binder.ConsumerProperties +The following binding properties are available for input bindings only and must be prefixed with spring.cloud.stream.bindings.<channelName>.consumer. (for example, spring.cloud.stream.bindings.input.consumer.concurrency=3). +Default values can be set by using the spring.cloud.stream.default.consumer prefix (for example, spring.cloud.stream.default.consumer.headerMode=none). + + +concurrency + +The concurrency of the inbound consumer. +Default: 1. + + + +partitioned + +Whether the consumer receives data from a partitioned producer. +Default: false. + + + +headerMode + +When set to none, disables header parsing on input. +Effective only for messaging middleware that does not support message headers natively and requires header embedding. +This option is useful when consuming data from non-Spring Cloud Stream applications when native headers are not supported. +When set to headers, it uses the middleware’s native header mechanism. +When set to embeddedHeaders, it embeds headers into the message payload. +Default: depends on the binder implementation. + + + +maxAttempts + +If processing fails, the number of attempts to process the message (including the first). +Set to 1 to disable retry. +Default: 3. + + + +backOffInitialInterval + +The backoff initial interval on retry. +Default: 1000. + + + +backOffMaxInterval + +The maximum backoff interval. +Default: 10000. + + + +backOffMultiplier + +The backoff multiplier. +Default: 2.0. + + + +defaultRetryable + +Whether exceptions thrown by the listener that are not listed in the retryableExceptions are retryable. +Default: true. + + + +instanceIndex + +When set to a value greater than equal to zero, it allows customizing the instance index of this consumer (if different from spring.cloud.stream.instanceIndex). +When set to a negative value, it defaults to spring.cloud.stream.instanceIndex. +See for more information. +Default: -1. + + + +instanceCount + +When set to a value greater than equal to zero, it allows customizing the instance count of this consumer (if different from spring.cloud.stream.instanceCount). +When set to a negative value, it defaults to spring.cloud.stream.instanceCount. +See for more information. +Default: -1. + + + +retryableExceptions + +A map of Throwable class names in the key and a boolean in the value. +Specify those exceptions (and subclasses) that will or won’t be retried. +Also see defaultRetriable. +Example: spring.cloud.stream.bindings.input.consumer.retryable-exceptions.java.lang.IllegalStateException=false. +Default: empty. + + + +useNativeDecoding + +When set to true, the inbound message is deserialized directly by the client library, which must be configured correspondingly (for example, setting an appropriate Kafka producer value deserializer). +When this configuration is being used, the inbound message unmarshalling is not based on the contentType of the binding. +When native decoding is used, it is the responsibility of the producer to use an appropriate encoder (for example, the Kafka producer value serializer) to serialize the outbound message. +Also, when native encoding and decoding is used, the headerMode=embeddedHeaders property is ignored and headers are not embedded in the message. +See the producer property useNativeEncoding. +Default: false. + + + +
+
+Producer Properties +These properties are exposed via org.springframework.cloud.stream.binder.ProducerProperties +The following binding properties are available for output bindings only and must be prefixed with spring.cloud.stream.bindings.<channelName>.producer. (for example, spring.cloud.stream.bindings.input.producer.partitionKeyExpression=payload.id). +Default values can be set by using the prefix spring.cloud.stream.default.producer (for example, spring.cloud.stream.default.producer.partitionKeyExpression=payload.id). + + +partitionKeyExpression + +A SpEL expression that determines how to partition outbound data. +If set, or if partitionKeyExtractorClass is set, outbound data on this channel is partitioned. partitionCount must be set to a value greater than 1 to be effective. +Mutually exclusive with partitionKeyExtractorClass. +See . +Default: null. + + + +partitionKeyExtractorClass + +A PartitionKeyExtractorStrategy implementation. +If set, or if partitionKeyExpression is set, outbound data on this channel is partitioned. partitionCount must be set to a value greater than 1 to be effective. +Mutually exclusive with partitionKeyExpression. +See . +Default: null. + + + +partitionSelectorClass + + A PartitionSelectorStrategy implementation. +Mutually exclusive with partitionSelectorExpression. +If neither is set, the partition is selected as the hashCode(key) % partitionCount, where key is computed through either partitionKeyExpression or partitionKeyExtractorClass. +Default: null. + + + +partitionSelectorExpression + +A SpEL expression for customizing partition selection. +Mutually exclusive with partitionSelectorClass. +If neither is set, the partition is selected as the hashCode(key) % partitionCount, where key is computed through either partitionKeyExpression or partitionKeyExtractorClass. +Default: null. + + + +partitionCount + +The number of target partitions for the data, if partitioning is enabled. +Must be set to a value greater than 1 if the producer is partitioned. +On Kafka, it is interpreted as a hint. The larger of this and the partition count of the target topic is used instead. +Default: 1. + + + +requiredGroups + +A comma-separated list of groups to which the producer must ensure message delivery even if they start after it has been created (for example, by pre-creating durable queues in RabbitMQ). + + + +headerMode + +When set to none, it disables header embedding on output. +It is effective only for messaging middleware that does not support message headers natively and requires header embedding. +This option is useful when producing data for non-Spring Cloud Stream applications when native headers are not supported. +When set to headers, it uses the middleware’s native header mechanism. +When set to embeddedHeaders, it embeds headers into the message payload. +Default: Depends on the binder implementation. + + + +useNativeEncoding + +When set to true, the outbound message is serialized directly by the client library, which must be configured correspondingly (for example, setting an appropriate Kafka producer value serializer). +When this configuration is being used, the outbound message marshalling is not based on the contentType of the binding. +When native encoding is used, it is the responsibility of the consumer to use an appropriate decoder (for example, the Kafka consumer value de-serializer) to deserialize the inbound message. +Also, when native encoding and decoding is used, the headerMode=embeddedHeaders property is ignored and headers are not embedded in the message. +See the consumer property useNativeDecoding. +Default: false. + + + +errorChannelEnabled + +When set to true, if the binder supports asynchroous send results, send failures are sent to an error channel for the destination. +See for more information. +Default: false. + + + +
+
+
+Using Dynamically Bound Destinations +Besides the channels defined by using @EnableBinding, Spring Cloud Stream lets applications send messages to dynamically bound destinations. +This is useful, for example, when the target destination needs to be determined at runtime. +Applications can do so by using the BinderAwareChannelResolver bean, registered automatically by the @EnableBinding annotation. +The 'spring.cloud.stream.dynamicDestinations' property can be used for restricting the dynamic destination names to a known set (whitelisting). +If this property is not set, any destination can be bound dynamically. +The BinderAwareChannelResolver can be used directly, as shown in the following example of a REST controller using a path variable to decide the target channel: +@EnableBinding +@Controller +public class SourceWithDynamicDestination { + + @Autowired + private BinderAwareChannelResolver resolver; + + @RequestMapping(path = "/{target}", method = POST, consumes = "*/*") + @ResponseStatus(HttpStatus.ACCEPTED) + public void handleRequest(@RequestBody String body, @PathVariable("target") target, + @RequestHeader(HttpHeaders.CONTENT_TYPE) Object contentType) { + sendMessage(body, target, contentType); + } + + private void sendMessage(String body, String target, Object contentType) { + resolver.resolveDestination(target).send(MessageBuilder.createMessage(body, + new MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, contentType)))); + } +} +Now consider what happens when we start the application on the default port (8080) and make the following requests with CURL: +curl -H "Content-Type: application/json" -X POST -d "customer-1" http://localhost:8080/customers + +curl -H "Content-Type: application/json" -X POST -d "order-1" http://localhost:8080/orders +The destinations, 'customers' and 'orders', are created in the broker (in the exchange for Rabbit or in the topic for Kafka) with names of 'customers' and 'orders', and the data is published to the appropriate destinations. +The BinderAwareChannelResolver is a general-purpose Spring Integration DestinationResolver and can be injected in other components — for example, in a router using a SpEL expression based on the target field of an incoming JSON message. The following example includes a router that reads SpEL expressions: +@EnableBinding +@Controller +public class SourceWithDynamicDestination { + + @Autowired + private BinderAwareChannelResolver resolver; + + + @RequestMapping(path = "/", method = POST, consumes = "application/json") + @ResponseStatus(HttpStatus.ACCEPTED) + public void handleRequest(@RequestBody String body, @RequestHeader(HttpHeaders.CONTENT_TYPE) Object contentType) { + sendMessage(body, contentType); + } + + private void sendMessage(Object body, Object contentType) { + routerChannel().send(MessageBuilder.createMessage(body, + new MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, contentType)))); + } + + @Bean(name = "routerChannel") + public MessageChannel routerChannel() { + return new DirectChannel(); + } + + @Bean + @ServiceActivator(inputChannel = "routerChannel") + public ExpressionEvaluatingRouter router() { + ExpressionEvaluatingRouter router = + new ExpressionEvaluatingRouter(new SpelExpressionParser().parseExpression("payload.target")); + router.setDefaultOutputChannelName("default-output"); + router.setChannelResolver(resolver); + return router; + } +} +The Router Sink Application uses this technique to create the destinations on-demand. +If the channel names are known in advance, you can configure the producer properties as with any other destination. +Alternatively, if you register a NewDestinationBindingCallback<> bean, it is invoked just before the binding is created. +The callback takes the generic type of the extended producer properties used by the binder. +It has one method: +void configure(String channelName, MessageChannel channel, ProducerProperties producerProperties, + T extendedProducerProperties); +The following example shows how to use the RabbitMQ binder: +@Bean +public NewDestinationBindingCallback<RabbitProducerProperties> dynamicConfigurer() { + return (name, channel, props, extended) -> { + props.setRequiredGroups("bindThisQueue"); + extended.setQueueNameGroupOnly(true); + extended.setAutoBindDlq(true); + extended.setDeadLetterQueueName("myDLQ"); + }; +} + +If you need to support dynamic destinations with multiple binder types, use Object for the generic type and cast the extended argument as needed. + +
+
+ +Content Type Negotiation +Data transformation is one of the core features of any message-driven microservice architecture. Given that, in Spring Cloud Stream, such data +is represented as a Spring Message, a message may have to be transformed to a desired shape or size before reaching its destination. This is required for two reasons: + + +To convert the contents of the incoming message to match the signature of the application-provided handler. + + +To convert the contents of the outgoing message to the wire format. + + +The wire format is typically byte[] (that is true for the Kafka and Rabbit binders), but it is governed by the binder implementation. +In Spring Cloud Stream, message transformation is accomplished with an org.springframework.messaging.converter.MessageConverter. + +As a supplement to the details to follow, you may also want to read the following blog post. + +
+Mechanics +To better understand the mechanics and the necessity behind content-type negotiation, we take a look at a very simple use case by using the following message handler as an example: +@StreamListener(Processor.INPUT) +@SendTo(Processor.OUTPUT) +public String handle(Person person) {..} + +For simplicity, we assume that this is the only handler in the application (we assume there is no internal pipeline). + +The handler shown in the preceding example expects a Person object as an argument and produces a String type as an output. +In order for the framework to succeed in passing the incoming Message as an argument to this handler, it has to somehow transform the payload of the Message type from the wire format to a Person type. +In other words, the framework must locate and apply the appropriate MessageConverter. +To accomplish that, the framework needs some instructions from the user. +One of these instructions is already provided by the signature of the handler method itself (Person type). +Consequently, in theory, that should be (and, in some cases, is) enough. +However, for the majority of use cases, in order to select the appropriate MessageConverter, the framework needs an additional piece of information. +That missing piece is contentType. +Spring Cloud Stream provides three mechanisms to define contentType (in order of precedence): + + +HEADER: The contentType can be communicated through the Message itself. By providing a contentType header, you declare the content type to use to locate and apply the appropriate MessageConverter. + + +BINDING: The contentType can be set per destination binding by setting the spring.cloud.stream.bindings.input.content-type property. + +The input segment in the property name corresponds to the actual name of the destination (which is “input” in our case). This approach lets you declare, on a per-binding basis, the content type to use to locate and apply the appropriate MessageConverter. + + + +DEFAULT: If contentType is not present in the Message header or the binding, the default application/json content type is used to +locate and apply the appropriate MessageConverter. + + +As mentioned earlier, the preceding list also demonstrates the order of precedence in case of a tie. For example, a header-provided content type takes precedence over any other content type. +The same applies for a content type set on a per-binding basis, which essentially lets you override the default content type. +However, it also provides a sensible default (which was determined from community feedback). +Another reason for making application/json the default stems from the interoperability requirements driven by distributed microservices architectures, where producer and consumer not only run in different JVMs but can also run on different non-JVM platforms. +When the non-void handler method returns, if the the return value is already a Message, that Message becomes the payload. However, when the return value is not a Message, the new Message is constructed with the return value as the payload while inheriting +headers from the input Message minus the headers defined or filtered by SpringIntegrationProperties.messageHandlerNotPropagatedHeaders. +By default, there is only one header set there: contentType. This means that the new Message does not have contentType header set, thus ensuring that the contentType can evolve. +You can always opt out of returning a Message from the handler method where you can inject any header you wish. +If there is an internal pipeline, the Message is sent to the next handler by going through the same process of conversion. However, if there is no internal pipeline or you have reached the end of it, the Message is sent back to the output destination. +
+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. +The logic for selecting the appropriate MessageConverter resides with the argument resolvers (HandlerMethodArgumentResolvers), which trigger right before the invocation of the user-defined handler method (which is when the actual argument type is known to the framework). +If the argument type does not match the type of the current payload, the framework delegates to the stack of the +pre-configured MessageConverters to see if any one of them can convert the payload. +As you can see, the Object fromMessage(Message<?> message, Class<?> targetClass); +operation of the MessageConverter takes targetClass as one of its arguments. +The framework also ensures that the provided Message always contains a contentType header. +When no contentType header was already present, it injects either the per-binding contentType header or the default contentType header. +The combination of contentType argument type is the mechanism by which framework determines if message can be converted to a target type. +If no appropriate MessageConverter is found, an exception is thrown, which you can handle by adding a custom MessageConverter (see ). +But what if the payload type matches the target type declared by the handler method? In this case, there is nothing to convert, and the +payload is passed unmodified. While this sounds pretty straightforward and logical, keep in mind handler methods that take a Message<?> or Object as an argument. +By declaring the target type to be Object (which is an instanceof everything in Java), you essentially forfeit the conversion process. + +Do not expect Message to be converted into some other type based only on the contentType. +Remember that the contentType is complementary to the target type. +If you wish, you can provide a hint, which MessageConverter may or may not take into consideration. + +
+
+Message Converters +MessageConverters define two methods: +Object fromMessage(Message<?> message, Class<?> targetClass); + +Message<?> toMessage(Object payload, @Nullable MessageHeaders headers); +It is important to understand the contract of these methods and their usage, specifically in the context of Spring Cloud Stream. +The fromMessage method converts an incoming Message to an argument type. +The payload of the Message could be any type, and it is +up to the actual implementation of the MessageConverter to support multiple types. +For example, some JSON converter may support the payload type as byte[], String, and others. +This is important when the application contains an internal pipeline (that is, input → handler1 → handler2 →. . . → output) and the output of the upstream handler results in a Message which may not be in the initial wire format. +However, the toMessage method has a more strict contract and must always convert Message to the wire format: byte[]. +So, for all intents and purposes (and especially when implementing your own converter) you regard the two methods as having the following signatures: +Object fromMessage(Message<?> message, Class<?> targetClass); + +Message<byte[]> toMessage(Object payload, @Nullable MessageHeaders headers); +
+
+
+Provided MessageConverters +As mentioned earlier, the framework already provides a stack of MessageConverters to handle most common use cases. +The following list describes the provided MessageConverters, in order of precedence (the first MessageConverter that works is used): + + +ApplicationJsonMessageMarshallingConverter: Variation of the org.springframework.messaging.converter.MappingJackson2MessageConverter. Supports conversion of the payload of the Message to/from POJO for cases when contentType is application/json (DEFAULT). + + +TupleJsonMessageConverter: DEPRECATED Supports conversion of the payload of the Message to/from org.springframework.tuple.Tuple. + + +ByteArrayMessageConverter: Supports conversion of the payload of the Message from byte[] to byte[] for cases when contentType is application/octet-stream. It is essentially a pass through and exists primarily for backward compatibility. + + +ObjectStringMessageConverter: Supports conversion of any type to a String when contentType is text/plain. +It invokes Object’s toString() method or, if the payload is byte[], a new String(byte[]). + + +JavaSerializationMessageConverter: DEPRECATED Supports conversion based on java serialization when contentType is application/x-java-serialized-object. + + +KryoMessageConverter: DEPRECATED Supports conversion based on Kryo serialization when contentType is application/x-java-object. + + +JsonUnmarshallingConverter: Similar to the ApplicationJsonMessageMarshallingConverter. It supports conversion of any type when contentType is application/x-java-object. +It expects the actual type information to be embedded in the contentType as an attribute (for example, application/x-java-object;type=foo.bar.Cat). + + +When no appropriate converter is found, the framework throws an exception. When that happens, you should check your code and configuration and ensure you did not miss anything (that is, ensure that you provided a contentType by using a binding or a header). +However, most likely, you found some uncommon case (such as a custom contentType perhaps) and the current stack of provided MessageConverters +does not know how to convert. If that is the case, you can add custom MessageConverter. See . +
+
+User-defined Message Converters +Spring Cloud Stream exposes a mechanism to define and register additional MessageConverters. +To use it, implement org.springframework.messaging.converter.MessageConverter, configure it as a @Bean, and annotate it with @StreamMessageConverter. +It is then apended to the existing stack of `MessageConverter`s. + +It is important to understand that custom MessageConverter implementations are added to the head of the existing stack. +Consequently, custom MessageConverter implementations take precedence over the existing ones, which lets you override as well as add to the existing converters. + +The following example shows how to create a message converter bean to support a new content type called application/bar: +@EnableBinding(Sink.class) +@SpringBootApplication +public static class SinkApplication { + + ... + + @Bean + @StreamMessageConverter + public MessageConverter customMessageConverter() { + return new MyCustomMessageConverter(); + } +} + +public class MyCustomMessageConverter extends AbstractMessageConverter { + + public MyCustomMessageConverter() { + super(new MimeType("application", "bar")); + } + + @Override + protected boolean supports(Class<?> clazz) { + return (Bar.class.equals(clazz)); + } + + @Override + protected Object convertFromInternal(Message<?> message, Class<?> targetClass, Object conversionHint) { + Object payload = message.getPayload(); + return (payload instanceof Bar ? payload : new Bar((byte[]) payload)); + } +} +Spring Cloud Stream also provides support for Avro-based converters and schema evolution. +See for details. +
+
+ +Schema Evolution Support +Spring Cloud Stream provides support for schema evolution so that the data can be evolved over time and still work with older or newer producers and consumers and vice versa. +Most serialization models, especially the ones that aim for portability across different platforms and languages, rely on a schema that describes how the data is serialized in the binary payload. +In order to serialize the data and then to interpret it, both the sending and receiving sides must have access to a schema that describes the binary format. +In certain cases, the schema can be inferred from the payload type on serialization or from the target type on deserialization. +However, many applications benefit from having access to an explicit schema that describes the binary data format. +A schema registry lets you store schema information in a textual format (typically JSON) and makes that information accessible to various applications that need it to receive and send data in binary format. +A schema is referenceable as a tuple consisting of: + + +A subject that is the logical name of the schema + + +The schema version + + +The schema format, which describes the binary format of the data + + +This following sections goes through the details of various components involved in schema evolution process. +
+Schema Registry Client +The client-side abstraction for interacting with schema registry servers is the SchemaRegistryClient interface, which has the following structure: +public interface SchemaRegistryClient { + + SchemaRegistrationResponse register(String subject, String format, String schema); + + String fetch(SchemaReference schemaReference); + + String fetch(Integer id); + +} +Spring Cloud Stream provides out-of-the-box implementations for interacting with its own schema server and for interacting with the Confluent Schema Registry. +A client for the Spring Cloud Stream schema registry can be configured by using the @EnableSchemaRegistryClient, as follows: + @EnableBinding(Sink.class) + @SpringBootApplication + @EnableSchemaRegistryClient + public static class AvroSinkApplication { + ... + } + +The default converter is optimized to cache not only the schemas from the remote server but also the parse() and toString() methods, which are quite expensive. +Because of this, it uses a DefaultSchemaRegistryClient that does not cache responses. +If you intend to change the default behavior, you can use the client directly on your code and override it to the desired outcome. +To do so, you have to add the property spring.cloud.stream.schemaRegistryClient.cached=true to your application properties. + +
+Schema Registry Client Properties +The Schema Registry Client supports the following properties: + + +spring.cloud.stream.schemaRegistryClient.endpoint + +The location of the schema-server. +When setting this, use a full URL, including protocol (http or https) , port, and context path. + + + +Default + +http://localhost:8990/ + + + +spring.cloud.stream.schemaRegistryClient.cached + +Whether the client should cache schema server responses. +Normally set to false, as the caching happens in the message converter. +Clients using the schema registry client should set this to true. + + + +Default + +false + + + +
+
+
+Avro Schema Registry Client Message Converters +For applications that have a SchemaRegistryClient bean registered with the application context, Spring Cloud Stream auto configures an Apache Avro message converter for schema management. +This eases schema evolution, as applications that receive messages can get easy access to a writer schema that can be reconciled with their own reader schema. +For outbound messages, if the content type of the channel is set to application/*+avro, the MessageConverter is activated, as shown in the following example: +spring.cloud.stream.bindings.output.contentType=application/*+avro +During the outbound conversion, the message converter tries to infer the schema of each outbound messages (based on its type) and register it to a subject (based on the payload type) by using the SchemaRegistryClient. +If an identical schema is already found, then a reference to it is retrieved. +If not, the schema is registered, and a new version number is provided. +The message is sent with a contentType header by using the following scheme: application/[prefix].[subject].v[version]+avro, where prefix is configurable and subject is deduced from the payload type. +For example, a message of the type User might be sent as a binary payload with a content type of application/vnd.user.v2+avro, where user is the subject and 2 is the version number. +When receiving messages, the converter infers the schema reference from the header of the incoming message and tries to retrieve it. The schema is used as the writer schema in the deserialization process. +
+Avro Schema Registry Message Converter Properties +If you have enabled Avro based schema registry client by setting spring.cloud.stream.bindings.output.contentType=application/*+avro, you can customize the behavior of the registration by setting the following properties. + + +spring.cloud.stream.schema.avro.dynamicSchemaGenerationEnabled + +Enable if you want the converter to use reflection to infer a Schema from a POJO. +Default: false + + + +spring.cloud.stream.schema.avro.readerSchema + +Avro compares schema versions by looking at a writer schema (origin payload) and a reader schema (your application payload). See the Avro documentation for more information. If set, this overrides any lookups at the schema server and uses the local schema as the reader schema. +Default: null + + + +spring.cloud.stream.schema.avro.schemaLocations + +Registers any .avsc files listed in this property with the Schema Server. +Default: empty + + + +spring.cloud.stream.schema.avro.prefix + +The prefix to be used on the Content-Type header. +Default: vnd + + + +
+
+
+Apache Avro Message Converters +Spring Cloud Stream provides support for schema-based message converters through its spring-cloud-stream-schema module. +Currently, the only serialization format supported out of the box for schema-based message converters is Apache Avro, with more formats to be added in future versions. +The spring-cloud-stream-schema module contains two types of message converters that can be used for Apache Avro serialization: + + +Converters that use the class information of the serialized or deserialized objects or a schema with a location known at startup. + + +Converters that use a schema registry. They locate the schemas at runtime and dynamically register new schemas as domain objects evolve. + + +
+
+Converters with Schema Support +The AvroSchemaMessageConverter supports serializing and deserializing messages either by using a predefined schema or by using the schema information available in the class (either reflectively or contained in the SpecificRecord). +If you provide a custom converter, then the default AvroSchemaMessageConverter bean is not created. The following example shows a custom converter: +To use custom converters, you can simply add it to the application context, optionally specifying one or more MimeTypes with which to associate it. +The default MimeType is application/avro. +If the target type of the conversion is a GenericRecord, a schema must be set. +The following example shows how to configure a converter in a sink application by registering the Apache Avro MessageConverter without a predefined schema. +In this example, note that the mime type value is avro/bytes, not the default application/avro. +@EnableBinding(Sink.class) +@SpringBootApplication +public static class SinkApplication { + + ... + + @Bean + public MessageConverter userMessageConverter() { + return new AvroSchemaMessageConverter(MimeType.valueOf("avro/bytes")); + } +} +Conversely, the following application registers a converter with a predefined schema (found on the classpath): +@EnableBinding(Sink.class) +@SpringBootApplication +public static class SinkApplication { + + ... + + @Bean + public MessageConverter userMessageConverter() { + AvroSchemaMessageConverter converter = new AvroSchemaMessageConverter(MimeType.valueOf("avro/bytes")); + converter.setSchemaLocation(new ClassPathResource("schemas/User.avro")); + return converter; + } +} +
+
+Schema Registry Server +Spring Cloud Stream provides a schema registry server implementation. +To use it, you can add the spring-cloud-stream-schema-server artifact to your project and use the @EnableSchemaRegistryServer annotation, which adds the schema registry server REST controller to your application. +This annotation is intended to be used with Spring Boot web applications, and the listening port of the server is controlled by the server.port property. +The spring.cloud.stream.schema.server.path property can be used to control the root path of the schema server (especially when it is embedded in other applications). +The spring.cloud.stream.schema.server.allowSchemaDeletion boolean property enables the deletion of a schema. By default, this is disabled. +The schema registry server uses a relational database to store the schemas. +By default, it uses an embedded database. +You can customize the schema storage by using the Spring Boot SQL database and JDBC configuration options. +The following example shows a Spring Boot application that enables the schema registry: +@SpringBootApplication +@EnableSchemaRegistryServer +public class SchemaRegistryServerApplication { + public static void main(String[] args) { + SpringApplication.run(SchemaRegistryServerApplication.class, args); + } +} +
+Schema Registry Server API +The Schema Registry Server API consists of the following operations: + + +POST / — see + + +'GET /{subject}/{format}/{version}' — see + + +GET /{subject}/{format} — see + + +GET /schemas/{id} — see + + +DELETE /{subject}/{format}/{version} — see + + +DELETE /schemas/{id} — see + + +DELETE /{subject} — see + + +
+Registering a New Schema +To register a new schema, send a POST request to the / endpoint. +The / accepts a JSON payload with the following fields: + + +subject: The schema subject + + +format: The schema format + + +definition: The schema definition + + +Its response is a schema object in JSON, with the following fields: + + +id: The schema ID + + +subject: The schema subject + + +format: The schema format + + +version: The schema version + + +definition: The schema definition + + +
+
+Retrieving an Existing Schema by Subject, Format, and Version +To retrieve an existing schema by subject, format, and version, send GET request to the /{subject}/{format}/{version} endpoint. +Its response is a schema object in JSON, with the following fields: + + +id: The schema ID + + +subject: The schema subject + + +format: The schema format + + +version: The schema version + + +definition: The schema definition + + +
+
+Retrieving an Existing Schema by Subject and Format +To retrieve an existing schema by subject and format, send a GET request to the /subject/format endpoint. +Its response is a list of schemas with each schema object in JSON, with the following fields: + + +id: The schema ID + + +subject: The schema subject + + +format: The schema format + + +version: The schema version + + +definition: The schema definition + + +
+
+Retrieving an Existing Schema by ID +To retrieve a schema by its ID, send a GET request to the /schemas/{id} endpoint. +Its response is a schema object in JSON, with the following fields: + + +id: The schema ID + + +subject: The schema subject + + +format: The schema format + + +version: The schema version + + +definition: The schema definition + + +
+
+Deleting a Schema by Subject, Format, and Version +To delete a schema identified by its subject, format, and version, send a DELETE request to the /{subject}/{format}/{version} endpoint. +
+
+Deleting a Schema by ID +To delete a schema by its ID, send a DELETE request to the /schemas/{id} endpoint. +
+
+Deleting a Schema by Subject +DELETE /{subject} +Delete existing schemas by their subject. + +This note applies to users of Spring Cloud Stream 1.1.0.RELEASE only. +Spring Cloud Stream 1.1.0.RELEASE used the table name, schema, for storing Schema objects. Schema is a keyword in a number of database implementations. +To avoid any conflicts in the future, starting with 1.1.1.RELEASE, we have opted for the name SCHEMA_REPOSITORY for the storage table. +Any Spring Cloud Stream 1.1.0.RELEASE users who upgrade should migrate their existing schemas to the new table before upgrading. + +
+
+
+Using Confluent’s Schema Registry +The default configuration creates a DefaultSchemaRegistryClient bean. +If you want to use the Confluent schema registry, you need to create a bean of type ConfluentSchemaRegistryClient, which supersedes the one configured by default by the framework. The following example shows how to create such a bean: +@Bean +public SchemaRegistryClient schemaRegistryClient(@Value("${spring.cloud.stream.schemaRegistryClient.endpoint}") String endpoint){ + ConfluentSchemaRegistryClient client = new ConfluentSchemaRegistryClient(); + client.setEndpoint(endpoint); + return client; +} + +The ConfluentSchemaRegistryClient is tested against Confluent platform version 4.0.0. + +
+
+
+Schema Registration and Resolution +To better understand how Spring Cloud Stream registers and resolves new schemas and its use of Avro schema comparison features, we provide two separate subsections: + + + + + + + + +
+Schema Registration Process (Serialization) +The first part of the registration process is extracting a schema from the payload that is being sent over a channel. +Avro types such as SpecificRecord or GenericRecord already contain a schema, which can be retrieved immediately from the instance. +In the case of POJOs, a schema is inferred if the spring.cloud.stream.schema.avro.dynamicSchemaGenerationEnabled property is set to true (the default). +
+Schema Writer Resolution Process + + + + +schema resolution + +
+Ones a schema is obtained, the converter loads its metadata (version) from the remote server. +First, it queries a local cache. If no result is found, it submits the data to the server, which replies with versioning information. +The converter always caches the results to avoid the overhead of querying the Schema Server for every new message that needs to be serialized. +
+Schema Registration Process + + + + +registration + +
+With the schema version information, the converter sets the contentType header of the message to carry the version information — for example: application/vnd.user.v1+avro. +
+
+Schema Resolution Process (Deserialization) +When reading messages that contain version information (that is, a contentType header with a scheme like the one described under ), the converter queries the Schema server to fetch the writer schema of the message. +Once it has found the correct schema of the incoming message, it retrieves the reader schema and, by using Avro’s schema resolution support, reads it into the reader definition (setting defaults and any missing properties). +
+Schema Reading Resolution Process + + + + +schema reading + +
+ +You should understand the difference between a writer schema (the application that wrote the message) and a reader schema (the receiving application). +We suggest taking a moment to read the Avro terminology and understand the process. +Spring Cloud Stream always fetches the writer schema to determine how to read a message. +If you want to get Avro’s schema evolution support working, you need to make sure that a readerSchema was properly set for your application. + +
+
+
+ +Inter-Application Communication +Spring Cloud Stream enables communication between applications. Inter-application communication is a complex issue spanning several concerns, as described in the following topics: + + + + + + + + + + + +
+Connecting Multiple Application Instances +While Spring Cloud Stream makes it easy for individual Spring Boot applications to connect to messaging systems, the typical scenario for Spring Cloud Stream is the creation of multi-application pipelines, where microservice applications send data to each other. +You can achieve this scenario by correlating the input and output destinations of adjacent applications. +Suppose a design calls for the Time Source application to send data to the Log Sink application. You could use a common destination named ticktock for bindings within both applications. +Time Source (that has the channel name output) would set the following property: +spring.cloud.stream.bindings.output.destination=ticktock +Log Sink (that has the channel name input) would set the following property: +spring.cloud.stream.bindings.input.destination=ticktock +
+
+Instance Index and Instance Count +When scaling up Spring Cloud Stream applications, each instance can receive information about how many other instances of the same application exist and what its own instance index is. +Spring Cloud Stream does this through the spring.cloud.stream.instanceCount and spring.cloud.stream.instanceIndex properties. +For example, if there are three instances of a HDFS sink application, all three instances have spring.cloud.stream.instanceCount set to 3, and the individual applications have spring.cloud.stream.instanceIndex set to 0, 1, and 2, respectively. +When Spring Cloud Stream applications are deployed through Spring Cloud Data Flow, these properties are configured automatically; when Spring Cloud Stream applications are launched independently, these properties must be set correctly. +By default, spring.cloud.stream.instanceCount is 1, and spring.cloud.stream.instanceIndex is 0. +In a scaled-up scenario, correct configuration of these two properties is important for addressing partitioning behavior (see below) in general, and the two properties are always required by certain binders (for example, the Kafka binder) in order to ensure that data are split correctly across multiple consumer instances. +
+
+Partitioning +Partitioning in Spring Cloud Stream consists of two tasks: + + + + + + + + +
+Configuring Output Bindings for Partitioning +You can configure an output binding to send partitioned data by setting one and only one of its partitionKeyExpression or partitionKeyExtractorName properties, as well as its partitionCount property. +For example, the following is a valid and typical configuration: +spring.cloud.stream.bindings.output.producer.partitionKeyExpression=payload.id +spring.cloud.stream.bindings.output.producer.partitionCount=5 +Based on that example configuration, data is sent to the target partition by using the following logic. +A partition key’s value is calculated for each message sent to a partitioned output channel based on the partitionKeyExpression. +The partitionKeyExpression is a SpEL expression that is evaluated against the outbound message for extracting the partitioning key. +If a SpEL expression is not sufficient for your needs, you can instead calculate the partition key value by providing an implementation of org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy and configuring it as a bean (by using the @Bean annotation). +If you have more then one bean of type org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy available in the Application Context, you can further filter it by specifying its name with the partitionKeyExtractorName property, as shown in the following example: +--spring.cloud.stream.bindings.output.producer.partitionKeyExtractorName=customPartitionKeyExtractor +--spring.cloud.stream.bindings.output.producer.partitionCount=5 +. . . +@Bean +public CustomPartitionKeyExtractorClass customPartitionKeyExtractor() { + return new CustomPartitionKeyExtractorClass(); +} + +In previous versions of Spring Cloud Stream, you could specify the implementation of org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy by setting the spring.cloud.stream.bindings.output.producer.partitionKeyExtractorClass property. +Since version 2.0, this property is deprecated, and support for it will be removed in a future version. + +Once the message key is calculated, the partition selection process determines the target partition as a value between 0 and partitionCount - 1. +The default calculation, applicable in most scenarios, is based on the following formula: key.hashCode() % partitionCount. +This can be customized on the binding, either by setting a SpEL expression to be evaluated against the 'key' (through the partitionSelectorExpression property) or by configuring an implementation of org.springframework.cloud.stream.binder.PartitionSelectorStrategy as a bean (by using the @Bean annotation). +Similar to the PartitionKeyExtractorStrategy, you can further filter it by using the spring.cloud.stream.bindings.output.producer.partitionSelectorName property when more than one bean of this type is available in the Application Context, as shown in the following example: +--spring.cloud.stream.bindings.output.producer.partitionSelectorName=customPartitionSelector +. . . +@Bean +public CustomPartitionSelectorClass customPartitionSelector() { + return new CustomPartitionSelectorClass(); +} + +In previous versions of Spring Cloud Stream you could specify the implementation of org.springframework.cloud.stream.binder.PartitionSelectorStrategy by setting the spring.cloud.stream.bindings.output.producer.partitionSelectorClass property. +Since version 2.0, this property is deprecated and support for it will be removed in a future version. + +
+
+Configuring Input Bindings for Partitioning +An input binding (with the channel name input) is configured to receive partitioned data by setting its partitioned property, as well as the instanceIndex and instanceCount properties on the application itself, as shown in the following example: +spring.cloud.stream.bindings.input.consumer.partitioned=true +spring.cloud.stream.instanceIndex=3 +spring.cloud.stream.instanceCount=5 +The instanceCount value represents the total number of application instances between which the data should be partitioned. +The instanceIndex must be a unique value across the multiple instances, with a value between 0 and instanceCount - 1. +The instance index helps each application instance to identify the unique partition(s) from which it receives data. +It is required by binders using technology that does not support partitioning natively. +For example, with RabbitMQ, there is a queue for each partition, with the queue name containing the instance index. +With Kafka, if autoRebalanceEnabled is true (default), Kafka takes care of distributing partitions across instances, and these properties are not required. +If autoRebalanceEnabled is set to false, the instanceCount and instanceIndex are used by the binder to determine which partition(s) the instance subscribes to (you must have at least as many partitions as there are instances). +The binder allocates the partitions instead of Kafka. +This might be useful if you want messages for a particular partition to always go to the same instance. +When a binder configuration requires them, it is important to set both values correctly in order to ensure that all of the data is consumed and that the application instances receive mutually exclusive datasets. +While a scenario in which using multiple instances for partitioned data processing may be complex to set up in a standalone case, Spring Cloud Dataflow can simplify the process significantly by populating both the input and output values correctly and by letting you rely on the runtime infrastructure to provide information about the instance index and instance count. +
+
+
+ +Testing +Spring Cloud Stream provides support for testing your microservice applications without connecting to a messaging system. +You can do that by using the TestSupportBinder provided by the spring-cloud-stream-test-support library, which can be added as a test dependency to the application, as shown in the following example: + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-stream-test-support</artifactId> + <scope>test</scope> + </dependency> + +The TestSupportBinder uses the Spring Boot autoconfiguration mechanism to supersede the other binders found on the classpath. +Therefore, when adding a binder as a dependency, you must make sure that the test scope is being used. + +The TestSupportBinder lets you interact with the bound channels and inspect any messages sent and received by the application. +For outbound message channels, the TestSupportBinder registers a single subscriber and retains the messages emitted by the application in a MessageCollector. +They can be retrieved during tests and have assertions made against them. +You can also send messages to inbound message channels so that the consumer application can consume the messages. +The following example shows how to test both input and output channels on a processor: +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT) +public class ExampleTest { + + @Autowired + private Processor processor; + + @Autowired + private MessageCollector messageCollector; + + @Test + @SuppressWarnings("unchecked") + public void testWiring() { + Message<String> message = new GenericMessage<>("hello"); + processor.input().send(message); + Message<String> received = (Message<String>) messageCollector.forChannel(processor.output()).poll(); + assertThat(received.getPayload(), equalTo("hello world")); + } + + + @SpringBootApplication + @EnableBinding(Processor.class) + public static class MyProcessor { + + @Autowired + private Processor channels; + + @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) + public String transform(String in) { + return in + " world"; + } + } +} +In the preceding example, we create an application that has an input channel and an output channel, both bound through the Processor interface. +The bound interface is injected into the test so that we can have access to both channels. +We send a message on the input channel, and we use the MessageCollector provided by Spring Cloud Stream’s test support to capture that the message has been sent to the output channel as a result. +Once we have received the message, we can validate that the component functions correctly. +
+Disabling the Test Binder Autoconfiguration +The intent behind the test binder superseding all the other binders on the classpath is to make it easy to test your applications without making changes to your production dependencies. +In some cases (for example, integration tests) it is useful to use the actual production binders instead, and that requires disabling the test binder autoconfiguration. +To do so, you can exclude the org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration class by using one of the Spring Boot autoconfiguration exclusion mechanisms, as shown in the following example: + @SpringBootApplication(exclude = TestSupportBinderAutoConfiguration.class) + @EnableBinding(Processor.class) + public static class MyProcessor { + + @Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT) + public String transform(String in) { + return in + " world"; + } + } +When autoconfiguration is disabled, the test binder is available on the classpath, and its defaultCandidate property is set to false so that it does not interfere with the regular user configuration. It can be referenced under the name, test, as shown in the following example: +spring.cloud.stream.defaultBinder=test +
+
+ +Health Indicator +Spring Cloud Stream provides a health indicator for binders. +It is registered under the name binders and can be enabled or disabled by setting the management.health.binders.enabled property. +To enable health check you first need to enable both "web" and "actuator" by including its dependencies (see ) +If management.health.binders.enabled is not set explicitly by the application, then management.health.defaults.enabled is matched as true and the binder health indicators are enabled. +If you want to disable health indicator completely, then you have to set management.health.binders.enabled to false. +You can use Spring Boot actuator health endpoint to access the health indicator - /actuator/health. +By default, you will only receive the top level application status when you hit the above endpoint. +In order to receive the full details from the binder specific health indicators, you need to include the property management.endpoint.health.show-details with the value ALWAYS in your application. +Health indicators are binder-specific and certain binder implementations may not necessarily provide a health indicator. +If you want to completely disable all health indicators available out of the box and instead provide your own health indicators, +you can do so by setting property management.health.binders.enabled to false and then provide your own HealthIndicator beans in your application. +In this case, the health indicator infrastructure from Spring Boot will still pick up these custom beans. +Even if you are not disabling the binder health indicators, you can still enhance the health checks by providing your own HealthIndicator beans in addition to the out of the box health checks. +When you have multiple binders in the same application, health indicators are enabled by default unless the application turns them off by setting management.health.binders.enabled to false. +In this case, if the user wants to disable health check for a subset of the binders, then that should be done by setting management.health.binders.enabled to false in the multi binder configurations’s environment. +See Connecting to Multiple Systems for details on how environment specific properties can be provided. + + +Metrics Emitter +Spring Boot Actuator provides dependency management and auto-configuration for Micrometer, an application metrics +facade that supports numerous monitoring systems. +Spring Cloud Stream provides support for emitting any available micrometer-based metrics to a binding destination, allowing for periodic +collection of metric data from stream applications without relying on polling individual endpoints. +Metrics Emitter is activated by defining the spring.cloud.stream.bindings.applicationMetrics.destination property, +which specifies the name of the binding destination used by the current binder to publish metric messages. +For example: +spring.cloud.stream.bindings.applicationMetrics.destination=myMetricDestination +The preceding example instructs the binder to bind to myMetricDestination (that is, Rabbit exchange, Kafka topic, and others). +The following properties can be used for customizing the emission of metrics: + + +spring.cloud.stream.metrics.key + +The name of the metric being emitted. Should be a unique value per application. +Default: ${spring.application.name:${vcap.application.name:${spring.config.name:application}}} + + + +spring.cloud.stream.metrics.properties + +Allows white listing application properties that are added to the metrics payload +Default: null. + + + +spring.cloud.stream.metrics.meter-filter + +Pattern to control the 'meters' one wants to capture. +For example, specifying spring.integration.* captures metric information for meters whose name starts with spring.integration. +Default: all 'meters' are captured. + + + +spring.cloud.stream.metrics.schedule-interval + +Interval to control the rate of publishing metric data. +Default: 1 min + + + +Consider the following: +java -jar time-source.jar \ + --spring.cloud.stream.bindings.applicationMetrics.destination=someMetrics \ + --spring.cloud.stream.metrics.properties=spring.application** \ + --spring.cloud.stream.metrics.meter-filter=spring.integration.* +The following example shows the payload of the data published to the binding destination as a result of the preceding command: +{ + "name": "application", + "createdTime": "2018-03-23T14:48:12.700Z", + "properties": { + }, + "metrics": [ + { + "id": { + "name": "spring.integration.send", + "tags": [ + { + "key": "exception", + "value": "none" + }, + { + "key": "name", + "value": "input" + }, + { + "key": "result", + "value": "success" + }, + { + "key": "type", + "value": "channel" + } + ], + "type": "TIMER", + "description": "Send processing time", + "baseUnit": "milliseconds" + }, + "timestamp": "2018-03-23T14:48:12.697Z", + "sum": 130.340546, + "count": 6, + "mean": 21.72342433333333, + "upper": 116.176299, + "total": 130.340546 + } + ] +} + +Given that the format of the Metric message has slightly changed after migrating to Micrometer, the published message will also have +a STREAM_CLOUD_STREAM_VERSION header set to 2.x to help distinguish between Metric messages from the older versions of the Spring Cloud Stream. + + + +Samples +For Spring Cloud Stream samples, see the spring-cloud-stream-samples repository on GitHub. +
+Deploying Stream Applications on CloudFoundry +On CloudFoundry, services are usually exposed through a special environment variable called VCAP_SERVICES. +When configuring your binder connections, you can use the values from an environment variable as explained on the dataflow Cloud Foundry Server docs. +
+
+ +Binder Implementations +The following is the list of available binder implementations + + +RabbitMQ + + +Apache Kafka + + +Amazon Kinesis + + +Google PubSub (partner maintained) + + +Solace PubSub+ (partner maintained) + + +Azure Event Hubs (partner maintained) + + + +
+
\ No newline at end of file