Sync docs from vFinchley.M8 to gh-pages
71
Finchley.M8/configprops.groovy
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Run this file with groovy and collect the result as an asciidoctor source file:
|
||||
* <pre>
|
||||
* $ groovy configprops.groovy | egrep -v PathMatchingResourcePatternResolver | tee configprops.adoc
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@GrabResolver(name='milestone', root='http://repo.spring.io/milestone/')
|
||||
@Grab('org.codehaus.groovy:groovy-json:2.4.3')
|
||||
@Grab('org.springframework.cloud:spring-cloud-stream:1.2.2.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-starter-bus-amqp:1.3.1.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-starter-config:1.3.2.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-config-server:1.3.2.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-netflix-eureka-server:1.3.4.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-starter-eureka:1.3.4.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-starter-aws:1.2.1.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-starter-security:1.2.1.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-starter-consul-all:1.2.1.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-starter-zookeeper-all:1.1.2.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-starter-sleuth:1.2.4.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-starter-cloudfoundry:1.1.0.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-cloudfoundry-discovery:1.1.0.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-contract-stub-runner:1.1.3.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-vault-config:1.0.2.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-vault-config-aws:1.0.2.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-vault-config-databases:1.0.2.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-vault-config-consul:1.0.2.RELEASE')
|
||||
@Grab('org.springframework.cloud:spring-cloud-vault-config-rabbitmq:1.0.2.RELEASE')
|
||||
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver
|
||||
import org.springframework.core.io.Resource
|
||||
import groovy.json.JsonSlurper
|
||||
|
||||
def resources = new PathMatchingResourcePatternResolver().getResources("classpath*:/META-INF/spring-configuration-metadata.json")
|
||||
|
||||
TreeSet names = new TreeSet()
|
||||
def descriptions = [:]
|
||||
resources.each { it ->
|
||||
if (it.url.toString().contains("cloud")) {
|
||||
def slurper = new JsonSlurper()
|
||||
slurper.parseText(it.inputStream.text).properties.each { val ->
|
||||
names.add val.name
|
||||
descriptions[val.name] = new ConfigValue(val.name, val.description, val.defaultValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
println "|==="
|
||||
println "|Name | Default | Description"
|
||||
println ""
|
||||
names.each { it ->
|
||||
println descriptions[it]
|
||||
println ""
|
||||
}
|
||||
println "|==="
|
||||
|
||||
|
||||
class ConfigValue {
|
||||
String name
|
||||
String description
|
||||
Object defaultValue
|
||||
ConfigValue(){}
|
||||
ConfigValue(String name, String description, Object defaultValue) {
|
||||
this.name = name
|
||||
this.description = description
|
||||
this.defaultValue = defaultValue
|
||||
}
|
||||
String toString() {
|
||||
def value = defaultValue==null?'':"${defaultValue}"
|
||||
"|${name} | ${value} | ${description?:''}"
|
||||
}
|
||||
}
|
||||
35
Finchley.M8/css/highlight.css
Normal file
@@ -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;
|
||||
}
|
||||
9
Finchley.M8/css/manual-multipage.css
Normal file
@@ -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;
|
||||
}
|
||||
6
Finchley.M8/css/manual-singlepage.css
Normal file
@@ -0,0 +1,6 @@
|
||||
@IMPORT url("manual.css");
|
||||
|
||||
body {
|
||||
background: url("../images/background.png") no-repeat center top;
|
||||
}
|
||||
|
||||
344
Finchley.M8/css/manual.css
Normal file
@@ -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;
|
||||
}
|
||||
348
Finchley.M8/ghpages.sh
Normal file
@@ -0,0 +1,348 @@
|
||||
#!/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) && [[ "${RELEASE_TRAIN}" != "yes" ]] ; 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() {
|
||||
if [[ "${RELEASE_TRAIN}" != "yes" ]] ; then
|
||||
git checkout v${VERSION}
|
||||
fi
|
||||
}
|
||||
|
||||
# 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}' \
|
||||
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
|
||||
-P docs \
|
||||
-pl docs)
|
||||
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} && cd ${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
|
||||
if [[ -z "${RELEASE_TRAIN}" ]] ; then
|
||||
DESTINATION_REPO_FOLDER=${clonedStatic}/${REPO_NAME}
|
||||
else
|
||||
DESTINATION_REPO_FOLDER=${clonedStatic}
|
||||
fi
|
||||
mkdir -p ${DESTINATION_REPO_FOLDER}
|
||||
else
|
||||
if [[ ! -e "${DESTINATION}/.git" ]]; then
|
||||
echo "[${DESTINATION}] is not a git repository"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z "${RELEASE_TRAIN}" ]] ; then
|
||||
DESTINATION_REPO_FOLDER=${DESTINATION}/${REPO_NAME}
|
||||
else
|
||||
DESTINATION_REPO_FOLDER=${DESTINATION}
|
||||
fi
|
||||
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}" && -z "${RELEASE_TRAIN}" ]] ; 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 1.0.0.RELEASE/ 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 1.0.0.RELEASE/ 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}], RELEASE_TRAIN [${RELEASE_TRAIN}], 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
|
||||
if [[ "${RELEASE_TRAIN}" != "" && -z "${VERSION}" ]] ; then echo "Release train was set but no version was passed!"; exit 1;fi
|
||||
}
|
||||
|
||||
# Prints the usage
|
||||
function print_usage() {
|
||||
cat <<EOF
|
||||
The idea of this script is to update gh-pages branch with the generated docs. Without any options
|
||||
the script will work in the following manner:
|
||||
|
||||
- if there's no gh-pages / target for docs module then the script ends
|
||||
- for master branch the generated docs are copied to the root of gh-pages branch
|
||||
- for any other branch (if that branch is whitelisted) a subfolder with branch name is created
|
||||
and docs are copied there
|
||||
- if the version switch is passed (-v) then a tag with (v) prefix will be retrieved and a folder
|
||||
with that version number will be created in the gh-pages branch. WARNING! No whitelist verification will take place
|
||||
- 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/<project-name>/<version>`
|
||||
- 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/<project-name>/<version>`
|
||||
- if the release train switch is passed (-r) 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/<version>`
|
||||
|
||||
USAGE:
|
||||
|
||||
You can use the following options:
|
||||
|
||||
-v|--version - the script will apply the whole procedure for a particular library version
|
||||
-r|--releasetrain - instead of nesting the docs under the project_name/version folder the docs will end up in 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
|
||||
;;
|
||||
-r|--releasetrain)
|
||||
RELEASE_TRAIN="yes"
|
||||
;;
|
||||
-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
|
||||
0
Finchley.M8/images/.gitkeep
Normal file
BIN
Finchley.M8/images/Deps.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
Finchley.M8/images/Hystrix.png
Normal file
|
After Width: | Height: | Size: 225 KiB |
BIN
Finchley.M8/images/HystrixFallback.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
Finchley.M8/images/HystrixGraph.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
Finchley.M8/images/RequestLatency.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
Finchley.M8/images/SCSt-groups.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
Finchley.M8/images/SCSt-partitioning.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
Finchley.M8/images/SCSt-sensors.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
Finchley.M8/images/SCSt-with-binder.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
Finchley.M8/images/Stubs1.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
Finchley.M8/images/Stubs2.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
Finchley.M8/images/background.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
Finchley.M8/images/caution.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
Finchley.M8/images/dependencies.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
Finchley.M8/images/important.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
Finchley.M8/images/kibana.png
Normal file
|
After Width: | Height: | Size: 183 KiB |
BIN
Finchley.M8/images/logo.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
Finchley.M8/images/note.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
Finchley.M8/images/parents.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
Finchley.M8/images/part-bindings.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
Finchley.M8/images/part-exchange.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
Finchley.M8/images/part-queues.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
Finchley.M8/images/producers-consumers.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
Finchley.M8/images/pws.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
Finchley.M8/images/rabbit-binder.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
Finchley.M8/images/redis-binder.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
Finchley.M8/images/registration.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
Finchley.M8/images/schema_reading.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
Finchley.M8/images/schema_resolution.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
Finchley.M8/images/sts_exception.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
Finchley.M8/images/tip.png
Normal file
|
After Width: | Height: | Size: 931 B |
BIN
Finchley.M8/images/trace-id.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
Finchley.M8/images/warning.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
Finchley.M8/images/web-selected.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
Finchley.M8/images/zipkin-error-trace-screenshot.png
Normal file
|
After Width: | Height: | Size: 206 KiB |
BIN
Finchley.M8/images/zipkin-error-traces.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
Finchley.M8/images/zipkin-trace-screenshot.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
Finchley.M8/images/zipkin-traces.png
Normal file
|
After Width: | Height: | Size: 149 KiB |
BIN
Finchley.M8/images/zipkin-ui.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
117
Finchley.M8/index.html
Normal file
@@ -0,0 +1,117 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="generator" content="Asciidoctor 1.5.5">
|
||||
<title>spring-cloud</title>
|
||||
<link rel="stylesheet" href="css/manual-singlepage.css">
|
||||
<style>
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.switch {
|
||||
border-width: 1px 1px 0 1px;
|
||||
border-style: solid;
|
||||
border-color: #7a2518;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.switch--item {
|
||||
padding: 10px;
|
||||
background-color: #ffffff;
|
||||
color: #7a2518;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.switch--item.selected {
|
||||
background-color: #7a2519;
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/zepto/1.2.0/zepto.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
function addBlockSwitches() {
|
||||
$('.primary').each(function() {
|
||||
primary = $(this);
|
||||
createSwitchItem(primary, createBlockSwitch(primary)).item.addClass("selected");
|
||||
primary.children('.title').remove();
|
||||
});
|
||||
$('.secondary').each(function(idx, node) {
|
||||
secondary = $(node);
|
||||
primary = findPrimary(secondary);
|
||||
switchItem = createSwitchItem(secondary, primary.children('.switch'));
|
||||
switchItem.content.addClass('hidden');
|
||||
findPrimary(secondary).append(switchItem.content);
|
||||
secondary.remove();
|
||||
});
|
||||
}
|
||||
|
||||
function createBlockSwitch(primary) {
|
||||
blockSwitch = $('<div class="switch"></div>');
|
||||
primary.prepend(blockSwitch);
|
||||
return blockSwitch;
|
||||
}
|
||||
|
||||
function findPrimary(secondary) {
|
||||
candidate = secondary.prev();
|
||||
while (!candidate.is('.primary')) {
|
||||
candidate = candidate.prev();
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
|
||||
function createSwitchItem(block, blockSwitch) {
|
||||
blockName = block.children('.title').text();
|
||||
content = block.children('.content').first().append(block.next('.colist'));
|
||||
item = $('<div class="switch--item">' + blockName + '</div>');
|
||||
item.on('click', '', content, function(e) {
|
||||
$(this).addClass('selected');
|
||||
$(this).siblings().removeClass('selected');
|
||||
e.data.siblings('.content').addClass('hidden');
|
||||
e.data.removeClass('hidden');
|
||||
});
|
||||
blockSwitch.append(item);
|
||||
return {'item': item, 'content': content};
|
||||
}
|
||||
|
||||
$(addBlockSwitches);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="article">
|
||||
<div id="header">
|
||||
<h1>spring-cloud</h1>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>1.3.5.BUILD-SNAPSHOT</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect1">
|
||||
<h2 id="_pick_the_documentation_option">Pick The Documentation Option</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p><a href="single/spring-cloud.html">Single HTML</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="multi/multi_spring-cloud.html">Multi HTML</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.js"></script>
|
||||
<script>prettyPrint()</script>
|
||||
</body>
|
||||
</html>
|
||||
35
Finchley.M8/multi/css/highlight.css
Normal file
@@ -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;
|
||||
}
|
||||
9
Finchley.M8/multi/css/manual-multipage.css
Normal file
@@ -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;
|
||||
}
|
||||
6
Finchley.M8/multi/css/manual-singlepage.css
Normal file
@@ -0,0 +1,6 @@
|
||||
@IMPORT url("manual.css");
|
||||
|
||||
body {
|
||||
background: url("../images/background.png") no-repeat center top;
|
||||
}
|
||||
|
||||
344
Finchley.M8/multi/css/manual.css
Normal file
@@ -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;
|
||||
}
|
||||
BIN
Finchley.M8/multi/images/background.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
Finchley.M8/multi/images/caution.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
Finchley.M8/multi/images/important.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
Finchley.M8/multi/images/logo.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
Finchley.M8/multi/images/note.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
Finchley.M8/multi/images/sts_exception.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
Finchley.M8/multi/images/tip.png
Normal file
|
After Width: | Height: | Size: 931 B |
BIN
Finchley.M8/multi/images/warning.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
Finchley.M8/multi/images/web-selected.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
3
Finchley.M8/multi/multi__actuator_api.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>113. Actuator API</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_gateway.html" title="Part XV. Spring Cloud Gateway"><link rel="prev" href="multi__configuration_2.html" title="112. Configuration"><link rel="next" href="multi__developer_guide.html" title="114. Developer Guide"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">113. Actuator API</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__configuration_2.html">Prev</a> </td><th width="60%" align="center">Part XV. Spring Cloud Gateway</th><td width="20%" align="right"> <a accesskey="n" href="multi__developer_guide.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_actuator_api" href="#_actuator_api"></a>113. Actuator API</h2></div></div></div><p>TODO: document the <code class="literal">/gateway</code> actuator endpoint</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__configuration_2.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_gateway.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__developer_guide.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">112. Configuration </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 114. Developer Guide</td></tr></table></div></body></html>
|
||||
3
Finchley.M8/multi/multi__additional_resources.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>48. Additional resources</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__introduction.html" title="47. Introduction"><link rel="next" href="multi__features_2.html" title="49. Features"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">48. Additional resources</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__introduction.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__features_2.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_additional_resources" href="#_additional_resources"></a>48. Additional resources</h2></div></div></div><p><span class="strong"><strong>Marcin Grzejszczak talking about Spring Cloud Sleuth and Zipkin</strong></span></p><p><a class="link" href="https://www.youtube.com/watch?v=eQV71Mw1u1c" target="_top">click here to see the video</a></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__introduction.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__features_2.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">47. Introduction </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 49. Features</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>42. Addressing all instances of a service</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_bus.html" title="Part VII. Spring Cloud Bus"><link rel="prev" href="multi__addressing_an_instance.html" title="41. Addressing an Instance"><link rel="next" href="multi__service_id_must_be_unique.html" title="43. Service ID must be unique"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">42. Addressing all instances of a service</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__addressing_an_instance.html">Prev</a> </td><th width="60%" align="center">Part VII. Spring Cloud Bus</th><td width="20%" align="right"> <a accesskey="n" href="multi__service_id_must_be_unique.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_addressing_all_instances_of_a_service" href="#_addressing_all_instances_of_a_service"></a>42. Addressing all instances of a service</h2></div></div></div><p>The "destination" parameter is used in a Spring <code class="literal">PathMatcher</code> (with the path separator as a colon <code class="literal">:</code>) to determine if an instance will process the message. Using the example from above, "/bus/refresh?destination=customers:**" will target all instances of the "customers" service regardless of the rest of the service ID.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__addressing_an_instance.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_bus.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__service_id_must_be_unique.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">41. Addressing an Instance </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 43. Service ID must be unique</td></tr></table></div></body></html>
|
||||
3
Finchley.M8/multi/multi__addressing_an_instance.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>41. Addressing an Instance</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_bus.html" title="Part VII. Spring Cloud Bus"><link rel="prev" href="multi__quick_start_2.html" title="40. Quick Start"><link rel="next" href="multi__addressing_all_instances_of_a_service.html" title="42. Addressing all instances of a service"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">41. Addressing an Instance</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__quick_start_2.html">Prev</a> </td><th width="60%" align="center">Part VII. Spring Cloud Bus</th><td width="20%" align="right"> <a accesskey="n" href="multi__addressing_all_instances_of_a_service.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_addressing_an_instance" href="#_addressing_an_instance"></a>41. Addressing an Instance</h2></div></div></div><p>Each instance of the application has a service ID, whose value can be set using <code class="literal">spring.cloud.bus.id</code>, and whose value is expected to be a colon-separated list of identifiers, in order of least specific to most specific. The default value is constructed from the environment as a combination of the <code class="literal">spring.application.name</code> and <code class="literal">server.port</code> (or <code class="literal">spring.application.index</code> if set). The default value of the ID is constructed in the form <code class="literal">app:index:id</code> where:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">app</code> is the <code class="literal">vcap.application.name</code> if it exists, or <code class="literal">spring.application.name</code></li><li class="listitem"><code class="literal">index</code> is the <code class="literal">vcap.application.instance_index</code> if it exists, or else <code class="literal">spring.application.index</code>, or else <code class="literal">local.server.port</code> (or <code class="literal">server.port</code> or <code class="literal">0</code>).</li><li class="listitem"><code class="literal">id</code> is the <code class="literal">vcap.application.instance_id</code> if it exists, or else a random value.</li></ul></div><p>The HTTP endpoints accept a "destination" parameter, e.g. "/bus/refresh?destination=customers:9000", where the destination is a service ID. If the ID is owned by an instance on the Bus then it will process the message and all other instances will ignore it.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__quick_start_2.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_bus.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__addressing_all_instances_of_a_service.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">40. Quick Start </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 42. Addressing all instances of a service</td></tr></table></div></body></html>
|
||||
342
Finchley.M8/multi/multi__apache_kafka_binder.html
Normal file
@@ -0,0 +1,342 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>37. Apache Kafka Binder</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__binder_implementations.html" title="Part VI. Binder Implementations"><link rel="prev" href="multi__binder_implementations.html" title="Part VI. Binder Implementations"><link rel="next" href="multi__apache_kafka_streams_binder.html" title="38. Apache Kafka Streams Binder"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">37. Apache Kafka Binder</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__binder_implementations.html">Prev</a> </td><th width="60%" align="center">Part VI. Binder Implementations</th><td width="20%" align="right"> <a accesskey="n" href="multi__apache_kafka_streams_binder.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_apache_kafka_binder" href="#_apache_kafka_binder"></a>37. Apache Kafka Binder</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_usage" href="#_usage"></a>37.1 Usage</h2></div></div></div><p>For using the Apache Kafka binder, you just need to add it to your Spring Cloud Stream application, using the following Maven coordinates:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-stream-binder-kafka<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p>Alternatively, you can also use the Spring Cloud Stream Kafka Starter.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-stream-kafka<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_apache_kafka_binder_overview" href="#_apache_kafka_binder_overview"></a>37.2 Apache Kafka Binder Overview</h2></div></div></div><p>A simplified diagram of how the Apache Kafka binder operates can be seen below.</p><div class="figure"><a name="d0e9555" href="#d0e9555"></a><p class="title"><b>Figure 37.1. Kafka Binder</b></p><div class="figure-contents"><div class="mediaobject"><img src="images/kafka-binder.png" alt="kafka binder"></div></div></div><br class="figure-break"><p>The Apache Kafka Binder implementation maps each destination to an Apache Kafka topic.
|
||||
The consumer group maps directly to the same Apache Kafka concept.
|
||||
Partitioning also maps directly to Apache Kafka partitions as well.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_configuration_options_2" href="#_configuration_options_2"></a>37.3 Configuration Options</h2></div></div></div><p>This section contains the configuration options used by the Apache Kafka binder.</p><p>For common configuration options and properties pertaining to binder, refer to the <a class="link" href="multi__configuration_options.html#binding-properties" title="28.2 Binding Properties">core documentation</a>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_kafka_binder_properties" href="#_kafka_binder_properties"></a>37.3.1 Kafka Binder Properties</h3></div></div></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">spring.cloud.stream.kafka.binder.brokers</span></dt><dd><p class="simpara">A list of brokers to which the Kafka binder will connect.</p><p class="simpara">Default: <code class="literal">localhost</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.defaultBrokerPort</span></dt><dd><p class="simpara"> <code class="literal">brokers</code> allows hosts specified with or without port information (e.g., <code class="literal">host1,host2:port2</code>).
|
||||
This sets the default port when no port is configured in the broker list.</p><p class="simpara">Default: <code class="literal">9092</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.zkNodes</span></dt><dd><p class="simpara">A list of ZooKeeper nodes to which the Kafka binder can connect.</p><p class="simpara">Default: <code class="literal">localhost</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.defaultZkPort</span></dt><dd><p class="simpara"> <code class="literal">zkNodes</code> allows hosts specified with or without port information (e.g., <code class="literal">host1,host2:port2</code>).
|
||||
This sets the default port when no port is configured in the node list.</p><p class="simpara">Default: <code class="literal">2181</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.configuration</span></dt><dd><p class="simpara"> Key/Value map of client properties (both producers and consumer) passed to all clients created by the binder.
|
||||
Due to the fact that these properties will be used by both producers and consumers, usage should be restricted to common properties, especially security settings.</p><p class="simpara">Default: Empty map.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.headers</span></dt><dd><p class="simpara">The list of custom headers that will be transported by the binder.</p><p class="simpara">Default: empty.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.healthTimeout</span></dt><dd><p class="simpara">The time to wait to get partition information in seconds; default 60.
|
||||
Health will report as down if this timer expires.</p><p class="simpara">Default: 10.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.offsetUpdateTimeWindow</span></dt><dd><p class="simpara"> The frequency, in milliseconds, with which offsets are saved.
|
||||
Ignored if <code class="literal">0</code>.</p><p class="simpara">Default: <code class="literal">10000</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.offsetUpdateCount</span></dt><dd><p class="simpara"> The frequency, in number of updates, which which consumed offsets are persisted.
|
||||
Ignored if <code class="literal">0</code>.
|
||||
Mutually exclusive with <code class="literal">offsetUpdateTimeWindow</code>.</p><p class="simpara">Default: <code class="literal">0</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.requiredAcks</span></dt><dd><p class="simpara">The number of required acks on the broker.</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.minPartitionCount</span></dt><dd><p class="simpara"> Effective only if <code class="literal">autoCreateTopics</code> or <code class="literal">autoAddPartitions</code> is set.
|
||||
The global minimum number of partitions that the binder will configure on topics on which it produces/consumes data.
|
||||
It can be superseded by the <code class="literal">partitionCount</code> setting of the producer or by the value of <code class="literal">instanceCount</code> * <code class="literal">concurrency</code> settings of the producer (if either is larger).</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.replicationFactor</span></dt><dd><p class="simpara">The replication factor of auto-created topics if <code class="literal">autoCreateTopics</code> is active.</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.autoCreateTopics</span></dt><dd><p class="simpara"> If set to <code class="literal">true</code>, the binder will create new topics automatically.
|
||||
If set to <code class="literal">false</code>, the binder will rely on the topics being already configured.
|
||||
In the latter case, if the topics do not exist, the binder will fail to start.
|
||||
Of note, this setting is independent of the <code class="literal">auto.topic.create.enable</code> setting of the broker and it does not influence it: if the server is set to auto-create topics, they may be created as part of the metadata retrieval request, with default broker settings.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.autoAddPartitions</span></dt><dd><p class="simpara"> If set to <code class="literal">true</code>, the binder will create add new partitions if required.
|
||||
If set to <code class="literal">false</code>, the binder will rely on the partition size of the topic being already configured.
|
||||
If the partition count of the target topic is smaller than the expected value, the binder will fail to start.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.socketBufferSize</span></dt><dd><p class="simpara">Size (in bytes) of the socket buffer to be used by the Kafka consumers.</p><p class="simpara">Default: <code class="literal">2097152</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.transaction.transactionIdPrefix</span></dt><dd><p class="simpara">Enable transactions in the binder; see <code class="literal">transaction.id</code> in the Kafka documentation and <a class="link" href="https://docs.spring.io/spring-kafka/reference/html/_reference.html#transactions" target="_top">Transactions</a> in the <code class="literal">spring-kafka</code> documentation.
|
||||
When transactions are enabled, individual <code class="literal">producer</code> properties are ignored and all producers use the <code class="literal">spring.cloud.stream.kafka.binder.transaction.producer.*</code> properties.</p><p class="simpara">Default <code class="literal">null</code> (no transactions)</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.transaction.producer.*</span></dt><dd><p class="simpara">Global producer properties for producers in a transactional binder.
|
||||
See <code class="literal">spring.cloud.stream.kafka.binder.transaction.transactionIdPrefix</code> and <a class="xref" href="multi__apache_kafka_binder.html#kafka-producer-properties" title="37.3.3 Kafka Producer Properties">Section 37.3.3, “Kafka Producer Properties”</a> and the general producer properties supported by all binders.</p><p class="simpara">Default: See individual producer properties.</p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="kafka-consumer-properties" href="#kafka-consumer-properties"></a>37.3.2 Kafka Consumer Properties</h3></div></div></div><p>The following properties are available for Kafka consumers only and
|
||||
must be prefixed with <code class="literal">spring.cloud.stream.kafka.bindings.<channelName>.consumer.</code>.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">autoRebalanceEnabled</span></dt><dd><p class="simpara">When <code class="literal">true</code>, topic partitions will be automatically rebalanced between the members of a consumer group.
|
||||
When <code class="literal">false</code>, each consumer will be assigned a fixed set of partitions based on <code class="literal">spring.cloud.stream.instanceCount</code> and <code class="literal">spring.cloud.stream.instanceIndex</code>.
|
||||
This requires both <code class="literal">spring.cloud.stream.instanceCount</code> and <code class="literal">spring.cloud.stream.instanceIndex</code> properties to be set appropriately on each launched instance.
|
||||
The property <code class="literal">spring.cloud.stream.instanceCount</code> must typically be greater than 1 in this case.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">autoCommitOffset</span></dt><dd><p class="simpara"> Whether to autocommit offsets when a message has been processed.
|
||||
If set to <code class="literal">false</code>, a header with the key <code class="literal">kafka_acknowledgment</code> of the type <code class="literal">org.springframework.kafka.support.Acknowledgment</code> header will be present in the inbound message.
|
||||
Applications may use this header for acknowledging messages.
|
||||
See the examples section for details.
|
||||
When this property is set to <code class="literal">false</code>, Kafka binder will set the ack mode to <code class="literal">org.springframework.kafka.listener.AbstractMessageListenerContainer.AckMode.MANUAL</code>.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">autoCommitOnError</span></dt><dd><p class="simpara"> Effective only if <code class="literal">autoCommitOffset</code> is set to <code class="literal">true</code>.
|
||||
If set to <code class="literal">false</code> it suppresses auto-commits for messages that result in errors, and will commit only for successful messages, allows a stream to automatically replay from the last successfully processed message, in case of persistent failures.
|
||||
If set to <code class="literal">true</code>, it will always auto-commit (if auto-commit is enabled).
|
||||
If not set (default), it effectively has the same value as <code class="literal">enableDlq</code>, auto-committing erroneous messages if they are sent to a DLQ, and not committing them otherwise.</p><p class="simpara">Default: not set.</p></dd><dt><span class="term">recoveryInterval</span></dt><dd><p class="simpara">The interval between connection recovery attempts, in milliseconds.</p><p class="simpara">Default: <code class="literal">5000</code>.</p></dd><dt><span class="term">startOffset</span></dt><dd><p class="simpara"> The starting offset for new groups.
|
||||
Allowed values: <code class="literal">earliest</code>, <code class="literal">latest</code>.
|
||||
If the consumer group is set explicitly for the consumer 'binding' (via <code class="literal">spring.cloud.stream.bindings.<channelName>.group</code>), then 'startOffset' is set to <code class="literal">earliest</code>; otherwise it is set to <code class="literal">latest</code> for the <code class="literal">anonymous</code> consumer group.</p><p class="simpara">Default: null (equivalent to <code class="literal">earliest</code>).</p></dd><dt><span class="term">enableDlq</span></dt><dd><p class="simpara">When set to true, it will send enable DLQ behavior for the consumer.
|
||||
By default, messages that result in errors will be forwarded to a topic named <code class="literal">error.<destination>.<group></code>.
|
||||
The DLQ topic name can be configurable via the property <code class="literal">dlqName</code>.
|
||||
This provides an alternative option to the more common Kafka replay scenario for the case when the number of errors is relatively small and replaying the entire original topic may be too cumbersome.
|
||||
See <a class="xref" href="multi__apache_kafka_binder.html#kafka-dlq-processing" title="37.6 Dead-Letter Topic Processing">Section 37.6, “Dead-Letter Topic Processing”</a> processing for more information.
|
||||
Starting with <span class="emphasis"><em>version 2.0</em></span>, messages sent to the DLQ topic are enhanced with the following headers: <code class="literal">x-original-topic</code>, <code class="literal">x-exception-message</code> and <code class="literal">x-exception-stacktrace</code> as <code class="literal">byte[]</code>.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">configuration</span></dt><dd><p class="simpara">Map with a key/value pair containing generic Kafka consumer properties.</p><p class="simpara">Default: Empty map.</p></dd><dt><span class="term">dlqName</span></dt><dd><p class="simpara">The name of the DLQ topic to receive the error messages.</p><p class="simpara">Default: null (If not specified, messages that result in errors will be forwarded to a topic named <code class="literal">error.<destination>.<group></code>).</p></dd><dt><span class="term">dlqProducerProperties</span></dt><dd><p class="simpara">Using this, dlq specific producer properties can be set.
|
||||
All the properties available through kafka producer properties can be set through this property.</p><p class="simpara">Default: Default Kafka producer properties.</p></dd><dt><span class="term">standardHeaders</span></dt><dd><p class="simpara">Indicates which standard headers are populated by the inbound channel adapter.
|
||||
<code class="literal">none</code>, <code class="literal">id</code>, <code class="literal">timestamp</code> or <code class="literal">both</code>.
|
||||
Useful if using native deserialization and the first component to receive a message needs an <code class="literal">id</code> (such as an aggregator that is configured to use a JDBC message store).</p><p class="simpara">Default: <code class="literal">none</code></p></dd><dt><span class="term">converterBeanName</span></dt><dd><p class="simpara">The name of a bean that implements <code class="literal">RecordMessageConverter</code>; used in the inbound channel adapter to replace the default <code class="literal">MessagingMessageConverter</code>.</p><p class="simpara">Default: <code class="literal">null</code></p></dd><dt><span class="term">idleEventInterval</span></dt><dd><p class="simpara">The interval, in milliseconds between events indicating that no messages have recently been received.
|
||||
Use an <code class="literal">ApplicationListener<ListenerContainerIdleEvent></code> to receive these events.
|
||||
See <a class="xref" href="multi__apache_kafka_binder.html#pause-resume" title="Example: Pausing and Resuming the Consumer">the section called “Example: Pausing and Resuming the Consumer”</a> for a usage example.</p><p class="simpara">Default: <code class="literal">30000</code></p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="kafka-producer-properties" href="#kafka-producer-properties"></a>37.3.3 Kafka Producer Properties</h3></div></div></div><p>The following properties are available for Kafka producers only and
|
||||
must be prefixed with <code class="literal">spring.cloud.stream.kafka.bindings.<channelName>.producer.</code>.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">bufferSize</span></dt><dd><p class="simpara">Upper limit, in bytes, of how much data the Kafka producer will attempt to batch before sending.</p><p class="simpara">Default: <code class="literal">16384</code>.</p></dd><dt><span class="term">sync</span></dt><dd><p class="simpara">Whether the producer is synchronous.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">batchTimeout</span></dt><dd><p class="simpara"> How long the producer will wait before sending in order to allow more messages to accumulate in the same batch.
|
||||
(Normally the producer does not wait at all, and simply sends all the messages that accumulated while the previous send was in progress.) A non-zero value may increase throughput at the expense of latency.</p><p class="simpara">Default: <code class="literal">0</code>.</p></dd><dt><span class="term">messageKeyExpression</span></dt><dd><p class="simpara"> A SpEL expression evaluated against the outgoing message used to populate the key of the produced Kafka message.
|
||||
For example <code class="literal">headers.key</code> or <code class="literal">payload.myKey</code>.</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">headerPatterns</span></dt><dd><p class="simpara">A comma-delimited list of simple patterns to match spring-messaging headers to be mapped to the kafka <code class="literal">Headers</code> in the <code class="literal">ProducerRecord</code>.
|
||||
Patterns can begin or end with the wildcard character (asterisk).
|
||||
Patterns can be negated by prefixing with <code class="literal">!</code>; matching stops after the first match (positive or negative).
|
||||
For example <code class="literal">!foo,fo*</code> will pass <code class="literal">fox</code> but not <code class="literal">foo</code>.
|
||||
<code class="literal">id</code> and <code class="literal">timestamp</code> are never mapped.</p><p class="simpara">Default: <code class="literal">*</code> (all headers - except the <code class="literal">id</code> and <code class="literal">timestamp</code>)</p></dd><dt><span class="term">configuration</span></dt><dd><p class="simpara">Map with a key/value pair containing generic Kafka producer properties.</p><p class="simpara">Default: Empty map.</p></dd></dl></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The Kafka binder will use the <code class="literal">partitionCount</code> setting of the producer as a hint to create a topic with the given partition count (in conjunction with the <code class="literal">minPartitionCount</code>, the maximum of the two being the value being used).
|
||||
Exercise caution when configuring both <code class="literal">minPartitionCount</code> for a binder and <code class="literal">partitionCount</code> for an application, as the larger value will be used.
|
||||
If a topic already exists with a smaller partition count and <code class="literal">autoAddPartitions</code> is disabled (the default), then the binder will fail to start.
|
||||
If a topic already exists with a smaller partition count and <code class="literal">autoAddPartitions</code> is enabled, new partitions will be added.
|
||||
If a topic already exists with a larger number of partitions than the maximum of (<code class="literal">minPartitionCount</code> and <code class="literal">partitionCount</code>), the existing partition count will be used.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_usage_examples" href="#_usage_examples"></a>37.3.4 Usage examples</h3></div></div></div><p>In this section, we illustrate the use of the above properties for specific scenarios.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_example_setting_literal_autocommitoffset_literal_false_and_relying_on_manual_acking" href="#_example_setting_literal_autocommitoffset_literal_false_and_relying_on_manual_acking"></a>Example: Setting <code class="literal">autoCommitOffset</code> false and relying on manual acking.</h4></div></div></div><p>This example illustrates how one may manually acknowledge offsets in a consumer application.</p><p>This example requires that <code class="literal">spring.cloud.stream.kafka.bindings.input.consumer.autoCommitOffset</code> is set to false.
|
||||
Use the corresponding input channel name for your example.</p><pre class="screen">@SpringBootApplication
|
||||
@EnableBinding(Sink.class)
|
||||
public class ManuallyAcknowdledgingConsumer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ManuallyAcknowdledgingConsumer.class, args);
|
||||
}
|
||||
|
||||
@StreamListener(Sink.INPUT)
|
||||
public void process(Message<?> message) {
|
||||
Acknowledgment acknowledgment = message.getHeaders().get(KafkaHeaders.ACKNOWLEDGMENT, Acknowledgment.class);
|
||||
if (acknowledgment != null) {
|
||||
System.out.println("Acknowledgment provided");
|
||||
acknowledgment.acknowledge();
|
||||
}
|
||||
}
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_example_security_configuration" href="#_example_security_configuration"></a>Example: security configuration</h4></div></div></div><p>Apache Kafka 0.9 supports secure connections between client and brokers.
|
||||
To take advantage of this feature, follow the guidelines in the <a class="link" href="http://kafka.apache.org/090/documentation.html#security_configclients" target="_top">Apache Kafka Documentation</a> as well as the Kafka 0.9 <a class="link" href="http://docs.confluent.io/2.0.0/kafka/security.html" target="_top">security guidelines from the Confluent documentation</a>.
|
||||
Use the <code class="literal">spring.cloud.stream.kafka.binder.configuration</code> option to set security properties for all clients created by the binder.</p><p>For example, for setting <code class="literal">security.protocol</code> to <code class="literal">SASL_SSL</code>, set:</p><pre class="screen">spring.cloud.stream.kafka.binder.configuration.security.protocol=SASL_SSL</pre><p>All the other security properties can be set in a similar manner.</p><p>When using Kerberos, follow the instructions in the <a class="link" href="http://kafka.apache.org/090/documentation.html#security_sasl_clientconfig" target="_top">reference documentation</a> for creating and referencing the JAAS configuration.</p><p>Spring Cloud Stream supports passing JAAS configuration information to the application using a JAAS configuration file and using Spring Boot properties.</p><div class="section"><div class="titlepage"><div><div><h5 class="title"><a name="_using_jaas_configuration_files" href="#_using_jaas_configuration_files"></a>Using JAAS configuration files</h5></div></div></div><p>The JAAS, and (optionally) krb5 file locations can be set for Spring Cloud Stream applications by using system properties.
|
||||
Here is an example of launching a Spring Cloud Stream application with SASL and Kerberos using a JAAS configuration file:</p><pre class="screen"> java -Djava.security.auth.login.config=/path.to/kafka_client_jaas.conf -jar log.jar \
|
||||
--spring.cloud.stream.kafka.binder.brokers=secure.server:9092 \
|
||||
--spring.cloud.stream.kafka.binder.zkNodes=secure.zookeeper:2181 \
|
||||
--spring.cloud.stream.bindings.input.destination=stream.ticktock \
|
||||
--spring.cloud.stream.kafka.binder.configuration.security.protocol=SASL_PLAINTEXT</pre></div><div class="section"><div class="titlepage"><div><div><h5 class="title"><a name="_using_spring_boot_properties" href="#_using_spring_boot_properties"></a>Using Spring Boot properties</h5></div></div></div><p>As an alternative to having a JAAS configuration file, Spring Cloud Stream provides a mechanism for setting up the JAAS configuration for Spring Cloud Stream applications using Spring Boot properties.</p><p>The following properties can be used for configuring the login context of the Kafka client.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">spring.cloud.stream.kafka.binder.jaas.loginModule</span></dt><dd><p class="simpara">The login module name. Not necessary to be set in normal cases.</p><p class="simpara">Default: <code class="literal">com.sun.security.auth.module.Krb5LoginModule</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.jaas.controlFlag</span></dt><dd><p class="simpara">The control flag of the login module.</p><p class="simpara">Default: <code class="literal">required</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.jaas.options</span></dt><dd><p class="simpara">Map with a key/value pair containing the login module options.</p><p class="simpara">Default: Empty map.</p></dd></dl></div><p>Here is an example of launching a Spring Cloud Stream application with SASL and Kerberos using Spring Boot configuration properties:</p><pre class="screen"> java --spring.cloud.stream.kafka.binder.brokers=secure.server:9092 \
|
||||
--spring.cloud.stream.kafka.binder.zkNodes=secure.zookeeper:2181 \
|
||||
--spring.cloud.stream.bindings.input.destination=stream.ticktock \
|
||||
--spring.cloud.stream.kafka.binder.autoCreateTopics=false \
|
||||
--spring.cloud.stream.kafka.binder.configuration.security.protocol=SASL_PLAINTEXT \
|
||||
--spring.cloud.stream.kafka.binder.jaas.options.useKeyTab=true \
|
||||
--spring.cloud.stream.kafka.binder.jaas.options.storeKey=true \
|
||||
--spring.cloud.stream.kafka.binder.jaas.options.keyTab=/etc/security/keytabs/kafka_client.keytab \
|
||||
--spring.cloud.stream.kafka.binder.jaas.options.principal=kafka-client-1@EXAMPLE.COM</pre><p>This represents the equivalent of the following JAAS file:</p><pre class="screen">KafkaClient {
|
||||
com.sun.security.auth.module.Krb5LoginModule required
|
||||
useKeyTab=true
|
||||
storeKey=true
|
||||
keyTab="/etc/security/keytabs/kafka_client.keytab"
|
||||
principal="kafka-client-1@EXAMPLE.COM";
|
||||
};</pre><p>If the topics required already exist on the broker, or will be created by an administrator, autocreation can be turned off and only client JAAS properties need to be sent. As an alternative to setting <code class="literal">spring.cloud.stream.kafka.binder.autoCreateTopics</code> you can simply remove the broker dependency from the application. See <a class="xref" href="multi__apache_kafka_binder.html#exclude-admin-utils" title="Excluding Kafka broker jar from the classpath of the binder based application">the section called “Excluding Kafka broker jar from the classpath of the binder based application”</a> for details.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Do not mix JAAS configuration files and Spring Boot properties in the same application.
|
||||
If the <code class="literal">-Djava.security.auth.login.config</code> system property is already present, Spring Cloud Stream will ignore the Spring Boot properties.</p></td></tr></table></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Exercise caution when using the <code class="literal">autoCreateTopics</code> and <code class="literal">autoAddPartitions</code> if using Kerberos.
|
||||
Usually applications may use principals that do not have administrative rights in Kafka and Zookeeper, and relying on Spring Cloud Stream to create/modify topics may fail.
|
||||
In secure environments, we strongly recommend creating topics and managing ACLs administratively using Kafka tooling.</p></td></tr></table></div></div></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="pause-resume" href="#pause-resume"></a>Example: Pausing and Resuming the Consumer</h4></div></div></div><p>If you wish to suspend consumption, but not cause a partition rebalance, you can pause and resume the consumer.
|
||||
This is facilitated by adding the <code class="literal">Consumer</code> as a parameter to your <code class="literal">@StreamListener</code>.
|
||||
To resume, you need an <code class="literal">ApplicationListener</code> for <code class="literal">ListenerContainerIdleEvent</code> s; the frequency at which events are published is controlled by the <code class="literal">idleEventInterval</code> property.
|
||||
Since the consumer is not thread-safe, you must call these methods on the calling thread.</p><p>The following simple application shows how to pause and resume.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Sink.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(Application.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Sink.INPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> in(String in, <em><span class="hl-annotation" style="color: gray">@Header(KafkaHeaders.CONSUMER)</span></em> Consumer<?, ?> consumer) {
|
||||
System.out.println(in);
|
||||
consumer.pause(Collections.singleton(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TopicPartition(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"myTopic"</span>, <span class="hl-number">0</span>)));
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> ApplicationListener<ListenerContainerIdleEvent> idleListener() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> event -> {
|
||||
System.out.println(event);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (event.getConsumer().paused().size() > <span class="hl-number">0</span>) {
|
||||
event.getConsumer().resume(event.getConsumer().paused());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_using_the_binder_with_apache_kafka_0_10" href="#_using_the_binder_with_apache_kafka_0_10"></a>Using the binder with Apache Kafka 0.10</h4></div></div></div><p>The default Kafka support in Spring Cloud Stream Kafka binder is for Kafka version 0.10.1.1. The binder also supports connecting to other 0.10 based versions and 0.9 clients.
|
||||
In order to do this, when you create the project that contains your application, include <code class="literal">spring-cloud-starter-stream-kafka</code> as you normally would do for the default binder.
|
||||
Then add these dependencies at the top of the <code class="literal"><dependencies></code> section in the pom.xml file to override the dependencies.</p><p>Here is an example for downgrading your application to 0.10.0.1. Since it is still on the 0.10 line, the default <code class="literal">spring-kafka</code> and <code class="literal">spring-integration-kafka</code> versions can be retained.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.apache.kafka<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>kafka_2.11<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>0.10.0.1<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><exclusions></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><exclusion></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.slf4j<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>slf4j-log4j12<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></exclusion></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></exclusions></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.apache.kafka<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>kafka-clients<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>0.10.0.1<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p>Here is another example of using 0.9.0.1 version.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.kafka<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-kafka<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>1.0.5.RELEASE<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.integration<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-integration-kafka<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>2.0.1.RELEASE<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.apache.kafka<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>kafka_2.11<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>0.9.0.1<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><exclusions></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><exclusion></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.slf4j<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>slf4j-log4j12<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></exclusion></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></exclusions></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.apache.kafka<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>kafka-clients<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>0.9.0.1<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The versions above are provided only for the sake of the example.
|
||||
For best results, we recommend using the most recent 0.10-compatible versions of the projects.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="exclude-admin-utils" href="#exclude-admin-utils"></a>Excluding Kafka broker jar from the classpath of the binder based application</h4></div></div></div><p>The Apache Kafka Binder uses the administrative utilities which are part of the Apache Kafka server library to create and reconfigure topics.
|
||||
If the inclusion of the Apache Kafka server library and its dependencies is not necessary at runtime because the application will rely on the topics being configured administratively, the Kafka binder allows for Apache Kafka server dependency to be excluded from the application.</p><p>If you use non default versions for Kafka dependencies as advised above, all you have to do is not to include the kafka broker dependency.
|
||||
If you use the default Kafka version, then ensure that you exclude the kafka broker jar from the <code class="literal">spring-cloud-starter-stream-kafka</code> dependency as following.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-stream-kafka<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><exclusions></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><exclusion></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.apache.kafka<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>kafka_2.11<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></exclusion></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></exclusions></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p>If you exclude the Apache Kafka server dependency and the topic is not present on the server, then the Apache Kafka broker will create the topic if auto topic creation is enabled on the server.
|
||||
Please keep in mind that if you are relying on this, then the Kafka server will use the default number of partitions and replication factors.
|
||||
On the other hand, if auto topic creation is disabled on the server, then care must be taken before running the application to create the topic with the desired number of partitions.</p><p>If you want to have full control over how partitions are allocated, then leave the default settings as they are, i.e. do not exclude the kafka broker jar and ensure that <code class="literal">spring.cloud.stream.kafka.binder.autoCreateTopics</code> is set to <code class="literal">true</code>, which is the default.</p></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="kafka-error-channels" href="#kafka-error-channels"></a>37.4 Error Channels</h2></div></div></div><p>Starting with <span class="emphasis"><em>version 1.3</em></span>, the binder unconditionally sends exceptions to an error channel for each consumer destination, and can be configured to send async producer send failures to an error channel too.
|
||||
See <a class="xref" href="multi__programming_model.html#binder-error-channels" title="Message Channel Binders and Error Channels">the section called “Message Channel Binders and Error Channels”</a> for more information.</p><p>The payload of the <code class="literal">ErrorMessage</code> for a send failure is a <code class="literal">KafkaSendFailureException</code> with properties:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">failedMessage</code> - the spring-messaging <code class="literal">Message<?></code> that failed to be sent.</li><li class="listitem"><code class="literal">record</code> - the raw <code class="literal">ProducerRecord</code> that was created from the <code class="literal">failedMessage</code></li></ul></div><p>There is no automatic handling of producer exceptions (such as sending to a <a class="link" href="multi__apache_kafka_binder.html#kafka-dlq-processing" title="37.6 Dead-Letter Topic Processing">Dead-Letter queue</a>); you can consume these exceptions with your own Spring Integration flow.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="kafka-metrics" href="#kafka-metrics"></a>37.5 Kafka Metrics</h2></div></div></div><p>Kafka binder module exposes the following metrics:</p><p><code class="literal">spring.cloud.stream.binder.kafka.someGroup.someTopic.lag</code> - this metric indicates how many messages have not been yet consumed from given binder’s topic by given consumer group.
|
||||
For example if the value of the metric <code class="literal">spring.cloud.stream.binder.kafka.myGroup.myTopic.lag</code> is <code class="literal">1000</code>, then consumer group <code class="literal">myGroup</code> has <code class="literal">1000</code> messages to waiting to be consumed from topic <code class="literal">myTopic</code>.
|
||||
This metric is particularly useful to provide auto-scaling feedback to PaaS platform of your choice.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="kafka-dlq-processing" href="#kafka-dlq-processing"></a>37.6 Dead-Letter Topic Processing</h2></div></div></div><p>Because it can’t be anticipated how users would want to dispose of dead-lettered messages, the framework does not provide any standard mechanism to handle them.
|
||||
If the reason for the dead-lettering is transient, you may wish to route the messages back to the original topic.
|
||||
However, if the problem is a permanent issue, that could cause an infinite loop.
|
||||
The following <code class="literal">spring-boot</code> application is an example of how to route those messages back to the original topic, but moves them to a third "parking lot" topic after three attempts.
|
||||
The application is simply another spring-cloud-stream application that reads from the dead-letter topic.
|
||||
It terminates when no messages are received for 5 seconds.</p><p>The examples assume the original destination is <code class="literal">so8400out</code> and the consumer group is <code class="literal">so8400</code>.</p><p>There are several considerations.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Consider only running the rerouting when the main application is not running.
|
||||
Otherwise, the retries for transient errors will be used up very quickly.</li><li class="listitem">Alternatively, use a two-stage approach - use this application to route to a third topic, and another to route from there back to the main topic.</li><li class="listitem">Since this technique uses a message header to keep track of retries, it won’t work with <code class="literal">headerMode=raw</code>.
|
||||
In that case, consider adding some data to the payload (that can be ignored by the main application).</li><li class="listitem"><code class="literal">x-retries</code> has to be added to the <code class="literal">headers</code> property <code class="literal">spring.cloud.stream.kafka.binder.headers=x-retries</code> on both this, and the main application so that the header is transported between the applications.</li><li class="listitem">Since kafka is publish/subscribe, replayed messages will be sent to each consumer group, even those that successfully processed a message the first time around.</li></ul></div><p><b>application.properties. </b>
|
||||
</p><pre class="screen">spring.cloud.stream.bindings.input.group=so8400replay
|
||||
spring.cloud.stream.bindings.input.destination=error.so8400out.so8400
|
||||
|
||||
spring.cloud.stream.bindings.output.destination=so8400out
|
||||
spring.cloud.stream.bindings.output.producer.partitioned=true
|
||||
|
||||
spring.cloud.stream.bindings.parkingLot.destination=so8400in.parkingLot
|
||||
spring.cloud.stream.bindings.parkingLot.producer.partitioned=true
|
||||
|
||||
spring.cloud.stream.kafka.binder.configuration.auto.offset.reset=earliest
|
||||
|
||||
spring.cloud.stream.kafka.binder.headers=x-retries</pre><p>
|
||||
</p><p><b>Application. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(TwoOutputProcessor.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> ReRouteDlqKApplication <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">implements</span> CommandLineRunner {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String X_RETRIES_HEADER = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-retries"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(ReRouteDlqKApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args).close();
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> AtomicInteger processed = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> AtomicInteger();
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> MessageChannel parkingLot;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Processor.INPUT)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@SendTo(Processor.OUTPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Message<?> reRoute(Message<?> failed) {
|
||||
processed.incrementAndGet();
|
||||
Integer retries = failed.getHeaders().get(X_RETRIES_HEADER, Integer.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (retries == null) {
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"First retry for "</span> + failed);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> MessageBuilder.fromMessage(failed)
|
||||
.setHeader(X_RETRIES_HEADER, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Integer(<span class="hl-number">1</span>))
|
||||
.setHeader(BinderHeaders.PARTITION_OVERRIDE,
|
||||
failed.getHeaders().get(KafkaHeaders.RECEIVED_PARTITION_ID))
|
||||
.build();
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">else</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (retries.intValue() < <span class="hl-number">3</span>) {
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Another retry for "</span> + failed);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> MessageBuilder.fromMessage(failed)
|
||||
.setHeader(X_RETRIES_HEADER, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Integer(retries.intValue() + <span class="hl-number">1</span>))
|
||||
.setHeader(BinderHeaders.PARTITION_OVERRIDE,
|
||||
failed.getHeaders().get(KafkaHeaders.RECEIVED_PARTITION_ID))
|
||||
.build();
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">else</span> {
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Retries exhausted for "</span> + failed);
|
||||
parkingLot.send(MessageBuilder.fromMessage(failed)
|
||||
.setHeader(BinderHeaders.PARTITION_OVERRIDE,
|
||||
failed.getHeaders().get(KafkaHeaders.RECEIVED_PARTITION_ID))
|
||||
.build());
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> null;
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> run(String... args) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">while</span> (true) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">int</span> count = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.processed.get();
|
||||
Thread.sleep(<span class="hl-number">5000</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (count == <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.processed.get()) {
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Idle, terminating"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> TwoOutputProcessor <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> Processor {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Output("parkingLot")</span></em>
|
||||
MessageChannel parkingLot();
|
||||
|
||||
}
|
||||
|
||||
}</pre><p>
|
||||
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_partitioning_with_the_kafka_binder" href="#_partitioning_with_the_kafka_binder"></a>37.7 Partitioning with the Kafka Binder</h2></div></div></div><p>Apache Kafka supports topic partitioning natively.</p><p>Sometimes it is advantageous to send data to specific partitions, for example when you want to strictly order message processing - all messages for a particular customer should go to the same partition.</p><p>The following illustrates how to configure the producer and consumer side:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Source.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> KafkaPartitionProducerApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> Random RANDOM = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Random(System.currentTimeMillis());
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String[] data = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> String[] {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo1"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"bar1"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"qux1"</span>,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo2"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"bar2"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"qux2"</span>,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo3"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"bar3"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"qux3"</span>,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo4"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"bar4"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"qux4"</span>,
|
||||
};
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> SpringApplicationBuilder(KafkaPartitionProducerApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>)
|
||||
.web(false)
|
||||
.run(args);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@InboundChannelAdapter(channel = Source.OUTPUT, poller = @Poller(fixedRate = "5000"))</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Message<?> generate() {
|
||||
String value = data[RANDOM.nextInt(data.length)];
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Sending: "</span> + value);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> MessageBuilder.withPayload(value)
|
||||
.setHeader(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"partitionKey"</span>, value)
|
||||
.build();
|
||||
}
|
||||
|
||||
}</pre><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> stream</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> bindings</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> output</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> destination</span>: partitioned.topic
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> producer</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> partitioned</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">true</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> partition-key-expression</span>: headers[<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'partitionKey'</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> partition-count</span>: <span class="hl-number">12</span></pre><p>
|
||||
</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>The topic must be provisioned to have enough partitions to achieve the desired concurrency for all consumer groups.
|
||||
The above configuration will support up to 12 consumer instances (or 6 if their <code class="literal">concurrency</code> is 2, etc.).
|
||||
It is generally best to "over provision" the partitions to allow for future increases in consumers and/or concurrency.</p></td></tr></table></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The above configuration uses the default partitioning (<code class="literal">key.hashCode() % partitionCount</code>).
|
||||
This may or may not provide a suitably balanced algorithm, depending on the key values; you can override this default by using the <code class="literal">partitionSelectorExpression</code> or <code class="literal">partitionSelectorClass</code> properties.</p></td></tr></table></div><p>Since partitions are natively handled by Kafka, no special configuration is needed on the consumer side.
|
||||
Kafka will allocate partitions across the instances.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Sink.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> KafkaPartitionConsumerApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> SpringApplicationBuilder(KafkaPartitionConsumerApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>)
|
||||
.web(false)
|
||||
.run(args);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Sink.INPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> listen(<em><span class="hl-annotation" style="color: gray">@Payload</span></em> String in, <em><span class="hl-annotation" style="color: gray">@Header(KafkaHeaders.RECEIVED_PARTITION_ID)</span></em> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">int</span> partition) {
|
||||
System.out.println(in + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">" received from partition "</span> + partition);
|
||||
}
|
||||
|
||||
}</pre><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> stream</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> bindings</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> input</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> destination</span>: partitioned.topic
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> group</span>: myGroup</pre><p>
|
||||
</p><p>You can add instances as needed; Kafka will rebalance the partition allocations.
|
||||
If the instance count (or <code class="literal">instance count * concurrency</code>) exceeds the number of partitions, some consumers will be idle.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__binder_implementations.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__binder_implementations.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__apache_kafka_streams_binder.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part VI. Binder Implementations </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 38. Apache Kafka Streams Binder</td></tr></table></div></body></html>
|
||||
241
Finchley.M8/multi/multi__apache_kafka_streams_binder.html
Normal file
@@ -0,0 +1,241 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>38. Apache Kafka Streams Binder</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__binder_implementations.html" title="Part VI. Binder Implementations"><link rel="prev" href="multi__apache_kafka_binder.html" title="37. Apache Kafka Binder"><link rel="next" href="multi__rabbitmq_binder.html" title="39. RabbitMQ Binder"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">38. Apache Kafka Streams Binder</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__apache_kafka_binder.html">Prev</a> </td><th width="60%" align="center">Part VI. Binder Implementations</th><td width="20%" align="right"> <a accesskey="n" href="multi__rabbitmq_binder.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_apache_kafka_streams_binder" href="#_apache_kafka_streams_binder"></a>38. Apache Kafka Streams Binder</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_usage_2" href="#_usage_2"></a>38.1 Usage</h2></div></div></div><p>For using the Kafka Streams binder, you just need to add it to your Spring Cloud Stream application, using the following
|
||||
Maven coordinates:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-stream-binder-kafka-streams<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_kafka_streams_binder_overview" href="#_kafka_streams_binder_overview"></a>38.2 Kafka Streams Binder Overview</h2></div></div></div><p>Spring Cloud Stream’s Apache Kafka support also includes a binder implementation designed explicitly for Apache Kafka
|
||||
Streams binding. With this native integration, a Spring Cloud Stream "processor" application can directly use the
|
||||
<a class="link" href="https://kafka.apache.org/documentation/streams/developer-guide" target="_top">Apache Kafka Streams</a> APIs in the core business logic.</p><p>Kafka Streams binder implementation builds on the foundation provided by the <a class="link" href="http://docs.spring.io/spring-kafka/reference/html/_reference.html#kafka-streams" target="_top">Kafka Streams in Spring Kafka</a>
|
||||
project.</p><p>As part of this native integration, the high-level <a class="link" href="https://docs.confluent.io/current/streams/developer-guide/dsl-api.html" target="_top">Streams DSL</a>
|
||||
provided by the Kafka Streams API is available for use in the business logic, too.</p><p>An early version of the <a class="link" href="https://docs.confluent.io/current/streams/developer-guide/processor-api.html" target="_top">Processor API</a>
|
||||
support is available as well.</p><p>As noted early-on, Kafka Streams support in Spring Cloud Stream strictly only available for use in the Processor model.
|
||||
A model in which the messages read from an inbound topic, business processing can be applied, and the transformed messages
|
||||
can be written to an outbound topic. It can also be used in Processor applications with a no-outbound destination.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_streams_dsl" href="#_streams_dsl"></a>38.2.1 Streams DSL</h3></div></div></div><p>This application consumes data from a Kafka topic (e.g., <code class="literal">words</code>), computes word count for each unique word in a 5 seconds
|
||||
time window, and the computed results are sent to a downstream topic (e.g., <code class="literal">counts</code>) for further processing.</p><pre class="screen">@SpringBootApplication
|
||||
@EnableBinding(KStreamProcessor.class)
|
||||
public class WordCountProcessorApplication {
|
||||
|
||||
@StreamListener("input")
|
||||
@SendTo("output")
|
||||
public KStream<?, WordCount> process(KStream<?, String> input) {
|
||||
return input
|
||||
.flatMapValues(value -> Arrays.asList(value.toLowerCase().split("\\W+")))
|
||||
.groupBy((key, value) -> value)
|
||||
.windowedBy(TimeWindows.of(5000))
|
||||
.count(Materialized.as("WordCounts-multi"))
|
||||
.toStream()
|
||||
.map((key, value) -> new KeyValue<>(null, new WordCount(key.key(), value, new Date(key.window().start()), new Date(key.window().end()))));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WordCountProcessorApplication.class, args);
|
||||
}</pre><p>Once built as a uber-jar (e.g., <code class="literal">wordcount-processor.jar</code>), you can run the above example like the following.</p><pre class="screen">java -jar wordcount-processor.jar --spring.cloud.stream.bindings.input.destination=words --spring.cloud.stream.bindings.output.destination=counts</pre><p>This application will consume messages from the Kafka topic <code class="literal">words</code> and the computed results are published to an output
|
||||
topic <code class="literal">counts</code>.</p><p>Spring Cloud Stream will ensure that the messages from both the incoming and outgoing topics are automatically bound as
|
||||
KStream objects. As a developer, you can exclusively focus on the business aspects of the code, i.e. writing the logic
|
||||
required in the processor. Setting up the Streams DSL specific configuration required by the Kafka Streams infrastructure
|
||||
is automatically handled by the framework.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_configuration_options_3" href="#_configuration_options_3"></a>38.3 Configuration Options</h2></div></div></div><p>This section contains the configuration options used by the Kafka Streams binder.</p><p>For common configuration options and properties pertaining to binder, refer to the <a class="link" href="multi__configuration_options.html#binding-properties" title="28.2 Binding Properties">core documentation</a>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_kafka_streams_properties" href="#_kafka_streams_properties"></a>38.3.1 Kafka Streams Properties</h3></div></div></div><p>The following properties are available at the binder level and must be prefixed with <code class="literal">spring.cloud.stream.kafka.binder.</code>
|
||||
literal.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">configuration</span></dt><dd> Map with a key/value pair containing properties pertaining to Apache Kafka Streams API.
|
||||
This property must be prefixed with <code class="literal">spring.cloud.stream.kafka.streams.binder.</code>.
|
||||
Following are some examples of using this property.</dd></dl></div><pre class="screen">spring.cloud.stream.kafka.streams.binder.configuration.default.key.serde=org.apache.kafka.common.serialization.Serdes$StringSerde
|
||||
spring.cloud.stream.kafka.streams.binder.configuration.default.value.serde=org.apache.kafka.common.serialization.Serdes$StringSerde
|
||||
spring.cloud.stream.kafka.streams.binder.configuration.commit.interval.ms=1000</pre><p>For more information about all the properties that may go into streams configuration, see StreamsConfig JavaDocs in
|
||||
Apache Kafka Streams docs.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">brokers</span></dt><dd><p class="simpara">Broker URL</p><p class="simpara">Default: <code class="literal">localhost</code></p></dd><dt><span class="term">zkNodes</span></dt><dd><p class="simpara">Zookeeper URL</p><p class="simpara">Default: <code class="literal">localhost</code></p></dd><dt><span class="term">serdeError</span></dt><dd><p class="simpara">Deserialization error handler type.
|
||||
Possible values are - <code class="literal">logAndContinue</code>, <code class="literal">logAndFail</code> or <code class="literal">sendToDlq</code></p><p class="simpara">Default: <code class="literal">logAndFail</code></p></dd><dt><span class="term">applicationId</span></dt><dd><p class="simpara">Application ID for all the stream configurations in the current application context.
|
||||
You can override the application id for an individual <code class="literal">StreamListener</code> method using the <code class="literal">group</code> property on the binding.
|
||||
You have to ensure that you are using the same group name for all input bindings in the case of multiple inputs on the same methods.</p><p class="simpara">Default: <code class="literal">default</code></p></dd></dl></div><p>The following properties are <span class="emphasis"><em>only</em></span> available for Kafka Streams producers and must be prefixed with <code class="literal">spring.cloud.stream.kafka.streams.bindings.<binding name>.producer.</code>
|
||||
literal.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">keySerde</span></dt><dd><p class="simpara">key serde to use</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">valueSerde</span></dt><dd><p class="simpara">value serde to use</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">useNativeEncoding</span></dt><dd><p class="simpara">flag to enable native encoding</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd></dl></div><p>The following properties are <span class="emphasis"><em>only</em></span> available for Kafka Streams consumers and must be prefixed with <code class="literal">spring.cloud.stream.kafka.streams.bindings.<binding name>.consumer.</code>
|
||||
literal.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">keySerde</span></dt><dd><p class="simpara">key serde to use</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">valueSerde</span></dt><dd><p class="simpara">value serde to use</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">materializedAs</span></dt><dd><p class="simpara">state store to materialize when using incoming KTable types</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">useNativeDecoding</span></dt><dd><p class="simpara">flag to enable native decoding</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">dlqName</span></dt><dd><p class="simpara">DLQ topic name.</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_timewindow_properties" href="#_timewindow_properties"></a>38.3.2 TimeWindow properties:</h3></div></div></div><p>Windowing is an important concept in stream processing applications. Following properties are available to configure
|
||||
time-window computations.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">spring.cloud.stream.kafka.streams.timeWindow.length</span></dt><dd><p class="simpara">When this property is given, you can autowire a <code class="literal">TimeWindows</code> bean into the application.
|
||||
The value is expressed in milliseconds.</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">spring.cloud.stream.kstream.timeWindow.advanceBy</span></dt><dd><p class="simpara">Value is given in milliseconds.</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd></dl></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_multiple_input_bindings" href="#_multiple_input_bindings"></a>38.4 Multiple Input Bindings</h2></div></div></div><p>For use cases that requires multiple incoming KStream objects or a combination of KStream and KTable objects, the Kafka
|
||||
Streams binder provides multiple bindings support.</p><p>Let’s see it in action.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_multiple_input_bindings_as_a_sink" href="#_multiple_input_bindings_as_a_sink"></a>38.4.1 Multiple Input Bindings as a Sink</h3></div></div></div><pre class="screen">@EnableBinding(KStreamKTableBinding.class)
|
||||
.....
|
||||
.....
|
||||
@StreamListener
|
||||
public void process(@Input("inputStream") KStream<String, PlayEvent> playEvents,
|
||||
@Input("inputTable") KTable<Long, Song> songTable) {
|
||||
....
|
||||
....
|
||||
}
|
||||
|
||||
interface KStreamKTableBinding {
|
||||
|
||||
@Input("inputStream")
|
||||
KStream<?, ?> inputStream();
|
||||
|
||||
@Input("inputTable")
|
||||
KTable<?, ?> inputTable();
|
||||
}</pre><p>In the above example, the application is written as a sink, i.e. there are no output bindings and the application has to
|
||||
decide concerning downstream processing. When you write applications in this style, you might want to send the information
|
||||
downstream or store them in a state store (See below for Queryable State Stores).</p><p>In the case of incoming KTable, if you want to materialize the computations to a state store, you have to express it
|
||||
through the following property.</p><pre class="screen">spring.cloud.stream.kafka.streams.bindings.inputTable.consumer.materializedAs: all-songs</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_multiple_input_bindings_as_a_processor" href="#_multiple_input_bindings_as_a_processor"></a>38.4.2 Multiple Input Bindings as a Processor</h3></div></div></div><pre class="screen">@EnableBinding(KStreamKTableBinding.class)
|
||||
....
|
||||
....
|
||||
|
||||
@StreamListener
|
||||
@SendTo("output")
|
||||
public KStream<String, Long> process(@Input("input") KStream<String, Long> userClicksStream,
|
||||
@Input("inputTable") KTable<String, String> userRegionsTable) {
|
||||
....
|
||||
....
|
||||
}
|
||||
|
||||
interface KStreamKTableBinding extends KafkaStreamsProcessor {
|
||||
|
||||
@Input("inputX")
|
||||
KTable<?, ?> inputTable();
|
||||
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_multiple_output_bindings_aka_branching" href="#_multiple_output_bindings_aka_branching"></a>38.5 Multiple Output Bindings (aka Branching)</h2></div></div></div><p>Kafka Streams allow outbound data to be split into multiple topics based on some predicates. The Kafka Streams binder provides
|
||||
support for this feature without compromising the programming model exposed through <code class="literal">StreamListener</code> in the end user application.</p><p>You can write the application in the usual way as demonstrated above in the word count example. However, when using the
|
||||
branching feature, you are required to do a few things. First, you need to make sure that your return type is <code class="literal">KStream[]</code>
|
||||
instead of a regular <code class="literal">KStream</code>. Second, you need to use the <code class="literal">SendTo</code> annotation containing the output bindings in the order
|
||||
(see example below). For each of these output bindings, you need to configure destination, content-type etc., complying with
|
||||
the standard Spring Cloud Stream expectations.</p><p>Here is an example:</p><pre class="screen">@EnableBinding(KStreamProcessorWithBranches.class)
|
||||
@EnableAutoConfiguration
|
||||
public static class WordCountProcessorApplication {
|
||||
|
||||
@Autowired
|
||||
private TimeWindows timeWindows;
|
||||
|
||||
@StreamListener("input")
|
||||
@SendTo({"output1","output2","output3})
|
||||
public KStream<?, WordCount>[] process(KStream<Object, String> input) {
|
||||
|
||||
Predicate<Object, WordCount> isEnglish = (k, v) -> v.word.equals("english");
|
||||
Predicate<Object, WordCount> isFrench = (k, v) -> v.word.equals("french");
|
||||
Predicate<Object, WordCount> isSpanish = (k, v) -> v.word.equals("spanish");
|
||||
|
||||
return input
|
||||
.flatMapValues(value -> Arrays.asList(value.toLowerCase().split("\\W+")))
|
||||
.groupBy((key, value) -> value)
|
||||
.windowedBy(timeWindows)
|
||||
.count(Materialized.as("WordCounts-1"))
|
||||
.toStream()
|
||||
.map((key, value) -> new KeyValue<>(null, new WordCount(key.key(), value, new Date(key.window().start()), new Date(key.window().end()))))
|
||||
.branch(isEnglish, isFrench, isSpanish);
|
||||
}
|
||||
|
||||
interface KStreamProcessorWithBranches {
|
||||
|
||||
@Input("input")
|
||||
KStream<?, ?> input();
|
||||
|
||||
@Output("output1")
|
||||
KStream<?, ?> output1();
|
||||
|
||||
@Output("output2")
|
||||
KStream<?, ?> output2();
|
||||
|
||||
@Output("output3")
|
||||
KStream<?, ?> output3();
|
||||
}
|
||||
}</pre><p>Properties:</p><pre class="screen">spring.cloud.stream.bindings.output1.contentType: application/json
|
||||
spring.cloud.stream.bindings.output2.contentType: application/json
|
||||
spring.cloud.stream.bindings.output3.contentType: application/json
|
||||
spring.cloud.stream.kafka.streams.binder.configuration.commit.interval.ms: 1000
|
||||
spring.cloud.stream.kafka.streams.binder.configuration:
|
||||
default.key.serde: org.apache.kafka.common.serialization.Serdes$StringSerde
|
||||
default.value.serde: org.apache.kafka.common.serialization.Serdes$StringSerde
|
||||
spring.cloud.stream.bindings.output1:
|
||||
destination: foo
|
||||
producer:
|
||||
headerMode: raw
|
||||
spring.cloud.stream.bindings.output2:
|
||||
destination: bar
|
||||
producer:
|
||||
headerMode: raw
|
||||
spring.cloud.stream.bindings.output3:
|
||||
destination: fox
|
||||
producer:
|
||||
headerMode: raw
|
||||
spring.cloud.stream.bindings.input:
|
||||
destination: words
|
||||
consumer:
|
||||
headerMode: raw</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_message_conversion" href="#_message_conversion"></a>38.6 Message Conversion</h2></div></div></div><p>Similar to message-channel based binder applications, the Kafka Streams binder adapts to the out-of-the-box content-type
|
||||
conversions without any compromise.</p><p>It is typical for Kafka Streams operations to know the type of SerDe’s used to transform the key and value correctly.
|
||||
Therefore, it may be more natural to rely on the SerDe facilities provided by the Apache Kafka Streams library itself at
|
||||
the inbound and outbound conversions rather than using the content-type conversions offered by the framework.
|
||||
On the other hand, you might be already familiar with the content-type conversion patterns provided by the framework, and
|
||||
that, you’d like to continue using for inbound and outbound conversions.</p><p>Both the options are supported in the Kafka Streams binder implementation.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_outbound_serialization" href="#_outbound_serialization"></a>38.6.1 Outbound serialization</h3></div></div></div><p>If native encoding is disabled (which is the default), then the framework will convert the message using the contentType
|
||||
set by the user (otherwise, the default <code class="literal">application/json</code> will be applied). It will ignore any SerDe set on the outbound
|
||||
in this case for outbound serialization.</p><p>Here is the property to set the contentType on the outbound.</p><pre class="screen">spring.cloud.stream.bindings.output.contentType: application/json</pre><p>Here is the property to enable native encoding.</p><pre class="screen">spring.cloud.stream.bindings.output.nativeEncoding: true</pre><p>If native encoding is enabled on the output binding (user has to enable it as above explicitly), then the framework will
|
||||
skip any form of automatic message conversion on the outbound. In that case, it will switch to the Serde set by the user.
|
||||
The <code class="literal">valueSerde</code> property set on the actual output binding will be used. Here is an example.</p><pre class="screen">spring.cloud.stream.kafka.streams.bindings.output.producer.valueSerde: org.apache.kafka.common.serialization.Serdes$StringSerde</pre><p>If this property is not set, then it will use the "default" SerDe: <code class="literal">spring.cloud.stream.kafka.streams.binder.configuration.default.value.serde</code>.</p><p>It is worth to mention that Kafka Streams binder does not serialize the keys on outbound - it simply relies on Kafka itself.
|
||||
Therefore, you either have to specify the <code class="literal">keySerde</code> property on the binding or it will default to the application-wide common
|
||||
<code class="literal">keySerde</code>.</p><p>Binding level key serde:</p><pre class="screen">spring.cloud.stream.kafka.streams.bindings.output.producer.keySerde</pre><p>Common Key serde:</p><pre class="screen">spring.cloud.stream.kafka.streams.binder.configuration.default.key.serde</pre><p>If branching is used, then you need to use multiple output bindings. For example,</p><pre class="screen">interface KStreamProcessorWithBranches {
|
||||
|
||||
@Input("input")
|
||||
KStream<?, ?> input();
|
||||
|
||||
@Output("output1")
|
||||
KStream<?, ?> output1();
|
||||
|
||||
@Output("output2")
|
||||
KStream<?, ?> output2();
|
||||
|
||||
@Output("output3")
|
||||
KStream<?, ?> output3();
|
||||
}</pre><p>If <code class="literal">nativeEncoding</code> is set, then you can set different SerDe’s on individual output bindings as below.</p><pre class="screen">spring.cloud.stream.kstream.bindings.output1.producer.valueSerde=IntegerSerde
|
||||
spring.cloud.stream.kstream.bindings.output2.producer.valueSerde=StringSerde
|
||||
spring.cloud.stream.kstream.bindings.output3.producer.valueSerde=JsonSerde</pre><p>Then if you have <code class="literal">SendTo</code> like this, @SendTo({"output1", "output2", "output3"}), the <code class="literal">KStream[]</code> from the branches are
|
||||
applied with proper SerDe objects as defined above. If you are not enabling <code class="literal">nativeEncoding</code>, you can then set different
|
||||
contentType values on the output bindings as below. In that case, the framework will use the appropriate message converter
|
||||
to convert the messages before sending to Kafka.</p><pre class="screen">spring.cloud.stream.bindings.output1.contentType: application/json
|
||||
spring.cloud.stream.bindings.output2.contentType: application/java-serialzied-object
|
||||
spring.cloud.stream.bindings.output3.contentType: application/octet-stream</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_inbound_deserialization" href="#_inbound_deserialization"></a>38.6.2 Inbound Deserialization</h3></div></div></div><p>Similar rules apply to data deserialization on the inbound.</p><p>If native decoding is disabled (which is the default), then the framework will convert the message using the contentType
|
||||
set by the user (otherwise, the default <code class="literal">application/json</code> will be applied). It will ignore any SerDe set on the inbound
|
||||
in this case for inbound deserialization.</p><p>Here is the property to set the contentType on the inbound.</p><pre class="screen">spring.cloud.stream.bindings.input.contentType: application/json</pre><p>Here is the property to enable native decoding.</p><pre class="screen">spring.cloud.stream.bindings.input.nativeDecoding: true</pre><p>If native decoding is enabled on the input binding (user has to enable it as above explicitly), then the framework will
|
||||
skip doing any message conversion on the inbound. In that case, it will switch to the SerDe set by the user. The <code class="literal">valueSerde</code>
|
||||
property set on the actual output binding will be used. Here is an example.</p><pre class="screen">spring.cloud.stream.kafka.streams.bindings.input.consumer.valueSerde: org.apache.kafka.common.serialization.Serdes$StringSerde</pre><p>If this property is not set, it will use the default SerDe: <code class="literal">spring.cloud.stream.kafka.streams.binder.configuration.default.value.serde</code>.</p><p>It is worth to mention that Kafka Streams binder does not deserialize the keys on inbound - it simply relies on Kafka itself.
|
||||
Therefore, you either have to specify the <code class="literal">keySerde</code> property on the binding or it will default to the application-wide common
|
||||
<code class="literal">keySerde</code>.</p><p>Binding level key serde:</p><pre class="screen">spring.cloud.stream.kafka.streams.bindings.input.consumer.keySerde</pre><p>Common Key serde:</p><pre class="screen">spring.cloud.stream.kafka.streams.binder.configuration.default.key.serde</pre><p>As in the case of KStream branching on the outbound, the benefit of setting value SerDe per binding is that if you have
|
||||
multiple input bindings (multiple KStreams object) and they all require separate value SerDe’s, then you can configure
|
||||
them individually. If you use the common configuration approach, then this feature won’t be applicable.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_error_handling" href="#_error_handling"></a>38.7 Error Handling</h2></div></div></div><p>Apache Kafka Streams provide the capability for natively handling exceptions from deserialization errors.
|
||||
For details on this support, please see <a class="link" href="https://cwiki.apache.org/confluence/display/KAFKA/KIP-161%3A+streams+deserialization+exception+handlers" target="_top">this</a>
|
||||
Out of the box, Apache Kafka Streams provide two kinds of deserialization exception handlers - <code class="literal">logAndContinue</code> and <code class="literal">logAndFail</code>.
|
||||
As the name indicates, the former will log the error and continue processing the next records and the latter will log the
|
||||
error and fail. <code class="literal">LogAndFail</code> is the default deserialization exception handler.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_handling_deserialization_exceptions" href="#_handling_deserialization_exceptions"></a>38.7.1 Handling Deserialization Exceptions</h3></div></div></div><p>Kafka Streams binder supports a selection of exception handlers through the following properties.</p><pre class="screen">spring.cloud.stream.kafka.streams.binder.serdeError: logAndContinue</pre><p>In addition to the above two deserialization exception handlers, the binder also provides a third one for sending the erroneous
|
||||
records (poison pills) to a DLQ topic. Here is how you enable this DLQ exception handler.</p><pre class="screen">spring.cloud.stream.kafka.streams.binder.serdeError: sendToDlq</pre><p>When the above property is set, all the deserialization error records are automatically sent to the DLQ topic.</p><pre class="screen">spring.cloud.stream.kafka.streams.bindings.input.consumer.dlqName: foo-dlq</pre><p>If this is set, then the error records are sent to the topic <code class="literal">foo-dlq</code>. If this is not set, then it will create a DLQ
|
||||
topic with the name <code class="literal">error.<input-topic-name>.<group-name></code>.</p><p>A couple of things to keep in mind when using the exception handling feature in Kafka Streams binder.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">The property <code class="literal">spring.cloud.stream.kafka.streams.binder.serdeError</code> is applicable for the entire application. This implies
|
||||
that if there are multiple <code class="literal">StreamListener</code> methods in the same application, this property is applied to all of them.</li><li class="listitem">The exception handling for deserialization works consistently with native deserialization and framework provided message
|
||||
conversion.</li></ul></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_handling_non_deserialization_exceptions" href="#_handling_non_deserialization_exceptions"></a>38.7.2 Handling Non-Deserialization Exceptions</h3></div></div></div><p>For general error handling in Kafka Streams binder, it is up to the end user applications to handle application level errors.
|
||||
As a side effect of providing a DLQ for deserialization exception handlers, Kafka Streams binder provides a way to get
|
||||
access to the DLQ sending bean directly from your application.
|
||||
Once you get access to that bean, you can programmatically send any exception records from your application to the DLQ.</p><p>It continues to remain hard to robust error handling using the high-level DSL; Kafka Streams doesn’t natively support error
|
||||
handling yet.</p><p>However, when you use the low-level Processor API in your application, there are options to control this behavior. See
|
||||
below.</p><pre class="screen">@Autowired
|
||||
private SendToDlqAndContinue dlqHandler;
|
||||
|
||||
@StreamListener("input")
|
||||
@SendTo("output")
|
||||
public KStream<?, WordCount> process(KStream<Object, String> input) {
|
||||
|
||||
input.process(() -> new Processor() {
|
||||
ProcessorContext context;
|
||||
|
||||
@Override
|
||||
public void init(ProcessorContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Object o, Object o2) {
|
||||
|
||||
try {
|
||||
.....
|
||||
.....
|
||||
}
|
||||
catch(Exception e) {
|
||||
//explicitly provide the kafka topic corresponding to the input binding as the first argument.
|
||||
//DLQ handler will correctly map to the dlq topic from the actual incoming destination.
|
||||
dlqHandler.sendToDlq("topic-name", (byte[]) o1, (byte[]) o2, context.partition());
|
||||
}
|
||||
}
|
||||
|
||||
.....
|
||||
.....
|
||||
});
|
||||
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_interactive_queries" href="#_interactive_queries"></a>38.8 Interactive Queries</h2></div></div></div><p>As part of the public Kafka Streams binder API, we expose a class called <code class="literal">QueryableStoreRegistry</code>. You can access this
|
||||
as a Spring bean in your application. An easy way to get access to this bean from your application is to "autowire" the bean
|
||||
in your application.</p><pre class="screen">@Autowired
|
||||
private QueryableStoreRegistry queryableStoreRegistry;</pre><p>Once you gain access to this bean, then you can query for the particular state-store that you are interested. See below.</p><pre class="screen">ReadOnlyKeyValueStore<Object, Object> keyValueStore =
|
||||
queryableStoreRegistry.getQueryableStoreType("my-store", QueryableStoreTypes.keyValueStore());</pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__apache_kafka_binder.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__binder_implementations.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__rabbitmq_binder.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">37. Apache Kafka Binder </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 39. RabbitMQ Binder</td></tr></table></div></body></html>
|
||||
3
Finchley.M8/multi/multi__binder_implementations.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>Part VI. Binder Implementations</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="prev" href="multi__getting_started.html" title="36. Getting Started"><link rel="next" href="multi__apache_kafka_binder.html" title="37. Apache Kafka Binder"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Part VI. Binder Implementations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__getting_started.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__apache_kafka_binder.html">Next</a></td></tr></table><hr></div><div class="part"><div class="titlepage"><div><div><h1 class="title"><a name="_binder_implementations" href="#_binder_implementations"></a>Part VI. Binder Implementations</h1></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__getting_started.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__apache_kafka_binder.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">36. Getting Started </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 37. Apache Kafka Binder</td></tr></table></div></body></html>
|
||||
58
Finchley.M8/multi/multi__binders.html
Normal file
@@ -0,0 +1,58 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>27. Binders</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="prev" href="multi__programming_model.html" title="26. Programming Model"><link rel="next" href="multi__configuration_options.html" title="28. Configuration Options"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">27. Binders</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__programming_model.html">Prev</a> </td><th width="60%" align="center">Part V. Spring Cloud Stream</th><td width="20%" align="right"> <a accesskey="n" href="multi__configuration_options.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_binders" href="#_binders"></a>27. Binders</h2></div></div></div><p>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.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_producers_and_consumers" href="#_producers_and_consumers"></a>27.1 Producers and Consumers</h2></div></div></div><div class="figure"><a name="d0e7183" href="#d0e7183"></a><p class="title"><b>Figure 27.1. Producers and Consumers</b></p><div class="figure-contents"><div class="mediaobject"><img src="images/producers-consumers.png" alt="producers consumers"></div></div></div><br class="figure-break"><p>A <span class="emphasis"><em>producer</em></span> is any component that sends messages to a channel.
|
||||
The channel can be bound to an external message broker via a Binder implementation for that broker.
|
||||
When invoking the <code class="literal">bindProducer()</code> 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 will send 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.</p><p>A <span class="emphasis"><em>consumer</em></span> 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 <code class="literal">bindConsumer()</code> 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 (i.e., publish-subscribe semantics).
|
||||
If there are multiple consumer instances bound using the same group name, then messages will be 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 (i.e., queueing semantics).</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_binder_spi" href="#_binder_spi"></a>27.2 Binder SPI</h2></div></div></div><p>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.</p><p>The key point of the SPI is the <code class="literal">Binder</code> interface which is a strategy for connecting inputs and outputs to external middleware.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> Binder<T, C <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> ConsumerProperties, P <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> ProducerProperties> {
|
||||
Binding<T> bindConsumer(String name, String group, T inboundBindTarget, C consumerProperties);
|
||||
|
||||
Binding<T> bindProducer(String name, T outboundBindTarget, P producerProperties);
|
||||
}</pre><p>The interface is parameterized, offering a number of extension points:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">input and output bind targets - as of version 1.0, only <code class="literal">MessageChannel</code> is supported, but this is intended to be used as an extension point in the future;</li><li class="listitem">extended consumer and producer properties - allowing specific Binder implementations to add supplemental properties which can be supported in a type-safe manner.</li></ul></div><p>A typical binder implementation consists of the following</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">a class that implements the <code class="literal">Binder</code> interface;</li><li class="listitem">a Spring <code class="literal">@Configuration</code> class that creates a bean of the type above along with the middleware connection infrastructure;</li><li class="listitem">a <code class="literal">META-INF/spring.binders</code> file found on the classpath containing one or more binder definitions, e.g.</li></ul></div><pre class="screen">kafka:\
|
||||
org.springframework.cloud.stream.binder.kafka.config.KafkaBinderConfiguration</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_binder_detection" href="#_binder_detection"></a>27.3 Binder Detection</h2></div></div></div><p>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.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_classpath_detection" href="#_classpath_detection"></a>27.3.1 Classpath Detection</h3></div></div></div><p>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 will use it automatically.
|
||||
For example, a Spring Cloud Stream project that aims to bind only to RabbitMQ can simply add the following dependency:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-stream-binder-rabbit<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p>For the specific maven coordinates of other binder dependencies, please refer to the documentation of that binder implementation.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="multiple-binders" href="#multiple-binders"></a>27.4 Multiple Binders on the Classpath</h2></div></div></div><p>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 <code class="literal">META-INF/spring.binders</code>, which is a simple properties file:</p><pre class="screen">rabbit:\
|
||||
org.springframework.cloud.stream.binder.rabbit.config.RabbitServiceAutoConfiguration</pre><p>Similar files exist for the other provided binder implementations (e.g., 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 <code class="literal">org.springframework.cloud.stream.binder.Binder</code>.</p><p>Binder selection can either be performed globally, using the <code class="literal">spring.cloud.stream.defaultBinder</code> property (e.g., <code class="literal">spring.cloud.stream.defaultBinder=rabbit</code>) or individually, by configuring the binder on each channel binding.
|
||||
For instance, a processor application (that has channels with the names <code class="literal">input</code> and <code class="literal">output</code> for read/write respectively) which reads from Kafka and writes to RabbitMQ can specify the following configuration:</p><pre class="screen">spring.cloud.stream.bindings.input.binder=kafka
|
||||
spring.cloud.stream.bindings.output.binder=rabbit</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="multiple-systems" href="#multiple-systems"></a>27.5 Connecting to Multiple Systems</h2></div></div></div><p>By default, binders share the application’s Spring Boot auto-configuration, so that one instance of each binder found on the classpath will be 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.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Turning on explicit binder configuration will disable the default binder configuration process altogether.
|
||||
If you do this, 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 will not affect the default binder configuration.
|
||||
In order to do so, a binder configuration may have its <code class="literal">defaultCandidate</code> flag set to false, e.g. <code class="literal">spring.cloud.stream.binders.<configurationName>.defaultCandidate=false</code>.
|
||||
This denotes a configuration that will exist independently of the default binder configuration process.</p></td></tr></table></div><p>For example, this is the typical configuration for a processor application which connects to two RabbitMQ broker instances:</p><pre class="programlisting">spring:
|
||||
cloud:
|
||||
stream:
|
||||
bindings:
|
||||
input:
|
||||
destination: foo
|
||||
binder: rabbit1
|
||||
output:
|
||||
destination: bar
|
||||
binder: rabbit2
|
||||
binders:
|
||||
rabbit1:
|
||||
type: rabbit
|
||||
environment:
|
||||
spring:
|
||||
rabbitmq:
|
||||
host: <host1>
|
||||
rabbit2:
|
||||
type: rabbit
|
||||
environment:
|
||||
spring:
|
||||
rabbitmq:
|
||||
host: <host2></pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_binder_configuration_properties" href="#_binder_configuration_properties"></a>27.6 Binder configuration properties</h2></div></div></div><p>The following properties are available when creating custom binder configurations.
|
||||
They must be prefixed with <code class="literal">spring.cloud.stream.binders.<configurationName></code>.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">type</span></dt><dd><p class="simpara"> The binder type.
|
||||
It typically references one of the binders found on the classpath, in particular a key in a <code class="literal">META-INF/spring.binders</code> file.</p><p class="simpara">By default, it has the same value as the configuration name.</p></dd><dt><span class="term">inheritEnvironment</span></dt><dd><p class="simpara">Whether the configuration will inherit the environment of the application itself.</p><p class="simpara">Default <code class="literal">true</code>.</p></dd><dt><span class="term">environment</span></dt><dd><p class="simpara"> Root for a set of properties that can be used to customize the environment of the binder.
|
||||
When this is configured, the context in which the binder is being created is not a child of the application context.
|
||||
This allows for complete separation between the binder components and the application components.</p><p class="simpara">Default <code class="literal">empty</code>.</p></dd><dt><span class="term">defaultCandidate</span></dt><dd><p class="simpara"> Whether the binder configuration is a candidate for being considered a default binder, or can be used only when explicitly referenced.
|
||||
This allows adding binder configurations without interfering with the default processing.</p><p class="simpara">Default <code class="literal">true</code>.</p></dd></dl></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__programming_model.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_stream.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__configuration_options.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">26. Programming Model </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 28. Configuration Options</td></tr></table></div></body></html>
|
||||
36
Finchley.M8/multi/multi__broadcasting_your_own_events.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>46. Broadcasting Your Own Events</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_bus.html" title="Part VII. Spring Cloud Bus"><link rel="prev" href="multi__tracing_bus_events.html" title="45. Tracing Bus Events"><link rel="next" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">46. Broadcasting Your Own Events</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__tracing_bus_events.html">Prev</a> </td><th width="60%" align="center">Part VII. Spring Cloud Bus</th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_sleuth.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_broadcasting_your_own_events" href="#_broadcasting_your_own_events"></a>46. Broadcasting Your Own Events</h2></div></div></div><p>The Bus can carry any event of type <code class="literal">RemoteApplicationEvent</code>, but the
|
||||
default transport is JSON and the deserializer needs to know which
|
||||
types are going to be used ahead of time. To register a new type it
|
||||
needs to be in a subpackage of <code class="literal">org.springframework.cloud.bus.event</code>.</p><p>To customise the event name you can use <code class="literal">@JsonTypeName</code> on your custom class
|
||||
or rely on the default strategy which is to use the simple name of the class.
|
||||
Note that both the producer and the consumer will need access to the class
|
||||
definition.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_registering_events_in_custom_packages" href="#_registering_events_in_custom_packages"></a>46.1 Registering events in custom packages</h2></div></div></div><p>If you cannot or don’t want to use a subpackage of <code class="literal">org.springframework.cloud.bus.event</code>
|
||||
for your custom events, you must specify which packages to scan for events of
|
||||
type <code class="literal">RemoteApplicationEvent</code> using <code class="literal">@RemoteApplicationEventScan</code>. Packages
|
||||
specified with <code class="literal">@RemoteApplicationEventScan</code> include subpackages.</p><p>For example, if you have a custom event called <code class="literal">FooEvent</code>:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.acme;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> FooEvent <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> RemoteApplicationEvent {
|
||||
...
|
||||
}</pre><p>you can register this event with the deserializer in the following way:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.acme;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@RemoteApplicationEventScan</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> BusConfiguration {
|
||||
...
|
||||
}</pre><p>Without specifying a value, the package of the class where <code class="literal">@RemoteApplicationEventScan</code>
|
||||
is used will be registered. In this example <code class="literal">com.acme</code> will be registered using the
|
||||
package of <code class="literal">BusConfiguration</code>.</p><p>You can also explicitly specify the packages to scan using the <code class="literal">value</code>, <code class="literal">basePackages</code> or
|
||||
<code class="literal">basePackageClasses</code> properties on <code class="literal">@RemoteApplicationEventScan</code>. For example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.acme;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//@RemoteApplicationEventScan({"com.acme", "foo.bar"})</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//@RemoteApplicationEventScan(basePackages = {"com.acme", "foo.bar", "fizz.buzz"})</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@RemoteApplicationEventScan(basePackageClasses = BusConfiguration.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> BusConfiguration {
|
||||
...
|
||||
}</pre><p>All examples of <code class="literal">@RemoteApplicationEventScan</code> above are equivalent,
|
||||
in that the <code class="literal">com.acme</code> package will be registered by explicitly specifying the
|
||||
packages on <code class="literal">@RemoteApplicationEventScan</code>. Note, you can specify multiple base
|
||||
packages to scan.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__tracing_bus_events.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_bus.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_sleuth.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">45. Tracing Bus Events </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part VIII. Spring Cloud Sleuth</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,19 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>115. Building a Simple Gateway Using Spring MVC</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_gateway.html" title="Part XV. Spring Cloud Gateway"><link rel="prev" href="multi__developer_guide.html" title="114. Developer Guide"><link rel="next" href="multi__appendix_compendium_of_configuration_properties.html" title="Part XVI. Appendix: Compendium of Configuration Properties"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">115. Building a Simple Gateway Using Spring MVC</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__developer_guide.html">Prev</a> </td><th width="60%" align="center">Part XV. Spring Cloud Gateway</th><td width="20%" align="right"> <a accesskey="n" href="multi__appendix_compendium_of_configuration_properties.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_building_a_simple_gateway_using_spring_mvc" href="#_building_a_simple_gateway_using_spring_mvc"></a>115. Building a Simple Gateway Using Spring MVC</h2></div></div></div><p>Spring Cloud Gateway provides a utility object called <code class="literal">ProxyExchange</code> which you can use inside a regular Spring MVC handler as a method parameter. It supports basic downstream HTTP exchanges via methods that mirror the HTTP verbs, or forwarding to a local handler via the <code class="literal">forward()</code> method.</p><p>Example (proxying a request to "/test" downstream to a remote server):</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@RestController</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> GatewaySampleApplication {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Value("${remote.home}")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> URI home;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@GetMapping("/test")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> ResponseEntity<?> proxy(ProxyExchange<Object> proxy) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> proxy.uri(home.toString() + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/image/png"</span>).get();
|
||||
}
|
||||
|
||||
}</pre><p>There are convenience methods on the <code class="literal">ProxyExchange</code> to enable the handler method to discover and enhance the URI path of the incoming request. For example you might want to extract the trailing elements of a path to pass them downstream:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@GetMapping("/proxy/path/**")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> ResponseEntity<?> proxyPath(ProxyExchange<?> proxy) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
String path = proxy.path(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/proxy/path/"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> proxy.uri(home.toString() + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/foos/"</span> + path).get();
|
||||
}</pre><p>All the features of Spring MVC are available to Gateway handler methods. So you can inject request headers and query parameters, for instance, and you can constrain the incoming requests with declarations in the mapping annotation. See the documentation for <code class="literal">@RequestMapping</code> in Spring MVC for more details of those features.</p><p>Headers can be added to the downstream response using the <code class="literal">header()</code> methods on <code class="literal">ProxyExchange</code>.</p><p>You can also manipulate response headers (and anything else you like in the response) by adding a mapper to the <code class="literal">get()</code> etc. method. The mapper is a <code class="literal">Function</code> that takes the incoming <code class="literal">ResponseEntity</code> and converts it to an outgoing one.</p><p>First class support is provided for "sensitive" headers ("cookie" and "authorization" by default) which are not passed downstream, and for "proxy" headers (<code class="literal">x-forwarded-*</code>).</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__developer_guide.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_gateway.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__appendix_compendium_of_configuration_properties.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">114. Developer Guide </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part XVI. Appendix: Compendium of Configuration Properties</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,52 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>13. Circuit Breaker: Hystrix Clients</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_netflix.html" title="Part III. Spring Cloud Netflix"><link rel="prev" href="multi_spring-cloud-eureka-server.html" title="12. Service Discovery: Eureka Server"><link rel="next" href="multi__circuit_breaker_hystrix_dashboard.html" title="14. Circuit Breaker: Hystrix Dashboard"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">13. Circuit Breaker: Hystrix Clients</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_spring-cloud-eureka-server.html">Prev</a> </td><th width="60%" align="center">Part III. Spring Cloud Netflix</th><td width="20%" align="right"> <a accesskey="n" href="multi__circuit_breaker_hystrix_dashboard.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_circuit_breaker_hystrix_clients" href="#_circuit_breaker_hystrix_clients"></a>13. Circuit Breaker: Hystrix Clients</h2></div></div></div><p>Netflix has created a library called <a class="link" href="https://github.com/Netflix/Hystrix" target="_top">Hystrix</a> that implements the <a class="link" href="http://martinfowler.com/bliki/CircuitBreaker.html" target="_top">circuit breaker pattern</a>. In a microservice architecture it is common to have multiple layers of service calls.</p><div class="figure"><a name="d0e3376" href="#d0e3376"></a><p class="title"><b>Figure 13.1. Microservice Graph</b></p><div class="figure-contents"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-netflix/master/docs/src/main/asciidoc/images/Hystrix.png" alt="Hystrix"></div></div></div><br class="figure-break"><p>A service failure in the lower level of services can cause cascading failure all the way up to the user. When calls to a particular service is greater than <code class="literal">circuitBreaker.requestVolumeThreshold</code> (default: 20 requests) and failue percentage is greater than <code class="literal">circuitBreaker.errorThresholdPercentage</code> (default: >50%) in a rolling window defined by <code class="literal">metrics.rollingStats.timeInMilliseconds</code> (default: 10 seconds), the circuit opens and the call is not made. In cases of error and an open circuit a fallback can be provided by the developer.</p><div class="figure"><a name="d0e3396" href="#d0e3396"></a><p class="title"><b>Figure 13.2. Hystrix fallback prevents cascading failures</b></p><div class="figure-contents"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-netflix/master/docs/src/main/asciidoc/images/HystrixFallback.png" alt="HystrixFallback"></div></div></div><br class="figure-break"><p>Having an open circuit stops cascading failures and allows overwhelmed or failing services time to heal. The fallback can be another Hystrix protected call, static data or a sane empty value. Fallbacks may be chained so the first fallback makes some other business call which in turn falls back to static data.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="netflix-hystrix-starter" href="#netflix-hystrix-starter"></a>13.1 How to Include Hystrix</h2></div></div></div><p>To include Hystrix in your project use the starter with group <code class="literal">org.springframework.cloud</code>
|
||||
and artifact id <code class="literal">spring-cloud-starter-netflix-hystrix</code>. See the <a class="link" href="http://projects.spring.io/spring-cloud/" target="_top">Spring Cloud Project page</a>
|
||||
for details on setting up your build system with the current Spring Cloud Release Train.</p><p>Example boot app:</p><pre class="screen">@SpringBootApplication
|
||||
@EnableCircuitBreaker
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpringApplicationBuilder(Application.class).web(true).run(args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Component
|
||||
public class StoreIntegration {
|
||||
|
||||
@HystrixCommand(fallbackMethod = "defaultStores")
|
||||
public Object getStores(Map<String, Object> parameters) {
|
||||
//do stuff that might fail
|
||||
}
|
||||
|
||||
public Object defaultStores(Map<String, Object> parameters) {
|
||||
return /* something useful */;
|
||||
}
|
||||
}</pre><p>The <code class="literal">@HystrixCommand</code> is provided by a Netflix contrib library called
|
||||
<a class="link" href="https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica" target="_top">"javanica"</a>.
|
||||
Spring Cloud automatically wraps Spring beans with that
|
||||
annotation in a proxy that is connected to the Hystrix circuit
|
||||
breaker. The circuit breaker calculates when to open and close the
|
||||
circuit, and what to do in case of a failure.</p><p>To configure the <code class="literal">@HystrixCommand</code> you can use the <code class="literal">commandProperties</code>
|
||||
attribute with a list of <code class="literal">@HystrixProperty</code> annotations. See
|
||||
<a class="link" href="https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica#configuration" target="_top">here</a>
|
||||
for more details. See the <a class="link" href="https://github.com/Netflix/Hystrix/wiki/Configuration" target="_top">Hystrix wiki</a>
|
||||
for details on the properties available.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_propagating_the_security_context_or_using_spring_scopes" href="#_propagating_the_security_context_or_using_spring_scopes"></a>13.2 Propagating the Security Context or using Spring Scopes</h2></div></div></div><p>If you want some thread local context to propagate into a <code class="literal">@HystrixCommand</code> the default declaration will not work because it executes the command in a thread pool (in case of timeouts). You can switch Hystrix to use the same thread as the caller using some configuration, or directly in the annotation, by asking it to use a different "Isolation Strategy". For example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@HystrixCommand(fallbackMethod = "stubMyService",
|
||||
commandProperties = {
|
||||
@HystrixProperty(name="execution.isolation.strategy", value="SEMAPHORE")
|
||||
}
|
||||
)</span></em>
|
||||
...</pre><p>The same thing applies if you are using <code class="literal">@SessionScope</code> or <code class="literal">@RequestScope</code>. You will know when you need to do this because of a runtime exception that says it can’t find the scoped context.</p><p>You also have the option to set the <code class="literal">hystrix.shareSecurityContext</code> property to <code class="literal">true</code>. Doing so will auto configure an Hystrix concurrency strategy plugin hook who will transfer the <code class="literal">SecurityContext</code> from your main thread to the one used by the Hystrix command. Hystrix does not allow multiple hystrix concurrency strategy to be registered so an extension mechanism is available by declaring your own <code class="literal">HystrixConcurrencyStrategy</code> as a Spring bean. Spring Cloud will lookup for your implementation within the Spring context and wrap it inside its own plugin.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_health_indicator_4" href="#_health_indicator_4"></a>13.3 Health Indicator</h2></div></div></div><p>The state of the connected circuit breakers are also exposed in the
|
||||
<code class="literal">/health</code> endpoint of the calling application.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">{</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"hystrix"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">{</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"openCircuitBreakers"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">[</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"StoreIntegration::getStoresByLocationLink"</span>
|
||||
]<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"status"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"CIRCUIT_OPEN"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">},</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"status"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"UP"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">}</span></pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_hystrix_metrics_stream" href="#_hystrix_metrics_stream"></a>13.4 Hystrix Metrics Stream</h2></div></div></div><p>To enable the Hystrix metrics stream include a dependency on <code class="literal">spring-boot-starter-actuator</code>. This will expose the <code class="literal">/hystrix.stream</code> as a management endpoint.</p><pre class="programlisting"> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-starter-actuator<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_spring-cloud-eureka-server.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_netflix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__circuit_breaker_hystrix_dashboard.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">12. Service Discovery: Eureka Server </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 14. Circuit Breaker: Hystrix Dashboard</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>14. Circuit Breaker: Hystrix Dashboard</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_netflix.html" title="Part III. Spring Cloud Netflix"><link rel="prev" href="multi__circuit_breaker_hystrix_clients.html" title="13. Circuit Breaker: Hystrix Clients"><link rel="next" href="multi__hystrix_timeouts_and_ribbon_clients.html" title="15. Hystrix Timeouts And Ribbon Clients"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14. Circuit Breaker: Hystrix Dashboard</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__circuit_breaker_hystrix_clients.html">Prev</a> </td><th width="60%" align="center">Part III. Spring Cloud Netflix</th><td width="20%" align="right"> <a accesskey="n" href="multi__hystrix_timeouts_and_ribbon_clients.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_circuit_breaker_hystrix_dashboard" href="#_circuit_breaker_hystrix_dashboard"></a>14. Circuit Breaker: Hystrix Dashboard</h2></div></div></div><p>One of the main benefits of Hystrix is the set of metrics it gathers about each HystrixCommand. The Hystrix Dashboard displays the health of each circuit breaker in an efficient manner.</p><div class="figure"><a name="d0e3510" href="#d0e3510"></a><p class="title"><b>Figure 14.1. Hystrix Dashboard</b></p><div class="figure-contents"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-netflix/master/docs/src/main/asciidoc/images/Hystrix.png" alt="Hystrix"></div></div></div><br class="figure-break"></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__circuit_breaker_hystrix_clients.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_netflix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__hystrix_timeouts_and_ribbon_clients.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">13. Circuit Breaker: Hystrix Clients </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 15. Hystrix Timeouts And Ribbon Clients</td></tr></table></div></body></html>
|
||||
67
Finchley.M8/multi/multi__client_side_usage_2.html
Normal file
@@ -0,0 +1,67 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>97. Client Side Usage</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_vault.html" title="Part XIV. Spring Cloud Vault"><link rel="prev" href="multi__quick_start_3.html" title="96. Quick Start"><link rel="next" href="multi_vault.config.authentication.html" title="98. Authentication methods"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">97. Client Side Usage</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__quick_start_3.html">Prev</a> </td><th width="60%" align="center">Part XIV. Spring Cloud Vault</th><td width="20%" align="right"> <a accesskey="n" href="multi_vault.config.authentication.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_client_side_usage_2" href="#_client_side_usage_2"></a>97. Client Side Usage</h2></div></div></div><p>To use these features in an application, just build it as a Spring
|
||||
Boot application that depends on <code class="literal">spring-cloud-vault-config</code> (e.g. see
|
||||
the test cases). Example Maven configuration:</p><div class="example"><a name="d0e24144" href="#d0e24144"></a><p class="title"><b>Example 97.1. pom.xml</b></p><div class="example-contents"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><parent></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-starter-parent<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>1.5.4.RELEASE<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><relativePath /></span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- lookup parent from repository --></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></parent></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-vault-config<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>1.3.5.BUILD-SNAPSHOT<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-starter-test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><scope></span>test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></scope></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencies></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><build></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><plugins></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><plugin></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-maven-plugin<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></plugin></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></plugins></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></build></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- repositories also needed for snapshots and milestones --></span></pre></div></div><br class="example-break"><p>Then you can create a standard Spring Boot application, like this simple HTTP server:</p><div class="informalexample"><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@RestController</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestMapping("/")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String home() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Hello World!"</span>;
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(Application.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
}
|
||||
}</pre></div><p>When it runs it will pick up the external configuration from the
|
||||
default local Vault server on port <code class="literal">8200</code> if it is running. To modify
|
||||
the startup behavior you can change the location of the Vault server
|
||||
using <code class="literal">bootstrap.properties</code> (like <code class="literal">application.properties</code> but for
|
||||
the bootstrap phase of an application context), e.g.</p><div class="example"><a name="d0e24165" href="#d0e24165"></a><p class="title"><b>Example 97.2. bootstrap.yml</b></p><div class="example-contents"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.cloud.vault</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> host</span>: localhost
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> port</span>: <span class="hl-number">8200</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> scheme</span>: https
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: https://localhost:<span class="hl-number">8200</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> connection-timeout</span>: <span class="hl-number">5000</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> read-timeout</span>: <span class="hl-number">15000</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> config</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> order</span>: -<span class="hl-number">10</span></pre></div></div><br class="example-break"><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">host</code> sets the hostname of the Vault host. The host name will be used
|
||||
for SSL certificate validation</li><li class="listitem"><code class="literal">port</code> sets the Vault port</li><li class="listitem"><code class="literal">scheme</code> setting the scheme to <code class="literal">http</code> will use plain HTTP.
|
||||
Supported schemes are <code class="literal">http</code> and <code class="literal">https</code>.</li><li class="listitem"><code class="literal">uri</code> configure the Vault endpoint with an URI. Takes precedence over host/port/scheme configuration</li><li class="listitem"><code class="literal">connection-timeout</code> sets the connection timeout in milliseconds</li><li class="listitem"><code class="literal">read-timeout</code> sets the read timeout in milliseconds</li><li class="listitem"><code class="literal">config.order</code> sets the order for the property source</li></ul></div><p>Enabling further integrations requires additional dependencies and
|
||||
configuration. Depending on how you have set up Vault you might need
|
||||
additional configuration like
|
||||
<a class="link" href="http://cloud.spring.io/spring-cloud-vault/spring-cloud-vault.html#vault.config.ssl" target="_top">SSL</a> and
|
||||
<a class="link" href="http://cloud.spring.io/spring-cloud-vault/spring-cloud-vault.html#vault.config.authentication" target="_top">authentication</a>.</p><p>If the application imports the <code class="literal">spring-boot-starter-actuator</code> project, the
|
||||
status of the vault server will be available via the <code class="literal">/health</code> endpoint.</p><p>The vault health indicator can be enabled or disabled through the
|
||||
property <code class="literal">health.vault.enabled</code> (default <code class="literal">true</code>).</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_authentication_2" href="#_authentication_2"></a>97.1 Authentication</h2></div></div></div><p>Vault requires an <a class="link" href="https://www.vaultproject.io/docs/concepts/auth.html" target="_top">authentication mechanism</a> to <a class="link" href="https://www.vaultproject.io/docs/concepts/tokens.html" target="_top">authorize client requests</a>.</p><p>Spring Cloud Vault supports multiple <a class="link" href="http://cloud.spring.io/spring-cloud-vault/spring-cloud-vault.html#vault.config.authentication" target="_top">authentication mechanisms</a> to authenticate applications with Vault.</p><p>For a quickstart, use the root token printed by the <a class="link" href="multi__quick_start_3.html#quickstart.vault.start">Vault initialization</a>.</p><div class="example"><a name="d0e24260" href="#d0e24260"></a><p class="title"><b>Example 97.3. bootstrap.yml</b></p><div class="example-contents"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.cloud.vault</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> token</span>: <span class="hl-number">19</span>aefa97-cccc-bbbb-aaaa-<span class="hl-number">225940e63d</span>76</pre></div></div><br class="example-break"><div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Warning"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="images/warning.png"></td><th align="left">Warning</th></tr><tr><td align="left" valign="top"><p>Consider carefully your security requirements. Static token authentication is fine if you want quickly get started with Vault, but a static token is not protected any further. Any disclosure to unintended parties allows Vault use with the associated token roles.</p></td></tr></table></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__quick_start_3.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_vault.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_vault.config.authentication.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">96. Quick Start </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 98. Authentication methods</td></tr></table></div></body></html>
|
||||
9
Finchley.M8/multi/multi__cloud_native_applications.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>Part I. Cloud Native Applications</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="prev" href="multi__features.html" title="1. Features"><link rel="next" href="multi__spring_cloud_context_application_context_services.html" title="2. Spring Cloud Context: Application Context Services"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Part I. Cloud Native Applications</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__features.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_context_application_context_services.html">Next</a></td></tr></table><hr></div><div class="part"><div class="titlepage"><div><div><h1 class="title"><a name="_cloud_native_applications" href="#_cloud_native_applications"></a>Part I. Cloud Native Applications</h1></div></div></div><div class="partintro"><div></div><p><a class="link" href="http://pivotal.io/platform-as-a-service/migrating-to-cloud-native-application-architectures-ebook" target="_top">Cloud Native</a> is a style of application development that encourages easy adoption of best practices in the areas of continuous delivery and value-driven development.
|
||||
A related discipline is that of building <a class="link" href="http://12factor.net/" target="_top">12-factor Applications</a>, in which development practices are aligned with delivery and operations goals — for instance, by using declarative programming and management and monitoring.
|
||||
Spring Cloud facilitates these styles of development in a number of specific ways.
|
||||
The starting point is a set of features to which all components in a distributed system need easy access.</p><p>Many of those features are covered by <a class="link" href="http://projects.spring.io/spring-boot" target="_top">Spring Boot</a>, on which Spring Cloud builds. Some more features are delivered by Spring Cloud as two libraries: Spring Cloud Context and Spring Cloud Commons.
|
||||
Spring Cloud Context provides utilities and special services for the <code class="literal">ApplicationContext</code> of a Spring Cloud application (bootstrap context, encryption, refresh scope, and environment endpoints). Spring Cloud Commons is a set of abstractions and common classes used in different Spring Cloud implementations (such as Spring Cloud Netflix and Spring Cloud Consul).</p><p>If you get an exception due to "Illegal key size" and you use Sun’s JDK, you need to install the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files.
|
||||
See the following links for more information:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="link" href="http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html" target="_top">Java 6 JCE</a></li><li class="listitem"><a class="link" href="http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html" target="_top">Java 7 JCE</a></li><li class="listitem"><a class="link" href="http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html" target="_top">Java 8 JCE</a></li></ul></div><p>Extract the files into the JDK/jre/lib/security folder for whichever version of JRE/JDK x64/x86 you use.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Spring Cloud is released under the non-restrictive Apache 2.0 license.
|
||||
If you would like to contribute to this section of the documentation or if you find an error, you can find the source code and issue trackers for the project at <a class="link" href="https://github.com/spring-cloud/spring-cloud-commons/tree/master/docs/src/main/asciidoc" target="_top">github</a>.</p></td></tr></table></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__features.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_context_application_context_services.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">1. Features </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 2. Spring Cloud Context: Application Context Services</td></tr></table></div></body></html>
|
||||
47
Finchley.M8/multi/multi__configuration_2.html
Normal file
@@ -0,0 +1,47 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>112. Configuration</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_gateway.html" title="Part XV. Spring Cloud Gateway"><link rel="prev" href="multi__global_filters.html" title="111. Global Filters"><link rel="next" href="multi__actuator_api.html" title="113. Actuator API"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">112. Configuration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__global_filters.html">Prev</a> </td><th width="60%" align="center">Part XV. Spring Cloud Gateway</th><td width="20%" align="right"> <a accesskey="n" href="multi__actuator_api.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_configuration_2" href="#_configuration_2"></a>112. Configuration</h2></div></div></div><p>Configuration for Spring Cloud Gateway is driven by a collection of `RouteDefinitionLocator`s.</p><p><b>RouteDefinitionLocator.java. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> RouteDefinitionLocator {
|
||||
Flux<RouteDefinition> getRouteDefinitions();
|
||||
}</pre><p>
|
||||
</p><p>By default, a <code class="literal">PropertiesRouteDefinitionLocator</code> loads properties using Spring Boot’s <code class="literal">@ConfigurationProperties</code> mechanism.</p><p>The configuration examples above all use a shortcut notation that uses positional arguments rather than named ones. The two examples below are equivalent:</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: setstatus_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: SetStatus
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> args</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> status</span>: <span class="hl-number">401</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: setstatusshortcut_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - SetStatus</span>=<span class="hl-number">401</span></pre><p>
|
||||
</p><p>For some usages of the gateway, properties will be adequate, but some production use cases will benefit from loading configuration from an external source, such as a database. Future milestone versions will have <code class="literal">RouteDefinitionLocator</code> implementations based off of Spring Data Repositories such as: Redis, MongoDB and Cassandra.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_fluent_java_routes_api" href="#_fluent_java_routes_api"></a>112.1 Fluent Java Routes API</h2></div></div></div><p>To allow for simple configuration in Java, there is a fluent API defined in the <code class="literal">Routes</code> class.</p><p><b>GatewaySampleApplication.java. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// static imports from GatewayFilters and RoutePredicates</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> RouteLocator customRouteLocator(RouteLocatorBuilder builder, ThrottleGatewayFilterFactory throttle) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> builder.routes()
|
||||
.route(r -> r.host(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"**.abc.org"</span>).and().path(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/image/png"</span>)
|
||||
.filters(f ->
|
||||
f.addResponseHeader(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"X-TestHeader"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foobar"</span>))
|
||||
.uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://httpbin.org:80"</span>)
|
||||
)
|
||||
.route(r -> r.path(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/image/webp"</span>)
|
||||
.filters(f ->
|
||||
f.addResponseHeader(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"X-AnotherHeader"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"baz"</span>))
|
||||
.uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://httpbin.org:80"</span>)
|
||||
)
|
||||
.route(r -> r.order(-<span class="hl-number">1</span>)
|
||||
.host(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"**.throttle.org"</span>).and().path(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/get"</span>)
|
||||
.filters(f -> f.filter(throttle.apply(<span class="hl-number">1</span>,
|
||||
<span class="hl-number">1</span>,
|
||||
<span class="hl-number">10</span>,
|
||||
TimeUnit.SECONDS)))
|
||||
.uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://httpbin.org:80"</span>)
|
||||
)
|
||||
.build();
|
||||
}</pre><p>
|
||||
</p><p>This style also allows for more custom predicate assertions. The predicates defined by <code class="literal">RouteDefinitionLocator</code> beans are combined using logical <code class="literal">and</code>. By using the fluent Java API, you can use the <code class="literal">and()</code>, <code class="literal">or()</code> and <code class="literal">negate()</code> operators on the <code class="literal">Predicate</code> class.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_discoveryclient_route_definition_locator" href="#_discoveryclient_route_definition_locator"></a>112.2 DiscoveryClient Route Definition Locator</h2></div></div></div><p>The Gateway can be configured to create routes based on services registered with a <code class="literal">DiscoveryClient</code> compatible service registry.</p><p>To enable this, set <code class="literal">spring.cloud.gateway.discovery.locator.enabled=true</code> and make sure a <code class="literal">DiscoveryClient</code> implementation is on the classpath and enabled (such as Netflix Eureka, Consul or Zookeeper).</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__global_filters.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_gateway.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__actuator_api.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">111. Global Filters </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 113. Actuator API</td></tr></table></div></body></html>
|
||||
120
Finchley.M8/multi/multi__configuration_options.html
Normal file
@@ -0,0 +1,120 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>28. Configuration Options</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="prev" href="multi__binders.html" title="27. Binders"><link rel="next" href="multi_contenttypemanagement.html" title="29. Content Type and Transformation"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">28. Configuration Options</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__binders.html">Prev</a> </td><th width="60%" align="center">Part V. Spring Cloud Stream</th><td width="20%" align="right"> <a accesskey="n" href="multi_contenttypemanagement.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_configuration_options" href="#_configuration_options"></a>28. Configuration Options</h2></div></div></div><p>Spring Cloud Stream supports general configuration options as well as configuration for bindings and binders.
|
||||
Some binders allow additional binding properties to support middleware-specific features.</p><p>Configuration options can be provided to Spring Cloud Stream applications via any mechanism supported by Spring Boot.
|
||||
This includes application arguments, environment variables, and YAML or .properties files.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spring_cloud_stream_properties" href="#_spring_cloud_stream_properties"></a>28.1 Spring Cloud Stream Properties</h2></div></div></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">spring.cloud.stream.instanceCount</span></dt><dd><p class="simpara"> The number of deployed instances of an application.
|
||||
Must be set for partitioning on the producer side, and on the consumer side if using RabbitMQ and with Kafka if <code class="literal">autoRebalanceEnabled=false</code>.</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">spring.cloud.stream.instanceIndex</span></dt><dd> The instance index of the application: a number from <code class="literal">0</code> to <code class="literal">instanceCount</code>-1.
|
||||
Used for partitioning with RabbitMQ and with Kafka if <code class="literal">autoRebalanceEnabled=false</code>.
|
||||
Automatically set in Cloud Foundry to match the application’s instance index.</dd><dt><span class="term">spring.cloud.stream.dynamicDestinations</span></dt><dd><p class="simpara"> A list of destinations that can be bound dynamically (for example, in a dynamic routing scenario).
|
||||
If set, only listed destinations can be bound.</p><p class="simpara">Default: empty (allowing any destination to be bound).</p></dd><dt><span class="term">spring.cloud.stream.defaultBinder</span></dt><dd><p class="simpara"> The default binder to use, if multiple binders are configured.
|
||||
See <a class="link" href="multi__binders.html#multiple-binders" title="27.4 Multiple Binders on the Classpath">Multiple Binders on the Classpath</a>.</p><p class="simpara">Default: empty.</p></dd><dt><span class="term">spring.cloud.stream.overrideCloudConnectors</span></dt><dd><p class="simpara"> This property is only applicable when the <code class="literal">cloud</code> profile is active and Spring Cloud Connectors are provided with the application.
|
||||
If the property is false (the default), the binder will detect a suitable bound service (e.g. a RabbitMQ service bound in Cloud Foundry for the RabbitMQ binder) and will use it for creating connections (usually via Spring Cloud Connectors).
|
||||
When set to true, this property instructs binders to completely ignore the bound services and rely on Spring Boot properties (e.g. relying on the <code class="literal">spring.rabbitmq.*</code> properties provided in the environment for the RabbitMQ binder).
|
||||
The typical usage of this property is to be nested in a customized environment <a class="link" href="multi__binders.html#multiple-systems" title="27.5 Connecting to Multiple Systems">when connecting to multiple systems</a>.</p><p class="simpara">Default: false.</p></dd><dt><span class="term">spring.cloud.stream.bindingRetryInterval</span></dt><dd><p class="simpara"> The interval (seconds) between retrying binding creation when, for example, the binder doesn’t support late binding and the broker is down (e.g. Apache Kafka).
|
||||
Set to zero to treat such conditions as fatal, preventing the application from starting.</p><p class="simpara">Default: 30</p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="binding-properties" href="#binding-properties"></a>28.2 Binding Properties</h2></div></div></div><p>Binding properties are supplied using the format <code class="literal">spring.cloud.stream.bindings.<channelName>.<property>=<value></code>.
|
||||
The <code class="literal"><channelName></code> represents the name of the channel being configured (e.g., <code class="literal">output</code> for a <code class="literal">Source</code>).</p><p>To avoid repetition, Spring Cloud Stream supports setting values for all channels, in the format <code class="literal">spring.cloud.stream.default.<property>=<value></code>.</p><p>In what follows, we indicate where we have omitted the <code class="literal">spring.cloud.stream.bindings.<channelName>.</code> prefix and focus just on the property name, with the understanding that the prefix will be included at runtime.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_properties_for_use_of_spring_cloud_stream" href="#_properties_for_use_of_spring_cloud_stream"></a>28.2.1 Properties for Use of Spring Cloud Stream</h3></div></div></div><p>The following binding properties are available for both input and output bindings and must be prefixed with <code class="literal">spring.cloud.stream.bindings.<channelName>.</code>, e.g. <code class="literal">spring.cloud.stream.bindings.input.destination=ticktock</code>.</p><p>Default values can be set by using the prefix <code class="literal">spring.cloud.stream.default</code>, e.g. <code class="literal">spring.cloud.stream.default.contentType=application/json</code>.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">destination</span></dt><dd>The target destination of a channel on the bound middleware (e.g., 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.</dd><dt><span class="term">group</span></dt><dd><p class="simpara"> The consumer group of the channel.
|
||||
Applies only to inbound bindings.
|
||||
See <a class="link" href="multi__main_concepts.html#consumer-groups" title="25.4 Consumer Groups">Consumer Groups</a>.</p><p class="simpara">Default: null (indicating an anonymous consumer).</p></dd><dt><span class="term">contentType</span></dt><dd><p class="simpara">The content type of the channel.</p><p class="simpara">Default: null (so that no type coercion is performed).</p></dd><dt><span class="term">binder</span></dt><dd><p class="simpara"> The binder used by this binding.
|
||||
See <a class="xref" href="multi__binders.html#multiple-binders" title="27.4 Multiple Binders on the Classpath">Section 27.4, “Multiple Binders on the Classpath”</a> for details.</p><p class="simpara">Default: null (the default binder will be used, if one exists).</p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_consumer_properties" href="#_consumer_properties"></a>28.2.2 Consumer properties</h3></div></div></div><p>The following binding properties are available for input bindings only and must be prefixed with <code class="literal">spring.cloud.stream.bindings.<channelName>.consumer.</code>, e.g. <code class="literal">spring.cloud.stream.bindings.input.consumer.concurrency=3</code>.</p><p>Default values can be set by using the prefix <code class="literal">spring.cloud.stream.default.consumer</code>, e.g. <code class="literal">spring.cloud.stream.default.consumer.headerMode=none</code>.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">concurrency</span></dt><dd><p class="simpara">The concurrency of the inbound consumer.</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">partitioned</span></dt><dd><p class="simpara">Whether the consumer receives data from a partitioned producer.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">headerMode</span></dt><dd><p class="simpara"> When set to <code class="literal">none</code>, 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 <code class="literal">headers</code>, uses the middleware’s native header mechanism.
|
||||
When set to <code class="literal">embeddedHeaders</code>, embeds headers into the message payload.</p><p class="simpara">Default: depends on binder implementation.</p></dd><dt><span class="term">maxAttempts</span></dt><dd><p class="simpara">If processing fails, the number of attempts to process the message (including the first).
|
||||
Set to 1 to disable retry.</p><p class="simpara">Default: <code class="literal">3</code>.</p></dd><dt><span class="term">backOffInitialInterval</span></dt><dd><p class="simpara">The backoff initial interval on retry.</p><p class="simpara">Default: <code class="literal">1000</code>.</p></dd><dt><span class="term">backOffMaxInterval</span></dt><dd><p class="simpara">The maximum backoff interval.</p><p class="simpara">Default: <code class="literal">10000</code>.</p></dd><dt><span class="term">backOffMultiplier</span></dt><dd><p class="simpara">The backoff multiplier.</p><p class="simpara">Default: <code class="literal">2.0</code>.</p></dd><dt><span class="term">instanceIndex</span></dt><dd><p class="simpara"> When set to a value greater than equal to zero, allows customizing the instance index of this consumer (if different from <code class="literal">spring.cloud.stream.instanceIndex</code>).
|
||||
When set to a negative value, it will default to <code class="literal">spring.cloud.stream.instanceIndex</code>.
|
||||
See that property for more information.</p><p class="simpara">Default: <code class="literal">-1</code>.</p></dd><dt><span class="term">instanceCount</span></dt><dd><p class="simpara"> When set to a value greater than equal to zero, allows customizing the instance count of this consumer (if different from <code class="literal">spring.cloud.stream.instanceCount</code>).
|
||||
When set to a negative value, it will default to <code class="literal">spring.cloud.stream.instanceCount</code>.
|
||||
See that property for more information.</p><p class="simpara">Default: <code class="literal">-1</code>.</p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_producer_properties" href="#_producer_properties"></a>28.2.3 Producer Properties</h3></div></div></div><p>The following binding properties are available for output bindings only and must be prefixed with <code class="literal">spring.cloud.stream.bindings.<channelName>.producer.</code>, e.g. <code class="literal">spring.cloud.stream.bindings.input.producer.partitionKeyExpression=payload.id</code>.</p><p>Default values can be set by using the prefix <code class="literal">spring.cloud.stream.default.producer</code>, e.g. <code class="literal">spring.cloud.stream.default.producer.partitionKeyExpression=payload.id</code>.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">partitionKeyExpression</span></dt><dd><p class="simpara"> A SpEL expression that determines how to partition outbound data.
|
||||
If set, or if <code class="literal">partitionKeyExtractorClass</code> is set, outbound data on this channel will be partitioned, and <code class="literal">partitionCount</code> must be set to a value greater than 1 to be effective.
|
||||
The two options are mutually exclusive.
|
||||
See <a class="xref" href="multi__main_concepts.html#partitioning" title="25.6 Partitioning Support">Section 25.6, “Partitioning Support”</a>.</p><p class="simpara">Default: null.</p></dd><dt><span class="term">partitionKeyExtractorClass</span></dt><dd><p class="simpara"> A <code class="literal">PartitionKeyExtractorStrategy</code> implementation.
|
||||
If set, or if <code class="literal">partitionKeyExpression</code> is set, outbound data on this channel will be partitioned, and <code class="literal">partitionCount</code> must be set to a value greater than 1 to be effective.
|
||||
The two options are mutually exclusive.
|
||||
See <a class="xref" href="multi__main_concepts.html#partitioning" title="25.6 Partitioning Support">Section 25.6, “Partitioning Support”</a>.</p><p class="simpara">Default: null.</p></dd><dt><span class="term">partitionSelectorClass</span></dt><dd><p class="simpara"> A <code class="literal">PartitionSelectorStrategy</code> implementation.
|
||||
Mutually exclusive with <code class="literal">partitionSelectorExpression</code>.
|
||||
If neither is set, the partition will be selected as the <code class="literal">hashCode(key) % partitionCount</code>, where <code class="literal">key</code> is computed via either <code class="literal">partitionKeyExpression</code> or <code class="literal">partitionKeyExtractorClass</code>.</p><p class="simpara">Default: null.</p></dd><dt><span class="term">partitionSelectorExpression</span></dt><dd><p class="simpara"> A SpEL expression for customizing partition selection.
|
||||
Mutually exclusive with <code class="literal">partitionSelectorClass</code>.
|
||||
If neither is set, the partition will be selected as the <code class="literal">hashCode(key) % partitionCount</code>, where <code class="literal">key</code> is computed via either <code class="literal">partitionKeyExpression</code> or <code class="literal">partitionKeyExtractorClass</code>.</p><p class="simpara">Default: null.</p></dd><dt><span class="term">partitionCount</span></dt><dd><p class="simpara"> 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, interpreted as a
|
||||
hint; the larger of this and the partition count of the target topic is used instead.</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">requiredGroups</span></dt><dd>A comma-separated list of groups to which the producer must ensure message delivery even if they start after it has been created (e.g., by pre-creating durable queues in RabbitMQ).</dd><dt><span class="term">headerMode</span></dt><dd><p class="simpara"> When set to <code class="literal">none</code>, disables header embedding on output.
|
||||
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 <code class="literal">headers</code>, uses the middleware’s native header mechanism.
|
||||
When set to <code class="literal">embeddedHeaders</code>, embeds headers into the message payload.</p><p class="simpara">Default: Depends on binder implementation.</p></dd><dt><span class="term">useNativeEncoding</span></dt><dd><p class="simpara"> When set to <code class="literal">true</code>, the outbound message is serialized directly by client library, which must be configured correspondingly (e.g. setting an appropriate Kafka producer value serializer).
|
||||
When this configuration is being used, the outbound message marshalling is not based on the <code class="literal">contentType</code> of the binding.
|
||||
When native encoding is used, it is the responsibility of the consumer to use appropriate decoder (ex: Kafka consumer value de-serializer) to deserialize the inbound message.
|
||||
Also, when native encoding/decoding is used the <code class="literal">headerMode=embeddedHeaders</code> property is ignored and headers will not be embedded into the message.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">errorChannelEnabled</span></dt><dd><p class="simpara">When set to <code class="literal">true</code>, if the binder supports async send results; send failures will be sent to an error channel for the destination.
|
||||
See <a class="xref" href="multi__programming_model.html#binder-error-channels" title="Message Channel Binders and Error Channels">the section called “Message Channel Binders and Error Channels”</a> for more information.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd></dl></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="dynamicdestination" href="#dynamicdestination"></a>28.3 Using dynamically bound destinations</h2></div></div></div><p>Besides the channels defined via <code class="literal">@EnableBinding</code>, Spring Cloud Stream allows applications to 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 <code class="literal">BinderAwareChannelResolver</code> bean, registered automatically by the <code class="literal">@EnableBinding</code> annotation.</p><p>The property 'spring.cloud.stream.dynamicDestinations' can be used for restricting the dynamic destination names to a set known beforehand (whitelisting).
|
||||
If the property is not set, any destination can be bound dynamically.</p><p>The <code class="literal">BinderAwareChannelResolver</code> can be used directly as in the following example, in which a REST controller uses a path variable to decide the target channel.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Controller</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> SourceWithDynamicDestination {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> BinderAwareChannelResolver resolver;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestMapping(path = "/{target}", method = POST, consumes = "*/*")</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@ResponseStatus(HttpStatus.ACCEPTED)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> handleRequest(<em><span class="hl-annotation" style="color: gray">@RequestBody</span></em> String body, <em><span class="hl-annotation" style="color: gray">@PathVariable("target")</span></em> target,
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestHeader(HttpHeaders.CONTENT_TYPE)</span></em> Object contentType) {
|
||||
sendMessage(body, target, contentType);
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> sendMessage(String body, String target, Object contentType) {
|
||||
resolver.resolveDestination(target).send(MessageBuilder.createMessage(body,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, contentType))));
|
||||
}
|
||||
}</pre><p>After starting the application on the default port 8080, when sending the following data:</p><pre class="screen">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</pre><p>The destinations 'customers' and 'orders' are created in the broker (for example: exchange in case of Rabbit or topic in case of Kafka) with the names 'customers' and 'orders', and the data is published to the appropriate destinations.</p><p>The <code class="literal">BinderAwareChannelResolver</code> is a general purpose Spring Integration <code class="literal">DestinationResolver</code> and can be injected in other components.
|
||||
For example, in a router using a SpEL expression based on the <code class="literal">target</code> field of an incoming JSON message.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Controller</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> SourceWithDynamicDestination {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> BinderAwareChannelResolver resolver;
|
||||
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestMapping(path = "/", method = POST, consumes = "application/json")</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@ResponseStatus(HttpStatus.ACCEPTED)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> handleRequest(<em><span class="hl-annotation" style="color: gray">@RequestBody</span></em> String body, <em><span class="hl-annotation" style="color: gray">@RequestHeader(HttpHeaders.CONTENT_TYPE)</span></em> Object contentType) {
|
||||
sendMessage(body, contentType);
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> sendMessage(Object body, Object contentType) {
|
||||
routerChannel().send(MessageBuilder.createMessage(body,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, contentType))));
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean(name = "routerChannel")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> MessageChannel routerChannel() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> DirectChannel();
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@ServiceActivator(inputChannel = "routerChannel")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> ExpressionEvaluatingRouter router() {
|
||||
ExpressionEvaluatingRouter router =
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ExpressionEvaluatingRouter(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> SpelExpressionParser().parseExpression(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"payload.target"</span>));
|
||||
router.setDefaultOutputChannelName(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"default-output"</span>);
|
||||
router.setChannelResolver(resolver);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> router;
|
||||
}
|
||||
}</pre><p>The <a class="link" href="https://github.com/spring-cloud-stream-app-starters/router" target="_top">Router Sink Application</a> uses this technique to create the destinations on-demand.</p><p>If the channel names are known in advance, you can configure the producer properties as with any other destination.
|
||||
Alternatively, if you register a <code class="literal">NewBindingCallback<></code> bean, it will be 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:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> configure(String channelName, MessageChannel channel, ProducerProperties producerProperties,
|
||||
T extendedProducerProperties);</pre><p>The following is an example using the RabbitMQ binder:</p><pre class="programlisting">@Bean
|
||||
public NewBindingCallback<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><RabbitProducerProperties></span> dynamicConfigurer() {
|
||||
return (name, channel, props, extended) -> {
|
||||
props.setRequiredGroups("bindThisQueue");
|
||||
extended.setQueueNameGroupOnly(true);
|
||||
extended.setAutoBindDlq(true);
|
||||
extended.setDeadLetterQueueName("myDLQ");
|
||||
};
|
||||
}</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>If you need to support dynamic destinations with multiple binder types, use <code class="literal">Object</code> for the generic type and cast the <code class="literal">extended</code> argument as needed.</p></td></tr></table></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__binders.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_stream.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_contenttypemanagement.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">27. Binders </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 29. Content Type and Transformation</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,17 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>80. Configuring Authentication Downstream of a Zuul Proxy</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_security.html" title="Part XI. Spring Cloud Security"><link rel="prev" href="multi__more_detail.html" title="79. More Detail"><link rel="next" href="multi__spring_cloud_for_cloud_foundry.html" title="Part XII. Spring Cloud for Cloud Foundry"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">80. Configuring Authentication Downstream of a Zuul Proxy</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__more_detail.html">Prev</a> </td><th width="60%" align="center">Part XI. Spring Cloud Security</th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_for_cloud_foundry.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_configuring_authentication_downstream_of_a_zuul_proxy" href="#_configuring_authentication_downstream_of_a_zuul_proxy"></a>80. Configuring Authentication Downstream of a Zuul Proxy</h2></div></div></div><p>You can control the authorization behaviour downstream of an
|
||||
<code class="literal">@EnableZuulProxy</code> through the <code class="literal">proxy.auth.*</code> settings. Example:</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">proxy</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> auth</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> customers</span>: oauth2
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> stores</span>: passthru
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> recommendations</span>: none</pre><p>
|
||||
</p><p>In this example the "customers" service gets an OAuth2 token relay,
|
||||
the "stores" service gets a passthrough (the authorization header is
|
||||
just passed downstream), and the "recommendations" service has its
|
||||
authorization header removed. The default behaviour is to do a token
|
||||
relay if there is a token available, and passthru otherwise.</p><p>See
|
||||
<a class="link" href="https://github.com/spring-cloud/spring-cloud-security/tree/master/src/main/java/org/springframework/cloud/security/oauth2/proxy/ProxyAuthenticationProperties" target="_top">
|
||||
ProxyAuthenticationProperties</a> for full details.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__more_detail.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_security.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_for_cloud_foundry.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">79. More Detail </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part XII. Spring Cloud for Cloud Foundry</td></tr></table></div></body></html>
|
||||
1706
Finchley.M8/multi/multi__contract_dsl.html
Normal file
20
Finchley.M8/multi/multi__current_span.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>53. Current Span</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__current_tracing_component.html" title="52. Current Tracing Component"><link rel="next" href="multi__instrumentation.html" title="54. Instrumentation"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">53. Current Span</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__current_tracing_component.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__instrumentation.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_current_span" href="#_current_span"></a>53. Current Span</h2></div></div></div><p>Brave supports a "current span" concept which represents the in-flight
|
||||
operation. <code class="literal">Tracer.currentSpan()</code> can be used to add custom tags to a
|
||||
span and <code class="literal">Tracer.nextSpan()</code> can be used to create a child of whatever
|
||||
is in-flight.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_setting_a_span_in_scope_manually" href="#_setting_a_span_in_scope_manually"></a>53.1 Setting a span in scope manually</h2></div></div></div><p>When writing new instrumentation, it is important to place a span you
|
||||
created in scope as the current span. Not only does this allow users to
|
||||
access it with <code class="literal">Tracer.currentSpan()</code>, but it also allows customizations
|
||||
like SLF4J MDC to see the current trace IDs.</p><p><code class="literal">Tracer.withSpanInScope(Span)</code> facilitates this and is most conveniently
|
||||
employed via the try-with-resources idiom. Whenever external code might
|
||||
be invoked (such as proceeding an interceptor or otherwise), place the
|
||||
span in scope like this.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> (SpanInScope ws = tracer.withSpanInScope(span)) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> inboundRequest.invoke();
|
||||
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">finally</span> { <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// note the scope is independent of the span</span>
|
||||
span.finish();
|
||||
}</pre><p>In edge cases, you may need to clear the current span temporarily. For
|
||||
example, launching a task that should not be associated with the current
|
||||
request. To do this, simply pass null to <code class="literal">withSpanInScope</code>.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> (SpanInScope cleared = tracer.withSpanInScope(null)) {
|
||||
startBackgroundThread();
|
||||
}</pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__current_tracing_component.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__instrumentation.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">52. Current Tracing Component </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 54. Instrumentation</td></tr></table></div></body></html>
|
||||
9
Finchley.M8/multi/multi__current_tracing_component.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>52. Current Tracing Component</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__propagation.html" title="51. Propagation"><link rel="next" href="multi__current_span.html" title="53. Current Span"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">52. Current Tracing Component</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__propagation.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__current_span.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_current_tracing_component" href="#_current_tracing_component"></a>52. Current Tracing Component</h2></div></div></div><p>Brave supports a "current tracing component" concept which should only
|
||||
be used when you have no other means to get a reference. This was made
|
||||
for JDBC connections, as they often initialize prior to the tracing
|
||||
component.</p><p>The most recent tracing component instantiated is available via
|
||||
<code class="literal">Tracing.current()</code>. You there’s also a shortcut to get only the tracer
|
||||
via <code class="literal">Tracing.currentTracer()</code>. If you use either of these methods, do
|
||||
noot cache the result. Instead, look them up each time you need them.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__propagation.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__current_span.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">51. Propagation </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 53. Current Span</td></tr></table></div></body></html>
|
||||
217
Finchley.M8/multi/multi__customization.html
Normal file
@@ -0,0 +1,217 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>91. Customization</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_contract.html" title="Part XIII. Spring Cloud Contract"><link rel="prev" href="multi__contract_dsl.html" title="90. Contract DSL"><link rel="next" href="multi__using_the_pluggable_architecture.html" title="92. Using the Pluggable Architecture"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">91. Customization</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__contract_dsl.html">Prev</a> </td><th width="60%" align="center">Part XIII. Spring Cloud Contract</th><td width="20%" align="right"> <a accesskey="n" href="multi__using_the_pluggable_architecture.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_customization" href="#_customization"></a>91. Customization</h2></div></div></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>This section is valid only for Groovy DSL</p></td></tr></table></div><p>You can customize the Spring Cloud Contract Verifier by extending the DSL, as shown in
|
||||
the remainder of this section.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_extending_the_dsl" href="#_extending_the_dsl"></a>91.1 Extending the DSL</h2></div></div></div><p>You can provide your own functions to the DSL. The key requirement for this feature is to
|
||||
maintain the static compatibility. Later in this document, you can see examples of:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Creating a JAR with reusable classes.</li><li class="listitem">Referencing of these classes in the DSLs.</li></ul></div><p>You can find the full example
|
||||
<a class="link" href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples" target="_top">here</a>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_common_jar" href="#_common_jar"></a>91.1.1 Common JAR</h3></div></div></div><p>The following examples show three classes that can be reused in the DSLs.</p><p><span class="strong"><strong>PatternUtils</strong></span> contains functions used by both the <span class="strong"><strong>consumer</strong></span> and the <span class="strong"><strong>producer</strong></span>.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.example;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> java.util.regex.Pattern;
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* If you want to use {@link Pattern} directly in your tests
|
||||
* then you can create a class resembling this one. It can
|
||||
* contain all the {@link Pattern} you want to use in the DSL.
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* request {
|
||||
* body(
|
||||
* [ age: $(c(PatternUtils.oldEnough()))]
|
||||
* )
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Notice that we're using both {@code $()} for dynamic values
|
||||
* and {@code c()} for the consumer side.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//tag::impl[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> PatternUtils {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> String tooYoung() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::start[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"[0-1][0-9]"</span>;
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::end[return]</span>
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> Pattern oldEnough() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::start[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> Pattern.compile(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"[2-9][0-9]"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::end[return]</span>
|
||||
}
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* Makes little sense but it's just an example ;)
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> Pattern ok() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::start[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> Pattern.compile(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"OK"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::end[return]</span>
|
||||
}
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//end::impl[]</span></pre><p><span class="strong"><strong>ConsumerUtils</strong></span> contains functions used by the <span class="strong"><strong>consumer</strong></span>.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.example;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.contract.spec.internal.ClientDslProperty;
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* DSL Properties passed to the DSL from the consumer's perspective.
|
||||
* That means that on the input side {@code Request} for HTTP
|
||||
* or {@code Input} for messaging you can have a regular expression.
|
||||
* On the {@code Response} for HTTP or {@code Output} for messaging
|
||||
* you have to have a concrete value.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//tag::impl[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> ConsumerUtils {
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* Consumer side property. By using the {@link ClientDslProperty}
|
||||
* you can omit most of boilerplate code from the perspective
|
||||
* of dynamic values. Example
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* request {
|
||||
* body(
|
||||
* [ age: $(ConsumerUtils.oldEnough())]
|
||||
* )
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* That way it's in the implementation that we decide what value we will pass to the consumer
|
||||
* and which one to the producer.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> ClientDslProperty oldEnough() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::start[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// this example is not the best one and</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// theoretically you could just pass the regex instead of `ServerDslProperty` but</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// it's just to show some new tricks :)</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ClientDslProperty(PatternUtils.oldEnough(), <span class="hl-number">40</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::end[return]</span>
|
||||
}
|
||||
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//end::impl[]</span></pre><p><span class="strong"><strong>ProducerUtils</strong></span> contains functions used by the <span class="strong"><strong>producer</strong></span>.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.example;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.contract.spec.internal.ServerDslProperty;
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* DSL Properties passed to the DSL from the producer's perspective.
|
||||
* That means that on the input side {@code Request} for HTTP
|
||||
* or {@code Input} for messaging you have to have a concrete value.
|
||||
* On the {@code Response} for HTTP or {@code Output} for messaging
|
||||
* you can have a regular expression.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//tag::impl[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> ProducerUtils {
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* Producer side property. By using the {@link ProducerUtils}
|
||||
* you can omit most of boilerplate code from the perspective
|
||||
* of dynamic values. Example
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* response {
|
||||
* body(
|
||||
* [ status: $(ProducerUtils.ok())]
|
||||
* )
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* That way it's in the implementation that we decide what value we will pass to the consumer
|
||||
* and which one to the producer.
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> ServerDslProperty ok() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// this example is not the best one and</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// theoretically you could just pass the regex instead of `ServerDslProperty` but</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// it's just to show some new tricks :)</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ServerDslProperty( PatternUtils.ok(), <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"OK"</span>);
|
||||
}
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//end::impl[]</span></pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_adding_the_dependency_to_the_project" href="#_adding_the_dependency_to_the_project"></a>91.1.2 Adding the Dependency to the Project</h3></div></div></div><p>In order for the plugins and IDE to be able to reference the common JAR classes, you need
|
||||
to pass the dependency to your project.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_test_the_dependency_in_the_project_s_dependencies" href="#_test_the_dependency_in_the_project_s_dependencies"></a>91.1.3 Test the Dependency in the Project’s Dependencies</h3></div></div></div><p>First, add the common jar dependency as a test dependency. Because your contracts files
|
||||
are available on the test resources path, the common jar classes automatically become
|
||||
visible in your Groovy files. The following examples show how to test the dependency:</p><p class="primary"><b>Maven. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>com.example<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>beer-common<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>${project.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><scope></span>test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></scope></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p class="primary">
|
||||
</p><p class="secondary"><b>Gradle. </b>
|
||||
</p><pre class="programlisting">testCompile(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"com.example:beer-common:0.0.1-SNAPSHOT"</span>)</pre><p class="secondary">
|
||||
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_test_a_dependency_in_the_plugin_s_dependencies" href="#_test_a_dependency_in_the_plugin_s_dependencies"></a>91.1.4 Test a Dependency in the Plugin’s Dependencies</h3></div></div></div><p>Now, you must add the dependency for the plugin to reuse at runtime, as shown in the
|
||||
following example:</p><p class="primary"><b>Maven. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><plugin></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-contract-maven-plugin<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>${spring-cloud-contract.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><extensions></span>true<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></extensions></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><configuration></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><packageWithBaseClasses></span>com.example<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></packageWithBaseClasses></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><baseClassMappings></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><baseClassMapping></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><contractPackageRegex></span>.*intoxication.*<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></contractPackageRegex></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><baseClassFQN></span>com.example.intoxication.BeerIntoxicationBase<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></baseClassFQN></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></baseClassMapping></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></baseClassMappings></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></configuration></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>com.example<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>beer-common<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>${project.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><scope></span>compile<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></scope></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></plugin></span></pre><p class="primary">
|
||||
</p><p class="secondary"><b>Gradle. </b>
|
||||
</p><pre class="programlisting">classpath <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"com.example:beer-common:0.0.1-SNAPSHOT"</span></pre><p class="secondary">
|
||||
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_referencing_classes_in_dsls" href="#_referencing_classes_in_dsls"></a>91.1.5 Referencing classes in DSLs</h3></div></div></div><p>You can now reference your classes in your DSL, as shown in the following example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> contracts.beer.rest
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> com.example.ConsumerUtils
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> com.example.ProducerUtils
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.contract.spec.Contract
|
||||
|
||||
Contract.make {
|
||||
description(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">""</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"
|
||||
</span>Represents a successful scenario of getting a beer
|
||||
|
||||
```
|
||||
given:
|
||||
client is old enough
|
||||
when:
|
||||
he applies <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">for</span> a beer
|
||||
then:
|
||||
we<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'ll grant him the beer
|
||||
</span>```
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">""</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">")
|
||||
</span> request {
|
||||
method <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'POST'</span>
|
||||
url <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'/check'</span>
|
||||
body(
|
||||
age: $(ConsumerUtils.oldEnough())
|
||||
)
|
||||
headers {
|
||||
contentType(applicationJson())
|
||||
}
|
||||
}
|
||||
response {
|
||||
status <span class="hl-number">200</span>
|
||||
body(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">""</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"
|
||||
</span> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"status"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"${value(ProducerUtils.ok())}"</span>
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">""</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">")
|
||||
</span> headers {
|
||||
contentType(applicationJson())
|
||||
}
|
||||
}
|
||||
}</pre></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__contract_dsl.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_contract.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__using_the_pluggable_architecture.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">90. Contract DSL </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 92. Using the Pluggable Architecture</td></tr></table></div></body></html>
|
||||
46
Finchley.M8/multi/multi__customizations.html
Normal file
@@ -0,0 +1,46 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>58. Customizations</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__managing_spans_with_annotations.html" title="57. Managing spans with annotations"><link rel="next" href="multi__sending_spans_to_zipkin.html" title="59. Sending spans to Zipkin"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">58. Customizations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__managing_spans_with_annotations.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__sending_spans_to_zipkin.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_customizations" href="#_customizations"></a>58. Customizations</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spring_integration" href="#_spring_integration"></a>58.1 Spring Integration</h2></div></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_http" href="#_http"></a>58.2 HTTP</h2></div></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_tracefilter" href="#_tracefilter"></a>58.3 TraceFilter</h2></div></div></div><p>You can also modify the behaviour of the <code class="literal">TraceFilter</code> - the component that is responsible
|
||||
for processing the input HTTP request and adding tags basing on the HTTP response. You can customize
|
||||
the tags, or modify the response headers by registering your own instance of the <code class="literal">TraceFilter</code> bean.</p><p>In the following example we will register the <code class="literal">TraceFilter</code> bean and we will add the
|
||||
<code class="literal">ZIPKIN-TRACE-ID</code> response header containing the current Span’s trace id. Also we will
|
||||
add to the Span a tag with key <code class="literal">custom</code> and a value <code class="literal">tag</code>.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Component</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Order(TraceFilter.ORDER + 1)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyFilter <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> GenericFilterBean {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> Tracer tracer;
|
||||
|
||||
MyFilter(Tracer tracer) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracer = tracer;
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> IOException, ServletException {
|
||||
Span currentSpan = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracer.currentSpan();
|
||||
then(currentSpan).isNotNull();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// for readability we're returning trace id in a hex form</span>
|
||||
((HttpServletResponse) response)
|
||||
.addHeader(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"ZIPKIN-TRACE-ID"</span>,
|
||||
currentSpan.context().traceIdString());
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// we can also add some custom tags</span>
|
||||
currentSpan.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"custom"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tag"</span>);
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_custom_service_name" href="#_custom_service_name"></a>58.4 Custom service name</h2></div></div></div><p>By default Sleuth assumes that when you send a span to Zipkin, you want the span’s service name
|
||||
to be equal to <code class="literal">spring.application.name</code> value. That’s not always the case though. There
|
||||
are situations in which you want to explicitly provide a different service name for all spans coming
|
||||
from your application. To achieve that it’s enough to just pass the following property
|
||||
to your application to override that value (example for <code class="literal">foo</code> service name):</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.zipkin.service.name</span>: foo</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_customization_of_reported_spans" href="#_customization_of_reported_spans"></a>58.5 Customization of reported spans</h2></div></div></div><p>Before reporting spans to e.g. Zipkin you can be interested in modifying that span in some way.
|
||||
You can achieve that by using the <code class="literal">SpanAdjuster</code> interface.</p><p>In Sleuth we’re generating spans with a fixed name. Some users want to modify the name depending on values
|
||||
of tags. Implementation of the <code class="literal">SpanAdjuster</code> interface can be used to alter that name. Example:</p><p>Example. If you register two beans of <code class="literal">SpanAdjuster</code> type:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em> SpanAdjuster adjusterOne() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> span -> span.toBuilder().name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo"</span>).build();
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em> SpanAdjuster adjusterTwo() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> span -> span.toBuilder().name(span.name() + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">" bar"</span>).build();
|
||||
}</pre><p>This will lead in changing the name of the reported span to <code class="literal">foo bar</code>, just before it gets reported (e.g. to Zipkin).</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_host_locator" href="#_host_locator"></a>58.6 Host locator</h2></div></div></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>This section is about defining <span class="strong"><strong>host</strong></span> from service discovery. It’s <span class="strong"><strong>NOT</strong></span>
|
||||
about finding Zipkin in service discovery.</p></td></tr></table></div><p>In order to define the host that is corresponding to a particular span we need to resolve the host name
|
||||
and port. The default approach is to take it from server properties. If those for some reason are not set
|
||||
then we’re trying to retrieve the host name from the network interfaces.</p><p>If you have the discovery client enabled and prefer to retrieve the host address from the registered
|
||||
instance in a service registry then you have to set the property (it’s applicable for both HTTP and
|
||||
Stream based span reporting).</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.zipkin.locator.discovery.enabled</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">true</span></pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__managing_spans_with_annotations.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__sending_spans_to_zipkin.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">57. Managing spans with annotations </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 59. Sending spans to Zipkin</td></tr></table></div></body></html>
|
||||
17
Finchley.M8/multi/multi__customizing_the_message_broker.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>44. Customizing the Message Broker</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_bus.html" title="Part VII. Spring Cloud Bus"><link rel="prev" href="multi__service_id_must_be_unique.html" title="43. Service ID must be unique"><link rel="next" href="multi__tracing_bus_events.html" title="45. Tracing Bus Events"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">44. Customizing the Message Broker</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__service_id_must_be_unique.html">Prev</a> </td><th width="60%" align="center">Part VII. Spring Cloud Bus</th><td width="20%" align="right"> <a accesskey="n" href="multi__tracing_bus_events.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_customizing_the_message_broker" href="#_customizing_the_message_broker"></a>44. Customizing the Message Broker</h2></div></div></div><p>Spring Cloud Bus uses
|
||||
<a class="link" href="https://cloud.spring.io/spring-cloud-stream" target="_top">Spring Cloud Stream</a> to
|
||||
broadcast the messages so to get messages to flow you only need to
|
||||
include the binder implementation of your choice in the
|
||||
classpath. There are convenient starters specifically for the bus with
|
||||
AMQP (RabbitMQ) and Kafka
|
||||
(<code class="literal">spring-cloud-starter-bus-[amqp,kafka]</code>). Generally speaking
|
||||
Spring Cloud Stream relies on Spring Boot autoconfiguration
|
||||
conventions for configuring middleware, so for instance the AMQP
|
||||
broker address can be changed with <code class="literal">spring.rabbitmq.*</code>
|
||||
configuration properties. Spring Cloud Bus has a handful of native
|
||||
configuration properties in <code class="literal">spring.cloud.bus.*</code>
|
||||
(e.g. <code class="literal">spring.cloud.bus.destination</code> is the name of the topic to use
|
||||
the the externall middleware). Normally the defaults will suffice.</p><p>To lean more about how to customize the message broker settings
|
||||
consult the Spring Cloud Stream documentation.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__service_id_must_be_unique.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_bus.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__tracing_bus_events.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">43. Service ID must be unique </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 45. Tracing Bus Events</td></tr></table></div></body></html>
|
||||
3
Finchley.M8/multi/multi__developer_guide.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>114. Developer Guide</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_gateway.html" title="Part XV. Spring Cloud Gateway"><link rel="prev" href="multi__actuator_api.html" title="113. Actuator API"><link rel="next" href="multi__building_a_simple_gateway_using_spring_mvc.html" title="115. Building a Simple Gateway Using Spring MVC"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">114. Developer Guide</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__actuator_api.html">Prev</a> </td><th width="60%" align="center">Part XV. Spring Cloud Gateway</th><td width="20%" align="right"> <a accesskey="n" href="multi__building_a_simple_gateway_using_spring_mvc.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_developer_guide" href="#_developer_guide"></a>114. Developer Guide</h2></div></div></div><p>TODO: overview of writing custom integrations</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_writing_custom_route_predicate_factories" href="#_writing_custom_route_predicate_factories"></a>114.1 Writing Custom Route Predicate Factories</h2></div></div></div><p>TODO: document writing Custom Route Predicate Factories</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_writing_custom_gatewayfilter_factories" href="#_writing_custom_gatewayfilter_factories"></a>114.2 Writing Custom GatewayFilter Factories</h2></div></div></div><p>TODO: document writing Custom GatewayFilter Factories</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_writing_custom_global_filters" href="#_writing_custom_global_filters"></a>114.3 Writing Custom Global Filters</h2></div></div></div><p>TODO: document writing Custom Global Filters</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_writing_custom_route_locators_and_writers" href="#_writing_custom_route_locators_and_writers"></a>114.4 Writing Custom Route Locators and Writers</h2></div></div></div><p>TODO: document writing Custom Route Locators and Writers</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__actuator_api.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_gateway.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__building_a_simple_gateway_using_spring_mvc.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">113. Actuator API </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 115. Building a Simple Gateway Using Spring MVC</td></tr></table></div></body></html>
|
||||
22
Finchley.M8/multi/multi__discovery.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>81. Discovery</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_for_cloud_foundry.html" title="Part XII. Spring Cloud for Cloud Foundry"><link rel="prev" href="multi__spring_cloud_for_cloud_foundry.html" title="Part XII. Spring Cloud for Cloud Foundry"><link rel="next" href="multi__single_sign_on_2.html" title="82. Single Sign On"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">81. Discovery</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_for_cloud_foundry.html">Prev</a> </td><th width="60%" align="center">Part XII. Spring Cloud for Cloud Foundry</th><td width="20%" align="right"> <a accesskey="n" href="multi__single_sign_on_2.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_discovery" href="#_discovery"></a>81. Discovery</h2></div></div></div><p>Here’s a Spring Cloud app with Cloud Foundry discovery:</p><p><b>app.groovy. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Grab('org.springframework.cloud:spring-cloud-cloudfoundry')</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@RestController</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableDiscoveryClient</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
DiscoveryClient client
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestMapping('/')</span></em>
|
||||
String home() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'Hello from '</span> + client.getLocalServiceInstance()
|
||||
}
|
||||
|
||||
}</pre><p>
|
||||
</p><p>If you run it without any service bindings:</p><pre class="screen">$ spring jar app.jar app.groovy
|
||||
$ cf push -p app.jar</pre><p>It will show its app name in the home page.</p><p>The <code class="literal">DiscoveryClient</code> can lists all the apps in a space, according to
|
||||
the credentials it is authenticated with, where the space defaults to
|
||||
the one the client is running in (if any). If neither org nor space
|
||||
are configured, they default per the user’s profile in Cloud Foundry.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_for_cloud_foundry.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_for_cloud_foundry.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__single_sign_on_2.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part XII. Spring Cloud for Cloud Foundry </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 82. Single Sign On</td></tr></table></div></body></html>
|
||||
21
Finchley.M8/multi/multi__embedding_the_config_server.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>8. Embedding the Config Server</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_config.html" title="Part II. Spring Cloud Config"><link rel="prev" href="multi__serving_plain_text.html" title="7. Serving Plain Text"><link rel="next" href="multi__push_notifications_and_spring_cloud_bus.html" title="9. Push Notifications and Spring Cloud Bus"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8. Embedding the Config Server</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__serving_plain_text.html">Prev</a> </td><th width="60%" align="center">Part II. Spring Cloud Config</th><td width="20%" align="right"> <a accesskey="n" href="multi__push_notifications_and_spring_cloud_bus.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_embedding_the_config_server" href="#_embedding_the_config_server"></a>8. Embedding the Config Server</h2></div></div></div><p>The Config Server runs best as a standalone application, but if you
|
||||
need to you can embed it in another application. Just use the
|
||||
<code class="literal">@EnableConfigServer</code> annotation. An optional property that can be
|
||||
useful in this case is <code class="literal">spring.cloud.config.server.bootstrap</code> which is
|
||||
a flag to indicate that the server should configure itself from its
|
||||
own remote repository. The flag is off by default because it can delay
|
||||
startup, but when embedded in another application it makes sense to
|
||||
initialize the same way as any other application.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>It should be obvious, but remember that if you use the bootstrap
|
||||
flag the config server will need to have its name and repository URI
|
||||
configured in <code class="literal">bootstrap.yml</code>.</p></td></tr></table></div><p>To change the location of the server endpoints you can (optionally)
|
||||
set <code class="literal">spring.cloud.config.server.prefix</code>, e.g. "/config", to serve the
|
||||
resources under a prefix. The prefix should start but not end with a
|
||||
"/". It is applied to the <code class="literal">@RequestMappings</code> in the Config Server
|
||||
(i.e. underneath the Spring Boot prefixes <code class="literal">server.servletPath</code> and
|
||||
<code class="literal">server.contextPath</code>).</p><p>If you want to read the configuration for an application directly from
|
||||
the backend repository (instead of from the config server) that’s
|
||||
basically an embedded config server with no endpoints. You can switch
|
||||
off the endpoints entirely if you don’t use the <code class="literal">@EnableConfigServer</code>
|
||||
annotation (just set <code class="literal">spring.cloud.config.server.bootstrap=true</code>).</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__serving_plain_text.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_config.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__push_notifications_and_spring_cloud_bus.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">7. Serving Plain Text </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 9. Push Notifications and Spring Cloud Bus</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>17. External Configuration: Archaius</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_netflix.html" title="Part III. Spring Cloud Netflix"><link rel="prev" href="multi_spring-cloud-ribbon.html" title="16. Client Side Load Balancer: Ribbon"><link rel="next" href="multi__router_and_filter_zuul.html" title="18. Router and Filter: Zuul"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">17. External Configuration: Archaius</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_spring-cloud-ribbon.html">Prev</a> </td><th width="60%" align="center">Part III. Spring Cloud Netflix</th><td width="20%" align="right"> <a accesskey="n" href="multi__router_and_filter_zuul.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_external_configuration_archaius" href="#_external_configuration_archaius"></a>17. External Configuration: Archaius</h2></div></div></div><p><a class="link" href="https://github.com/Netflix/archaius" target="_top">Archaius</a> is the Netflix client side configuration library. It is the library used by all of the Netflix OSS components for configuration. Archaius is an extension of the <a class="link" href="http://commons.apache.org/proper/commons-configuration" target="_top">Apache Commons Configuration</a> project. It allows updates to configuration by either polling a source for changes or for a source to push changes to the client. Archaius uses Dynamic<Type>Property classes as handles to properties.</p><p><b>Archaius Example. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> ArchaiusTest {
|
||||
DynamicStringProperty myprop = DynamicPropertyFactory
|
||||
.getInstance()
|
||||
.getStringProperty(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"my.prop"</span>);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> doSomething() {
|
||||
OtherClass.someMethod(myprop.get());
|
||||
}
|
||||
}</pre><p>
|
||||
</p><p>Archaius has its own set of configuration files and loading priorities. Spring applications should generally not use Archaius directly, but the need to configure the Netflix tools natively remains. Spring Cloud has a Spring Environment Bridge so Archaius can read properties from the Spring Environment. This allows Spring Boot projects to use the normal configuration toolchain, while allowing them to configure the Netflix tools, for the most part, as documented.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_spring-cloud-ribbon.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_netflix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__router_and_filter_zuul.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">16. Client Side Load Balancer: Ribbon </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 18. Router and Filter: Zuul</td></tr></table></div></body></html>
|
||||
4
Finchley.M8/multi/multi__features.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>1. Features</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="prev" href="multi_pr01.html" title=""><link rel="next" href="multi__cloud_native_applications.html" title="Part I. Cloud Native Applications"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">1. Features</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_pr01.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__cloud_native_applications.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_features" href="#_features"></a>1. Features</h1></div></div></div><p>Spring Cloud focuses on providing good out of box experience for typical use cases
|
||||
and extensibility mechanism to cover others.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Distributed/versioned configuration</li><li class="listitem">Service registration and discovery</li><li class="listitem">Routing</li><li class="listitem">Service-to-service calls</li><li class="listitem">Load balancing</li><li class="listitem">Circuit Breakers</li><li class="listitem">Distributed messaging</li></ul></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_pr01.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__cloud_native_applications.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top"> </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part I. Cloud Native Applications</td></tr></table></div></body></html>
|
||||
126
Finchley.M8/multi/multi__features_2.html
Normal file
@@ -0,0 +1,126 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>49. Features</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__additional_resources.html" title="48. Additional resources"><link rel="next" href="multi__sampling.html" title="50. Sampling"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">49. Features</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__additional_resources.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__sampling.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_features_2" href="#_features_2"></a>49. Features</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p class="simpara">Adds trace and span ids to the Slf4J MDC, so you can extract all the logs from a given trace or span in a log aggregator. Example logs:</p><pre class="screen">2016-02-02 15:30:57.902 INFO [bar,6bfd228dc00d216b,6bfd228dc00d216b,false] 23030 --- [nio-8081-exec-3] ...
|
||||
2016-02-02 15:30:58.372 ERROR [bar,6bfd228dc00d216b,6bfd228dc00d216b,false] 23030 --- [nio-8081-exec-3] ...
|
||||
2016-02-02 15:31:01.936 INFO [bar,46ab0d418373cbc9,46ab0d418373cbc9,false] 23030 --- [nio-8081-exec-4] ...</pre><p class="simpara">notice the <code class="literal">[appname,traceId,spanId,exportable]</code> entries from the MDC:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem"><span class="strong"><strong>spanId</strong></span> - the id of a specific operation that took place</li><li class="listitem"><span class="strong"><strong>appname</strong></span> - the name of the application that logged the span</li><li class="listitem"><span class="strong"><strong>traceId</strong></span> - the id of the latency graph that contains the span</li><li class="listitem"><span class="strong"><strong>exportable</strong></span> - whether the log should be exported to Zipkin or not. When would you like the span not to be
|
||||
exportable? In the case in which you want to wrap some operation in a Span and have it written to the logs
|
||||
only.</li></ul></div></li><li class="listitem">Provides an abstraction over common distributed tracing data models: traces, spans (forming a DAG), annotations,
|
||||
key-value annotations. Loosely based on HTrace, but Zipkin (Dapper) compatible.</li><li class="listitem"><p class="simpara">Sleuth records timing information to aid in latency analysis. Using sleuth, you can pinpoint causes of
|
||||
latency in your applications. Sleuth is written to not log too much, and to not cause your production application to crash.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem">propagates structural data about your call-graph in-band, and the rest out-of-band.</li><li class="listitem">includes opinionated instrumentation of layers such as HTTP</li><li class="listitem">includes sampling policy to manage volume</li><li class="listitem">can report to a Zipkin system for query and visualization</li></ul></div></li><li class="listitem">Instruments common ingress and egress points from Spring applications (servlet filter, async endpoints,
|
||||
rest template, scheduled actions, message channels, zuul filters, feign client).</li><li class="listitem">Sleuth includes default logic to join a trace across http or messaging boundaries. For example, http propagation
|
||||
works via Zipkin-compatible request headers. This propagation logic is defined and customized via
|
||||
<code class="literal">SpanInjector</code> and <code class="literal">SpanExtractor</code> implementations.</li><li class="listitem">Sleuth gives you the possibility to propagate context (also known as baggage) between processes. That means that if you set on a Span
|
||||
a baggage element then it will be sent downstream either via HTTP or messaging to other processes.</li><li class="listitem">Provides a way to create / continue spans and add tags and logs via annotations.</li><li class="listitem"><p class="simpara">If <code class="literal">spring-cloud-sleuth-zipkin</code> is on the classpath then the app will generate and collect Zipkin-compatible traces.
|
||||
By default it sends them via HTTP to a Zipkin server on localhost (port 9411).
|
||||
Configure the location of the service using <code class="literal">spring.zipkin.baseUrl</code>.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem">If you depend on <code class="literal">spring-rabbit</code> or <code class="literal">spring-kafka</code> your app will send traces to a broker instead of http.</li><li class="listitem">Note: <code class="literal">spring-cloud-sleuth-stream</code> is deprecated and should no longer be used.</li></ul></div></li><li class="listitem">Spring Cloud Sleuth is <a class="link" href="http://opentracing.io/" target="_top">OpenTracing</a> compatible</li></ul></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>If using Zipkin, configure the percentage of spans exported using <code class="literal">spring.sleuth.sampler.percentage</code>
|
||||
(default 0.1, i.e. 10%). <span class="strong"><strong>Otherwise you might think that Sleuth is not working cause it’s omitting some spans.</strong></span></p></td></tr></table></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>the SLF4J MDC is always set and logback users will immediately see the trace and span ids in logs per the example
|
||||
above. Other logging systems have to configure their own formatter to get the same result. The default is
|
||||
<code class="literal">logging.pattern.level</code> set to <code class="literal">%5p [${spring.zipkin.service.name:${spring.application.name:-}},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]</code>
|
||||
(this is a Spring Boot feature for logback users).
|
||||
<span class="strong"><strong>This means that if you’re not using SLF4J this pattern WILL NOT be automatically applied</strong></span>.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_introduction_to_brave" href="#_introduction_to_brave"></a>49.1 Introduction to Brave</h2></div></div></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Starting with version <code class="literal">2.0.0</code> Spring Cloud Sleuth uses
|
||||
<a class="link" href="https://github.com/openzipkin/brave" target="_top">Brave</a> as the tracing library.
|
||||
For your convenience we’re embedding part of the Brave’s docs here.</p></td></tr></table></div><p>Brave is a library used to capture and report latency information about
|
||||
distributed operations to Zipkin. Most users won’t use Brave directly,
|
||||
rather libraries or frameworks than employ Brave on their behalf.</p><p>This module includes tracer creates and joins spans that model the
|
||||
latency of potentially distributed work. It also includes libraries to
|
||||
propagate the trace context over network boundaries, for example, via
|
||||
http headers.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_tracing" href="#_tracing"></a>49.1.1 Tracing</h3></div></div></div><p>Most importantly, you need a <code class="literal">brave.Tracer</code>, configured to [report to Zipkin]
|
||||
(<a class="link" href="https://github.com/openzipkin/zipkin-reporter-java" target="_top">https://github.com/openzipkin/zipkin-reporter-java</a>).</p><p>Here’s an example setup that sends trace data (spans) to Zipkin over
|
||||
http (as opposed to Kafka).</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyClass {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> Tracer tracer;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Tracer will be autowired</span>
|
||||
MyClass(Tracer tracer) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracer = tracer;
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> doSth() {
|
||||
Span span = tracer.newTrace().name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>).start();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// ...</span>
|
||||
}
|
||||
}</pre><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>If your span contains a name greater than 50 chars, then that name will
|
||||
be truncated to 50 chars. Your names have to be explicit and concrete. Big names lead to
|
||||
latency issues and sometimes even thrown exceptions.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_tracing_2" href="#_tracing_2"></a>49.1.2 Tracing</h3></div></div></div><p>The tracer creates and joins spans that model the latency of potentially
|
||||
distributed work. It can employ sampling to reduce overhead in process
|
||||
or to reduce the amount of data sent to Zipkin.</p><p>Spans returned by a tracer report data to Zipkin when finished, or do
|
||||
nothing if unsampled. After starting a span, you can annotate events of
|
||||
interest or add tags containing details or lookup keys.</p><p>Spans have a context which includes trace identifiers that place it at
|
||||
the correct spot in the tree representing the distributed operation.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_local_tracing" href="#_local_tracing"></a>49.1.3 Local Tracing</h3></div></div></div><p>When tracing local code, just run it inside a span.</p><pre class="programlisting">Span span = tracer.newTrace().name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>).start();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> {
|
||||
doSomethingExpensive();
|
||||
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">finally</span> {
|
||||
span.finish();
|
||||
}</pre><p>In the above example, the span is the root of the trace. In many cases,
|
||||
you will be a part of an existing trace. When this is the case, call
|
||||
<code class="literal">newChild</code> instead of <code class="literal">newTrace</code></p><pre class="programlisting">Span span = tracer.newChild(root.context()).name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>).start();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> {
|
||||
doSomethingExpensive();
|
||||
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">finally</span> {
|
||||
span.finish();
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_customizing_spans" href="#_customizing_spans"></a>49.1.4 Customizing spans</h3></div></div></div><p>Once you have a span, you can add tags to it, which can be used as lookup
|
||||
keys or details. For example, you might add a tag with your runtime
|
||||
version.</p><pre class="programlisting">span.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"clnt/finagle.version"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"6.36.0"</span>);</pre><p>When exposing the ability to customize spans to third parties, prefer
|
||||
<code class="literal">brave.SpanCustomizer</code> as opposed to <code class="literal">brave.Span</code>. The former is simpler to
|
||||
understand and test, and doesn’t tempt users with span lifecycle hooks.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> MyTraceCallback {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> request(Request request, SpanCustomizer customizer);
|
||||
}</pre><p>Since <code class="literal">brave.Span</code> implements <code class="literal">brave.SpanCustomizer</code>, it is just as easy for you
|
||||
to pass to users.</p><p>Ex.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">for</span> (MyTraceCallback callback : userCallbacks) {
|
||||
callback.request(request, span);
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_implicitly_looking_up_the_current_span" href="#_implicitly_looking_up_the_current_span"></a>49.1.5 Implicitly looking up the current span</h3></div></div></div><p>Sometimes you won’t know if a trace is in progress or not, and you don’t
|
||||
want users to do null checks. <code class="literal">brave.CurrentSpanCustomizer</code> adds to any
|
||||
span that’s in progress or drops data accordingly.</p><p>Ex.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// user code can then inject this without a chance of it being null.</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowire</span></em> SpanCustomizer span;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> userCode() {
|
||||
span.annotate(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tx.started"</span>);
|
||||
...
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_rpc_tracing" href="#_rpc_tracing"></a>49.1.6 RPC tracing</h3></div></div></div><p>Check for <a class="link" href="https://github.com/openzipkin/sleuth/tree/master/instrumentation" target="_top">instrumentation written here</a>
|
||||
and <a class="link" href="http://zipkin.io/pages/existing_instrumentations.html" target="_top">Zipkin’s list</a>
|
||||
before rolling your own RPC instrumentation!</p><p>RPC tracing is often done automatically by interceptors. Under the scenes,
|
||||
they add tags and events that relate to their role in an RPC operation.</p><p>Here’s an example of a client span:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// before you send a request, add metadata that describes the operation</span>
|
||||
span = tracer.newTrace().name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"get"</span>).type(CLIENT);
|
||||
span.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"clnt/finagle.version"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"6.36.0"</span>);
|
||||
span.tag(TraceKeys.HTTP_PATH, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/api"</span>);
|
||||
span.remoteEndpoint(Endpoint.builder()
|
||||
.serviceName(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"backend"</span>)
|
||||
.ipv4(<span class="hl-number">127</span> << <span class="hl-number">24</span> | <span class="hl-number">1</span>)
|
||||
.port(<span class="hl-number">8080</span>).build());
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when the request is scheduled, start the span</span>
|
||||
span.start();
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// if you have callbacks for when data is on the wire, note those events</span>
|
||||
span.annotate(Constants.WIRE_SEND);
|
||||
span.annotate(Constants.WIRE_RECV);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when the response is complete, finish the span</span>
|
||||
span.finish();</pre><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_one_way_tracing" href="#_one_way_tracing"></a>One-Way tracing</h4></div></div></div><p>Sometimes you need to model an asynchronous operation, where there is a
|
||||
request, but no response. In normal RPC tracing, you use <code class="literal">span.finish()</code>
|
||||
which indicates the response was received. In one-way tracing, you use
|
||||
<code class="literal">span.flush()</code> instead, as you don’t expect a response.</p><p>Here’s how a client might model a one-way operation</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// start a new span representing a client request</span>
|
||||
oneWaySend = tracer.newSpan(parent).kind(Span.Kind.CLIENT);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Add the trace context to the request, so it can be propagated in-band</span>
|
||||
tracing.propagation().injector(Request::addHeader)
|
||||
.inject(oneWaySend.context(), request);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// fire off the request asynchronously, totally dropping any response</span>
|
||||
request.execute();
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// start the client side and flush instead of finish</span>
|
||||
oneWaySend.start().flush();</pre><p>And here’s how a server might handle this..</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// pull the context out of the incoming request</span>
|
||||
extractor = tracing.propagation().extractor(Request::getHeader);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// convert that context to a span which you can name and add tags to</span>
|
||||
oneWayReceive = nextSpan(tracer, extractor.extract(request))
|
||||
.name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"process-request"</span>)
|
||||
.kind(SERVER)
|
||||
... add tags etc.
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// start the server side and flush instead of finish</span>
|
||||
oneWayReceive.start().flush();
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// you should not modify this span anymore as it is complete. However,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// you can create children to represent follow-up work.</span>
|
||||
next = tracer.newSpan(oneWayReceive.context()).name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"step2"</span>).start();</pre><p><span class="strong"><strong>Note</strong></span> The above propagation logic is a simplified version of our [http handlers](<a class="link" href="https://github.com/openzipkin/sleuth/tree/master/instrumentation/http#http-server" target="_top">https://github.com/openzipkin/sleuth/tree/master/instrumentation/http#http-server</a>).</p><p>There’s a working example of a one-way span [here](src/test/java/sleuth/features/async/OneWaySpanTest.java).</p></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__additional_resources.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__sampling.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">48. Additional resources </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 50. Sampling</td></tr></table></div></body></html>
|
||||
55
Finchley.M8/multi/multi__getting_started.html
Normal file
@@ -0,0 +1,55 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>36. Getting Started</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="prev" href="multi__samples.html" title="35. Samples"><link rel="next" href="multi__binder_implementations.html" title="Part VI. Binder Implementations"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">36. Getting Started</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__samples.html">Prev</a> </td><th width="60%" align="center">Part V. Spring Cloud Stream</th><td width="20%" align="right"> <a accesskey="n" href="multi__binder_implementations.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_getting_started" href="#_getting_started"></a>36. Getting Started</h2></div></div></div><p>To get started with creating Spring Cloud Stream applications, visit the <a class="link" href="https://start.spring.io" target="_top">Spring Initializr</a> and create a new Maven project named "GreetingSource".
|
||||
Select Spring Boot {supported-spring-boot-version} in the dropdown.
|
||||
In the <span class="emphasis"><em>Search for dependencies</em></span> text box type <code class="literal">Stream Rabbit</code> or <code class="literal">Stream Kafka</code> depending on what binder you want to use.</p><p>Next, create a new class, <code class="literal">GreetingSource</code>, in the same package as the <code class="literal">GreetingSourceApplication</code> class.
|
||||
Give it the following code:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.stream.messaging.Source;
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.integration.annotation.InboundChannelAdapter;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Source.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> GreetingSource {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@InboundChannelAdapter(Source.OUTPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String greet() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"hello world "</span> + System.currentTimeMillis();
|
||||
}
|
||||
}</pre><p>The <code class="literal">@EnableBinding</code> annotation is what triggers the creation of Spring Integration infrastructure components.
|
||||
Specifically, it will create a Kafka connection factory, a Kafka outbound channel adapter, and the message channel defined inside the Source interface:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> Source {
|
||||
|
||||
String OUTPUT = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"output"</span>;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Output(Source.OUTPUT)</span></em>
|
||||
MessageChannel output();
|
||||
|
||||
}</pre><p>The auto-configuration also creates a default poller, so that the <code class="literal">greet()</code> method will be invoked once per second.
|
||||
The standard Spring Integration <code class="literal">@InboundChannelAdapter</code> annotation sends a message to the source’s output channel, using the return value as the payload of the message.</p><p>To test-drive this setup, run a Kafka message broker.
|
||||
An easy way to do this is to use a Docker image:</p><pre class="screen"># On OS X
|
||||
$ docker run -p 2181:2181 -p 9092:9092 --env ADVERTISED_HOST=`docker-machine ip \`docker-machine active\`` --env ADVERTISED_PORT=9092 spotify/kafka
|
||||
|
||||
# On Linux
|
||||
$ docker run -p 2181:2181 -p 9092:9092 --env ADVERTISED_HOST=localhost --env ADVERTISED_PORT=9092 spotify/kafka</pre><p>Build the application:</p><pre class="screen">./mvnw clean package</pre><p>The consumer application is coded in a similar manner.
|
||||
Go back to Initializr and create another project, named LoggingSink.
|
||||
Then create a new class, <code class="literal">LoggingSink</code>, in the same package as the class <code class="literal">LoggingSinkApplication</code> and with the following code:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.stream.annotation.StreamListener;
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.stream.messaging.Sink;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Sink.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> LoggingSink {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Sink.INPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> log(String message) {
|
||||
System.out.println(message);
|
||||
}
|
||||
}</pre><p>Build the application:</p><pre class="screen">./mvnw clean package</pre><p>To connect the GreetingSource application to the LoggingSink application, each application must share the same destination name.
|
||||
Starting up both applications as shown below, you will see the consumer application printing "hello world" and a timestamp to the console:</p><pre class="screen">cd GreetingSource
|
||||
java -jar target/GreetingSource-0.0.1-SNAPSHOT.jar --spring.cloud.stream.bindings.output.destination=mydest
|
||||
|
||||
cd LoggingSink
|
||||
java -jar target/LoggingSink-0.0.1-SNAPSHOT.jar --server.port=8090 --spring.cloud.stream.bindings.input.destination=mydest</pre><p>(The different server port prevents collisions of the HTTP port used to service the Spring Boot Actuator endpoints in the two applications.)</p><p>The output of the LoggingSink application will look something like the following:</p><pre class="screen">[ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8090 (http)
|
||||
[ main] com.example.LoggingSinkApplication : Started LoggingSinkApplication in 6.828 seconds (JVM running for 7.371)
|
||||
hello world 1458595076731
|
||||
hello world 1458595077732
|
||||
hello world 1458595078733
|
||||
hello world 1458595079734
|
||||
hello world 1458595080735</pre><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_deploying_stream_applications_on_cloudfoundry" href="#_deploying_stream_applications_on_cloudfoundry"></a>36.1 Deploying Stream applications on CloudFoundry</h2></div></div></div><p>On CloudFoundry services are usually exposed via a special environment variable called <a class="link" href="https://docs.cloudfoundry.org/devguide/deploy-apps/environment-variable.html#VCAP-SERVICES" target="_top">VCAP_SERVICES</a>.</p><p>When configuring your binder connections, you can use the values from an environment variable as explained on the <a class="link" href="http://docs.spring.io/spring-cloud-dataflow-server-cloudfoundry/docs/current-SNAPSHOT/reference/htmlsingle/#getting-started-ups" target="_top">dataflow cloudfoundry server</a> docs.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__samples.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_stream.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__binder_implementations.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">35. Samples </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part VI. Binder Implementations</td></tr></table></div></body></html>
|
||||
3
Finchley.M8/multi/multi__global_filters.html
Normal file
3
Finchley.M8/multi/multi__glossary.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>107. Glossary</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_gateway.html" title="Part XV. Spring Cloud Gateway"><link rel="prev" href="multi_gateway-starter.html" title="106. How to Include Spring Cloud Gateway"><link rel="next" href="multi_gateway-how-it-works.html" title="108. How It Works"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">107. Glossary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_gateway-starter.html">Prev</a> </td><th width="60%" align="center">Part XV. Spring Cloud Gateway</th><td width="20%" align="right"> <a accesskey="n" href="multi_gateway-how-it-works.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_glossary" href="#_glossary"></a>107. Glossary</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><span class="strong"><strong>Route</strong></span>: Route the basic building block of the gateway. It is defined by an ID, a destination URI, a collection of predicates and a collection of filters. A route is matched if aggregate predicate is true.</li><li class="listitem"><span class="strong"><strong>Predicate</strong></span>: This is a <a class="link" href="http://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html" target="_top">Java 8 Function Predicate</a>. The input type is a <a class="link" href="http://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/server/ServerWebExchange.html" target="_top">Spring Framework <code class="literal">ServerWebExchange</code></a>. This allows developers to match on anything from the HTTP request, such as headers or parameters.</li><li class="listitem"><span class="strong"><strong>Filter</strong></span>: These are instances <a class="link" href="http://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/server/GatewayFilter.html" target="_top">Spring Framework <code class="literal">GatewayFilter</code></a> constructed in with a specific factory. Here, requests and responses can be modified before or after sending the downstream request.</li></ul></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_gateway-starter.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_gateway.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_gateway-how-it-works.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">106. How to Include Spring Cloud Gateway </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 108. How It Works</td></tr></table></div></body></html>
|
||||
4
Finchley.M8/multi/multi__health_indicator_5.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>33. Health Indicator</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="prev" href="multi__testing.html" title="32. Testing"><link rel="next" href="multi__metrics_emitter.html" title="34. Metrics Emitter"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">33. Health Indicator</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__testing.html">Prev</a> </td><th width="60%" align="center">Part V. Spring Cloud Stream</th><td width="20%" align="right"> <a accesskey="n" href="multi__metrics_emitter.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_health_indicator_5" href="#_health_indicator_5"></a>33. Health Indicator</h2></div></div></div><p>Spring Cloud Stream provides a health indicator for binders.
|
||||
It is registered under the name of <code class="literal">binders</code> and can be enabled or disabled by setting the <code class="literal">management.health.binders.enabled</code> property.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__testing.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_stream.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__metrics_emitter.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">32. Testing </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 34. Metrics Emitter</td></tr></table></div></body></html>
|
||||
8
Finchley.M8/multi/multi__http_clients.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>22. HTTP Clients</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_netflix.html" title="Part III. Spring Cloud Netflix"><link rel="prev" href="multi_retrying-failed-requests.html" title="21. Retrying Failed Requests"><link rel="next" href="multi__spring_cloud_openfeign.html" title="Part IV. Spring Cloud OpenFeign"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">22. HTTP Clients</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_retrying-failed-requests.html">Prev</a> </td><th width="60%" align="center">Part III. Spring Cloud Netflix</th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_openfeign.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_http_clients" href="#_http_clients"></a>22. HTTP Clients</h2></div></div></div><p>Spring Cloud Netflix will automatically create the HTTP client used by Ribbon, Feign, and
|
||||
Zuul for you. However you can also provide your own HTTP clients customized how you please
|
||||
yourself. To do this you can either create a bean of type <code class="literal">ClosableHttpClient</code> if you
|
||||
are using the Apache Http Cient, or <code class="literal">OkHttpClient</code> if you are using OK HTTP.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>When you create your own HTTP client you are also responsible for implementing
|
||||
the correct connection management strategies for these clients. Doing this improperly
|
||||
can result in resource management issues.</p></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_retrying-failed-requests.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_netflix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_openfeign.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">21. Retrying Failed Requests </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part IV. Spring Cloud OpenFeign</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,26 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>15. Hystrix Timeouts And Ribbon Clients</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_netflix.html" title="Part III. Spring Cloud Netflix"><link rel="prev" href="multi__circuit_breaker_hystrix_dashboard.html" title="14. Circuit Breaker: Hystrix Dashboard"><link rel="next" href="multi_spring-cloud-ribbon.html" title="16. Client Side Load Balancer: Ribbon"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">15. Hystrix Timeouts And Ribbon Clients</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__circuit_breaker_hystrix_dashboard.html">Prev</a> </td><th width="60%" align="center">Part III. Spring Cloud Netflix</th><td width="20%" align="right"> <a accesskey="n" href="multi_spring-cloud-ribbon.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_hystrix_timeouts_and_ribbon_clients" href="#_hystrix_timeouts_and_ribbon_clients"></a>15. Hystrix Timeouts And Ribbon Clients</h2></div></div></div><p>When using Hystrix commands that wrap Ribbon clients you want to make sure your Hystrix timeout
|
||||
is configured to be longer than the configured Ribbon timeout, including any potential
|
||||
retries that might be made. For example, if your Ribbon connection timeout is one second and
|
||||
the Ribbon client might retry the request three times, than your Hystrix timeout should
|
||||
be slightly more than three seconds.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="netflix-hystrix-dashboard-starter" href="#netflix-hystrix-dashboard-starter"></a>15.1 How to Include Hystrix Dashboard</h2></div></div></div><p>To include the Hystrix Dashboard in your project use the starter with group <code class="literal">org.springframework.cloud</code>
|
||||
and artifact id <code class="literal">spring-cloud-starter-netflix-hystrix-dashboard</code>. See the <a class="link" href="http://projects.spring.io/spring-cloud/" target="_top">Spring Cloud Project page</a>
|
||||
for details on setting up your build system with the current Spring Cloud Release Train.</p><p>To run the Hystrix Dashboard annotate your Spring Boot main class with <code class="literal">@EnableHystrixDashboard</code>. You then visit <code class="literal">/hystrix</code> and point the dashboard to an individual instances <code class="literal">/hystrix.stream</code> endpoint in a Hystrix client application.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>When connecting to a <code class="literal">/hystrix.stream</code> endpoint which uses HTTPS the certificate used by the server
|
||||
must be trusted by the JVM. If the certificate is not trusted you must import the certificate into the JVM
|
||||
in order for the Hystrix Dashboard to make a successful connection to the stream endpoint.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_turbine" href="#_turbine"></a>15.2 Turbine</h2></div></div></div><p>Looking at an individual instances Hystrix data is not very useful in terms of the overall health of the system. <a class="link" href="https://github.com/Netflix/Turbine" target="_top">Turbine</a> is an application that aggregates all of the relevant <code class="literal">/hystrix.stream</code> endpoints into a combined <code class="literal">/turbine.stream</code> for use in the Hystrix Dashboard. Individual instances are located via Eureka. Running Turbine is as simple as annotating your main class with the <code class="literal">@EnableTurbine</code> annotation (e.g. using spring-cloud-starter-netflix-turbine to set up the classpath). All of the documented configuration properties from <a class="link" href="https://github.com/Netflix/Turbine/wiki/Configuration-(1.x)" target="_top">the Turbine 1 wiki</a> apply. The only difference is that the <code class="literal">turbine.instanceUrlSuffix</code> does not need the port prepended as this is handled automatically unless <code class="literal">turbine.instanceInsertPort=false</code>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>By default, Turbine looks for the <code class="literal">/hystrix.stream</code> endpoint on a registered instance by looking up its <code class="literal">hostName</code> and <code class="literal">port</code> entries in Eureka, then appending <code class="literal">/hystrix.stream</code> to it.
|
||||
If the instance’s metadata contains <code class="literal">management.port</code>, it will be used instead of the <code class="literal">port</code> value for the <code class="literal">/hystrix.stream</code> endpoint.
|
||||
By default, metadata entry <code class="literal">management.port</code> is equal to the <code class="literal">management.port</code> configuration property, it can be overridden though with following configuration:</p></td></tr></table></div><pre class="screen">eureka:
|
||||
instance:
|
||||
metadata-map:
|
||||
management.port: ${management.port:8081}</pre><p>The configuration key <code class="literal">turbine.appConfig</code> is a list of eureka serviceIds that turbine will use to lookup instances. The turbine stream is then used in the Hystrix dashboard using a url that looks like: <code class="literal"><a class="link" href="http://my.turbine.server:8080/turbine.stream?cluster=CLUSTERNAME" target="_top">http://my.turbine.server:8080/turbine.stream?cluster=CLUSTERNAME</a></code> (the cluster parameter can be omitted if the name is "default"). The <code class="literal">cluster</code> parameter must match an entry in <code class="literal">turbine.aggregator.clusterConfig</code>. Values returned from eureka are uppercase, thus we expect this example to work if there is an app registered with Eureka called "customers":</p><pre class="screen">turbine:
|
||||
aggregator:
|
||||
clusterConfig: CUSTOMERS
|
||||
appConfig: customers</pre><p>If you need to customize which cluster names should be used by Turbine (you don’t want to store cluster names in
|
||||
<code class="literal">turbine.aggregator.clusterConfig</code> configuration) provide a bean of type <code class="literal">TurbineClustersProvider</code>.</p><p>The <code class="literal">clusterName</code> can be customized by a SPEL expression in <code class="literal">turbine.clusterNameExpression</code> with root an instance of <code class="literal">InstanceInfo</code>. The default value is <code class="literal">appName</code>, which means that the Eureka serviceId ends up as the cluster key (i.e. the <code class="literal">InstanceInfo</code> for customers has an <code class="literal">appName</code> of "CUSTOMERS"). A different example would be <code class="literal">turbine.clusterNameExpression=aSGName</code>, which would get the cluster name from the AWS ASG name. Another example:</p><pre class="screen">turbine:
|
||||
aggregator:
|
||||
clusterConfig: SYSTEM,USER
|
||||
appConfig: customers,stores,ui,admin
|
||||
clusterNameExpression: metadata['cluster']</pre><p>In this case, the cluster name from 4 services is pulled from their metadata map, and is expected to have values that include "SYSTEM" and "USER".</p><p>To use the "default" cluster for all apps you need a string literal expression (with single quotes, and escaped with double quotes if it is in YAML as well):</p><pre class="screen">turbine:
|
||||
appConfig: customers,stores
|
||||
clusterNameExpression: "'default'"</pre><p>Spring Cloud provides a <code class="literal">spring-cloud-starter-netflix-turbine</code> that has all the dependencies you need to get a Turbine server running. Just create a Spring Boot application and annotate it with <code class="literal">@EnableTurbine</code>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>by default Spring Cloud allows Turbine to use the host and port to allow multiple processes per host, per cluster. If you want the native Netflix behaviour built into Turbine that does <span class="emphasis"><em>not</em></span> allow multiple processes per host, per cluster (the key to the instance id is the hostname), then set the property <code class="literal">turbine.combineHostPort=false</code>.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_turbine_stream" href="#_turbine_stream"></a>15.3 Turbine Stream</h2></div></div></div><p>In some environments (e.g. in a PaaS setting), the classic Turbine model of pulling metrics from all the distributed Hystrix commands doesn’t work. In that case you might want to have your Hystrix commands push metrics to Turbine, and Spring Cloud enables that with messaging. All you need to do on the client is add a dependency to <code class="literal">spring-cloud-netflix-hystrix-stream</code> and the <code class="literal">spring-cloud-starter-stream-*</code> of your choice (see Spring Cloud Stream documentation for details on the brokers, and how to configure the client credentials, but it should work out of the box for a local broker).</p><p>On the server side Just create a Spring Boot application and annotate it with <code class="literal">@EnableTurbineStream</code> and by default it will come up on port 8989 (point your Hystrix dashboard to that port, any path). You can customize the port using either <code class="literal">server.port</code> or <code class="literal">turbine.stream.port</code>. If you have <code class="literal">spring-boot-starter-web</code> and <code class="literal">spring-boot-starter-actuator</code> on the classpath as well, then you can open up the Actuator endpoints on a separate port (with Tomcat by default) by providing a <code class="literal">management.port</code> which is different.</p><p>You can then point the Hystrix Dashboard to the Turbine Stream Server instead of individual Hystrix streams. If Turbine Stream is running on port 8989 on myhost, then put <code class="literal"><a class="link" href="http://myhost:8989" target="_top">http://myhost:8989</a></code> in the stream input field in the Hystrix Dashboard. Circuits will be prefixed by their respective serviceId, followed by a dot, then the circuit name.</p><p>Spring Cloud provides a <code class="literal">spring-cloud-starter-netflix-turbine-stream</code> that has all the dependencies you need to get a Turbine Stream server running - just add the Stream binder of your choice, e.g. <code class="literal">spring-cloud-starter-stream-rabbit</code>. You need Java 8 to run the app because it is Netty-based.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__circuit_breaker_hystrix_dashboard.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_netflix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_spring-cloud-ribbon.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14. Circuit Breaker: Hystrix Dashboard </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 16. Client Side Load Balancer: Ribbon</td></tr></table></div></body></html>
|
||||
15
Finchley.M8/multi/multi__instrumentation.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>54. Instrumentation</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__current_span.html" title="53. Current Span"><link rel="next" href="multi__span_lifecycle.html" title="55. Span lifecycle"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">54. Instrumentation</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__current_span.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__span_lifecycle.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_instrumentation" href="#_instrumentation"></a>54. Instrumentation</h2></div></div></div><p>Spring Cloud Sleuth instruments all your Spring application
|
||||
automatically, so you shouldn’t have to do anything to activate
|
||||
it. The instrumentation is added using a variety of technologies
|
||||
according to the stack that is available, e.g. for a servlet web
|
||||
application we use a <code class="literal">Filter</code>, and for Spring Integration we use
|
||||
<code class="literal">ChannelInterceptors</code>.</p><p>You can customize the keys used in span tags. To limit the volume of
|
||||
span data, by default an HTTP request will be tagged only with a
|
||||
handful of metadata like the status code, host and URL. You can add
|
||||
request headers by configuring <code class="literal">spring.sleuth.keys.http.headers</code> (a
|
||||
list of header names).</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Remember that tags are only collected and exported if there is a
|
||||
<code class="literal">Sampler</code> that allows it (by default there is not, so there is no
|
||||
danger of accidentally collecting too much data without configuring
|
||||
something).</p></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__current_span.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__span_lifecycle.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">53. Current Span </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 55. Span lifecycle</td></tr></table></div></body></html>
|
||||
148
Finchley.M8/multi/multi__integrations.html
Normal file
@@ -0,0 +1,148 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>61. Integrations</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__zipkin_stream_span_consumer.html" title="60. Zipkin Stream Span Consumer"><link rel="next" href="multi__running_examples.html" title="62. Running examples"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">61. Integrations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__zipkin_stream_span_consumer.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__running_examples.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_integrations" href="#_integrations"></a>61. Integrations</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_opentracing" href="#_opentracing"></a>61.1 OpenTracing</h2></div></div></div><p>Spring Cloud Sleuth is <a class="link" href="http://opentracing.io/" target="_top">OpenTracing</a> compatible. If you have
|
||||
OpenTracing on the classpath we will automatically register the OpenTracing
|
||||
<code class="literal">Tracer</code> bean. If you wish to disable this just set <code class="literal">spring.sleuth.opentracing.enabled</code> to <code class="literal">false</code></p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_runnable_and_callable" href="#_runnable_and_callable"></a>61.2 Runnable and Callable</h2></div></div></div><p>If you’re wrapping your logic in <code class="literal">Runnable</code> or <code class="literal">Callable</code> it’s enough to wrap those classes in their Sleuth representative.</p><p>Example for <code class="literal">Runnable</code>:</p><pre class="programlisting">Runnable runnable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Runnable() {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> run() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// do some work</span>
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String toString() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"spanNameFromToStringMethod"</span>;
|
||||
}
|
||||
};
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Manual `TraceRunnable` creation with explicit "calculateTax" Span name</span>
|
||||
Runnable traceRunnable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TraceRunnable(tracer, spanNamer, errorParser,
|
||||
runnable, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"calculateTax"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Wrapping `Runnable` with `Tracing`. That way the current span will be available</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// in the thread of `Runnable`</span>
|
||||
Runnable traceRunnableFromTracer = tracing.currentTraceContext().wrap(runnable);</pre><p>Example for <code class="literal">Callable</code>:</p><pre class="programlisting">Callable<String> callable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Callable<String>() {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String call() <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> someLogic();
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String toString() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"spanNameFromToStringMethod"</span>;
|
||||
}
|
||||
};
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Manual `TraceCallable` creation with explicit "calculateTax" Span name</span>
|
||||
Callable<String> traceCallable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TraceCallable<>(tracer, spanNamer, errorParser,
|
||||
callable, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"calculateTax"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Wrapping `Callable` with `Tracing`. That way the current span will be available</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// in the thread of `Callable`</span>
|
||||
Callable<String> traceCallableFromTracer = tracing.currentTraceContext().wrap(callable);</pre><p>That way you will ensure that a new Span is created and closed for each execution.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_hystrix" href="#_hystrix"></a>61.3 Hystrix</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_custom_concurrency_strategy" href="#_custom_concurrency_strategy"></a>61.3.1 Custom Concurrency Strategy</h3></div></div></div><p>We’re registering a custom <a class="link" href="https://github.com/Netflix/Hystrix/wiki/Plugins#concurrencystrategy" target="_top"><code class="literal">HystrixConcurrencyStrategy</code></a>
|
||||
that wraps all <code class="literal">Callable</code> instances into their Sleuth representative -
|
||||
the <code class="literal">TraceCallable</code>. The strategy either starts or continues a span depending on the fact whether tracing was already going
|
||||
on before the Hystrix command was called. To disable the custom Hystrix Concurrency Strategy set the <code class="literal">spring.sleuth.hystrix.strategy.enabled</code> to <code class="literal">false</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_manual_command_setting" href="#_manual_command_setting"></a>61.3.2 Manual Command setting</h3></div></div></div><p>Assuming that you have the following <code class="literal">HystrixCommand</code>:</p><pre class="programlisting">HystrixCommand<String> hystrixCommand = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> HystrixCommand<String>(setter) {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">protected</span> String run() <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> someLogic();
|
||||
}
|
||||
};</pre><p>In order to pass the tracing information you have to wrap the same logic in the Sleuth version of the <code class="literal">HystrixCommand</code> which is the
|
||||
<code class="literal">TraceCommand</code>:</p><pre class="programlisting">TraceCommand<String> traceCommand = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TraceCommand<String>(tracer, traceKeys, setter) {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String doRun() <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> someLogic();
|
||||
}
|
||||
};</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_rxjava" href="#_rxjava"></a>61.4 RxJava</h2></div></div></div><p>We’re registering a custom <a class="link" href="https://github.com/ReactiveX/RxJava/wiki/Plugins#rxjavaschedulershook" target="_top"><code class="literal">RxJavaSchedulersHook</code></a>
|
||||
that wraps all <code class="literal">Action0</code> instances into their Sleuth representative -
|
||||
the <code class="literal">TraceAction</code>. The hook either starts or continues a span depending on the fact whether tracing was already going
|
||||
on before the Action was scheduled. To disable the custom RxJavaSchedulersHook set the <code class="literal">spring.sleuth.rxjava.schedulers.hook.enabled</code> to <code class="literal">false</code>.</p><p>You can define a list of regular expressions for thread names, for which you don’t want a Span to be created. Just provide a comma separated list
|
||||
of regular expressions in the <code class="literal">spring.sleuth.rxjava.schedulers.ignoredthreads</code> property.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_http_integration" href="#_http_integration"></a>61.5 HTTP integration</h2></div></div></div><p>Features from this section can be disabled by providing the <code class="literal">spring.sleuth.web.enabled</code> property with value equal to <code class="literal">false</code>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_http_filter" href="#_http_filter"></a>61.5.1 HTTP Filter</h3></div></div></div><p>Via the <code class="literal">TraceFilter</code> all sampled incoming requests result in creation of a Span. That Span’s name is <code class="literal">http:</code> + the path to which
|
||||
the request was sent. E.g. if the request was sent to <code class="literal">/foo/bar</code> then the name will be <code class="literal">http:/foo/bar</code>. You can configure which URIs you would
|
||||
like to skip via the <code class="literal">spring.sleuth.web.skipPattern</code> property. If you have <code class="literal">ManagementServerProperties</code> on classpath then
|
||||
its value of <code class="literal">contextPath</code> gets appended to the provided skip pattern. If you want to reuse the
|
||||
Sleuth’s default skip patterns and just append your own, pass those patterns via
|
||||
the <code class="literal">spring.sleuth.web.additionalSkipPattern</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_handlerinterceptor" href="#_handlerinterceptor"></a>61.5.2 HandlerInterceptor</h3></div></div></div><p>Since we want the span names to be precise we’re using a <code class="literal">TraceHandlerInterceptor</code> that either wraps an
|
||||
existing <code class="literal">HandlerInterceptor</code> or is added directly to the list of existing <code class="literal">HandlerInterceptors</code>. The
|
||||
<code class="literal">TraceHandlerInterceptor</code> adds a special request attribute to the given <code class="literal">HttpServletRequest</code>. If the
|
||||
the <code class="literal">TraceFilter</code> doesn’t see this attribute set it will create a "fallback" span which is an additional
|
||||
span created on the server side so that the trace is presented properly in the UI. Seeing that most likely
|
||||
signifies that there is a missing instrumentation. In that case please file an issue in Spring Cloud Sleuth.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_async_servlet_support" href="#_async_servlet_support"></a>61.5.3 Async Servlet support</h3></div></div></div><p>If your controller returns a <code class="literal">Callable</code> or a <code class="literal">WebAsyncTask</code> Spring Cloud Sleuth will continue the existing span instead of creating a new one.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_webflux_support" href="#_webflux_support"></a>61.5.4 WebFlux support</h3></div></div></div><p>Via the <code class="literal">TraceWebFilter</code> all sampled incoming requests result in creation of a Span. That Span’s name is <code class="literal">http:</code> + the path to which
|
||||
the request was sent. E.g. if the request was sent to <code class="literal">/foo/bar</code> then the name will be <code class="literal">http:/foo/bar</code>. You can configure which URIs you would
|
||||
like to skip via the <code class="literal">spring.sleuth.web.skipPattern</code> property. If you have <code class="literal">ManagementServerProperties</code> on classpath then
|
||||
its value of <code class="literal">contextPath</code> gets appended to the provided skip pattern. If you want to reuse the
|
||||
Sleuth’s default skip patterns and just append your own, pass those patterns via
|
||||
the <code class="literal">spring.sleuth.web.additionalSkipPattern</code>.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_http_client_integration" href="#_http_client_integration"></a>61.6 HTTP client integration</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_synchronous_rest_template" href="#_synchronous_rest_template"></a>61.6.1 Synchronous Rest Template</h3></div></div></div><p>We’re injecting a <code class="literal">RestTemplate</code> interceptor that ensures that all the tracing information is passed to the requests. Each time a
|
||||
call is made a new Span is created. It gets closed upon receiving the response. In order to block the synchronous <code class="literal">RestTemplate</code> features
|
||||
just set <code class="literal">spring.sleuth.web.client.enabled</code> to <code class="literal">false</code>.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>You have to register <code class="literal">RestTemplate</code> as a bean so that the interceptors will get injected.
|
||||
If you create a <code class="literal">RestTemplate</code> instance with a <code class="literal">new</code> keyword then the instrumentation WILL NOT work.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_asynchronous_rest_template" href="#_asynchronous_rest_template"></a>61.6.2 Asynchronous Rest Template</h3></div></div></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Starting with Sleuth <code class="literal">2.0.0</code> we no longer register
|
||||
a bean of <code class="literal">AsyncRestTemplate</code> type. It’s up to you to create such
|
||||
a bean. Then we will instrument it.</p></td></tr></table></div><p>To block the <code class="literal">AsyncRestTemplate</code> features set <code class="literal">spring.sleuth.web.async.client.enabled</code> to <code class="literal">false</code>.
|
||||
To disable creation of the default <code class="literal">TraceAsyncClientHttpRequestFactoryWrapper</code> set <code class="literal">spring.sleuth.web.async.client.factory.enabled</code>
|
||||
to <code class="literal">false</code>. If you don’t want to create <code class="literal">AsyncRestClient</code> at all set <code class="literal">spring.sleuth.web.async.client.template.enabled</code> to <code class="literal">false</code>.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_multiple_asynchronous_rest_templates" href="#_multiple_asynchronous_rest_templates"></a>Multiple Asynchronous Rest Templates</h4></div></div></div><p>Sometimes you need to use multiple implementations of Asynchronous Rest Template. In the following snippet you
|
||||
can see an example of how to set up such a custom <code class="literal">AsyncRestTemplate</code>.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Config {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean(name = "customAsyncRestTemplate")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> AsyncRestTemplate traceAsyncRestTemplate() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> AsyncRestTemplate(asyncClientFactory(), clientHttpRequestFactory());
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> ClientHttpRequestFactory clientHttpRequestFactory() {
|
||||
ClientHttpRequestFactory clientHttpRequestFactory = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> CustomClientHttpRequestFactory();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//CUSTOMIZE HERE</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> clientHttpRequestFactory;
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> AsyncClientHttpRequestFactory asyncClientFactory() {
|
||||
AsyncClientHttpRequestFactory factory = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> CustomAsyncClientHttpRequestFactory();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//CUSTOMIZE HERE</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> factory;
|
||||
}
|
||||
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_webclient" href="#_webclient"></a>61.6.3 WebClient</h3></div></div></div><p>We inject a <code class="literal">ExchangeFilterFunction</code> implementation that creates a span and via on success and on
|
||||
error callbacks takes care of closing client side spans.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>You have to register <code class="literal">WebClient</code> as a bean so that the tracing instrumention gets applied.
|
||||
If you create a <code class="literal">WebClient</code> instance with a <code class="literal">new</code> keyword then the instrumentation WILL NOT work.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_traverson" href="#_traverson"></a>61.6.4 Traverson</h3></div></div></div><p>If you’re using the <a class="link" href="http://docs.spring.io/spring-hateoas/docs/current/reference/html/#client.traverson" target="_top">Traverson</a> library
|
||||
it’s enough for you to inject a <code class="literal">RestTemplate</code> as a bean into your Traverson object. Since <code class="literal">RestTemplate</code>
|
||||
is already intercepted, you will get full support of tracing in your client. Below you can find a pseudo code
|
||||
of how to do that:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> RestTemplate restTemplate;
|
||||
|
||||
Traverson traverson = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Traverson(URI.create(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://some/address"</span>),
|
||||
MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8).setRestOperations(restTemplate);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// use Traverson</span></pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_feign" href="#_feign"></a>61.7 Feign</h2></div></div></div><p>By default Spring Cloud Sleuth provides integration with feign via the <code class="literal">TraceFeignClientAutoConfiguration</code>. You can disable it entirely
|
||||
by setting <code class="literal">spring.sleuth.feign.enabled</code> to false. If you do so then no Feign related instrumentation will take place.</p><p>Part of Feign instrumentation is done via a <code class="literal">FeignBeanPostProcessor</code>. You can disable it by providing the <code class="literal">spring.sleuth.feign.processor.enabled</code> equal to <code class="literal">false</code>.
|
||||
If you set it like this then Spring Cloud Sleuth will not instrument any of your custom Feign components. All the default instrumentation
|
||||
however will be still there.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_asynchronous_communication" href="#_asynchronous_communication"></a>61.8 Asynchronous communication</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="__async_annotated_methods" href="#__async_annotated_methods"></a>61.8.1 @Async annotated methods</h3></div></div></div><p>In Spring Cloud Sleuth we’re instrumenting async related components so that the tracing information is passed between threads.
|
||||
You can disable this behaviour by setting the value of <code class="literal">spring.sleuth.async.enabled</code> to <code class="literal">false</code>.</p><p>If you annotate your method with <code class="literal">@Async</code> then we’ll automatically create a new Span with the following characteristics:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">if the method is annotated with <code class="literal">@SpanName</code> then the value of the annotation will be the Span’s name</li><li class="listitem">if the method is <span class="strong"><strong>not</strong></span> annotated with <code class="literal">@SpanName</code> the Span name will be the annotated method name</li><li class="listitem">the Span will be tagged with that method’s class name and the method name too</li></ul></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="__scheduled_annotated_methods" href="#__scheduled_annotated_methods"></a>61.8.2 @Scheduled annotated methods</h3></div></div></div><p>In Spring Cloud Sleuth we’re instrumenting scheduled method execution so that the tracing information is passed between threads. You can disable this behaviour
|
||||
by setting the value of <code class="literal">spring.sleuth.scheduled.enabled</code> to <code class="literal">false</code>.</p><p>If you annotate your method with <code class="literal">@Scheduled</code> then we’ll automatically create a new Span with the following characteristics:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">the Span name will be the annotated method name</li><li class="listitem">the Span will be tagged with that method’s class name and the method name too</li></ul></div><p>If you want to skip Span creation for some <code class="literal">@Scheduled</code> annotated classes you can set the
|
||||
<code class="literal">spring.sleuth.scheduled.skipPattern</code> with a regular expression that will match the fully qualified name of the
|
||||
<code class="literal">@Scheduled</code> annotated class.</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>If you are using <code class="literal">spring-cloud-sleuth-stream</code> and <code class="literal">spring-cloud-netflix-hystrix-stream</code> together, Span will be created for
|
||||
each Hystrix metrics and sent to Zipkin. This may be annoying. You can prevent this by setting
|
||||
<code class="literal">spring.sleuth.scheduled.skipPattern=org.springframework.cloud.netflix.hystrix.stream.HystrixStreamTask</code></p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_executor_executorservice_and_scheduledexecutorservice" href="#_executor_executorservice_and_scheduledexecutorservice"></a>61.8.3 Executor, ExecutorService and ScheduledExecutorService</h3></div></div></div><p>We’re providing <code class="literal">LazyTraceExecutor</code>, <code class="literal">TraceableExecutorService</code> and <code class="literal">TraceableScheduledExecutorService</code>. Those implementations
|
||||
are creating Spans each time a new task is submitted, invoked or scheduled.</p><p>Here you can see an example of how to pass tracing information with <code class="literal">TraceableExecutorService</code> when working with <code class="literal">CompletableFuture</code>:</p><pre class="programlisting">CompletableFuture<Long> completableFuture = CompletableFuture.supplyAsync(() -> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// perform some logic</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span class="hl-number">1</span>_<span class="hl-number">000</span>_<span class="hl-number">000L</span>;
|
||||
}, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TraceableExecutorService(beanFactory, executorService,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// 'calculateTax' explicitly names the span - this param is optional</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"calculateTax"</span>));</pre><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Sleuth doesn’t work with <code class="literal">parallelStream()</code> out of the box. If you want
|
||||
to have the tracing information propagated through the stream you have to use the
|
||||
approach with <code class="literal">supplyAsync(…​)</code> as presented above.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_customization_of_executors" href="#_customization_of_executors"></a>Customization of Executors</h4></div></div></div><p>Sometimes you need to set up a custom instance of the <code class="literal">AsyncExecutor</code>. In the following snippet you
|
||||
can see an example of how to set up such a custom <code class="literal">Executor</code>.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAsync</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> CustomExecutorConfig <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> AsyncConfigurerSupport {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> BeanFactory beanFactory;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Executor getAsyncExecutor() {
|
||||
ThreadPoolTaskExecutor executor = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ThreadPoolTaskExecutor();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// CUSTOMIZE HERE</span>
|
||||
executor.setCorePoolSize(<span class="hl-number">7</span>);
|
||||
executor.setMaxPoolSize(<span class="hl-number">42</span>);
|
||||
executor.setQueueCapacity(<span class="hl-number">11</span>);
|
||||
executor.setThreadNamePrefix(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"MyExecutor-"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// DON'T FORGET TO INITIALIZE</span>
|
||||
executor.initialize();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> LazyTraceExecutor(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.beanFactory, executor);
|
||||
}
|
||||
}</pre></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_messaging" href="#_messaging"></a>61.9 Messaging</h2></div></div></div><p>Spring Cloud Sleuth integrates with <a class="link" href="http://projects.spring.io/spring-integration/" target="_top">Spring Integration</a>. It creates spans for publish and
|
||||
subscribe events. To disable Spring Integration instrumentation, set <code class="literal">spring.sleuth.integration.enabled</code> to false.</p><p>You can provide the <code class="literal">spring.sleuth.integration.patterns</code> pattern to explicitly
|
||||
provide the names of channels that you want to include for tracing. By default all channels
|
||||
are included.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>When using the <code class="literal">Executor</code> to build a Spring Integration <code class="literal">IntegrationFlow</code> remember to use the <span class="strong"><strong>untraced</strong></span> version of the <code class="literal">Executor</code>.
|
||||
Decorating Spring Integration Executor Channel with <code class="literal">TraceableExecutorService</code> will cause the spans to be improperly closed.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_zuul_2" href="#_zuul_2"></a>61.10 Zuul</h2></div></div></div><p>We’re instrumenting the Zuul Ribbon integration by enriching the Ribbon requests with tracing information.
|
||||
To disable Zuul support set the <code class="literal">spring.sleuth.zuul.enabled</code> property to <code class="literal">false</code>.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__zipkin_stream_span_consumer.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__running_examples.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">60. Zipkin Stream Span Consumer </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 62. Running examples</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,31 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>31. Inter-Application Communication</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="prev" href="multi_schema-evolution.html" title="30. Schema evolution support"><link rel="next" href="multi__testing.html" title="32. Testing"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">31. Inter-Application Communication</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_schema-evolution.html">Prev</a> </td><th width="60%" align="center">Part V. Spring Cloud Stream</th><td width="20%" align="right"> <a accesskey="n" href="multi__testing.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_inter_application_communication" href="#_inter_application_communication"></a>31. Inter-Application Communication</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_connecting_multiple_application_instances" href="#_connecting_multiple_application_instances"></a>31.1 Connecting Multiple Application Instances</h2></div></div></div><p>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.</p><p>Supposing that a design calls for the Time Source application to send data to the Log Sink application, you can use a common destination named <code class="literal">ticktock</code> for bindings within both applications.</p><p>Time Source (that has the channel name <code class="literal">output</code>) will set the following property:</p><pre class="screen">spring.cloud.stream.bindings.output.destination=ticktock</pre><p>Log Sink (that has the channel name <code class="literal">input</code>) will set the following property:</p><pre class="screen">spring.cloud.stream.bindings.input.destination=ticktock</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_instance_index_and_instance_count" href="#_instance_index_and_instance_count"></a>31.2 Instance Index and Instance Count</h2></div></div></div><p>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 <code class="literal">spring.cloud.stream.instanceCount</code> and <code class="literal">spring.cloud.stream.instanceIndex</code> properties.
|
||||
For example, if there are three instances of a HDFS sink application, all three instances will have <code class="literal">spring.cloud.stream.instanceCount</code> set to <code class="literal">3</code>, and the individual applications will have <code class="literal">spring.cloud.stream.instanceIndex</code> set to <code class="literal">0</code>, <code class="literal">1</code>, and <code class="literal">2</code>, respectively.</p><p>When Spring Cloud Stream applications are deployed via 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, <code class="literal">spring.cloud.stream.instanceCount</code> is <code class="literal">1</code>, and <code class="literal">spring.cloud.stream.instanceIndex</code> is <code class="literal">0</code>.</p><p>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 (e.g., the Kafka binder) in order to ensure that data are split correctly across multiple consumer instances.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_partitioning" href="#_partitioning"></a>31.3 Partitioning</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_configuring_output_bindings_for_partitioning" href="#_configuring_output_bindings_for_partitioning"></a>31.3.1 Configuring Output Bindings for Partitioning</h3></div></div></div><p>An output binding is configured to send partitioned data by setting one and only one of its <code class="literal">partitionKeyExpression</code> or <code class="literal">partitionKeyExtractorName</code> (see next paragraph) properties, as well as its <code class="literal">partitionCount</code> property.</p><p>For example, the following is a valid and typical configuration:</p><pre class="screen">spring.cloud.stream.bindings.output.producer.partitionKeyExpression=payload.id
|
||||
spring.cloud.stream.bindings.output.producer.partitionCount=5</pre><p>Based on the above example configuration, data will be sent to the target partition using the following logic.</p><p>A partition key’s value is calculated for each message sent to a partitioned output channel based on the <code class="literal">partitionKeyExpression</code>.
|
||||
The <code class="literal">partitionKeyExpression</code> is a SpEL expression which is evaluated against the outbound message for extracting the partitioning key.</p><p>If a SpEL expression is not sufficient for your needs, you can instead calculate the partition key value by providing implementation of <code class="literal">org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy</code> and configuring it as a bean (i.e., <code class="literal">@Bean</code>). In the event you have more then one bean of type <code class="literal">org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy</code> available in the Application Context you can further filter it by specifying its name via <code class="literal">partitionKeyExtractorName</code> property:</p><pre class="screen">--spring.cloud.stream.bindings.output.producer.partitionKeyExtractorName=customPartitionKeyExtractor
|
||||
--spring.cloud.stream.bindings.output.producer.partitionCount=5
|
||||
. . .
|
||||
@Bean
|
||||
public CustomPartitionKeyExtractorClass customPartitionKeyExtractor() {
|
||||
return new CustomPartitionKeyExtractorClass();
|
||||
}</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>In previous versions of Spring Cloud Stream you could specify the implementation of <code class="literal">org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy</code> as <code class="literal">spring.cloud.stream.bindings.output.producer.partitionKeyExtractorClass</code> property. Since version 2.0 this property is deprecated and support for it will be removed in a future version.</p></td></tr></table></div><p>Once the message key is calculated, the partition selection process will determine the target partition as a value between <code class="literal">0</code> and <code class="literal">partitionCount - 1</code>.
|
||||
The default calculation, applicable in most scenarios, is based on the formula <code class="literal">key.hashCode() % partitionCount</code>.
|
||||
This can be customized on the binding, either by setting a SpEL expression to be evaluated against the 'key' (via the <code class="literal">partitionSelectorExpression</code> property) or by configuring an implementation of <code class="literal">org.springframework.cloud.stream.binder.PartitionSelectorStrategy</code> as a bean (i.e., @Bean). And similarly to the <code class="literal">PartitionKeyExtractorStrategy</code> you can further filter it using <code class="literal">spring.cloud.stream.bindings.output.producer.partitionSelectorName</code> property in the event there are more then one bean of this type is available in the Application Context.</p><pre class="screen">--spring.cloud.stream.bindings.output.producer.partitionSelectorName=customPartitionSelector
|
||||
. . .
|
||||
@Bean
|
||||
public CustomPartitionSelectorClass customPartitionSelector() {
|
||||
return new CustomPartitionSelectorClass();
|
||||
}</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>In previous versions of Spring Cloud Stream you could specify the implementation of <code class="literal">org.springframework.cloud.stream.binder.PartitionSelectorStrategy</code> as <code class="literal">spring.cloud.stream.bindings.output.producer.partitionSelectorClass</code> property. Since version 2.0 this property is deprecated and support for it will be removed in a future version.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_configuring_input_bindings_for_partitioning" href="#_configuring_input_bindings_for_partitioning"></a>Configuring Input Bindings for Partitioning</h4></div></div></div><p>An input binding (with the channel name <code class="literal">input</code>) is configured to receive partitioned data by setting its <code class="literal">partitioned</code> property, as well as the <code class="literal">instanceIndex</code> and <code class="literal">instanceCount</code> properties on the application itself, as in the following example:</p><pre class="screen">spring.cloud.stream.bindings.input.consumer.partitioned=true
|
||||
spring.cloud.stream.instanceIndex=3
|
||||
spring.cloud.stream.instanceCount=5</pre><p>The <code class="literal">instanceCount</code> value represents the total number of application instances between which the data need to be partitioned, and the <code class="literal">instanceIndex</code> must be a unique value across the multiple instances, between <code class="literal">0</code> and <code class="literal">instanceCount - 1</code>.
|
||||
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 doesn’t 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 <code class="literal">autoRebalanceEnabled</code> is <code class="literal">true</code> (default), Kafka will take care of distributing partitions across instances and these properties are not required.
|
||||
If <code class="literal">autoRebalanceEnabled</code> is set to false, the <code class="literal">instanceCount</code> and <code class="literal">instanceIndex</code> are used by the binder to determine which partition(s) the instance will subscribe to (you must have at least as many partitions as there are instances).
|
||||
The binder will allocate 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 that 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.</p><p>While a scenario 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 as well as relying on the runtime infrastructure to provide information about the instance index and instance count.</p></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_schema-evolution.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_stream.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__testing.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">30. Schema evolution support </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 32. Testing</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,40 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>24. Introducing Spring Cloud Stream</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="prev" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="next" href="multi__main_concepts.html" title="25. Main Concepts"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">24. Introducing Spring Cloud Stream</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_stream.html">Prev</a> </td><th width="60%" align="center">Part V. Spring Cloud Stream</th><td width="20%" align="right"> <a accesskey="n" href="multi__main_concepts.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_introducing_spring_cloud_stream" href="#_introducing_spring_cloud_stream"></a>24. Introducing Spring Cloud Stream</h2></div></div></div><p>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.</p><p>You can add the <code class="literal">@EnableBinding</code> annotation to your application to get immediate connectivity to a message broker, and you can add <code class="literal">@StreamListener</code> to a method to cause it to receive events for stream processing.
|
||||
The following is a simple sink application which receives external messages.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Sink.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> VoteRecordingSinkApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(VoteRecordingSinkApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Sink.INPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> processVote(Vote vote) {
|
||||
votingService.recordVote(vote);
|
||||
}
|
||||
}</pre><p>The <code class="literal">@EnableBinding</code> annotation takes one or more interfaces as parameters (in this case, the parameter is a single <code class="literal">Sink</code> interface).
|
||||
An interface declares input and/or output channels.
|
||||
Spring Cloud Stream provides the interfaces <code class="literal">Source</code>, <code class="literal">Sink</code>, and <code class="literal">Processor</code>; you can also define your own interfaces.</p><p>The following is the definition of the <code class="literal">Sink</code> interface:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> Sink {
|
||||
String INPUT = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"input"</span>;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Input(Sink.INPUT)</span></em>
|
||||
SubscribableChannel input();
|
||||
}</pre><p>The <code class="literal">@Input</code> annotation identifies an <span class="emphasis"><em>input channel</em></span>, through which received messages enter the application; the <code class="literal">@Output</code> annotation identifies an <span class="emphasis"><em>output channel</em></span>, through which published messages leave the application.
|
||||
The <code class="literal">@Input</code> and <code class="literal">@Output</code> annotations can take a channel name as a parameter; if a name is not provided, the name of the annotated method will be used.</p><p>Spring Cloud Stream will create an implementation of the interface for you.
|
||||
You can use this in the application by autowiring it, as in the following example of a test case.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@RunWith(SpringJUnit4ClassRunner.class)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@SpringApplicationConfiguration(classes = VoteRecordingSinkApplication.class)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@WebAppConfiguration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@DirtiesContext</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> StreamApplicationTests {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> Sink sink;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Test</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> contextLoads() {
|
||||
assertNotNull(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.sink.input());
|
||||
}
|
||||
}</pre></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_stream.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_stream.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__main_concepts.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part V. Spring Cloud Stream </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 25. Main Concepts</td></tr></table></div></body></html>
|
||||