Sync docs from v2.1.3.RELEASE to gh-pages
35
spring-cloud-commons/2.1.3.RELEASE/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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
@IMPORT url("manual.css");
|
||||
|
||||
body {
|
||||
background: url("../images/background.png") no-repeat center top;
|
||||
}
|
||||
|
||||
342
spring-cloud-commons/2.1.3.RELEASE/css/manual.css
Normal file
@@ -0,0 +1,342 @@
|
||||
@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;
|
||||
}
|
||||
330
spring-cloud-commons/2.1.3.RELEASE/ghpages.sh
Normal file
@@ -0,0 +1,330 @@
|
||||
#!/bin/bash -x
|
||||
|
||||
set -e
|
||||
|
||||
# Set default props like MAVEN_PATH, ROOT_FOLDER etc.
|
||||
function set_default_props() {
|
||||
# The script should be executed from the root folder
|
||||
ROOT_FOLDER=`pwd`
|
||||
echo "Current folder is ${ROOT_FOLDER}"
|
||||
|
||||
if [[ ! -e "${ROOT_FOLDER}/.git" ]]; then
|
||||
echo "You're not in the root folder of the project!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Prop that will let commit the changes
|
||||
COMMIT_CHANGES="no"
|
||||
MAVEN_PATH=${MAVEN_PATH:-}
|
||||
echo "Path to Maven is [${MAVEN_PATH}]"
|
||||
REPO_NAME=${PWD##*/}
|
||||
echo "Repo name is [${REPO_NAME}]"
|
||||
SPRING_CLOUD_STATIC_REPO=${SPRING_CLOUD_STATIC_REPO:-git@github.com:spring-cloud/spring-cloud-static.git}
|
||||
echo "Spring Cloud Static repo is [${SPRING_CLOUD_STATIC_REPO}"
|
||||
}
|
||||
|
||||
# Check if gh-pages exists and docs have been built
|
||||
function check_if_anything_to_sync() {
|
||||
git remote set-url --push origin `git config remote.origin.url | sed -e 's/^git:/https:/'`
|
||||
|
||||
if ! (git remote set-branches --add origin gh-pages && git fetch -q); then
|
||||
echo "No gh-pages, so not syncing"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! [ -d docs/target/generated-docs ] && ! [ "${BUILD}" == "yes" ]; then
|
||||
echo "No gh-pages sources in docs/target/generated-docs, so not syncing"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
function retrieve_current_branch() {
|
||||
# Code getting the name of the current branch. For master we want to publish as we did until now
|
||||
# https://stackoverflow.com/questions/1593051/how-to-programmatically-determine-the-current-checked-out-git-branch
|
||||
# If there is a branch already passed will reuse it - otherwise will try to find it
|
||||
CURRENT_BRANCH=${BRANCH}
|
||||
if [[ -z "${CURRENT_BRANCH}" ]] ; then
|
||||
CURRENT_BRANCH=$(git symbolic-ref -q HEAD)
|
||||
CURRENT_BRANCH=${CURRENT_BRANCH##refs/heads/}
|
||||
CURRENT_BRANCH=${CURRENT_BRANCH:-HEAD}
|
||||
fi
|
||||
echo "Current branch is [${CURRENT_BRANCH}]"
|
||||
git checkout ${CURRENT_BRANCH} || echo "Failed to check the branch... continuing with the script"
|
||||
}
|
||||
|
||||
# Switches to the provided value of the release version. We always prefix it with `v`
|
||||
function switch_to_tag() {
|
||||
git checkout v${VERSION}
|
||||
}
|
||||
|
||||
# Build the docs if switch is on
|
||||
function build_docs_if_applicable() {
|
||||
if [[ "${BUILD}" == "yes" ]] ; then
|
||||
./mvnw clean install -P docs -pl docs -DskipTests
|
||||
fi
|
||||
}
|
||||
|
||||
# Get the name of the `docs.main` property
|
||||
# Get whitelisted branches - assumes that a `docs` module is available under `docs` profile
|
||||
function retrieve_doc_properties() {
|
||||
MAIN_ADOC_VALUE=$("${MAVEN_PATH}"mvn -q \
|
||||
-Dexec.executable="echo" \
|
||||
-Dexec.args='${docs.main}' \
|
||||
--non-recursive \
|
||||
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec)
|
||||
echo "Extracted 'main.adoc' from Maven build [${MAIN_ADOC_VALUE}]"
|
||||
|
||||
|
||||
WHITELIST_PROPERTY=${WHITELIST_PROPERTY:-"docs.whitelisted.branches"}
|
||||
WHITELISTED_BRANCHES_VALUE=$("${MAVEN_PATH}"mvn -q \
|
||||
-Dexec.executable="echo" \
|
||||
-Dexec.args="\${${WHITELIST_PROPERTY}}" \
|
||||
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
|
||||
-P docs \
|
||||
-pl docs)
|
||||
echo "Extracted '${WHITELIST_PROPERTY}' from Maven build [${WHITELISTED_BRANCHES_VALUE}]"
|
||||
}
|
||||
|
||||
# Stash any outstanding changes
|
||||
function stash_changes() {
|
||||
git diff-index --quiet HEAD && dirty=$? || (echo "Failed to check if the current repo is dirty. Assuming that it is." && dirty="1")
|
||||
if [ "$dirty" != "0" ]; then git stash; fi
|
||||
}
|
||||
|
||||
# Switch to gh-pages branch to sync it with current branch
|
||||
function add_docs_from_target() {
|
||||
local DESTINATION_REPO_FOLDER
|
||||
if [[ -z "${DESTINATION}" && -z "${CLONE}" ]] ; then
|
||||
DESTINATION_REPO_FOLDER=${ROOT_FOLDER}
|
||||
elif [[ "${CLONE}" == "yes" ]]; then
|
||||
mkdir -p ${ROOT_FOLDER}/target
|
||||
local clonedStatic=${ROOT_FOLDER}/target/spring-cloud-static
|
||||
if [[ ! -e "${clonedStatic}/.git" ]]; then
|
||||
echo "Cloning Spring Cloud Static to target"
|
||||
git clone ${SPRING_CLOUD_STATIC_REPO} ${clonedStatic} && git checkout gh-pages
|
||||
else
|
||||
echo "Spring Cloud Static already cloned - will pull changes"
|
||||
cd ${clonedStatic} && git checkout gh-pages && git pull origin gh-pages
|
||||
fi
|
||||
DESTINATION_REPO_FOLDER=${clonedStatic}/${REPO_NAME}
|
||||
mkdir -p ${DESTINATION_REPO_FOLDER}
|
||||
else
|
||||
if [[ ! -e "${DESTINATION}/.git" ]]; then
|
||||
echo "[${DESTINATION}] is not a git repository"
|
||||
exit 1
|
||||
fi
|
||||
DESTINATION_REPO_FOLDER=${DESTINATION}/${REPO_NAME}
|
||||
mkdir -p ${DESTINATION_REPO_FOLDER}
|
||||
echo "Destination was provided [${DESTINATION}]"
|
||||
fi
|
||||
cd ${DESTINATION_REPO_FOLDER}
|
||||
git checkout gh-pages
|
||||
git pull origin gh-pages
|
||||
|
||||
# Add git branches
|
||||
###################################################################
|
||||
if [[ -z "${VERSION}" ]] ; then
|
||||
copy_docs_for_current_version
|
||||
else
|
||||
copy_docs_for_provided_version
|
||||
fi
|
||||
commit_changes_if_applicable
|
||||
}
|
||||
|
||||
|
||||
# Copies the docs by using the retrieved properties from Maven build
|
||||
function copy_docs_for_current_version() {
|
||||
if [[ "${CURRENT_BRANCH}" == "master" ]] ; then
|
||||
echo -e "Current branch is master - will copy the current docs only to the root folder"
|
||||
for f in docs/target/generated-docs/*; do
|
||||
file=${f#docs/target/generated-docs/*}
|
||||
if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then
|
||||
# Not ignored...
|
||||
cp -rf $f ${ROOT_FOLDER}/
|
||||
git add -A ${ROOT_FOLDER}/$file
|
||||
fi
|
||||
done
|
||||
COMMIT_CHANGES="yes"
|
||||
else
|
||||
echo -e "Current branch is [${CURRENT_BRANCH}]"
|
||||
# https://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}], DESTINATION [${DESTINATION}], CLONE [${CLONE}]"
|
||||
if [[ "${VERSION}" != "" && (-z "${DESTINATION}" && -z "${CLONE}") ]] ; then echo "Version was set but destination / clone was not!"; exit 1;fi
|
||||
if [[ ("${DESTINATION}" != "" && "${CLONE}" != "") && -z "${VERSION}" ]] ; then echo "Destination / clone was set but version was not!"; exit 1;fi
|
||||
if [[ "${DESTINATION}" != "" && "${CLONE}" == "yes" ]] ; then echo "Destination and clone was set. Pick one!"; exit 1;fi
|
||||
}
|
||||
|
||||
# Prints the usage
|
||||
function print_usage() {
|
||||
cat <<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>`
|
||||
|
||||
USAGE:
|
||||
|
||||
You can use the following options:
|
||||
|
||||
-v|--version - the script will apply the whole procedure for a particular library version
|
||||
-d|--destination - the root of destination folder where the docs should be copied. You have to use the full path.
|
||||
E.g. point to spring-cloud-static folder. Can't be used with (-c)
|
||||
-b|--build - will run the standard build process after checking out the branch
|
||||
-c|--clone - will automatically clone the spring-cloud-static repo instead of providing the destination.
|
||||
Obviously can't be used with (-d)
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
# ==========================================
|
||||
# ____ ____ _____ _____ _____ _______
|
||||
# / ____|/ ____| __ \|_ _| __ \__ __|
|
||||
# | (___ | | | |__) | | | | |__) | | |
|
||||
# \___ \| | | _ / | | | ___/ | |
|
||||
# ____) | |____| | \ \ _| |_| | | |
|
||||
# |_____/ \_____|_| \_\_____|_| |_|
|
||||
#
|
||||
# ==========================================
|
||||
|
||||
while [[ $# > 0 ]]
|
||||
do
|
||||
key="$1"
|
||||
case ${key} in
|
||||
-v|--version)
|
||||
VERSION="$2"
|
||||
shift # past argument
|
||||
;;
|
||||
-d|--destination)
|
||||
DESTINATION="$2"
|
||||
shift # past argument
|
||||
;;
|
||||
-b|--build)
|
||||
BUILD="yes"
|
||||
;;
|
||||
-c|--clone)
|
||||
CLONE="yes"
|
||||
;;
|
||||
-h|--help)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Invalid option: [$1]"
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift # past argument or value
|
||||
done
|
||||
|
||||
assert_properties
|
||||
set_default_props
|
||||
check_if_anything_to_sync
|
||||
if [[ -z "${VERSION}" ]] ; then
|
||||
retrieve_current_branch
|
||||
else
|
||||
switch_to_tag
|
||||
fi
|
||||
build_docs_if_applicable
|
||||
retrieve_doc_properties
|
||||
stash_changes
|
||||
add_docs_from_target
|
||||
checkout_previous_branch
|
||||
BIN
spring-cloud-commons/2.1.3.RELEASE/images/background.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/images/callouts/1.png
Normal file
|
After Width: | Height: | Size: 329 B |
BIN
spring-cloud-commons/2.1.3.RELEASE/images/callouts/2.png
Normal file
|
After Width: | Height: | Size: 353 B |
BIN
spring-cloud-commons/2.1.3.RELEASE/images/callouts/3.png
Normal file
|
After Width: | Height: | Size: 350 B |
BIN
spring-cloud-commons/2.1.3.RELEASE/images/caution.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/images/important.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/images/logo.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/images/note.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/images/tip.png
Normal file
|
After Width: | Height: | Size: 931 B |
BIN
spring-cloud-commons/2.1.3.RELEASE/images/warning.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
35
spring-cloud-commons/2.1.3.RELEASE/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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
@IMPORT url("manual.css");
|
||||
|
||||
body {
|
||||
background: url("../images/background.png") no-repeat center top;
|
||||
}
|
||||
|
||||
342
spring-cloud-commons/2.1.3.RELEASE/multi/css/manual.css
Normal file
@@ -0,0 +1,342 @@
|
||||
@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
spring-cloud-commons/2.1.3.RELEASE/multi/images/background.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/multi/images/callouts/1.png
Normal file
|
After Width: | Height: | Size: 329 B |
BIN
spring-cloud-commons/2.1.3.RELEASE/multi/images/callouts/2.png
Normal file
|
After Width: | Height: | Size: 353 B |
BIN
spring-cloud-commons/2.1.3.RELEASE/multi/images/callouts/3.png
Normal file
|
After Width: | Height: | Size: 350 B |
BIN
spring-cloud-commons/2.1.3.RELEASE/multi/images/caution.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/multi/images/important.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/multi/images/logo.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/multi/images/note.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/multi/images/tip.png
Normal file
|
After Width: | Height: | Size: 931 B |
BIN
spring-cloud-commons/2.1.3.RELEASE/multi/images/warning.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,311 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>2. Spring Cloud Commons: Common Abstractions</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"><link rel="home" href="multi_spring-cloud-commons.html" title="Cloud Native Applications"><link rel="up" href="multi_spring-cloud-commons.html" title="Cloud Native Applications"><link rel="prev" href="multi__spring_cloud_context_application_context_services.html" title="1. 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">2. Spring Cloud Commons: Common Abstractions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_context_application_context_services.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> </td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_spring_cloud_commons_common_abstractions" href="#_spring_cloud_commons_common_abstractions"></a>2. Spring Cloud Commons: Common Abstractions</h1></div></div></div><p>Patterns such as service discovery, load balancing, and circuit breakers lend themselves to a common abstraction layer that can be consumed by all Spring Cloud clients, independent of the implementation (for example, discovery with Eureka or Consul).</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_enablediscoveryclient" href="#_enablediscoveryclient"></a>2.1 @EnableDiscoveryClient</h2></div></div></div><p>Spring Cloud Commons provides the <code class="literal">@EnableDiscoveryClient</code> annotation.
|
||||
This looks for implementations of the <code class="literal">DiscoveryClient</code> interface with <code class="literal">META-INF/spring.factories</code>.
|
||||
Implementations of the Discovery Client add a configuration class to <code class="literal">spring.factories</code> under the <code class="literal">org.springframework.cloud.client.discovery.EnableDiscoveryClient</code> key.
|
||||
Examples of <code class="literal">DiscoveryClient</code> implementations include <a class="link" href="https://cloud.spring.io/spring-cloud-netflix/" target="_top">Spring Cloud Netflix Eureka</a>, <a class="link" href="https://cloud.spring.io/spring-cloud-consul/" target="_top">Spring Cloud Consul Discovery</a>, and <a class="link" href="https://cloud.spring.io/spring-cloud-zookeeper/" target="_top">Spring Cloud Zookeeper Discovery</a>.</p><p>By default, implementations of <code class="literal">DiscoveryClient</code> auto-register the local Spring Boot server with the remote discovery server.
|
||||
This behavior can be disabled by setting <code class="literal">autoRegister=false</code> in <code class="literal">@EnableDiscoveryClient</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><code class="literal">@EnableDiscoveryClient</code> is no longer required.
|
||||
You can put a <code class="literal">DiscoveryClient</code> implementation on the classpath to cause the Spring Boot application to register with the service discovery server.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_health_indicator" href="#_health_indicator"></a>2.1.1 Health Indicator</h3></div></div></div><p>Commons creates a Spring Boot <code class="literal">HealthIndicator</code> that <code class="literal">DiscoveryClient</code> implementations can participate in by implementing <code class="literal">DiscoveryHealthIndicator</code>.
|
||||
To disable the composite <code class="literal">HealthIndicator</code>, set <code class="literal">spring.cloud.discovery.client.composite-indicator.enabled=false</code>.
|
||||
A generic <code class="literal">HealthIndicator</code> based on <code class="literal">DiscoveryClient</code> is auto-configured (<code class="literal">DiscoveryClientHealthIndicator</code>).
|
||||
To disable it, set <code class="literal">spring.cloud.discovery.client.health-indicator.enabled=false</code>.
|
||||
To disable the description field of the <code class="literal">DiscoveryClientHealthIndicator</code>, set <code class="literal">spring.cloud.discovery.client.health-indicator.include-description=false</code>.
|
||||
Otherwise, it can bubble up as the <code class="literal">description</code> of the rolled up <code class="literal">HealthIndicator</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_ordering_discoveryclient_instances" href="#_ordering_discoveryclient_instances"></a>2.1.2 Ordering <code class="literal">DiscoveryClient</code> instances</h3></div></div></div><p><code class="literal">DiscoveryClient</code> interface extends <code class="literal">Ordered</code>. This is useful when using multiple discovery
|
||||
clients, as it allows you to define the order of the returned discovery clients, similar to
|
||||
how you can order the beans loaded by a Spring application. By default, the order of any <code class="literal">DiscoveryClient</code> is set to
|
||||
<code class="literal">0</code>. If you want to set a different order for your custom <code class="literal">DiscoveryClient</code> implementations, you just need to override
|
||||
the <code class="literal">getOrder()</code> method so that it returns the value that is suitable for your setup. Apart from this, you can use
|
||||
properties to set the order of the <code class="literal">DiscoveryClient</code>
|
||||
implementations provided by Spring Cloud, among others <code class="literal">ConsulDiscoveryClient</code>, <code class="literal">EurekaDiscoveryClient</code> and
|
||||
<code class="literal">ZookeeperDiscoveryClient</code>. In order to do it, you just need to set the
|
||||
<code class="literal">spring.cloud.{clientIdentifier}.discovery.order</code> (or <code class="literal">eureka.client.order</code> for Eureka) property to the desired value.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_serviceregistry" href="#_serviceregistry"></a>2.2 ServiceRegistry</h2></div></div></div><p>Commons now provides a <code class="literal">ServiceRegistry</code> interface that provides methods such as <code class="literal">register(Registration)</code> and <code class="literal">deregister(Registration)</code>, which let you provide custom registered services.
|
||||
<code class="literal">Registration</code> is a marker interface.</p><p>The following example shows the <code class="literal">ServiceRegistry</code> in use:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@EnableDiscoveryClient(autoRegister=false)</xslthl:annotation>
|
||||
<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> MyConfiguration {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> ServiceRegistry registry;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> MyConfiguration(ServiceRegistry registry) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.registry = registry;
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// called through some external process, such as an event or a custom actuator endpoint</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">void</span> register() {
|
||||
Registration registration = constructRegistration();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.registry.register(registration);
|
||||
}
|
||||
}</pre><p>Each <code class="literal">ServiceRegistry</code> implementation has its own <code class="literal">Registry</code> implementation.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">ZookeeperRegistration</code> used with <code class="literal">ZookeeperServiceRegistry</code></li><li class="listitem"><code class="literal">EurekaRegistration</code> used with <code class="literal">EurekaServiceRegistry</code></li><li class="listitem"><code class="literal">ConsulRegistration</code> used with <code class="literal">ConsulServiceRegistry</code></li></ul></div><p>If you are using the <code class="literal">ServiceRegistry</code> interface, you are going to need to pass the
|
||||
correct <code class="literal">Registry</code> implementation for the <code class="literal">ServiceRegistry</code> implementation you
|
||||
are using.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_serviceregistry_auto_registration" href="#_serviceregistry_auto_registration"></a>2.2.1 ServiceRegistry Auto-Registration</h3></div></div></div><p>By default, the <code class="literal">ServiceRegistry</code> implementation auto-registers the running service.
|
||||
To disable that behavior, you can set:
|
||||
* <code class="literal">@EnableDiscoveryClient(autoRegister=false)</code> to permanently disable auto-registration.
|
||||
* <code class="literal">spring.cloud.service-registry.auto-registration.enabled=false</code> to disable the behavior through configuration.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_serviceregistry_auto_registration_events" href="#_serviceregistry_auto_registration_events"></a>ServiceRegistry Auto-Registration Events</h4></div></div></div><p>There are two events that will be fired when a service auto-registers. The first event, called
|
||||
<code class="literal">InstancePreRegisteredEvent</code>, is fired before the service is registered. The second
|
||||
event, called <code class="literal">InstanceRegisteredEvent</code>, is fired after the service is registered. You can register an
|
||||
<code class="literal">ApplicationListener</code>(s) to listen to and react to these events.</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>These events will not be fired if <code class="literal">spring.cloud.service-registry.auto-registration.enabled</code> is set to <code class="literal">false</code>.</p></td></tr></table></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_service_registry_actuator_endpoint" href="#_service_registry_actuator_endpoint"></a>2.2.2 Service Registry Actuator Endpoint</h3></div></div></div><p>Spring Cloud Commons provides a <code class="literal">/service-registry</code> actuator endpoint.
|
||||
This endpoint relies on a <code class="literal">Registration</code> bean in the Spring Application Context.
|
||||
Calling <code class="literal">/service-registry</code> with GET returns the status of the <code class="literal">Registration</code>.
|
||||
Using POST to the same endpoint with a JSON body changes the status of the current <code class="literal">Registration</code> to the new value.
|
||||
The JSON body has to include the <code class="literal">status</code> field with the preferred value.
|
||||
Please see the documentation of the <code class="literal">ServiceRegistry</code> implementation you use for the allowed values when updating the status and the values returned for the status.
|
||||
For instance, Eureka’s supported statuses are <code class="literal">UP</code>, <code class="literal">DOWN</code>, <code class="literal">OUT_OF_SERVICE</code>, and <code class="literal">UNKNOWN</code>.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spring_resttemplate_as_a_load_balancer_client" href="#_spring_resttemplate_as_a_load_balancer_client"></a>2.3 Spring RestTemplate as a Load Balancer Client</h2></div></div></div><p><code class="literal">RestTemplate</code> can be automatically configured to use a Load-balancer client under the hood.
|
||||
To create a load-balanced <code class="literal">RestTemplate</code>, create a <code class="literal">RestTemplate</code> <code class="literal">@Bean</code> and use the <code class="literal">@LoadBalanced</code> qualifier, as shown in the following example:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<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> MyConfiguration {
|
||||
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
RestTemplate restTemplate() {
|
||||
<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> RestTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
<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> MyClass {
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> RestTemplate restTemplate;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String doOtherStuff() {
|
||||
String results = restTemplate.getForObject(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://stores/stores"</span>, String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> results;
|
||||
}
|
||||
}</pre><div class="caution" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Caution"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="images/caution.png"></td><th align="left">Caution</th></tr><tr><td align="left" valign="top"><p>A <code class="literal">RestTemplate</code> bean is no longer created through auto-configuration.
|
||||
Individual applications must create it.</p></td></tr></table></div><p>The URI needs to use a virtual host name (that is, a service name, not a host name).
|
||||
The Ribbon client is used to create a full physical address.
|
||||
See <a class="link" href="https://github.com/spring-cloud/spring-cloud-netflix/blob/master/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java" target="_top">RibbonAutoConfiguration</a> for details of how the <code class="literal">RestTemplate</code> is set up.</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>In order to use a load-balanced <code class="literal">RestTemplate</code>, you need to have a load-balancer implementation in your classpath.
|
||||
The recommended implementation is <code class="literal">BlockingLoadBalancerClient</code>
|
||||
- add <code class="literal">org.springframework.cloud:spring-cloud-loadbalancer</code> in order to use it.
|
||||
The
|
||||
<code class="literal">RibbonLoadBalancerClient</code> also can be used, but it’s now under maintenance and we do not recommend adding it to new projects.</p></td></tr></table></div><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>If you want to use <code class="literal">BlockingLoadBalancerClient</code>, make sure you do not have
|
||||
<code class="literal">RibbonLoadBalancerClient</code> in the project classpath, as for backward compatibility reasons, it will be used by default.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spring_webclient_as_a_load_balancer_client" href="#_spring_webclient_as_a_load_balancer_client"></a>2.4 Spring WebClient as a Load Balancer Client</h2></div></div></div><p><code class="literal">WebClient</code> can be automatically configured to use a load-balancer client.
|
||||
To create a load-balanced <code class="literal">WebClient</code>, create a <code class="literal">WebClient.Builder</code> <code class="literal">@Bean</code> and use the <code class="literal">@LoadBalanced</code> qualifier, as shown in the following example:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<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> MyConfiguration {
|
||||
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> WebClient.Builder loadBalancedWebClientBuilder() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> WebClient.builder();
|
||||
}
|
||||
}
|
||||
|
||||
<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> MyClass {
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> WebClient.Builder webClientBuilder;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Mono<String> doOtherStuff() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> webClientBuilder.build().get().uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://stores/stores"</span>)
|
||||
.retrieve().bodyToMono(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
|
||||
}
|
||||
}</pre><p>The URI needs to use a virtual host name (that is, a service name, not a host name).
|
||||
The Ribbon client is used to create a full physical address.</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>If you want to use a <code class="literal">@LoadBalanced WebClient.Builder</code>, you need to have a loadbalancer
|
||||
implementation in the classpath. It is recommended that you add the
|
||||
<code class="literal">org.springframework.cloud:spring-cloud-loadbalancer</code> dependency to your project.
|
||||
Then, <code class="literal">ReactiveLoadBalancer</code> will be used underneath.
|
||||
Alternatively, this functionality will also work with spring-cloud-starter-netflix-ribbon, but the request
|
||||
will be handled by a non-reactive <code class="literal">LoadBalancerClient</code> under the hood. Additionally,
|
||||
spring-cloud-starter-netflix-ribbon is already in maintenance mode, so we do not recommned
|
||||
adding it to new projects.</p></td></tr></table></div><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>The <code class="literal">ReactorLoadBalancer</code> used underneath supports caching. If <code class="literal">cacheManager</code> is detected,
|
||||
cached version of <code class="literal">ServiceInstanceSupplier</code> will be used. If not, we will retrieve instances
|
||||
from discovery service without caching them. We recommend <a class="link" href="https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-caching.html" target="_top">enabling caching</a> in your project
|
||||
if you use <code class="literal">ReactiveLoadBalancer</code>.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_retrying_failed_requests" href="#_retrying_failed_requests"></a>2.4.1 Retrying Failed Requests</h3></div></div></div><p>A load-balanced <code class="literal">RestTemplate</code> can be configured to retry failed requests.
|
||||
By default, this logic is disabled.
|
||||
You can enable it by adding <a class="link" href="https://github.com/spring-projects/spring-retry" target="_top">Spring Retry</a> to your application’s classpath.
|
||||
The load-balanced <code class="literal">RestTemplate</code> honors some of the Ribbon configuration values related to retrying failed requests.
|
||||
You can use <code class="literal">client.ribbon.MaxAutoRetries</code>, <code class="literal">client.ribbon.MaxAutoRetriesNextServer</code>, and <code class="literal">client.ribbon.OkToRetryOnAllOperations</code> properties.
|
||||
If you would like to disable the retry logic with Spring Retry on the classpath, you can set <code class="literal">spring.cloud.loadbalancer.retry.enabled=false</code>.
|
||||
See the <a class="link" href="https://github.com/Netflix/ribbon/wiki/Getting-Started#the-properties-file-sample-clientproperties" target="_top">Ribbon documentation</a> for a description of what these properties do.</p><p>If you would like to implement a <code class="literal">BackOffPolicy</code> in your retries, you need to create a bean of type <code class="literal">LoadBalancedRetryFactory</code> and override the <code class="literal">createBackOffPolicy</code> method:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<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> MyConfiguration {
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
LoadBalancedRetryFactory retryFactory() {
|
||||
<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> LoadBalancedRetryFactory() {
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> BackOffPolicy createBackOffPolicy(String service) {
|
||||
<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> ExponentialBackOffPolicy();
|
||||
}
|
||||
};
|
||||
}
|
||||
}</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><code class="literal">client</code> in the preceding examples should be replaced with your Ribbon client’s name.</p></td></tr></table></div><p>If you want to add one or more <code class="literal">RetryListener</code> implementations to your retry functionality, you need to
|
||||
create a bean of type <code class="literal">LoadBalancedRetryListenerFactory</code> and return the <code class="literal">RetryListener</code> array
|
||||
you would like to use for a given service, as shown in the following example:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<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> MyConfiguration {
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
LoadBalancedRetryListenerFactory retryListenerFactory() {
|
||||
<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> LoadBalancedRetryListenerFactory() {
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> RetryListener[] createRetryListeners(String service) {
|
||||
<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> RetryListener[]{<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> RetryListener() {
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <T, E <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> Throwable> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> open(RetryContext context, RetryCallback<T, E> callback) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//TODO Do you business...</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> true;
|
||||
}
|
||||
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <T, E <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> Throwable> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//TODO Do you business...</span>
|
||||
}
|
||||
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <T, E <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> Throwable> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//TODO Do you business...</span>
|
||||
}
|
||||
}};
|
||||
}
|
||||
};
|
||||
}
|
||||
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_multiple_resttemplate_objects" href="#_multiple_resttemplate_objects"></a>2.5 Multiple RestTemplate objects</h2></div></div></div><p>If you want a <code class="literal">RestTemplate</code> that is not load-balanced, create a <code class="literal">RestTemplate</code> bean and inject it.
|
||||
To access the load-balanced <code class="literal">RestTemplate</code>, use the <code class="literal">@LoadBalanced</code> qualifier when you create your <code class="literal">@Bean</code>, as shown in the following example:\</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<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> MyConfiguration {
|
||||
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
RestTemplate loadBalanced() {
|
||||
<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> RestTemplate();
|
||||
}
|
||||
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Primary</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
RestTemplate restTemplate() {
|
||||
<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> RestTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
<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> MyClass {
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> RestTemplate restTemplate;
|
||||
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> RestTemplate loadBalanced;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String doOtherStuff() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> loadBalanced.getForObject(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://stores/stores"</span>, String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String doStuff() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> restTemplate.getForObject(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"https://example.com"</span>, String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</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>Notice the use of the <code class="literal">@Primary</code> annotation on the plain <code class="literal">RestTemplate</code> declaration in the preceding example to disambiguate the unqualified <code class="literal">@Autowired</code> injection.</p></td></tr></table></div><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 see errors such as <code class="literal">java.lang.IllegalArgumentException: Can not set org.springframework.web.client.RestTemplate field com.my.app.Foo.restTemplate to com.sun.proxy.$Proxy89</code>, try injecting <code class="literal">RestOperations</code> or setting <code class="literal">spring.aop.proxyTargetClass=true</code>.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="loadbalanced-webclient" href="#loadbalanced-webclient"></a>2.6 Spring WebFlux WebClient as a Load Balancer Client</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="webflux-with-reactive-loadbalancer" href="#webflux-with-reactive-loadbalancer"></a>2.6.1 Spring WebFlux WebClient with Reactive Load Balancer</h3></div></div></div><p><code class="literal">WebClient</code> can be configured to use the <code class="literal">ReactiveLoadBalancer</code>.
|
||||
If you add <code class="literal">org.springframework.cloud:spring-cloud-loadbalancer</code> to your project,
|
||||
<code class="literal">ReactorLoadBalancerExchangeFilterFunction</code> is auto-configured if <code class="literal">spring-webflux</code> is on the classpath.
|
||||
The following example shows how to configure a <code class="literal">WebClient</code> to use reactive load balancer under the hood:</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">class</span> MyClass {
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> ReactorLoadBalancerExchangeFilterFunction lbFunction;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Mono<String> doOtherStuff() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> WebClient.builder().baseUrl(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://stores"</span>)
|
||||
.filter(lbFunction)
|
||||
.build()
|
||||
.get()
|
||||
.uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/stores"</span>)
|
||||
.retrieve()
|
||||
.bodyToMono(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
|
||||
}
|
||||
}</pre><p>The URI needs to use a virtual host name (that is, a service name, not a host name).
|
||||
The <code class="literal">ReactorLoadBalancerClient</code> is used to create a full physical address.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_spring_webflux_webclient_with_non_reactive_load_balancer_client" href="#_spring_webflux_webclient_with_non_reactive_load_balancer_client"></a>2.6.2 Spring WebFlux WebClient with non-reactive Load Balancer Client</h3></div></div></div><p>If you you don’t have <code class="literal">org.springframework.cloud:spring-cloud-loadbalancer</code> in your project,
|
||||
but you do have spring-cloud-starter-netflix-ribbon, you can still use <code class="literal">WebClient</code> with <code class="literal">LoadBalancerClient</code>. <code class="literal">LoadBalancerExchangeFilterFunction</code>
|
||||
will be auto-configured if <code class="literal">spring-webflux</code> is on the classpath. Please note, however, that this is
|
||||
uses a non-reactive client under the hood.
|
||||
The following example shows how to configure a <code class="literal">WebClient</code> to use load balancer:</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">class</span> MyClass {
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> LoadBalancerExchangeFilterFunction lbFunction;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Mono<String> doOtherStuff() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> WebClient.builder().baseUrl(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://stores"</span>)
|
||||
.filter(lbFunction)
|
||||
.build()
|
||||
.get()
|
||||
.uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/stores"</span>)
|
||||
.retrieve()
|
||||
.bodyToMono(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
|
||||
}
|
||||
}</pre><p>The URI needs to use a virtual host name (that is, a service name, not a host name).
|
||||
The <code class="literal">LoadBalancerClient</code> is used to create a full physical address.</p><p>WARN:
|
||||
This approach is now deprecated.
|
||||
We suggest you use <a class="link" href="multi__spring_cloud_commons_common_abstractions.html#webflux-with-reactive-loadbalancer" title="2.6.1 Spring WebFlux WebClient with Reactive Load Balancer">WebFlux with reactive Load-Balancer</a>
|
||||
instead.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_passing_your_own_load_balancer_client_configuration" href="#_passing_your_own_load_balancer_client_configuration"></a>2.6.3 Passing your own Load-Balancer Client configuration</h3></div></div></div><p>You can also use the <code class="literal">@LoadBalancerClient</code> annotation to pass your own load-balancer client configuration, passing the name of the load-balancer client and the configuration class, like so:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalancerClient(value = "stores", configuration = StoresLoadBalancerClientConfiguration.class)</xslthl:annotation>
|
||||
<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> MyConfiguration {
|
||||
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> WebClient.Builder loadBalancedWebClientBuilder() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> WebClient.builder();
|
||||
}
|
||||
}</pre><p>It is also possible to pass together multiple configurations (for more than one load-balancer client) via the <code class="literal">@LoadBalancerClients</code> annotation, as shown below:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalancerClients({@LoadBalancerClient(value = "stores", configuration = StoresLoadBalancerClientConfiguration.class), @LoadBalancerClient(value = "customers", configuration = CustomersLoadBalancerClientConfiguration.class)})</xslthl:annotation>
|
||||
<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> MyConfiguration {
|
||||
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> WebClient.Builder loadBalancedWebClientBuilder() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> WebClient.builder();
|
||||
}
|
||||
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="ignore-network-interfaces" href="#ignore-network-interfaces"></a>2.7 Ignore Network Interfaces</h2></div></div></div><p>Sometimes, it is useful to ignore certain named network interfaces so that they can be excluded from Service Discovery registration (for example, when running in a Docker container).
|
||||
A list of regular expressions can be set to cause the desired network interfaces to be ignored.
|
||||
The following configuration ignores the <code class="literal">docker0</code> interface and all interfaces that start with <code class="literal">veth</code>:</p><p><b>application.yml. </b>
|
||||
</p><pre class="screen">spring:
|
||||
cloud:
|
||||
inetutils:
|
||||
ignoredInterfaces:
|
||||
- docker0
|
||||
- veth.*</pre><p>
|
||||
</p><p>You can also force the use of only specified network addresses by using a list of regular expressions, as shown in the following example:</p><p><b>bootstrap.yml. </b>
|
||||
</p><pre class="screen">spring:
|
||||
cloud:
|
||||
inetutils:
|
||||
preferredNetworks:
|
||||
- 192.168
|
||||
- 10.0</pre><p>
|
||||
</p><p>You can also force the use of only site-local addresses, as shown in the following example:
|
||||
.application.yml</p><pre class="screen">spring:
|
||||
cloud:
|
||||
inetutils:
|
||||
useOnlySiteLocalInterfaces: true</pre><p>See <a class="link" href="https://docs.oracle.com/javase/8/docs/api/java/net/Inet4Address.html#isSiteLocalAddress--" target="_top">Inet4Address.html.isSiteLocalAddress()</a> for more details about what constitutes a site-local address.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="http-clients" href="#http-clients"></a>2.8 HTTP Client Factories</h2></div></div></div><p>Spring Cloud Commons provides beans for creating both Apache HTTP clients (<code class="literal">ApacheHttpClientFactory</code>) and OK HTTP clients (<code class="literal">OkHttpClientFactory</code>).
|
||||
The <code class="literal">OkHttpClientFactory</code> bean is created only if the OK HTTP jar is on the classpath.
|
||||
In addition, Spring Cloud Commons provides beans for creating the connection managers used by both clients: <code class="literal">ApacheHttpClientConnectionManagerFactory</code> for the Apache HTTP client and <code class="literal">OkHttpClientConnectionPoolFactory</code> for the OK HTTP client.
|
||||
If you would like to customize how the HTTP clients are created in downstream projects, you can provide your own implementation of these beans.
|
||||
In addition, if you provide a bean of type <code class="literal">HttpClientBuilder</code> or <code class="literal">OkHttpClient.Builder</code>, the default factories use these builders as the basis for the builders returned to downstream projects.
|
||||
You can also disable the creation of these beans by setting <code class="literal">spring.cloud.httpclientfactories.apache.enabled</code> or <code class="literal">spring.cloud.httpclientfactories.ok.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="enabled-features" href="#enabled-features"></a>2.9 Enabled Features</h2></div></div></div><p>Spring Cloud Commons provides a <code class="literal">/features</code> actuator endpoint.
|
||||
This endpoint returns features available on the classpath and whether they are enabled.
|
||||
The information returned includes the feature type, name, version, and vendor.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_feature_types" href="#_feature_types"></a>2.9.1 Feature types</h3></div></div></div><p>There are two types of 'features': abstract and named.</p><p>Abstract features are features where an interface or abstract class is defined and that an implementation the creates, such as <code class="literal">DiscoveryClient</code>, <code class="literal">LoadBalancerClient</code>, or <code class="literal">LockService</code>.
|
||||
The abstract class or interface is used to find a bean of that type in the context.
|
||||
The version displayed is <code class="literal">bean.getClass().getPackage().getImplementationVersion()</code>.</p><p>Named features are features that do not have a particular class they implement, such as "Circuit Breaker", "API Gateway", "Spring Cloud Bus", and others. These features require a name and a bean type.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_declaring_features" href="#_declaring_features"></a>2.9.2 Declaring features</h3></div></div></div><p>Any module can declare any number of <code class="literal">HasFeature</code> beans, as shown in the following examples:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> HasFeatures commonsFeatures() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> HasFeatures.abstractFeatures(DiscoveryClient.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, LoadBalancerClient.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
|
||||
}
|
||||
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> HasFeatures consulFeatures() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> HasFeatures.namedFeatures(
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> NamedFeature(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Spring Cloud Bus"</span>, ConsulBusAutoConfiguration.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>),
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> NamedFeature(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Circuit Breaker"</span>, HystrixCommandAspect.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>));
|
||||
}
|
||||
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
HasFeatures localFeatures() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> HasFeatures.builder()
|
||||
.abstractFeature(Foo.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>)
|
||||
.namedFeature(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> NamedFeature(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Bar Feature"</span>, Bar.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>))
|
||||
.abstractFeature(Baz.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>)
|
||||
.build();
|
||||
}</pre><p>Each of these beans should go in an appropriately guarded <code class="literal">@Configuration</code>.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spring_cloud_compatibility_verification" href="#_spring_cloud_compatibility_verification"></a>2.10 Spring Cloud Compatibility Verification</h2></div></div></div><p>Due to the fact that some users have problem with setting up Spring Cloud application, we’ve decided
|
||||
to add a compatibility verification mechanism. It will break if your current setup is not compatible
|
||||
with Spring Cloud requirements, together with a report, showing what exactly went wrong.</p><p>At the moment we verify which version of Spring Boot is added to your classpath.</p><p>Example of a report</p><pre class="screen">***************************
|
||||
APPLICATION FAILED TO START
|
||||
***************************
|
||||
|
||||
Description:
|
||||
|
||||
Your project setup is incompatible with our requirements due to following reasons:
|
||||
|
||||
- Spring Boot [2.1.0.RELEASE] is not compatible with this Spring Cloud release train
|
||||
|
||||
|
||||
Action:
|
||||
|
||||
Consider applying the following actions:
|
||||
|
||||
- Change Spring Boot version to one of the following versions [1.2.x, 1.3.x] .
|
||||
You can find the latest Spring Boot versions here [https://spring.io/projects/spring-boot#learn].
|
||||
If you want to learn more about the Spring Cloud Release train compatibility, you can visit this page [https://spring.io/projects/spring-cloud#overview] and check the [Release Trains] section.</pre><p>In order to disable this feature, set <code class="literal">spring.cloud.compatibility-verifier.enabled</code> to <code class="literal">false</code>.
|
||||
If you want to override the compatible Spring Boot versions, just set the
|
||||
<code class="literal">spring.cloud.compatibility-verifier.compatible-boot-versions</code> property with a comma separated list
|
||||
of compatible Spring Boot versions.</p></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_context_application_context_services.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">1. Spring Cloud Context: Application Context Services </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud-commons.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,96 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>1. Spring Cloud Context: Application Context Services</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"><link rel="home" href="multi_spring-cloud-commons.html" title="Cloud Native Applications"><link rel="up" href="multi_spring-cloud-commons.html" title="Cloud Native Applications"><link rel="prev" href="multi_pr01.html" title=""><link rel="next" href="multi__spring_cloud_commons_common_abstractions.html" title="2. Spring Cloud Commons: Common Abstractions"></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. Spring Cloud Context: Application Context Services</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__spring_cloud_commons_common_abstractions.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_spring_cloud_context_application_context_services" href="#_spring_cloud_context_application_context_services"></a>1. Spring Cloud Context: Application Context Services</h1></div></div></div><p>Spring Boot has an opinionated view of how to build an application with Spring.
|
||||
For instance, it has conventional locations for common configuration files and has endpoints for common management and monitoring tasks.
|
||||
Spring Cloud builds on top of that and adds a few features that probably all components in a system would use or occasionally need.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_the_bootstrap_application_context" href="#_the_bootstrap_application_context"></a>1.1 The Bootstrap Application Context</h2></div></div></div><p>A Spring Cloud application operates by creating a <span class="quote">“<span class="quote">bootstrap</span>”</span> context, which is a parent context for the main application.
|
||||
It is responsible for loading configuration properties from the external sources and for decrypting properties in the local external configuration files.
|
||||
The two contexts share an <code class="literal">Environment</code>, which is the source of external properties for any Spring application.
|
||||
By default, bootstrap properties (not <code class="literal">bootstrap.properties</code> but properties that are loaded during the bootstrap phase) are added with high precedence, so they cannot be overridden by local configuration.</p><p>The bootstrap context uses a different convention for locating external configuration than the main application context.
|
||||
Instead of <code class="literal">application.yml</code> (or <code class="literal">.properties</code>), you can use <code class="literal">bootstrap.yml</code>, keeping the external configuration for bootstrap and main context
|
||||
nicely separate.
|
||||
The following listing shows an example:</p><p><b>bootstrap.yml. </b>
|
||||
</p><pre class="screen">spring:
|
||||
application:
|
||||
name: foo
|
||||
cloud:
|
||||
config:
|
||||
uri: ${SPRING_CONFIG_URI:http://localhost:8888}</pre><p>
|
||||
</p><p>If your application needs any application-specific configuration from the server, it is a good idea to set the <code class="literal">spring.application.name</code> (in <code class="literal">bootstrap.yml</code> or <code class="literal">application.yml</code>).
|
||||
In order for the property <code class="literal">spring.application.name</code> to be used as the application’s context ID you
|
||||
must set it in <code class="literal">bootstrap.[properties | yml]</code>.</p><p>You can disable the bootstrap process completely by setting <code class="literal">spring.cloud.bootstrap.enabled=false</code> (for example, in system properties).</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_application_context_hierarchies" href="#_application_context_hierarchies"></a>1.2 Application Context Hierarchies</h2></div></div></div><p>If you build an application context from <code class="literal">SpringApplication</code> or <code class="literal">SpringApplicationBuilder</code>, then the Bootstrap context is added as a parent to that context.
|
||||
It is a feature of Spring that child contexts inherit property sources and profiles from their parent, so the <span class="quote">“<span class="quote">main</span>”</span> application context contains additional property sources, compared to building the same context without Spring Cloud Config.
|
||||
The additional property sources are:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><span class="quote">“<span class="quote">bootstrap</span>”</span>: If any <code class="literal">PropertySourceLocators</code> are found in the Bootstrap context and if they have non-empty properties, an optional <code class="literal">CompositePropertySource</code> appears with high priority.
|
||||
An example would be properties from the Spring Cloud Config Server.
|
||||
See <span class="quote">“<span class="quote"><a class="xref" href="multi__spring_cloud_context_application_context_services.html#customizing-bootstrap-property-sources" title="1.6 Customizing the Bootstrap Property Sources">Section 1.6, “Customizing the Bootstrap Property Sources”</a></span>”</span> for instructions on how to customize the contents of this property source.</li><li class="listitem"><span class="quote">“<span class="quote">applicationConfig: [classpath:bootstrap.yml]</span>”</span> (and related files if Spring profiles are active): If you have a <code class="literal">bootstrap.yml</code> (or <code class="literal">.properties</code>), those properties are used to configure the Bootstrap context.
|
||||
Then they get added to the child context when its parent is set.
|
||||
They have lower precedence than the <code class="literal">application.yml</code> (or <code class="literal">.properties</code>) and any other property sources that are added to the child as a normal part of the process of creating a Spring Boot application.
|
||||
See <span class="quote">“<span class="quote"><a class="xref" href="multi__spring_cloud_context_application_context_services.html#customizing-bootstrap-properties" title="1.3 Changing the Location of Bootstrap Properties">Section 1.3, “Changing the Location of Bootstrap Properties”</a></span>”</span> for instructions on how to customize the contents of these property sources.</li></ul></div><p>Because of the ordering rules of property sources, the <span class="quote">“<span class="quote">bootstrap</span>”</span> entries take precedence.
|
||||
However, note that these do not contain any data from <code class="literal">bootstrap.yml</code>, which has very low precedence but can be used to set defaults.</p><p>You can extend the context hierarchy by setting the parent context of any <code class="literal">ApplicationContext</code> you create — for example, by using its own interface or with the <code class="literal">SpringApplicationBuilder</code> convenience methods (<code class="literal">parent()</code>, <code class="literal">child()</code> and <code class="literal">sibling()</code>).
|
||||
The bootstrap context is the parent of the most senior ancestor that you create yourself.
|
||||
Every context in the hierarchy has its own <span class="quote">“<span class="quote">bootstrap</span>”</span> (possibly empty) property source to avoid promoting values inadvertently from parents down to their descendants.
|
||||
If there is a Config Server, every context in the hierarchy can also (in principle) have a different <code class="literal">spring.application.name</code> and, hence, a different remote property source.
|
||||
Normal Spring application context behavior rules apply to property resolution: properties from a child context override those in
|
||||
the parent, by name and also by property source name.
|
||||
(If the child has a property source with the same name as the parent, the value from the parent is not included in the child).</p><p>Note that the <code class="literal">SpringApplicationBuilder</code> lets you share an <code class="literal">Environment</code> amongst the whole hierarchy, but that is not the default.
|
||||
Thus, sibling contexts, in particular, do not need to have the same profiles or property sources, even though they may share common values with their parent.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="customizing-bootstrap-properties" href="#customizing-bootstrap-properties"></a>1.3 Changing the Location of Bootstrap Properties</h2></div></div></div><p>The <code class="literal">bootstrap.yml</code> (or <code class="literal">.properties</code>) location can be specified by setting <code class="literal">spring.cloud.bootstrap.name</code> (default: <code class="literal">bootstrap</code>) or <code class="literal">spring.cloud.bootstrap.location</code> (default: empty) — for example, in System properties.
|
||||
Those properties behave like the <code class="literal">spring.config.*</code> variants with the same name.
|
||||
In fact, they are used to set up the bootstrap <code class="literal">ApplicationContext</code> by setting those properties in its <code class="literal">Environment</code>.
|
||||
If there is an active profile (from <code class="literal">spring.profiles.active</code> or through the <code class="literal">Environment</code> API in the
|
||||
context you are building), properties in that profile get loaded as well, the same as in a regular Spring Boot app — for example, from <code class="literal">bootstrap-development.properties</code> for a <code class="literal">development</code> profile.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="overriding-bootstrap-properties" href="#overriding-bootstrap-properties"></a>1.4 Overriding the Values of Remote Properties</h2></div></div></div><p>The property sources that are added to your application by the bootstrap context are often <span class="quote">“<span class="quote">remote</span>”</span> (from example, from Spring Cloud Config Server).
|
||||
By default, they cannot be overridden locally.
|
||||
If you want to let your applications override the remote properties with their own System properties or config files, the remote property source has to grant it permission by setting <code class="literal">spring.cloud.config.allowOverride=true</code> (it does not work to set this locally).
|
||||
Once that flag is set, two finer-grained settings control the location of the remote properties in relation to system properties and the application’s local configuration:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">spring.cloud.config.overrideNone=true</code>: Override from any local property source.</li><li class="listitem"><code class="literal">spring.cloud.config.overrideSystemProperties=false</code>: Only system properties, command line arguments, and environment variables (but not the local config files) should override the remote settings.</li></ul></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_customizing_the_bootstrap_configuration" href="#_customizing_the_bootstrap_configuration"></a>1.5 Customizing the Bootstrap Configuration</h2></div></div></div><p>The bootstrap context can be set to do anything you like by adding entries to <code class="literal">/META-INF/spring.factories</code> under a key named <code class="literal">org.springframework.cloud.bootstrap.BootstrapConfiguration</code>.
|
||||
This holds a comma-separated list of Spring <code class="literal">@Configuration</code> classes that are used to create the context.
|
||||
Any beans that you want to be available to the main application context for autowiring can be created here.
|
||||
There is a special contract for <code class="literal">@Beans</code> of type <code class="literal">ApplicationContextInitializer</code>.
|
||||
If you want to control the startup sequence, classes can be marked with an <code class="literal">@Order</code> annotation (the default order is <code class="literal">last</code>).</p><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>When adding custom <code class="literal">BootstrapConfiguration</code>, be careful that the classes you add are not <code class="literal">@ComponentScanned</code> by mistake into your <span class="quote">“<span class="quote">main</span>”</span> application context, where they might not be needed.
|
||||
Use a separate package name for boot configuration classes and make sure that name is not already covered by your <code class="literal">@ComponentScan</code> or <code class="literal">@SpringBootApplication</code> annotated configuration classes.</p></td></tr></table></div><p>The bootstrap process ends by injecting initializers into the main <code class="literal">SpringApplication</code> instance (which is the normal Spring Boot startup sequence, whether it is running as a standalone application or deployed in an application server).
|
||||
First, a bootstrap context is created from the classes found in <code class="literal">spring.factories</code>.
|
||||
Then, all <code class="literal">@Beans</code> of type <code class="literal">ApplicationContextInitializer</code> are added to the main <code class="literal">SpringApplication</code> before it is started.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="customizing-bootstrap-property-sources" href="#customizing-bootstrap-property-sources"></a>1.6 Customizing the Bootstrap Property Sources</h2></div></div></div><p>The default property source for external configuration added by the bootstrap process is the Spring Cloud Config Server, but you can add additional sources by adding beans of type <code class="literal">PropertySourceLocator</code> to the bootstrap context (through <code class="literal">spring.factories</code>).
|
||||
For instance, you can insert additional properties from a different server or from a database.</p><p>As an example, consider the following custom locator:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<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> CustomPropertySourceLocator <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">implements</span> PropertySourceLocator {
|
||||
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> PropertySource<?> locate(Environment environment) {
|
||||
<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> MapPropertySource(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"customProperty"</span>,
|
||||
Collections.<String, Object>singletonMap(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"property.from.sample.custom.source"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"worked as intended"</span>));
|
||||
}
|
||||
|
||||
}</pre><p>The <code class="literal">Environment</code> that is passed in is the one for the <code class="literal">ApplicationContext</code> about to be created — in other words, the one for which we supply additional property sources for.
|
||||
It already has its normal Spring Boot-provided property sources, so you can use those to locate a property source specific to this <code class="literal">Environment</code> (for example, by keying it on <code class="literal">spring.application.name</code>, as is done in the default Spring Cloud Config Server property source locator).</p><p>If you create a jar with this class in it and then add a <code class="literal">META-INF/spring.factories</code> containing the following, the <code class="literal">customProperty</code> <code class="literal">PropertySource</code> appears in any application that includes that jar on its classpath:</p><pre class="screen">org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_logging_configuration" href="#_logging_configuration"></a>1.7 Logging Configuration</h2></div></div></div><p>If you are going to use Spring Boot to configure log settings than
|
||||
you should place this configuration in `bootstrap.[yml | properties]
|
||||
if you would like it to apply to all events.</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>For Spring Cloud to initialize logging configuration properly you cannot use a custom prefix. For example,
|
||||
using <code class="literal">custom.loggin.logpath</code> will not be recognized by Spring Cloud when initializing the logging system.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_environment_changes" href="#_environment_changes"></a>1.8 Environment Changes</h2></div></div></div><p>The application listens for an <code class="literal">EnvironmentChangeEvent</code> and reacts to the change in a couple of standard ways (additional <code class="literal">ApplicationListeners</code> can be added as <code class="literal">@Beans</code> by the user in the normal way).
|
||||
When an <code class="literal">EnvironmentChangeEvent</code> is observed, it has a list of key values that have changed, and the application uses those to:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Re-bind any <code class="literal">@ConfigurationProperties</code> beans in the context</li><li class="listitem">Set the logger levels for any properties in <code class="literal">logging.level.*</code></li></ul></div><p>Note that the Config Client does not, by default, poll for changes in the <code class="literal">Environment</code>.
|
||||
Generally, we would not recommend that approach for detecting changes (although you could set it up with a
|
||||
<code class="literal">@Scheduled</code> annotation).
|
||||
If you have a scaled-out client application, it is better to broadcast the <code class="literal">EnvironmentChangeEvent</code> to all the instances instead of having them polling for changes (for example, by using the <a class="link" href="https://github.com/spring-cloud/spring-cloud-bus" target="_top">Spring Cloud Bus</a>).</p><p>The <code class="literal">EnvironmentChangeEvent</code> covers a large class of refresh use cases, as long as you can actually make a change to the <code class="literal">Environment</code> and publish the event.
|
||||
Note that those APIs are public and part of core Spring).
|
||||
You can verify that the changes are bound to <code class="literal">@ConfigurationProperties</code> beans by visiting the <code class="literal">/configprops</code> endpoint (a normal Spring Boot Actuator feature).
|
||||
For instance, a <code class="literal">DataSource</code> can have its <code class="literal">maxPoolSize</code> changed at runtime (the default <code class="literal">DataSource</code> created by Spring Boot is an <code class="literal">@ConfigurationProperties</code> bean) and grow capacity dynamically.
|
||||
Re-binding <code class="literal">@ConfigurationProperties</code> does not cover another large class of use cases, where you need more control over the refresh and where you need a change to be atomic over the whole <code class="literal">ApplicationContext</code>.
|
||||
To address those concerns, we have <code class="literal">@RefreshScope</code>.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="refresh-scope" href="#refresh-scope"></a>1.9 Refresh Scope</h2></div></div></div><p>When there is a configuration change, a Spring <code class="literal">@Bean</code> that is marked as <code class="literal">@RefreshScope</code> gets special treatment.
|
||||
This feature addresses the problem of stateful beans that only get their configuration injected when they are initialized.
|
||||
For instance, if a <code class="literal">DataSource</code> has open connections when the database URL is changed via the <code class="literal">Environment</code>, you probably want the holders of those connections to be able to complete what they are doing.
|
||||
Then, the next time something borrows a connection from the pool, it gets one with the new URL.</p><p>Sometimes, it might even be mandatory to apply the <code class="literal">@RefreshScope</code>
|
||||
annotation on some beans which can be only initialized once. If a bean
|
||||
is "immutable", you will have to either annotate the bean with <code class="literal">@RefreshScope</code>
|
||||
or specify the classname under the property key
|
||||
<code class="literal">spring.cloud.refresh.extra-refreshable</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>If you create a <code class="literal">DataSource</code> bean yourself and the implementation is a <code class="literal">HikariDataSource</code>, return the
|
||||
most specific type, in this case <code class="literal">HikariDataSource</code>. Otherwise, you will need to set
|
||||
<code class="literal">spring.cloud.refresh.extra-refreshable=javax.sql.DataSource</code>.</p></td></tr></table></div><p>Refresh scope beans are lazy proxies that initialize when they are used (that is, when a method is called), and the scope acts as a cache of initialized values.
|
||||
To force a bean to re-initialize on the next method call, you must invalidate its cache entry.</p><p>The <code class="literal">RefreshScope</code> is a bean in the context and has a public <code class="literal">refreshAll()</code> method to refresh all beans in the scope by clearing the target cache.
|
||||
The <code class="literal">/refresh</code> endpoint exposes this functionality (over HTTP or JMX).
|
||||
To refresh an individual bean by name, there is also a <code class="literal">refresh(String)</code> method.</p><p>To expose the <code class="literal">/refresh</code> endpoint, you need to add following configuration to your application:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">management</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> endpoints</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> web</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> exposure</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> include</span>: refresh</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><code class="literal">@RefreshScope</code> works (technically) on an <code class="literal">@Configuration</code> class, but it might lead to surprising behavior.
|
||||
For example, it does not mean that all the <code class="literal">@Beans</code> defined in that class are themselves in <code class="literal">@RefreshScope</code>.
|
||||
Specifically, anything that depends on those beans cannot rely on them being updated when a refresh is initiated, unless it is itself in <code class="literal">@RefreshScope</code>.
|
||||
In that case, it is rebuilt on a refresh and its dependencies are re-injected. At that point, they are re-initialized from the refreshed <code class="literal">@Configuration</code>).</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_encryption_and_decryption" href="#_encryption_and_decryption"></a>1.10 Encryption and Decryption</h2></div></div></div><p>Spring Cloud has an <code class="literal">Environment</code> pre-processor for decrypting property values locally.
|
||||
It follows the same rules as the Config Server and has the same external configuration through <code class="literal">encrypt.*</code>.
|
||||
Thus, you can use encrypted values in the form of <code class="literal">{cipher}*</code> and, as long as there is a valid key, they are decrypted before the main application context gets the <code class="literal">Environment</code> settings.
|
||||
To use the encryption features in an application, you need to include Spring Security RSA in your classpath (Maven co-ordinates: "org.springframework.security:spring-security-rsa"), and you also need the full strength JCE extensions in your JVM.</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="https://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="https://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="https://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><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_endpoints" href="#_endpoints"></a>1.11 Endpoints</h2></div></div></div><p>For a Spring Boot Actuator application, some additional management endpoints are available. You can use:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">POST</code> to <code class="literal">/actuator/env</code> to update the <code class="literal">Environment</code> and rebind <code class="literal">@ConfigurationProperties</code> and log levels.</li><li class="listitem"><code class="literal">/actuator/refresh</code> to re-load the boot strap context and refresh the <code class="literal">@RefreshScope</code> beans.</li><li class="listitem"><code class="literal">/actuator/restart</code> to close the <code class="literal">ApplicationContext</code> and restart it (disabled by default).</li><li class="listitem"><code class="literal">/actuator/pause</code> and <code class="literal">/actuator/resume</code> for calling the <code class="literal">Lifecycle</code> methods (<code class="literal">stop()</code> and <code class="literal">start()</code> on the <code class="literal">ApplicationContext</code>).</li></ul></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>If you disable the <code class="literal">/actuator/restart</code> endpoint then the <code class="literal">/actuator/pause</code> and <code class="literal">/actuator/resume</code> endpoints
|
||||
will also be disabled since they are just a special case of <code class="literal">/actuator/restart</code>.</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_pr01.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_commons_common_abstractions.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-commons.html">Home</a></td><td width="40%" align="right" valign="top"> 2. Spring Cloud Commons: Common Abstractions</td></tr></table></div></body></html>
|
||||
9
spring-cloud-commons/2.1.3.RELEASE/multi/multi_pr01.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title></title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"><link rel="home" href="multi_spring-cloud-commons.html" title="Cloud Native Applications"><link rel="up" href="multi_spring-cloud-commons.html" title="Cloud Native Applications"><link rel="prev" href="multi_spring-cloud-commons.html" title="Cloud Native Applications"><link rel="next" href="multi__spring_cloud_context_application_context_services.html" title="1. 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"></th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_spring-cloud-commons.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="preface"><div class="titlepage"><div><div><h1 class="title"><a name="d0e9" href="#d0e9"></a></h1></div></div></div><p><a class="link" href="https://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="https://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="https://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="https://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="https://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="https://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 class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_spring-cloud-commons.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">Cloud Native Applications </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud-commons.html">Home</a></td><td width="40%" align="right" valign="top"> 1. Spring Cloud Context: Application Context Services</td></tr></table></div></body></html>
|
||||
35
spring-cloud-commons/2.1.3.RELEASE/single/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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
@IMPORT url("manual.css");
|
||||
|
||||
body {
|
||||
background: url("../images/background.png") no-repeat center top;
|
||||
}
|
||||
|
||||
342
spring-cloud-commons/2.1.3.RELEASE/single/css/manual.css
Normal file
@@ -0,0 +1,342 @@
|
||||
@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
spring-cloud-commons/2.1.3.RELEASE/single/images/background.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/single/images/callouts/1.png
Normal file
|
After Width: | Height: | Size: 329 B |
BIN
spring-cloud-commons/2.1.3.RELEASE/single/images/callouts/2.png
Normal file
|
After Width: | Height: | Size: 353 B |
BIN
spring-cloud-commons/2.1.3.RELEASE/single/images/callouts/3.png
Normal file
|
After Width: | Height: | Size: 350 B |
BIN
spring-cloud-commons/2.1.3.RELEASE/single/images/caution.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/single/images/important.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/single/images/logo.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/single/images/note.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
spring-cloud-commons/2.1.3.RELEASE/single/images/tip.png
Normal file
|
After Width: | Height: | Size: 931 B |
BIN
spring-cloud-commons/2.1.3.RELEASE/single/images/warning.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
117
spring-cloud-commons/2.1.3.RELEASE/spring-cloud-commons.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.7.1">
|
||||
<title>spring-cloud-commons</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-commons</h1>
|
||||
</div>
|
||||
<div id="content">
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>2.1.3.RELEASE</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-commons.html">Single HTML</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="multi/multi_spring-cloud-commons.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>
|
||||
744
spring-cloud-commons/2.1.3.RELEASE/spring-cloud-commons.xml
Normal file
@@ -0,0 +1,744 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?asciidoc-toc?>
|
||||
<?asciidoc-numbered?>
|
||||
<book xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" version="5.0" xml:lang="en">
|
||||
<info>
|
||||
<title>Cloud Native Applications</title>
|
||||
<date>2019-09-09</date>
|
||||
</info>
|
||||
<preface>
|
||||
<title></title>
|
||||
<simpara><link xl:href="https://pivotal.io/platform-as-a-service/migrating-to-cloud-native-application-architectures-ebook">Cloud Native</link> 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 <link xl:href="https://12factor.net/">12-factor Applications</link>, 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.</simpara>
|
||||
<simpara>Many of those features are covered by <link xl:href="https://projects.spring.io/spring-boot">Spring Boot</link>, 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 <literal>ApplicationContext</literal> 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).</simpara>
|
||||
<simpara>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:</simpara>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<simpara><link xl:href="https://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html">Java 6 JCE</link></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><link xl:href="https://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html">Java 7 JCE</link></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><link xl:href="https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html">Java 8 JCE</link></simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<simpara>Extract the files into the JDK/jre/lib/security folder for whichever version of JRE/JDK x64/x86 you use.</simpara>
|
||||
<note>
|
||||
<simpara>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 <link xl:href="https://github.com/spring-cloud/spring-cloud-commons/tree/master/docs/src/main/asciidoc">github</link>.</simpara>
|
||||
</note>
|
||||
</preface>
|
||||
<chapter xml:id="_spring_cloud_context_application_context_services">
|
||||
<title>Spring Cloud Context: Application Context Services</title>
|
||||
<simpara>Spring Boot has an opinionated view of how to build an application with Spring.
|
||||
For instance, it has conventional locations for common configuration files and has endpoints for common management and monitoring tasks.
|
||||
Spring Cloud builds on top of that and adds a few features that probably all components in a system would use or occasionally need.</simpara>
|
||||
<section xml:id="_the_bootstrap_application_context">
|
||||
<title>The Bootstrap Application Context</title>
|
||||
<simpara>A Spring Cloud application operates by creating a <quote>bootstrap</quote> context, which is a parent context for the main application.
|
||||
It is responsible for loading configuration properties from the external sources and for decrypting properties in the local external configuration files.
|
||||
The two contexts share an <literal>Environment</literal>, which is the source of external properties for any Spring application.
|
||||
By default, bootstrap properties (not <literal>bootstrap.properties</literal> but properties that are loaded during the bootstrap phase) are added with high precedence, so they cannot be overridden by local configuration.</simpara>
|
||||
<simpara>The bootstrap context uses a different convention for locating external configuration than the main application context.
|
||||
Instead of <literal>application.yml</literal> (or <literal>.properties</literal>), you can use <literal>bootstrap.yml</literal>, keeping the external configuration for bootstrap and main context
|
||||
nicely separate.
|
||||
The following listing shows an example:</simpara>
|
||||
<formalpara>
|
||||
<title>bootstrap.yml</title>
|
||||
<para>
|
||||
<screen>spring:
|
||||
application:
|
||||
name: foo
|
||||
cloud:
|
||||
config:
|
||||
uri: ${SPRING_CONFIG_URI:http://localhost:8888}</screen>
|
||||
</para>
|
||||
</formalpara>
|
||||
<simpara>If your application needs any application-specific configuration from the server, it is a good idea to set the <literal>spring.application.name</literal> (in <literal>bootstrap.yml</literal> or <literal>application.yml</literal>).
|
||||
In order for the property <literal>spring.application.name</literal> to be used as the application’s context ID you
|
||||
must set it in <literal>bootstrap.[properties | yml]</literal>.</simpara>
|
||||
<simpara>You can disable the bootstrap process completely by setting <literal>spring.cloud.bootstrap.enabled=false</literal> (for example, in system properties).</simpara>
|
||||
</section>
|
||||
<section xml:id="_application_context_hierarchies">
|
||||
<title>Application Context Hierarchies</title>
|
||||
<simpara>If you build an application context from <literal>SpringApplication</literal> or <literal>SpringApplicationBuilder</literal>, then the Bootstrap context is added as a parent to that context.
|
||||
It is a feature of Spring that child contexts inherit property sources and profiles from their parent, so the <quote>main</quote> application context contains additional property sources, compared to building the same context without Spring Cloud Config.
|
||||
The additional property sources are:</simpara>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<simpara><quote>bootstrap</quote>: If any <literal>PropertySourceLocators</literal> are found in the Bootstrap context and if they have non-empty properties, an optional <literal>CompositePropertySource</literal> appears with high priority.
|
||||
An example would be properties from the Spring Cloud Config Server.
|
||||
See <quote><xref linkend="customizing-bootstrap-property-sources"/></quote> for instructions on how to customize the contents of this property source.</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><quote>applicationConfig: [classpath:bootstrap.yml]</quote> (and related files if Spring profiles are active): If you have a <literal>bootstrap.yml</literal> (or <literal>.properties</literal>), those properties are used to configure the Bootstrap context.
|
||||
Then they get added to the child context when its parent is set.
|
||||
They have lower precedence than the <literal>application.yml</literal> (or <literal>.properties</literal>) and any other property sources that are added to the child as a normal part of the process of creating a Spring Boot application.
|
||||
See <quote><xref linkend="customizing-bootstrap-properties"/></quote> for instructions on how to customize the contents of these property sources.</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<simpara>Because of the ordering rules of property sources, the <quote>bootstrap</quote> entries take precedence.
|
||||
However, note that these do not contain any data from <literal>bootstrap.yml</literal>, which has very low precedence but can be used to set defaults.</simpara>
|
||||
<simpara>You can extend the context hierarchy by setting the parent context of any <literal>ApplicationContext</literal> you create — for example, by using its own interface or with the <literal>SpringApplicationBuilder</literal> convenience methods (<literal>parent()</literal>, <literal>child()</literal> and <literal>sibling()</literal>).
|
||||
The bootstrap context is the parent of the most senior ancestor that you create yourself.
|
||||
Every context in the hierarchy has its own <quote>bootstrap</quote> (possibly empty) property source to avoid promoting values inadvertently from parents down to their descendants.
|
||||
If there is a Config Server, every context in the hierarchy can also (in principle) have a different <literal>spring.application.name</literal> and, hence, a different remote property source.
|
||||
Normal Spring application context behavior rules apply to property resolution: properties from a child context override those in
|
||||
the parent, by name and also by property source name.
|
||||
(If the child has a property source with the same name as the parent, the value from the parent is not included in the child).</simpara>
|
||||
<simpara>Note that the <literal>SpringApplicationBuilder</literal> lets you share an <literal>Environment</literal> amongst the whole hierarchy, but that is not the default.
|
||||
Thus, sibling contexts, in particular, do not need to have the same profiles or property sources, even though they may share common values with their parent.</simpara>
|
||||
</section>
|
||||
<section xml:id="customizing-bootstrap-properties">
|
||||
<title>Changing the Location of Bootstrap Properties</title>
|
||||
<simpara>The <literal>bootstrap.yml</literal> (or <literal>.properties</literal>) location can be specified by setting <literal>spring.cloud.bootstrap.name</literal> (default: <literal>bootstrap</literal>) or <literal>spring.cloud.bootstrap.location</literal> (default: empty) — for example, in System properties.
|
||||
Those properties behave like the <literal>spring.config.*</literal> variants with the same name.
|
||||
In fact, they are used to set up the bootstrap <literal>ApplicationContext</literal> by setting those properties in its <literal>Environment</literal>.
|
||||
If there is an active profile (from <literal>spring.profiles.active</literal> or through the <literal>Environment</literal> API in the
|
||||
context you are building), properties in that profile get loaded as well, the same as in a regular Spring Boot app — for example, from <literal>bootstrap-development.properties</literal> for a <literal>development</literal> profile.</simpara>
|
||||
</section>
|
||||
<section xml:id="overriding-bootstrap-properties">
|
||||
<title>Overriding the Values of Remote Properties</title>
|
||||
<simpara>The property sources that are added to your application by the bootstrap context are often <quote>remote</quote> (from example, from Spring Cloud Config Server).
|
||||
By default, they cannot be overridden locally.
|
||||
If you want to let your applications override the remote properties with their own System properties or config files, the remote property source has to grant it permission by setting <literal>spring.cloud.config.allowOverride=true</literal> (it does not work to set this locally).
|
||||
Once that flag is set, two finer-grained settings control the location of the remote properties in relation to system properties and the application’s local configuration:</simpara>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<simpara><literal>spring.cloud.config.overrideNone=true</literal>: Override from any local property source.</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>spring.cloud.config.overrideSystemProperties=false</literal>: Only system properties, command line arguments, and environment variables (but not the local config files) should override the remote settings.</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
<section xml:id="_customizing_the_bootstrap_configuration">
|
||||
<title>Customizing the Bootstrap Configuration</title>
|
||||
<simpara>The bootstrap context can be set to do anything you like by adding entries to <literal>/META-INF/spring.factories</literal> under a key named <literal>org.springframework.cloud.bootstrap.BootstrapConfiguration</literal>.
|
||||
This holds a comma-separated list of Spring <literal>@Configuration</literal> classes that are used to create the context.
|
||||
Any beans that you want to be available to the main application context for autowiring can be created here.
|
||||
There is a special contract for <literal>@Beans</literal> of type <literal>ApplicationContextInitializer</literal>.
|
||||
If you want to control the startup sequence, classes can be marked with an <literal>@Order</literal> annotation (the default order is <literal>last</literal>).</simpara>
|
||||
<warning>
|
||||
<simpara>When adding custom <literal>BootstrapConfiguration</literal>, be careful that the classes you add are not <literal>@ComponentScanned</literal> by mistake into your <quote>main</quote> application context, where they might not be needed.
|
||||
Use a separate package name for boot configuration classes and make sure that name is not already covered by your <literal>@ComponentScan</literal> or <literal>@SpringBootApplication</literal> annotated configuration classes.</simpara>
|
||||
</warning>
|
||||
<simpara>The bootstrap process ends by injecting initializers into the main <literal>SpringApplication</literal> instance (which is the normal Spring Boot startup sequence, whether it is running as a standalone application or deployed in an application server).
|
||||
First, a bootstrap context is created from the classes found in <literal>spring.factories</literal>.
|
||||
Then, all <literal>@Beans</literal> of type <literal>ApplicationContextInitializer</literal> are added to the main <literal>SpringApplication</literal> before it is started.</simpara>
|
||||
</section>
|
||||
<section xml:id="customizing-bootstrap-property-sources">
|
||||
<title>Customizing the Bootstrap Property Sources</title>
|
||||
<simpara>The default property source for external configuration added by the bootstrap process is the Spring Cloud Config Server, but you can add additional sources by adding beans of type <literal>PropertySourceLocator</literal> to the bootstrap context (through <literal>spring.factories</literal>).
|
||||
For instance, you can insert additional properties from a different server or from a database.</simpara>
|
||||
<simpara>As an example, consider the following custom locator:</simpara>
|
||||
<programlisting language="java" linenumbering="unnumbered">@Configuration
|
||||
public class CustomPropertySourceLocator implements PropertySourceLocator {
|
||||
|
||||
@Override
|
||||
public PropertySource<?> locate(Environment environment) {
|
||||
return new MapPropertySource("customProperty",
|
||||
Collections.<String, Object>singletonMap("property.from.sample.custom.source", "worked as intended"));
|
||||
}
|
||||
|
||||
}</programlisting>
|
||||
<simpara>The <literal>Environment</literal> that is passed in is the one for the <literal>ApplicationContext</literal> about to be created — in other words, the one for which we supply additional property sources for.
|
||||
It already has its normal Spring Boot-provided property sources, so you can use those to locate a property source specific to this <literal>Environment</literal> (for example, by keying it on <literal>spring.application.name</literal>, as is done in the default Spring Cloud Config Server property source locator).</simpara>
|
||||
<simpara>If you create a jar with this class in it and then add a <literal>META-INF/spring.factories</literal> containing the following, the <literal>customProperty</literal> <literal>PropertySource</literal> appears in any application that includes that jar on its classpath:</simpara>
|
||||
<screen>org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator</screen>
|
||||
</section>
|
||||
<section xml:id="_logging_configuration">
|
||||
<title>Logging Configuration</title>
|
||||
<simpara>If you are going to use Spring Boot to configure log settings than
|
||||
you should place this configuration in `bootstrap.[yml | properties]
|
||||
if you would like it to apply to all events.</simpara>
|
||||
<note>
|
||||
<simpara>For Spring Cloud to initialize logging configuration properly you cannot use a custom prefix. For example,
|
||||
using <literal>custom.loggin.logpath</literal> will not be recognized by Spring Cloud when initializing the logging system.</simpara>
|
||||
</note>
|
||||
</section>
|
||||
<section xml:id="_environment_changes">
|
||||
<title>Environment Changes</title>
|
||||
<simpara>The application listens for an <literal>EnvironmentChangeEvent</literal> and reacts to the change in a couple of standard ways (additional <literal>ApplicationListeners</literal> can be added as <literal>@Beans</literal> by the user in the normal way).
|
||||
When an <literal>EnvironmentChangeEvent</literal> is observed, it has a list of key values that have changed, and the application uses those to:</simpara>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<simpara>Re-bind any <literal>@ConfigurationProperties</literal> beans in the context</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara>Set the logger levels for any properties in <literal>logging.level.*</literal></simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<simpara>Note that the Config Client does not, by default, poll for changes in the <literal>Environment</literal>.
|
||||
Generally, we would not recommend that approach for detecting changes (although you could set it up with a
|
||||
<literal>@Scheduled</literal> annotation).
|
||||
If you have a scaled-out client application, it is better to broadcast the <literal>EnvironmentChangeEvent</literal> to all the instances instead of having them polling for changes (for example, by using the <link xl:href="https://github.com/spring-cloud/spring-cloud-bus">Spring Cloud Bus</link>).</simpara>
|
||||
<simpara>The <literal>EnvironmentChangeEvent</literal> covers a large class of refresh use cases, as long as you can actually make a change to the <literal>Environment</literal> and publish the event.
|
||||
Note that those APIs are public and part of core Spring).
|
||||
You can verify that the changes are bound to <literal>@ConfigurationProperties</literal> beans by visiting the <literal>/configprops</literal> endpoint (a normal Spring Boot Actuator feature).
|
||||
For instance, a <literal>DataSource</literal> can have its <literal>maxPoolSize</literal> changed at runtime (the default <literal>DataSource</literal> created by Spring Boot is an <literal>@ConfigurationProperties</literal> bean) and grow capacity dynamically.
|
||||
Re-binding <literal>@ConfigurationProperties</literal> does not cover another large class of use cases, where you need more control over the refresh and where you need a change to be atomic over the whole <literal>ApplicationContext</literal>.
|
||||
To address those concerns, we have <literal>@RefreshScope</literal>.</simpara>
|
||||
</section>
|
||||
<section xml:id="refresh-scope">
|
||||
<title>Refresh Scope</title>
|
||||
<simpara>When there is a configuration change, a Spring <literal>@Bean</literal> that is marked as <literal>@RefreshScope</literal> gets special treatment.
|
||||
This feature addresses the problem of stateful beans that only get their configuration injected when they are initialized.
|
||||
For instance, if a <literal>DataSource</literal> has open connections when the database URL is changed via the <literal>Environment</literal>, you probably want the holders of those connections to be able to complete what they are doing.
|
||||
Then, the next time something borrows a connection from the pool, it gets one with the new URL.</simpara>
|
||||
<simpara>Sometimes, it might even be mandatory to apply the <literal>@RefreshScope</literal>
|
||||
annotation on some beans which can be only initialized once. If a bean
|
||||
is "immutable", you will have to either annotate the bean with <literal>@RefreshScope</literal>
|
||||
or specify the classname under the property key
|
||||
<literal>spring.cloud.refresh.extra-refreshable</literal>.</simpara>
|
||||
<important>
|
||||
<simpara>If you create a <literal>DataSource</literal> bean yourself and the implementation is a <literal>HikariDataSource</literal>, return the
|
||||
most specific type, in this case <literal>HikariDataSource</literal>. Otherwise, you will need to set
|
||||
<literal>spring.cloud.refresh.extra-refreshable=javax.sql.DataSource</literal>.</simpara>
|
||||
</important>
|
||||
<simpara>Refresh scope beans are lazy proxies that initialize when they are used (that is, when a method is called), and the scope acts as a cache of initialized values.
|
||||
To force a bean to re-initialize on the next method call, you must invalidate its cache entry.</simpara>
|
||||
<simpara>The <literal>RefreshScope</literal> is a bean in the context and has a public <literal>refreshAll()</literal> method to refresh all beans in the scope by clearing the target cache.
|
||||
The <literal>/refresh</literal> endpoint exposes this functionality (over HTTP or JMX).
|
||||
To refresh an individual bean by name, there is also a <literal>refresh(String)</literal> method.</simpara>
|
||||
<simpara>To expose the <literal>/refresh</literal> endpoint, you need to add following configuration to your application:</simpara>
|
||||
<programlisting language="yaml" linenumbering="unnumbered">management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: refresh</programlisting>
|
||||
<note>
|
||||
<simpara><literal>@RefreshScope</literal> works (technically) on an <literal>@Configuration</literal> class, but it might lead to surprising behavior.
|
||||
For example, it does not mean that all the <literal>@Beans</literal> defined in that class are themselves in <literal>@RefreshScope</literal>.
|
||||
Specifically, anything that depends on those beans cannot rely on them being updated when a refresh is initiated, unless it is itself in <literal>@RefreshScope</literal>.
|
||||
In that case, it is rebuilt on a refresh and its dependencies are re-injected. At that point, they are re-initialized from the refreshed <literal>@Configuration</literal>).</simpara>
|
||||
</note>
|
||||
</section>
|
||||
<section xml:id="_encryption_and_decryption">
|
||||
<title>Encryption and Decryption</title>
|
||||
<simpara>Spring Cloud has an <literal>Environment</literal> pre-processor for decrypting property values locally.
|
||||
It follows the same rules as the Config Server and has the same external configuration through <literal>encrypt.*</literal>.
|
||||
Thus, you can use encrypted values in the form of <literal>{cipher}*</literal> and, as long as there is a valid key, they are decrypted before the main application context gets the <literal>Environment</literal> settings.
|
||||
To use the encryption features in an application, you need to include Spring Security RSA in your classpath (Maven co-ordinates: "org.springframework.security:spring-security-rsa"), and you also need the full strength JCE extensions in your JVM.</simpara>
|
||||
<simpara>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:</simpara>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<simpara><link xl:href="https://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html">Java 6 JCE</link></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><link xl:href="https://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html">Java 7 JCE</link></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><link xl:href="https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html">Java 8 JCE</link></simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<simpara>Extract the files into the JDK/jre/lib/security folder for whichever version of JRE/JDK x64/x86 you use.</simpara>
|
||||
</section>
|
||||
<section xml:id="_endpoints">
|
||||
<title>Endpoints</title>
|
||||
<simpara>For a Spring Boot Actuator application, some additional management endpoints are available. You can use:</simpara>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<simpara><literal>POST</literal> to <literal>/actuator/env</literal> to update the <literal>Environment</literal> and rebind <literal>@ConfigurationProperties</literal> and log levels.</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>/actuator/refresh</literal> to re-load the boot strap context and refresh the <literal>@RefreshScope</literal> beans.</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>/actuator/restart</literal> to close the <literal>ApplicationContext</literal> and restart it (disabled by default).</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>/actuator/pause</literal> and <literal>/actuator/resume</literal> for calling the <literal>Lifecycle</literal> methods (<literal>stop()</literal> and <literal>start()</literal> on the <literal>ApplicationContext</literal>).</simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<note>
|
||||
<simpara>If you disable the <literal>/actuator/restart</literal> endpoint then the <literal>/actuator/pause</literal> and <literal>/actuator/resume</literal> endpoints
|
||||
will also be disabled since they are just a special case of <literal>/actuator/restart</literal>.</simpara>
|
||||
</note>
|
||||
</section>
|
||||
</chapter>
|
||||
<chapter xml:id="_spring_cloud_commons_common_abstractions">
|
||||
<title>Spring Cloud Commons: Common Abstractions</title>
|
||||
<simpara>Patterns such as service discovery, load balancing, and circuit breakers lend themselves to a common abstraction layer that can be consumed by all Spring Cloud clients, independent of the implementation (for example, discovery with Eureka or Consul).</simpara>
|
||||
<section xml:id="_enablediscoveryclient">
|
||||
<title>@EnableDiscoveryClient</title>
|
||||
<simpara>Spring Cloud Commons provides the <literal>@EnableDiscoveryClient</literal> annotation.
|
||||
This looks for implementations of the <literal>DiscoveryClient</literal> interface with <literal>META-INF/spring.factories</literal>.
|
||||
Implementations of the Discovery Client add a configuration class to <literal>spring.factories</literal> under the <literal>org.springframework.cloud.client.discovery.EnableDiscoveryClient</literal> key.
|
||||
Examples of <literal>DiscoveryClient</literal> implementations include <link xl:href="https://cloud.spring.io/spring-cloud-netflix/">Spring Cloud Netflix Eureka</link>, <link xl:href="https://cloud.spring.io/spring-cloud-consul/">Spring Cloud Consul Discovery</link>, and <link xl:href="https://cloud.spring.io/spring-cloud-zookeeper/">Spring Cloud Zookeeper Discovery</link>.</simpara>
|
||||
<simpara>By default, implementations of <literal>DiscoveryClient</literal> auto-register the local Spring Boot server with the remote discovery server.
|
||||
This behavior can be disabled by setting <literal>autoRegister=false</literal> in <literal>@EnableDiscoveryClient</literal>.</simpara>
|
||||
<note>
|
||||
<simpara><literal>@EnableDiscoveryClient</literal> is no longer required.
|
||||
You can put a <literal>DiscoveryClient</literal> implementation on the classpath to cause the Spring Boot application to register with the service discovery server.</simpara>
|
||||
</note>
|
||||
<section xml:id="_health_indicator">
|
||||
<title>Health Indicator</title>
|
||||
<simpara>Commons creates a Spring Boot <literal>HealthIndicator</literal> that <literal>DiscoveryClient</literal> implementations can participate in by implementing <literal>DiscoveryHealthIndicator</literal>.
|
||||
To disable the composite <literal>HealthIndicator</literal>, set <literal>spring.cloud.discovery.client.composite-indicator.enabled=false</literal>.
|
||||
A generic <literal>HealthIndicator</literal> based on <literal>DiscoveryClient</literal> is auto-configured (<literal>DiscoveryClientHealthIndicator</literal>).
|
||||
To disable it, set <literal>spring.cloud.discovery.client.health-indicator.enabled=false</literal>.
|
||||
To disable the description field of the <literal>DiscoveryClientHealthIndicator</literal>, set <literal>spring.cloud.discovery.client.health-indicator.include-description=false</literal>.
|
||||
Otherwise, it can bubble up as the <literal>description</literal> of the rolled up <literal>HealthIndicator</literal>.</simpara>
|
||||
</section>
|
||||
<section xml:id="_ordering_discoveryclient_instances">
|
||||
<title>Ordering <literal>DiscoveryClient</literal> instances</title>
|
||||
<simpara><literal>DiscoveryClient</literal> interface extends <literal>Ordered</literal>. This is useful when using multiple discovery
|
||||
clients, as it allows you to define the order of the returned discovery clients, similar to
|
||||
how you can order the beans loaded by a Spring application. By default, the order of any <literal>DiscoveryClient</literal> is set to
|
||||
<literal>0</literal>. If you want to set a different order for your custom <literal>DiscoveryClient</literal> implementations, you just need to override
|
||||
the <literal>getOrder()</literal> method so that it returns the value that is suitable for your setup. Apart from this, you can use
|
||||
properties to set the order of the <literal>DiscoveryClient</literal>
|
||||
implementations provided by Spring Cloud, among others <literal>ConsulDiscoveryClient</literal>, <literal>EurekaDiscoveryClient</literal> and
|
||||
<literal>ZookeeperDiscoveryClient</literal>. In order to do it, you just need to set the
|
||||
<literal>spring.cloud.{clientIdentifier}.discovery.order</literal> (or <literal>eureka.client.order</literal> for Eureka) property to the desired value.</simpara>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="_serviceregistry">
|
||||
<title>ServiceRegistry</title>
|
||||
<simpara>Commons now provides a <literal>ServiceRegistry</literal> interface that provides methods such as <literal>register(Registration)</literal> and <literal>deregister(Registration)</literal>, which let you provide custom registered services.
|
||||
<literal>Registration</literal> is a marker interface.</simpara>
|
||||
<simpara>The following example shows the <literal>ServiceRegistry</literal> in use:</simpara>
|
||||
<programlisting language="java" linenumbering="unnumbered">@Configuration
|
||||
@EnableDiscoveryClient(autoRegister=false)
|
||||
public class MyConfiguration {
|
||||
private ServiceRegistry registry;
|
||||
|
||||
public MyConfiguration(ServiceRegistry registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
// called through some external process, such as an event or a custom actuator endpoint
|
||||
public void register() {
|
||||
Registration registration = constructRegistration();
|
||||
this.registry.register(registration);
|
||||
}
|
||||
}</programlisting>
|
||||
<simpara>Each <literal>ServiceRegistry</literal> implementation has its own <literal>Registry</literal> implementation.</simpara>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<simpara><literal>ZookeeperRegistration</literal> used with <literal>ZookeeperServiceRegistry</literal></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>EurekaRegistration</literal> used with <literal>EurekaServiceRegistry</literal></simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<simpara><literal>ConsulRegistration</literal> used with <literal>ConsulServiceRegistry</literal></simpara>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<simpara>If you are using the <literal>ServiceRegistry</literal> interface, you are going to need to pass the
|
||||
correct <literal>Registry</literal> implementation for the <literal>ServiceRegistry</literal> implementation you
|
||||
are using.</simpara>
|
||||
<section xml:id="_serviceregistry_auto_registration">
|
||||
<title>ServiceRegistry Auto-Registration</title>
|
||||
<simpara>By default, the <literal>ServiceRegistry</literal> implementation auto-registers the running service.
|
||||
To disable that behavior, you can set:
|
||||
* <literal>@EnableDiscoveryClient(autoRegister=false)</literal> to permanently disable auto-registration.
|
||||
* <literal>spring.cloud.service-registry.auto-registration.enabled=false</literal> to disable the behavior through configuration.</simpara>
|
||||
<section xml:id="_serviceregistry_auto_registration_events">
|
||||
<title>ServiceRegistry Auto-Registration Events</title>
|
||||
<simpara>There are two events that will be fired when a service auto-registers. The first event, called
|
||||
<literal>InstancePreRegisteredEvent</literal>, is fired before the service is registered. The second
|
||||
event, called <literal>InstanceRegisteredEvent</literal>, is fired after the service is registered. You can register an
|
||||
<literal>ApplicationListener</literal>(s) to listen to and react to these events.</simpara>
|
||||
<note>
|
||||
<simpara>These events will not be fired if <literal>spring.cloud.service-registry.auto-registration.enabled</literal> is set to <literal>false</literal>.</simpara>
|
||||
</note>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="_service_registry_actuator_endpoint">
|
||||
<title>Service Registry Actuator Endpoint</title>
|
||||
<simpara>Spring Cloud Commons provides a <literal>/service-registry</literal> actuator endpoint.
|
||||
This endpoint relies on a <literal>Registration</literal> bean in the Spring Application Context.
|
||||
Calling <literal>/service-registry</literal> with GET returns the status of the <literal>Registration</literal>.
|
||||
Using POST to the same endpoint with a JSON body changes the status of the current <literal>Registration</literal> to the new value.
|
||||
The JSON body has to include the <literal>status</literal> field with the preferred value.
|
||||
Please see the documentation of the <literal>ServiceRegistry</literal> implementation you use for the allowed values when updating the status and the values returned for the status.
|
||||
For instance, Eureka’s supported statuses are <literal>UP</literal>, <literal>DOWN</literal>, <literal>OUT_OF_SERVICE</literal>, and <literal>UNKNOWN</literal>.</simpara>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="_spring_resttemplate_as_a_load_balancer_client">
|
||||
<title>Spring RestTemplate as a Load Balancer Client</title>
|
||||
<simpara><literal>RestTemplate</literal> can be automatically configured to use a Load-balancer client under the hood.
|
||||
To create a load-balanced <literal>RestTemplate</literal>, create a <literal>RestTemplate</literal> <literal>@Bean</literal> and use the <literal>@LoadBalanced</literal> qualifier, as shown in the following example:</simpara>
|
||||
<programlisting language="java" linenumbering="unnumbered">@Configuration
|
||||
public class MyConfiguration {
|
||||
|
||||
@LoadBalanced
|
||||
@Bean
|
||||
RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
public class MyClass {
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
public String doOtherStuff() {
|
||||
String results = restTemplate.getForObject("http://stores/stores", String.class);
|
||||
return results;
|
||||
}
|
||||
}</programlisting>
|
||||
<caution>
|
||||
<simpara>A <literal>RestTemplate</literal> bean is no longer created through auto-configuration.
|
||||
Individual applications must create it.</simpara>
|
||||
</caution>
|
||||
<simpara>The URI needs to use a virtual host name (that is, a service name, not a host name).
|
||||
The Ribbon client is used to create a full physical address.
|
||||
See <link xl:href="https://github.com/spring-cloud/spring-cloud-netflix/blob/master/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java">RibbonAutoConfiguration</link> for details of how the <literal>RestTemplate</literal> is set up.</simpara>
|
||||
<important>
|
||||
<simpara>In order to use a load-balanced <literal>RestTemplate</literal>, you need to have a load-balancer implementation in your classpath.
|
||||
The recommended implementation is <literal>BlockingLoadBalancerClient</literal>
|
||||
- add <literal>org.springframework.cloud:spring-cloud-loadbalancer</literal> in order to use it.
|
||||
The
|
||||
<literal>RibbonLoadBalancerClient</literal> also can be used, but it’s now under maintenance and we do not recommend adding it to new projects.</simpara>
|
||||
</important>
|
||||
<warning>
|
||||
<simpara>If you want to use <literal>BlockingLoadBalancerClient</literal>, make sure you do not have
|
||||
<literal>RibbonLoadBalancerClient</literal> in the project classpath, as for backward compatibility reasons, it will be used by default.</simpara>
|
||||
</warning>
|
||||
</section>
|
||||
<section xml:id="_spring_webclient_as_a_load_balancer_client">
|
||||
<title>Spring WebClient as a Load Balancer Client</title>
|
||||
<simpara><literal>WebClient</literal> can be automatically configured to use a load-balancer client.
|
||||
To create a load-balanced <literal>WebClient</literal>, create a <literal>WebClient.Builder</literal> <literal>@Bean</literal> and use the <literal>@LoadBalanced</literal> qualifier, as shown in the following example:</simpara>
|
||||
<programlisting language="java" linenumbering="unnumbered">@Configuration
|
||||
public class MyConfiguration {
|
||||
|
||||
@Bean
|
||||
@LoadBalanced
|
||||
public WebClient.Builder loadBalancedWebClientBuilder() {
|
||||
return WebClient.builder();
|
||||
}
|
||||
}
|
||||
|
||||
public class MyClass {
|
||||
@Autowired
|
||||
private WebClient.Builder webClientBuilder;
|
||||
|
||||
public Mono<String> doOtherStuff() {
|
||||
return webClientBuilder.build().get().uri("http://stores/stores")
|
||||
.retrieve().bodyToMono(String.class);
|
||||
}
|
||||
}</programlisting>
|
||||
<simpara>The URI needs to use a virtual host name (that is, a service name, not a host name).
|
||||
The Ribbon client is used to create a full physical address.</simpara>
|
||||
<important>
|
||||
<simpara>If you want to use a <literal>@LoadBalanced WebClient.Builder</literal>, you need to have a loadbalancer
|
||||
implementation in the classpath. It is recommended that you add the
|
||||
<literal>org.springframework.cloud:spring-cloud-loadbalancer</literal> dependency to your project.
|
||||
Then, <literal>ReactiveLoadBalancer</literal> will be used underneath.
|
||||
Alternatively, this functionality will also work with spring-cloud-starter-netflix-ribbon, but the request
|
||||
will be handled by a non-reactive <literal>LoadBalancerClient</literal> under the hood. Additionally,
|
||||
spring-cloud-starter-netflix-ribbon is already in maintenance mode, so we do not recommned
|
||||
adding it to new projects.</simpara>
|
||||
</important>
|
||||
<tip>
|
||||
<simpara>The <literal>ReactorLoadBalancer</literal> used underneath supports caching. If <literal>cacheManager</literal> is detected,
|
||||
cached version of <literal>ServiceInstanceSupplier</literal> will be used. If not, we will retrieve instances
|
||||
from discovery service without caching them. We recommend <link xl:href="https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-caching.html">enabling caching</link> in your project
|
||||
if you use <literal>ReactiveLoadBalancer</literal>.</simpara>
|
||||
</tip>
|
||||
<section xml:id="_retrying_failed_requests">
|
||||
<title>Retrying Failed Requests</title>
|
||||
<simpara>A load-balanced <literal>RestTemplate</literal> can be configured to retry failed requests.
|
||||
By default, this logic is disabled.
|
||||
You can enable it by adding <link xl:href="https://github.com/spring-projects/spring-retry">Spring Retry</link> to your application’s classpath.
|
||||
The load-balanced <literal>RestTemplate</literal> honors some of the Ribbon configuration values related to retrying failed requests.
|
||||
You can use <literal>client.ribbon.MaxAutoRetries</literal>, <literal>client.ribbon.MaxAutoRetriesNextServer</literal>, and <literal>client.ribbon.OkToRetryOnAllOperations</literal> properties.
|
||||
If you would like to disable the retry logic with Spring Retry on the classpath, you can set <literal>spring.cloud.loadbalancer.retry.enabled=false</literal>.
|
||||
See the <link xl:href="https://github.com/Netflix/ribbon/wiki/Getting-Started#the-properties-file-sample-clientproperties">Ribbon documentation</link> for a description of what these properties do.</simpara>
|
||||
<simpara>If you would like to implement a <literal>BackOffPolicy</literal> in your retries, you need to create a bean of type <literal>LoadBalancedRetryFactory</literal> and override the <literal>createBackOffPolicy</literal> method:</simpara>
|
||||
<programlisting language="java" linenumbering="unnumbered">@Configuration
|
||||
public class MyConfiguration {
|
||||
@Bean
|
||||
LoadBalancedRetryFactory retryFactory() {
|
||||
return new LoadBalancedRetryFactory() {
|
||||
@Override
|
||||
public BackOffPolicy createBackOffPolicy(String service) {
|
||||
return new ExponentialBackOffPolicy();
|
||||
}
|
||||
};
|
||||
}
|
||||
}</programlisting>
|
||||
<note>
|
||||
<simpara><literal>client</literal> in the preceding examples should be replaced with your Ribbon client’s name.</simpara>
|
||||
</note>
|
||||
<simpara>If you want to add one or more <literal>RetryListener</literal> implementations to your retry functionality, you need to
|
||||
create a bean of type <literal>LoadBalancedRetryListenerFactory</literal> and return the <literal>RetryListener</literal> array
|
||||
you would like to use for a given service, as shown in the following example:</simpara>
|
||||
<programlisting language="java" linenumbering="unnumbered">@Configuration
|
||||
public class MyConfiguration {
|
||||
@Bean
|
||||
LoadBalancedRetryListenerFactory retryListenerFactory() {
|
||||
return new LoadBalancedRetryListenerFactory() {
|
||||
@Override
|
||||
public RetryListener[] createRetryListeners(String service) {
|
||||
return new RetryListener[]{new RetryListener() {
|
||||
@Override
|
||||
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
|
||||
//TODO Do you business...
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
|
||||
//TODO Do you business...
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
|
||||
//TODO Do you business...
|
||||
}
|
||||
}};
|
||||
}
|
||||
};
|
||||
}
|
||||
}</programlisting>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="_multiple_resttemplate_objects">
|
||||
<title>Multiple RestTemplate objects</title>
|
||||
<simpara>If you want a <literal>RestTemplate</literal> that is not load-balanced, create a <literal>RestTemplate</literal> bean and inject it.
|
||||
To access the load-balanced <literal>RestTemplate</literal>, use the <literal>@LoadBalanced</literal> qualifier when you create your <literal>@Bean</literal>, as shown in the following example:\</simpara>
|
||||
<programlisting language="java" linenumbering="unnumbered">@Configuration
|
||||
public class MyConfiguration {
|
||||
|
||||
@LoadBalanced
|
||||
@Bean
|
||||
RestTemplate loadBalanced() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
|
||||
@Primary
|
||||
@Bean
|
||||
RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
public class MyClass {
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@Autowired
|
||||
@LoadBalanced
|
||||
private RestTemplate loadBalanced;
|
||||
|
||||
public String doOtherStuff() {
|
||||
return loadBalanced.getForObject("http://stores/stores", String.class);
|
||||
}
|
||||
|
||||
public String doStuff() {
|
||||
return restTemplate.getForObject("https://example.com", String.class);
|
||||
}
|
||||
}</programlisting>
|
||||
<important>
|
||||
<simpara>Notice the use of the <literal>@Primary</literal> annotation on the plain <literal>RestTemplate</literal> declaration in the preceding example to disambiguate the unqualified <literal>@Autowired</literal> injection.</simpara>
|
||||
</important>
|
||||
<tip>
|
||||
<simpara>If you see errors such as <literal>java.lang.IllegalArgumentException: Can not set org.springframework.web.client.RestTemplate field com.my.app.Foo.restTemplate to com.sun.proxy.$Proxy89</literal>, try injecting <literal>RestOperations</literal> or setting <literal>spring.aop.proxyTargetClass=true</literal>.</simpara>
|
||||
</tip>
|
||||
</section>
|
||||
<section xml:id="loadbalanced-webclient">
|
||||
<title>Spring WebFlux WebClient as a Load Balancer Client</title>
|
||||
<section xml:id="webflux-with-reactive-loadbalancer">
|
||||
<title>Spring WebFlux WebClient with Reactive Load Balancer</title>
|
||||
<simpara><literal>WebClient</literal> can be configured to use the <literal>ReactiveLoadBalancer</literal>.
|
||||
If you add <literal>org.springframework.cloud:spring-cloud-loadbalancer</literal> to your project,
|
||||
<literal>ReactorLoadBalancerExchangeFilterFunction</literal> is auto-configured if <literal>spring-webflux</literal> is on the classpath.
|
||||
The following example shows how to configure a <literal>WebClient</literal> to use reactive load balancer under the hood:</simpara>
|
||||
<programlisting language="java" linenumbering="unnumbered">public class MyClass {
|
||||
@Autowired
|
||||
private ReactorLoadBalancerExchangeFilterFunction lbFunction;
|
||||
|
||||
public Mono<String> doOtherStuff() {
|
||||
return WebClient.builder().baseUrl("http://stores")
|
||||
.filter(lbFunction)
|
||||
.build()
|
||||
.get()
|
||||
.uri("/stores")
|
||||
.retrieve()
|
||||
.bodyToMono(String.class);
|
||||
}
|
||||
}</programlisting>
|
||||
<simpara>The URI needs to use a virtual host name (that is, a service name, not a host name).
|
||||
The <literal>ReactorLoadBalancerClient</literal> is used to create a full physical address.</simpara>
|
||||
</section>
|
||||
<section xml:id="_spring_webflux_webclient_with_non_reactive_load_balancer_client">
|
||||
<title>Spring WebFlux WebClient with non-reactive Load Balancer Client</title>
|
||||
<simpara>If you you don’t have <literal>org.springframework.cloud:spring-cloud-loadbalancer</literal> in your project,
|
||||
but you do have spring-cloud-starter-netflix-ribbon, you can still use <literal>WebClient</literal> with <literal>LoadBalancerClient</literal>. <literal>LoadBalancerExchangeFilterFunction</literal>
|
||||
will be auto-configured if <literal>spring-webflux</literal> is on the classpath. Please note, however, that this is
|
||||
uses a non-reactive client under the hood.
|
||||
The following example shows how to configure a <literal>WebClient</literal> to use load balancer:</simpara>
|
||||
<programlisting language="java" linenumbering="unnumbered">public class MyClass {
|
||||
@Autowired
|
||||
private LoadBalancerExchangeFilterFunction lbFunction;
|
||||
|
||||
public Mono<String> doOtherStuff() {
|
||||
return WebClient.builder().baseUrl("http://stores")
|
||||
.filter(lbFunction)
|
||||
.build()
|
||||
.get()
|
||||
.uri("/stores")
|
||||
.retrieve()
|
||||
.bodyToMono(String.class);
|
||||
}
|
||||
}</programlisting>
|
||||
<simpara>The URI needs to use a virtual host name (that is, a service name, not a host name).
|
||||
The <literal>LoadBalancerClient</literal> is used to create a full physical address.</simpara>
|
||||
<simpara>WARN:
|
||||
This approach is now deprecated.
|
||||
We suggest you use <link linkend="webflux-with-reactive-loadbalancer">WebFlux with reactive Load-Balancer</link>
|
||||
instead.</simpara>
|
||||
</section>
|
||||
<section xml:id="_passing_your_own_load_balancer_client_configuration">
|
||||
<title>Passing your own Load-Balancer Client configuration</title>
|
||||
<simpara>You can also use the <literal>@LoadBalancerClient</literal> annotation to pass your own load-balancer client configuration, passing the name of the load-balancer client and the configuration class, like so:</simpara>
|
||||
<programlisting language="java" linenumbering="unnumbered">@Configuration
|
||||
@LoadBalancerClient(value = "stores", configuration = StoresLoadBalancerClientConfiguration.class)
|
||||
public class MyConfiguration {
|
||||
|
||||
@Bean
|
||||
@LoadBalanced
|
||||
public WebClient.Builder loadBalancedWebClientBuilder() {
|
||||
return WebClient.builder();
|
||||
}
|
||||
}</programlisting>
|
||||
<simpara>It is also possible to pass together multiple configurations (for more than one load-balancer client) via the <literal>@LoadBalancerClients</literal> annotation, as shown below:</simpara>
|
||||
<programlisting language="java" linenumbering="unnumbered">@Configuration
|
||||
@LoadBalancerClients({@LoadBalancerClient(value = "stores", configuration = StoresLoadBalancerClientConfiguration.class), @LoadBalancerClient(value = "customers", configuration = CustomersLoadBalancerClientConfiguration.class)})
|
||||
public class MyConfiguration {
|
||||
|
||||
@Bean
|
||||
@LoadBalanced
|
||||
public WebClient.Builder loadBalancedWebClientBuilder() {
|
||||
return WebClient.builder();
|
||||
}
|
||||
}</programlisting>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="ignore-network-interfaces">
|
||||
<title>Ignore Network Interfaces</title>
|
||||
<simpara>Sometimes, it is useful to ignore certain named network interfaces so that they can be excluded from Service Discovery registration (for example, when running in a Docker container).
|
||||
A list of regular expressions can be set to cause the desired network interfaces to be ignored.
|
||||
The following configuration ignores the <literal>docker0</literal> interface and all interfaces that start with <literal>veth</literal>:</simpara>
|
||||
<formalpara>
|
||||
<title>application.yml</title>
|
||||
<para>
|
||||
<screen>spring:
|
||||
cloud:
|
||||
inetutils:
|
||||
ignoredInterfaces:
|
||||
- docker0
|
||||
- veth.*</screen>
|
||||
</para>
|
||||
</formalpara>
|
||||
<simpara>You can also force the use of only specified network addresses by using a list of regular expressions, as shown in the following example:</simpara>
|
||||
<formalpara>
|
||||
<title>bootstrap.yml</title>
|
||||
<para>
|
||||
<screen>spring:
|
||||
cloud:
|
||||
inetutils:
|
||||
preferredNetworks:
|
||||
- 192.168
|
||||
- 10.0</screen>
|
||||
</para>
|
||||
</formalpara>
|
||||
<simpara>You can also force the use of only site-local addresses, as shown in the following example:
|
||||
.application.yml</simpara>
|
||||
<screen>spring:
|
||||
cloud:
|
||||
inetutils:
|
||||
useOnlySiteLocalInterfaces: true</screen>
|
||||
<simpara>See <link xl:href="https://docs.oracle.com/javase/8/docs/api/java/net/Inet4Address.html#isSiteLocalAddress--">Inet4Address.html.isSiteLocalAddress()</link> for more details about what constitutes a site-local address.</simpara>
|
||||
</section>
|
||||
<section xml:id="http-clients">
|
||||
<title>HTTP Client Factories</title>
|
||||
<simpara>Spring Cloud Commons provides beans for creating both Apache HTTP clients (<literal>ApacheHttpClientFactory</literal>) and OK HTTP clients (<literal>OkHttpClientFactory</literal>).
|
||||
The <literal>OkHttpClientFactory</literal> bean is created only if the OK HTTP jar is on the classpath.
|
||||
In addition, Spring Cloud Commons provides beans for creating the connection managers used by both clients: <literal>ApacheHttpClientConnectionManagerFactory</literal> for the Apache HTTP client and <literal>OkHttpClientConnectionPoolFactory</literal> for the OK HTTP client.
|
||||
If you would like to customize how the HTTP clients are created in downstream projects, you can provide your own implementation of these beans.
|
||||
In addition, if you provide a bean of type <literal>HttpClientBuilder</literal> or <literal>OkHttpClient.Builder</literal>, the default factories use these builders as the basis for the builders returned to downstream projects.
|
||||
You can also disable the creation of these beans by setting <literal>spring.cloud.httpclientfactories.apache.enabled</literal> or <literal>spring.cloud.httpclientfactories.ok.enabled</literal> to <literal>false</literal>.</simpara>
|
||||
</section>
|
||||
<section xml:id="enabled-features">
|
||||
<title>Enabled Features</title>
|
||||
<simpara>Spring Cloud Commons provides a <literal>/features</literal> actuator endpoint.
|
||||
This endpoint returns features available on the classpath and whether they are enabled.
|
||||
The information returned includes the feature type, name, version, and vendor.</simpara>
|
||||
<section xml:id="_feature_types">
|
||||
<title>Feature types</title>
|
||||
<simpara>There are two types of 'features': abstract and named.</simpara>
|
||||
<simpara>Abstract features are features where an interface or abstract class is defined and that an implementation the creates, such as <literal>DiscoveryClient</literal>, <literal>LoadBalancerClient</literal>, or <literal>LockService</literal>.
|
||||
The abstract class or interface is used to find a bean of that type in the context.
|
||||
The version displayed is <literal>bean.getClass().getPackage().getImplementationVersion()</literal>.</simpara>
|
||||
<simpara>Named features are features that do not have a particular class they implement, such as "Circuit Breaker", "API Gateway", "Spring Cloud Bus", and others. These features require a name and a bean type.</simpara>
|
||||
</section>
|
||||
<section xml:id="_declaring_features">
|
||||
<title>Declaring features</title>
|
||||
<simpara>Any module can declare any number of <literal>HasFeature</literal> beans, as shown in the following examples:</simpara>
|
||||
<programlisting language="java" linenumbering="unnumbered">@Bean
|
||||
public HasFeatures commonsFeatures() {
|
||||
return HasFeatures.abstractFeatures(DiscoveryClient.class, LoadBalancerClient.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HasFeatures consulFeatures() {
|
||||
return HasFeatures.namedFeatures(
|
||||
new NamedFeature("Spring Cloud Bus", ConsulBusAutoConfiguration.class),
|
||||
new NamedFeature("Circuit Breaker", HystrixCommandAspect.class));
|
||||
}
|
||||
|
||||
@Bean
|
||||
HasFeatures localFeatures() {
|
||||
return HasFeatures.builder()
|
||||
.abstractFeature(Foo.class)
|
||||
.namedFeature(new NamedFeature("Bar Feature", Bar.class))
|
||||
.abstractFeature(Baz.class)
|
||||
.build();
|
||||
}</programlisting>
|
||||
<simpara>Each of these beans should go in an appropriately guarded <literal>@Configuration</literal>.</simpara>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="_spring_cloud_compatibility_verification">
|
||||
<title>Spring Cloud Compatibility Verification</title>
|
||||
<simpara>Due to the fact that some users have problem with setting up Spring Cloud application, we’ve decided
|
||||
to add a compatibility verification mechanism. It will break if your current setup is not compatible
|
||||
with Spring Cloud requirements, together with a report, showing what exactly went wrong.</simpara>
|
||||
<simpara>At the moment we verify which version of Spring Boot is added to your classpath.</simpara>
|
||||
<simpara>Example of a report</simpara>
|
||||
<screen>***************************
|
||||
APPLICATION FAILED TO START
|
||||
***************************
|
||||
|
||||
Description:
|
||||
|
||||
Your project setup is incompatible with our requirements due to following reasons:
|
||||
|
||||
- Spring Boot [2.1.0.RELEASE] is not compatible with this Spring Cloud release train
|
||||
|
||||
|
||||
Action:
|
||||
|
||||
Consider applying the following actions:
|
||||
|
||||
- Change Spring Boot version to one of the following versions [1.2.x, 1.3.x] .
|
||||
You can find the latest Spring Boot versions here [https://spring.io/projects/spring-boot#learn].
|
||||
If you want to learn more about the Spring Cloud Release train compatibility, you can visit this page [https://spring.io/projects/spring-cloud#overview] and check the [Release Trains] section.</screen>
|
||||
<simpara>In order to disable this feature, set <literal>spring.cloud.compatibility-verifier.enabled</literal> to <literal>false</literal>.
|
||||
If you want to override the compatible Spring Boot versions, just set the
|
||||
<literal>spring.cloud.compatibility-verifier.compatible-boot-versions</literal> property with a comma separated list
|
||||
of compatible Spring Boot versions.</simpara>
|
||||
</section>
|
||||
</chapter>
|
||||
</book>
|
||||