diff --git a/docs/en/spring-cloud/document-overview.md b/docs/en/spring-cloud/document-overview.md
deleted file mode 100644
index c49aad44339bce14c40240b290b0bdcd2e9b7a4c..0000000000000000000000000000000000000000
--- a/docs/en/spring-cloud/document-overview.md
+++ /dev/null
@@ -1,38 +0,0 @@
-Spring Cloud Documentation
-==========
-
-
-This section provides a brief overview of Spring Cloud reference documentation. It serves
-as a map for the rest of the document.
-
-[](#documentation-about)[1. About the Documentation](#documentation-about)
-----------
-
-The Spring Cloud reference guide is available as
-
-* [Multi-page HTML](https://docs.spring.io/spring-cloud/docs/2021.0.1/reference/html)
-
-* [Single-page HTML](https://docs.spring.io/spring-cloud/docs/2021.0.1/reference/htmlsingle)
-
-* [PDF](https://docs.spring.io/spring-cloud/docs/2021.0.1/reference/pdf/spring-cloud.pdf)
-
-Copies of this document may be made for your own use and for distribution to others,
-provided that you do not charge any fee for such copies and further provided that each
-copy contains this Copyright Notice, whether distributed in print or electronically.
-
-[](#documentation-getting-help)[2. Getting Help](#documentation-getting-help)
-----------
-
-If you have trouble with Spring Cloud, we would like to help.
-
-* Learn the Spring Cloud basics. If you are
- starting out with Spring Cloud, try one of the [guides](https://spring.io/guides).
-
-* Ask a question. We monitor [stackoverflow.com](https://stackoverflow.com) for questions
- tagged with [`spring-cloud`](https://stackoverflow.com/tags/spring-cloud).
-
-* Chat with us at [Spring Cloud Gitter](https://gitter.im/spring-cloud/spring-cloud)
-
-| |All of Spring Cloud is open source, including the documentation. If you find
problems with the docs or if you want to improve them, please get involved.|
-|---|------------------------------------------------------------------------------------------------------------------------------------------------------------|
-
diff --git a/docs/en/spring-cloud/documentation-overview.md b/docs/en/spring-cloud/documentation-overview.md
new file mode 100644
index 0000000000000000000000000000000000000000..96ccf7ee7326e7e767c05eea95669562dd6ea302
--- /dev/null
+++ b/docs/en/spring-cloud/documentation-overview.md
@@ -0,0 +1,56 @@
+Spring Cloud Documentation.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\
\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Documentation
+
+Table of Contents
+
+* [1. About the Documentation](#documentation-about)
+* [2. Getting Help](#documentation-getting-help)
+
+This section provides a brief overview of Spring Cloud reference documentation. It serves
+as a map for the rest of the document.
+
+## [](#documentation-about)[1. About the Documentation](#documentation-about)
+
+The Spring Cloud reference guide is available as
+
+* [Multi-page HTML](https://docs.spring.io/spring-cloud/docs/2021.0.1/reference/html)
+
+* [Single-page HTML](https://docs.spring.io/spring-cloud/docs/2021.0.1/reference/htmlsingle)
+
+* [PDF](https://docs.spring.io/spring-cloud/docs/2021.0.1/reference/pdf/spring-cloud.pdf)
+
+Copies of this document may be made for your own use and for distribution to others,
+provided that you do not charge any fee for such copies and further provided that each
+copy contains this Copyright Notice, whether distributed in print or electronically.
+
+## [](#documentation-getting-help)[2. Getting Help](#documentation-getting-help)
+
+If you have trouble with Spring Cloud, we would like to help.
+
+* Learn the Spring Cloud basics. If you are
+ starting out with Spring Cloud, try one of the [guides](https://spring.io/guides).
+
+* Ask a question. We monitor [stackoverflow.com](https://stackoverflow.com) for questions
+ tagged with [`spring-cloud`](https://stackoverflow.com/tags/spring-cloud).
+
+* Chat with us at [Spring Cloud Gitter](https://gitter.im/spring-cloud/spring-cloud)
+
+| |All of Spring Cloud is open source, including the documentation. If you find
problems with the docs or if you want to improve them, please get involved.|
+|---|------------------------------------------------------------------------------------------------------------------------------------------------------------|
+
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/legal.md b/docs/en/spring-cloud/legal.md
index 58d7a335eba153c5c35465c6bd1e9f388ee299bd..0b555834efeb43e0df09904da740f2476ef7c770 100644
--- a/docs/en/spring-cloud/legal.md
+++ b/docs/en/spring-cloud/legal.md
@@ -1,5 +1,20 @@
-Legal
-==========
+Legal.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Legal
2021.0.1
@@ -9,3 +24,5 @@ Copies of this document may be made for your own use and for distribution to
others, provided that you do not charge any fee for such copies and further
provided that each copy contains this Copyright Notice, whether distributed in
print or electronically.
+
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-build.md b/docs/en/spring-cloud/spring-cloud-build.md
index b9470949d8bcde0a6760b8cdbf3099d7c9f1e860..07bf21415283eb491b8dbc424e074bf26448e229 100644
--- a/docs/en/spring-cloud/spring-cloud-build.md
+++ b/docs/en/spring-cloud/spring-cloud-build.md
@@ -1,12 +1,42 @@
-Spring Cloud Build
-==========
-
+Spring Cloud Build.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Build
+
+Table of Contents
+
+* [Building and Deploying](#_building_and_deploying)
+* [Contributing](#_contributing)
+ * [Sign the Contributor License Agreement](#_sign_the_contributor_license_agreement)
+ * [Code of Conduct](#_code_of_conduct)
+ * [Code Conventions and Housekeeping](#_code_conventions_and_housekeeping)
+ * [Checkstyle](#_checkstyle)
+ * [IDE setup](#_ide_setup)
+ * [Duplicate Finder](#_duplicate_finder)
+
+* [Flattening the POMs](#_flattening_the_poms)
+* [Reusing the documentation](#_reusing_the_documentation)
+* [Updating the guides](#_updating_the_guides)
+
+[![Build](https://github.com/spring-cloud/spring-cloud-build/workflows/Build/badge.svg?branch=main&style=svg)](https://github.com/spring-cloud/spring-cloud-build/actions)
Spring Cloud Build is a common utility project for Spring Cloud
to use for plugin and dependency management.
-[Building and Deploying](#_building_and_deploying)
-----------
+## [Building and Deploying](#_building_and_deploying)
To install locally:
@@ -40,8 +70,7 @@ $ mvn deploy -P central -DaltReleaseDeploymentRepository=sonatype-nexus-staging:
(the "central" profile is available for all projects in Spring Cloud and it sets up the gpg jar signing, and the repository has to be specified separately for this project because it is a parent of the starter parent which users in turn have as their own parent).
-[Contributing](#_contributing)
-----------
+## [Contributing](#_contributing)
Spring Cloud is released under the non-restrictive Apache 2.0 license,
and follows a very standard Github development process, using Github
@@ -49,7 +78,7 @@ tracker for issues and merging pull requests into master. If you want
to contribute even something trivial please do not hesitate, but
follow the guidelines below.
-### [Sign the Contributor License Agreement](#_sign_the_contributor_license_agreement) ###
+### [Sign the Contributor License Agreement](#_sign_the_contributor_license_agreement)
Before we accept a non-trivial patch or pull request we will need you to sign the[Contributor License Agreement](https://cla.pivotal.io/sign/spring).
Signing the contributor’s agreement does not grant anyone commit rights to the main
@@ -57,13 +86,13 @@ repository, but it does mean that we can accept your contributions, and you will
author credit if we do. Active contributors might be asked to join the core team, and
given the ability to merge pull requests.
-### [Code of Conduct](#_code_of_conduct) ###
+### [Code of Conduct](#_code_of_conduct)
This project adheres to the Contributor Covenant [code of
conduct](https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report
-unacceptable behavior to [[email protected]](/cdn-cgi/l/email-protection#98ebe8eaf1f6ffb5fbf7fcfdb5f7feb5fbf7f6fcedfbecd8e8f1eef7ecf9f4b6f1f7).
+unacceptable behavior to [[email protected]](/cdn-cgi/l/email-protection#dba8aba9b2b5bcf6b8b4bfbef6b4bdf6b8b4b5bfaeb8af9babb2adb4afbab7f5b2b4).
-### [Code Conventions and Housekeeping](#_code_conventions_and_housekeeping) ###
+### [Code Conventions and Housekeeping](#_code_conventions_and_housekeeping)
None of these is essential for a pull request, but they will all help. They can also be
added after the original pull request but before a merge.
@@ -93,7 +122,7 @@ added after the original pull request but before a merge.
if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit
message (where XXXX is the issue number).
-### [Checkstyle](#_checkstyle) ###
+### [Checkstyle](#_checkstyle)
Spring Cloud Build comes with a set of checkstyle rules. You can find them in the `spring-cloud-build-tools` module. The most notable files under the module are:
@@ -114,7 +143,7 @@ spring-cloud-build-tools/
|**2**| File header setup |
|**3**|Default suppression rules|
-#### [Checkstyle configuration](#_checkstyle_configuration) ####
+#### [Checkstyle configuration](#_checkstyle_configuration)
Checkstyle rules are **disabled by default**. To add checkstyle to your project just define the following properties and plugins.
@@ -181,9 +210,9 @@ $ curl https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/
$ touch .springformat
```
-### [IDE setup](#_ide_setup) ###
+### [IDE setup](#_ide_setup)
-#### [Intellij IDEA](#_intellij_idea) ####
+#### [Intellij IDEA](#_intellij_idea)
In order to setup Intellij you should import our coding conventions, inspection profiles and set up the checkstyle plugin.
The following files can be found in the [Spring Cloud Build](https://github.com/spring-cloud/spring-cloud-build/tree/master/spring-cloud-build-tools) project.
@@ -239,11 +268,11 @@ Go to `File` → `Settings` → `Other settings` → `Checkstyle`. There click o
| |Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources.|
|---|------------------------------------------------------------------------------------------------------------------|
-### [Duplicate Finder](#_duplicate_finder) ###
+### [Duplicate Finder](#_duplicate_finder)
Spring Cloud Build brings along the `basepom:duplicate-finder-maven-plugin`, that enables flagging duplicate and conflicting classes and resources on the java classpath.
-#### [Duplicate Finder configuration](#_duplicate_finder_configuration) ####
+#### [Duplicate Finder configuration](#_duplicate_finder_configuration)
Duplicate finder is **enabled by default** and will run in the `verify` phase of your Maven build, but it will only take effect in your project if you add the `duplicate-finder-maven-plugin` to the `build` section of the projecst’s `pom.xml`.
@@ -286,8 +315,7 @@ If you need to add `ignoredClassPatterns` or `ignoredResourcePatterns` to your s
```
-[Flattening the POMs](#_flattening_the_poms)
-----------
+## [Flattening the POMs](#_flattening_the_poms)
To avoid propagating build setup that is required to build a Spring Cloud project, we’re using the maven flatten plugin. It has the advantage of letting you use whatever features you need while publishing "clean" pom to the repository.
@@ -304,8 +332,7 @@ In order to add it, add the `org.codehaus.mojo:flatten-maven-plugin` to your `po
```
-[Reusing the documentation](#_reusing_the_documentation)
-----------
+## [Reusing the documentation](#_reusing_the_documentation)
Spring Cloud Build publishes its `spring-cloud-build-docs` module that contains
helpful scripts (e.g. README generation ruby script) and css, xslt and images
@@ -415,8 +442,7 @@ Spring Cloud Build Docs comes with a set of attributes for asciidoctor that you
```
-[Updating the guides](#_updating_the_guides)
-----------
+## [Updating the guides](#_updating_the_guides)
We assume that your project contains guides under the `guides` folder.
@@ -448,3 +474,5 @@ what will happen is that for GA project versions, we will clone `gs-guide1`, `gs
You can skip this by either not adding the `guides` profile, or passing the `-DskipGuides` system property when the profile is turned on.
You can configure the project version passed to guides via the `guides-project.version` (defaults to `${project.version}`). The phase at which guides get updated can be configured by `guides-update.phase` (defaults to `deploy`).
+
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-bus.md b/docs/en/spring-cloud/spring-cloud-bus.md
index c7fb7df8b0e02726c60abbf19626d75c60e100db..c1d881976b2e6da51c81d9c24d13973cb15ec247 100644
--- a/docs/en/spring-cloud/spring-cloud-bus.md
+++ b/docs/en/spring-cloud/spring-cloud-bus.md
@@ -1,5 +1,37 @@
-Spring Cloud Bus
-==========
+Spring Cloud Bus.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Bus
+
+Table of Contents
+
+* [1. Quick Start](#quick-start)
+* [2. Bus Endpoints](#bus-endpoints)
+ * [2.1. Bus Refresh Endpoint](#bus-refresh-endpoint)
+ * [2.2. Bus Env Endpoint](#bus-env-endpoint)
+
+* [3. Addressing an Instance](#addressing-an-instance)
+* [4. Addressing All Instances of a Service](#addressing-all-instances-of-a-service)
+* [5. Service ID Must Be Unique](#service-id-must-be-unique)
+* [6. Customizing the Message Broker](#customizing-the-message-broker)
+* [7. Tracing Bus Events](#tracing-bus-events)
+* [8. Broadcasting Your Own Events](#broadcasting-your-own-events)
+ * [8.1. Registering events in custom packages](#registering-events-in-custom-packages)
+
+* [9. Configuration properties](#configuration-properties)
Spring Cloud Bus links the nodes of a distributed system with a lightweight message
broker. This broker can then be used to broadcast state changes (such as configuration
@@ -11,8 +43,7 @@ either an AMQP broker or Kafka as the transport.
| |Spring Cloud is released under the non-restrictive Apache 2.0 license. If you would like to contribute to this section of the documentation or if you find an error, please find the source code and issue trackers in the project at [github](https://github.com/spring-cloud/spring-cloud-bus).|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#quick-start)[1. Quick Start](#quick-start)
-----------
+## [](#quick-start)[1. Quick Start](#quick-start)
Spring Cloud Bus works by adding Spring Boot autconfiguration if it detects itself on the
classpath. To enable the bus, add `spring-cloud-starter-bus-amqp` or`spring-cloud-starter-bus-kafka` to your dependency management. Spring Cloud takes care of
@@ -41,12 +72,11 @@ application’s configuration, as though they had all been pinged on their `/ref
| |The Spring Cloud Bus starters cover Rabbit and Kafka, because those are the two most
common implementations. However, Spring Cloud Stream is quite flexible, and the binder
works with `spring-cloud-bus`.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#bus-endpoints)[2. Bus Endpoints](#bus-endpoints)
-----------
+## [](#bus-endpoints)[2. Bus Endpoints](#bus-endpoints)
Spring Cloud Bus provides two endpoints, `/actuator/busrefresh` and `/actuator/busenv`that correspond to individual actuator endpoints in Spring Cloud Commons,`/actuator/refresh` and `/actuator/env` respectively.
-### [](#bus-refresh-endpoint)[2.1. Bus Refresh Endpoint](#bus-refresh-endpoint) ###
+### [](#bus-refresh-endpoint)[2.1. Bus Refresh Endpoint](#bus-refresh-endpoint)
The `/actuator/busrefresh` endpoint clears the `RefreshScope` cache and rebinds`@ConfigurationProperties`. See the [Refresh Scope](#refresh-scope) documentation for
more information.
@@ -58,7 +88,7 @@ application:
management.endpoints.web.exposure.include=busrefresh
```
-### [](#bus-env-endpoint)[2.2. Bus Env Endpoint](#bus-env-endpoint) ###
+### [](#bus-env-endpoint)[2.2. Bus Env Endpoint](#bus-env-endpoint)
The `/actuator/busenv` endpoint updates each instances environment with the specified
key/value pair across multiple instances.
@@ -79,8 +109,7 @@ The `/actuator/busenv` endpoint accepts `POST` requests with the following shape
}
```
-[](#addressing-an-instance)[3. Addressing an Instance](#addressing-an-instance)
-----------
+## [](#addressing-an-instance)[3. Addressing an Instance](#addressing-an-instance)
Each instance of the application has a service ID, whose value can be set with`spring.cloud.bus.id` and whose value is expected to be a colon-separated list of
identifiers, in order from least specific to most specific. The default value is
@@ -97,16 +126,14 @@ The HTTP endpoints accept a “destination” path parameter, such as`/busrefres
is owned by an instance on the bus, it processes the message, and all other instances
ignore it.
-[](#addressing-all-instances-of-a-service)[4. Addressing All Instances of a Service](#addressing-all-instances-of-a-service)
-----------
+## [](#addressing-all-instances-of-a-service)[4. Addressing All Instances of a Service](#addressing-all-instances-of-a-service)
The “destination” parameter is used in a Spring `PathMatcher` (with the path separator
as a colon — `:`) to determine if an instance processes the message. Using the example
from earlier, `/busenv/customers:**` targets all instances of the
“customers” service regardless of the rest of the service ID.
-[](#service-id-must-be-unique)[5. Service ID Must Be Unique](#service-id-must-be-unique)
-----------
+## [](#service-id-must-be-unique)[5. Service ID Must Be Unique](#service-id-must-be-unique)
The bus tries twice to eliminate processing an event — once from the original`ApplicationEvent` and once from the queue. To do so, it checks the sending service ID
against the current service ID. If multiple instances of a service have the same ID,
@@ -115,8 +142,7 @@ port, and that port is part of the ID. Cloud Foundry supplies an index to differ
To ensure that the ID is unique outside Cloud Foundry, set `spring.application.index` to
something unique for each instance of a service.
-[](#customizing-the-message-broker)[6. Customizing the Message Broker](#customizing-the-message-broker)
-----------
+## [](#customizing-the-message-broker)[6. Customizing the Message Broker](#customizing-the-message-broker)
Spring Cloud Bus uses [Spring Cloud Stream](https://cloud.spring.io/spring-cloud-stream) to
broadcast the messages. So, to get messages to flow, you need only include the binder
@@ -130,8 +156,7 @@ middleware). Normally, the defaults suffice.
To learn more about how to customize the message broker settings, consult the Spring Cloud
Stream documentation.
-[](#tracing-bus-events)[7. Tracing Bus Events](#tracing-bus-events)
-----------
+## [](#tracing-bus-events)[7. Tracing Bus Events](#tracing-bus-events)
Bus events (subclasses of `RemoteApplicationEvent`) can be traced by setting`spring.cloud.bus.trace.enabled=true`. If you do so, the Spring Boot `TraceRepository`(if it is present) shows each event sent and all the acks from each service instance. The
following example comes from the `/trace` endpoint:
@@ -178,8 +203,7 @@ there.
| |Any Bus application can trace acks. However, sometimes, it is
useful to do this in a central service that can do more complex
queries on the data or forward it to a specialized tracing service.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#broadcasting-your-own-events)[8. Broadcasting Your Own Events](#broadcasting-your-own-events)
-----------
+## [](#broadcasting-your-own-events)[8. Broadcasting Your Own Events](#broadcasting-your-own-events)
The Bus can carry any event of type `RemoteApplicationEvent`. The default transport is
JSON, and the deserializer needs to know which types are going to be used ahead of time.
@@ -191,7 +215,7 @@ the default strategy, which is to use the simple name of the class.
| |Both the producer and the consumer need access to the class definition.|
|---|-----------------------------------------------------------------------|
-### [](#registering-events-in-custom-packages)[8.1. Registering events in custom packages](#registering-events-in-custom-packages) ###
+### [](#registering-events-in-custom-packages)[8.1. Registering events in custom packages](#registering-events-in-custom-packages)
If you cannot or do not want to use a subpackage of `org.springframework.cloud.bus.event`for your custom events, you must specify which packages to scan for events of type`RemoteApplicationEvent` by using the `@RemoteApplicationEventScan` annotation. Packages
specified with `@RemoteApplicationEventScan` include subpackages.
@@ -240,7 +264,8 @@ All of the preceding examples of `@RemoteApplicationEventScan` are equivalent, i
| |You can specify multiple base packages to scan.|
|---|-----------------------------------------------|
-[](#configuration-properties)[9. Configuration properties](#configuration-properties)
-----------
+## [](#configuration-properties)[9. Configuration properties](#configuration-properties)
To see the list of all Bus related configuration properties please check [the Appendix page](appendix.html).
+
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-circuitbreaker.md b/docs/en/spring-cloud/spring-cloud-circuitbreaker.md
index d8c31d04277997558cf01475b0b05175e9b90319..0df6a6df2521b099052a42ee59e3f0f8d9bc33d8 100644
--- a/docs/en/spring-cloud/spring-cloud-circuitbreaker.md
+++ b/docs/en/spring-cloud/spring-cloud-circuitbreaker.md
@@ -1,17 +1,78 @@
-Spring Cloud Circuit Breaker
-==========
-
-
-[](#usage-documentation)[1. Usage Documentation](#usage-documentation)
-----------
+Spring Cloud Circuit Breaker.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Circuit Breaker
+
+Table of Contents
+
+* [1. Usage Documentation](#usage-documentation)
+ * [1.1. Configuring Resilience4J Circuit Breakers](#configuring-resilience4j-circuit-breakers)
+ * [1.1.1. Starters](#starters)
+ * [1.1.2. Auto-Configuration](#auto-configuration)
+ * [1.1.3. Default Configuration](#default-configuration)
+ * [Reactive Example](#reactive-example)
+
+ * [1.1.4. Specific Circuit Breaker Configuration](#specific-circuit-breaker-configuration)
+ * [Reactive Example](#reactive-example-2)
+
+ * [1.1.5. Circuit Breaker Properties Configuration](#circuit-breaker-properties-configuration)
+ * [1.1.6. Bulkhead pattern supporting](#bulkhead-pattern-supporting)
+ * [1.1.7. Specific Bulkhead Configuration](#specific-bulkhead-configuration)
+ * [Bulkhead Example](#bulkhead-example)
+ * [Thread Pool Bulkhead Example](#thread-pool-bulkhead-example)
+
+ * [1.1.8. Bulkhead Properties Configuration](#bulkhead-properties-configuration)
+ * [1.1.9. Collecting Metrics](#collecting-metrics)
+
+ * [1.2. Configuring Spring Retry Circuit Breakers](#configuring-spring-retry-circuit-breakers)
+ * [1.2.1. Default Configuration](#default-configuration-2)
+ * [1.2.2. Specific Circuit Breaker Configuration](#specific-circuit-breaker-configuration-2)
+
+* [2. Building](#building)
+ * [2.1. Basic Compile and Test](#basic-compile-and-test)
+ * [2.2. Documentation](#documentation)
+ * [2.3. Working with the code](#working-with-the-code)
+ * [2.3.1. Activate the Spring Maven profile](#activate-the-spring-maven-profile)
+ * [2.3.2. Importing into eclipse with m2eclipse](#importing-into-eclipse-with-m2eclipse)
+ * [2.3.3. Importing into eclipse without m2eclipse](#importing-into-eclipse-without-m2eclipse)
+
+* [3. Contributing](#contributing)
+ * [3.1. Sign the Contributor License Agreement](#sign-the-contributor-license-agreement)
+ * [3.2. Code of Conduct](#code-of-conduct)
+ * [3.3. Code Conventions and Housekeeping](#code-conventions-and-housekeeping)
+ * [3.4. Checkstyle](#checkstyle)
+ * [3.4.1. Checkstyle configuration](#checkstyle-configuration)
+
+ * [3.5. IDE setup](#ide-setup)
+ * [3.5.1. Intellij IDEA](#intellij-idea)
+
+ * [3.6. Duplicate Finder](#duplicate-finder)
+ * [3.6.1. Duplicate Finder configuration](#duplicate-finder-configuration)
+
+**2.1.1**
+
+## [](#usage-documentation)[1. Usage Documentation](#usage-documentation)
The Spring Cloud CircuitBreaker project contains implementations for Resilience4J and Spring Retry.
The APIs implemented in Spring Cloud CircuitBreaker live in Spring Cloud Commons. The usage documentation
for these APIs are located in the [Spring Cloud Commons documentation](https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-circuit-breaker).
-### [](#configuring-resilience4j-circuit-breakers)[1.1. Configuring Resilience4J Circuit Breakers](#configuring-resilience4j-circuit-breakers) ###
+### [](#configuring-resilience4j-circuit-breakers)[1.1. Configuring Resilience4J Circuit Breakers](#configuring-resilience4j-circuit-breakers)
-#### [](#starters)[1.1.1. Starters](#starters) ####
+#### [](#starters)[1.1.1. Starters](#starters)
There are two starters for the Resilience4J implementations, one for reactive applications and one for non-reactive applications.
@@ -19,11 +80,11 @@ There are two starters for the Resilience4J implementations, one for reactive ap
* `org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j` - reactive applications
-#### [](#auto-configuration)[1.1.2. Auto-Configuration](#auto-configuration) ####
+#### [](#auto-configuration)[1.1.2. Auto-Configuration](#auto-configuration)
You can disable the Resilience4J auto-configuration by setting`spring.cloud.circuitbreaker.resilience4j.enabled` to `false`.
-#### [](#default-configuration)[1.1.3. Default Configuration](#default-configuration) ####
+#### [](#default-configuration)[1.1.3. Default Configuration](#default-configuration)
To provide a default configuration for all of your circuit breakers create a `Customize` bean that is passed a`Resilience4JCircuitBreakerFactory` or `ReactiveResilience4JCircuitBreakerFactory`.
The `configureDefault` method can be used to provide a default configuration.
@@ -38,7 +99,7 @@ public Customizer defaultCustomizer() {
}
```
-##### [](#reactive-example)[Reactive Example](#reactive-example) #####
+##### [](#reactive-example)[Reactive Example](#reactive-example)
```
@Bean
@@ -49,7 +110,7 @@ public Customizer defaultCustomizer()
}
```
-#### [](#specific-circuit-breaker-configuration)[1.1.4. Specific Circuit Breaker Configuration](#specific-circuit-breaker-configuration) ####
+#### [](#specific-circuit-breaker-configuration)[1.1.4. Specific Circuit Breaker Configuration](#specific-circuit-breaker-configuration)
Similarly to providing a default configuration, you can create a `Customize` bean this is passed a`Resilience4JCircuitBreakerFactory` or `ReactiveResilience4JCircuitBreakerFactory`.
@@ -73,7 +134,7 @@ public Customizer slowCustomizer() {
}
```
-##### [](#reactive-example-2)[Reactive Example](#reactive-example-2) #####
+##### [](#reactive-example-2)[Reactive Example](#reactive-example-2)
```
@Bean
@@ -88,7 +149,7 @@ public Customizer slowCustomizer() {
}
```
-#### [](#circuit-breaker-properties-configuration)[1.1.5. Circuit Breaker Properties Configuration](#circuit-breaker-properties-configuration) ####
+#### [](#circuit-breaker-properties-configuration)[1.1.5. Circuit Breaker Properties Configuration](#circuit-breaker-properties-configuration)
You can configure `CircuitBreaker` and `TimeLimiter` instances in your application’s configuration properties file.
Property configuration has higher priority than Java `Customizer` configuration.
@@ -118,7 +179,7 @@ resilience4j.timelimiter:
For more information on Resilience4j property configuration, see [Resilience4J Spring Boot 2 Configuration](https://resilience4j.readme.io/docs/getting-started-3#configuration).
-#### [](#bulkhead-pattern-supporting)[1.1.6. Bulkhead pattern supporting](#bulkhead-pattern-supporting) ####
+#### [](#bulkhead-pattern-supporting)[1.1.6. Bulkhead pattern supporting](#bulkhead-pattern-supporting)
If `resilience4j-bulkhead` is on the classpath, Spring Cloud CircuitBreaker will wrap all methods with a Resilience4j Bulkhead.
You can disable the Resilience4j Bulkhead by setting `spring.cloud.circuitbreaker.bulkhead.resilience4j.enabled` to `false`.
@@ -145,7 +206,7 @@ public Customizer defaultBulkheadCustomizer() {
}
```
-#### [](#specific-bulkhead-configuration)[1.1.7. Specific Bulkhead Configuration](#specific-bulkhead-configuration) ####
+#### [](#specific-bulkhead-configuration)[1.1.7. Specific Bulkhead Configuration](#specific-bulkhead-configuration)
Similarly to proving a default 'Bulkhead' or 'ThreadPoolBulkhead' configuration, you can create a `Customize` bean this
is passed a `Resilience4jBulkheadProvider`.
@@ -162,7 +223,7 @@ public Customizer slowBulkheadProviderCustomizer()
In addition to configuring the Bulkhead that is created you can also customize the bulkhead and thread pool bulkhead after they
have been created but before they are returned to caller. To do this you can use the `addBulkheadCustomizer` and `addThreadPoolBulkheadCustomizer`methods.
-##### [](#bulkhead-example)[Bulkhead Example](#bulkhead-example) #####
+##### [](#bulkhead-example)[Bulkhead Example](#bulkhead-example)
```
@Bean
@@ -173,7 +234,7 @@ public Customizer customizer() {
}
```
-##### [](#thread-pool-bulkhead-example)[Thread Pool Bulkhead Example](#thread-pool-bulkhead-example) #####
+##### [](#thread-pool-bulkhead-example)[Thread Pool Bulkhead Example](#thread-pool-bulkhead-example)
```
@Bean
@@ -184,7 +245,7 @@ public Customizer slowThreadPoolBulkheadCustomizer
}
```
-#### [](#bulkhead-properties-configuration)[1.1.8. Bulkhead Properties Configuration](#bulkhead-properties-configuration) ####
+#### [](#bulkhead-properties-configuration)[1.1.8. Bulkhead Properties Configuration](#bulkhead-properties-configuration)
You can configure ThreadPoolBulkhead and SemaphoreBulkhead instances in your application’s configuration properties file.
Property configuration has higher priority than Java `Customizer` configuration.
@@ -203,7 +264,7 @@ resilience4j.bulkhead:
For more inforamtion on the Resilience4j property configuration, see [Resilience4J Spring Boot 2 Configuration](https://resilience4j.readme.io/docs/getting-started-3#configuration).
-#### [](#collecting-metrics)[1.1.9. Collecting Metrics](#collecting-metrics) ####
+#### [](#collecting-metrics)[1.1.9. Collecting Metrics](#collecting-metrics)
Spring Cloud Circuit Breaker Resilience4j includes auto-configuration to setup metrics collection as long as the right
dependencies are on the classpath. To enable metric collection you must include `org.springframework.boot:spring-boot-starter-actuator`, and `io.github.resilience4j:resilience4j-micrometer`. For more information on the metrics that
@@ -212,7 +273,7 @@ get produced when these dependencies are present, see the [Resilience4j document
| |You don’t have to include `micrometer-core` directly as it is brought in by `spring-boot-starter-actuator`|
|---|----------------------------------------------------------------------------------------------------------|
-### [](#configuring-spring-retry-circuit-breakers)[1.2. Configuring Spring Retry Circuit Breakers](#configuring-spring-retry-circuit-breakers) ###
+### [](#configuring-spring-retry-circuit-breakers)[1.2. Configuring Spring Retry Circuit Breakers](#configuring-spring-retry-circuit-breakers)
Spring Retry provides declarative retry support for Spring applications.
A subset of the project includes the ability to implement circuit breaker functionality.
@@ -220,7 +281,7 @@ Spring Retry provides a circuit breaker implementation via a combination of it
All circuit breakers created using Spring Retry will be created using the `CircuitBreakerRetryPolicy` and a[`DefaultRetryState`](https://github.com/spring-projects/spring-retry/blob/master/src/main/java/org/springframework/retry/support/DefaultRetryState.java).
Both of these classes can be configured using `SpringRetryConfigBuilder`.
-#### [](#default-configuration-2)[1.2.1. Default Configuration](#default-configuration-2) ####
+#### [](#default-configuration-2)[1.2.1. Default Configuration](#default-configuration-2)
To provide a default configuration for all of your circuit breakers create a `Customize` bean that is passed a`SpringRetryCircuitBreakerFactory`.
The `configureDefault` method can be used to provide a default configuration.
@@ -233,7 +294,7 @@ public Customizer defaultCustomizer() {
}
```
-#### [](#specific-circuit-breaker-configuration-2)[1.2.2. Specific Circuit Breaker Configuration](#specific-circuit-breaker-configuration-2) ####
+#### [](#specific-circuit-breaker-configuration-2)[1.2.2. Specific Circuit Breaker Configuration](#specific-circuit-breaker-configuration-2)
Similarly to providing a default configuration, you can create a `Customize` bean this is passed a`SpringRetryCircuitBreakerFactory`.
@@ -271,10 +332,9 @@ public Customizer slowCustomizer() {
}
```
-[](#building)[2. Building](#building)
-----------
+## [](#building)[2. Building](#building)
-### [](#basic-compile-and-test)[2.1. Basic Compile and Test](#basic-compile-and-test) ###
+### [](#basic-compile-and-test)[2.1. Basic Compile and Test](#basic-compile-and-test)
To build the source you will need to install JDK 17.
@@ -295,7 +355,7 @@ $ ./mvnw install
The projects that require middleware (i.e. Redis) for testing generally
require that a local instance of [Docker]([www.docker.com/get-started](https://www.docker.com/get-started)) is installed and running.
-### [](#documentation)[2.2. Documentation](#documentation) ###
+### [](#documentation)[2.2. Documentation](#documentation)
The spring-cloud-build module has a "docs" profile, and if you switch
that on it will try to build asciidoc sources from`src/main/asciidoc`. As part of that process it will look for a`README.adoc` and process it by loading all the includes, but not
@@ -303,18 +363,18 @@ parsing or rendering it, just copying it to `${main.basedir}`(defaults to `$/tmp
any changes in the README it will then show up after a Maven build as
a modified file in the correct place. Just commit it and push the change.
-### [](#working-with-the-code)[2.3. Working with the code](#working-with-the-code) ###
+### [](#working-with-the-code)[2.3. Working with the code](#working-with-the-code)
If you don’t have an IDE preference we would recommend that you use[Spring Tools Suite](https://www.springsource.com/developer/sts) or[Eclipse](https://eclipse.org) when working with the code. We use the[m2eclipse](https://eclipse.org/m2e/) eclipse plugin for maven support. Other IDEs and tools
should also work without issue as long as they use Maven 3.3.3 or better.
-#### [](#activate-the-spring-maven-profile)[2.3.1. Activate the Spring Maven profile](#activate-the-spring-maven-profile) ####
+#### [](#activate-the-spring-maven-profile)[2.3.1. Activate the Spring Maven profile](#activate-the-spring-maven-profile)
Spring Cloud projects require the 'spring' Maven profile to be activated to resolve
the spring milestone and snapshot repositories. Use your preferred IDE to set this
profile to be active, or you may experience build errors.
-#### [](#importing-into-eclipse-with-m2eclipse)[2.3.2. Importing into eclipse with m2eclipse](#importing-into-eclipse-with-m2eclipse) ####
+#### [](#importing-into-eclipse-with-m2eclipse)[2.3.2. Importing into eclipse with m2eclipse](#importing-into-eclipse-with-m2eclipse)
We recommend the [m2eclipse](https://eclipse.org/m2e/) eclipse plugin when working with
eclipse. If you don’t already have m2eclipse installed it is available from the "eclipse
@@ -323,7 +383,7 @@ marketplace".
| |Older versions of m2e do not support Maven 3.3, so once the
projects are imported into Eclipse you will also need to tell
m2eclipse to use the right profile for the projects. If you
see many different errors related to the POMs in the projects, check
that you have an up to date installation. If you can’t upgrade m2e,
add the "spring" profile to your `settings.xml`. Alternatively you can
copy the repository settings from the "spring" profile of the parent
pom into your `settings.xml`.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [](#importing-into-eclipse-without-m2eclipse)[2.3.3. Importing into eclipse without m2eclipse](#importing-into-eclipse-without-m2eclipse) ####
+#### [](#importing-into-eclipse-without-m2eclipse)[2.3.3. Importing into eclipse without m2eclipse](#importing-into-eclipse-without-m2eclipse)
If you prefer not to use m2eclipse you can generate eclipse project metadata using the
following command:
@@ -334,8 +394,7 @@ $ ./mvnw eclipse:eclipse
The generated eclipse projects can be imported by selecting `import existing projects`from the `file` menu.
-[](#contributing)[3. Contributing](#contributing)
-----------
+## [](#contributing)[3. Contributing](#contributing)
Spring Cloud is released under the non-restrictive Apache 2.0 license,
and follows a very standard Github development process, using Github
@@ -343,7 +402,7 @@ tracker for issues and merging pull requests into master. If you want
to contribute even something trivial please do not hesitate, but
follow the guidelines below.
-### [](#sign-the-contributor-license-agreement)[3.1. Sign the Contributor License Agreement](#sign-the-contributor-license-agreement) ###
+### [](#sign-the-contributor-license-agreement)[3.1. Sign the Contributor License Agreement](#sign-the-contributor-license-agreement)
Before we accept a non-trivial patch or pull request we will need you to sign the[Contributor License Agreement](https://cla.pivotal.io/sign/spring).
Signing the contributor’s agreement does not grant anyone commit rights to the main
@@ -351,13 +410,13 @@ repository, but it does mean that we can accept your contributions, and you will
author credit if we do. Active contributors might be asked to join the core team, and
given the ability to merge pull requests.
-### [](#code-of-conduct)[3.2. Code of Conduct](#code-of-conduct) ###
+### [](#code-of-conduct)[3.2. Code of Conduct](#code-of-conduct)
This project adheres to the Contributor Covenant [code of
conduct](https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report
-unacceptable behavior to [[email protected]](/cdn-cgi/l/email-protection#fd8e8d8f94939ad09e929998d0929bd09e929399889e89bd8d948b92899c91d39492).
+unacceptable behavior to [[email protected]](/cdn-cgi/l/email-protection#4c3f3c3e25222b612f23282961232a612f232228392f380c3c253a23382d20622523).
-### [](#code-conventions-and-housekeeping)[3.3. Code Conventions and Housekeeping](#code-conventions-and-housekeeping) ###
+### [](#code-conventions-and-housekeeping)[3.3. Code Conventions and Housekeeping](#code-conventions-and-housekeeping)
None of these is essential for a pull request, but they will all help. They can also be
added after the original pull request but before a merge.
@@ -387,7 +446,7 @@ added after the original pull request but before a merge.
if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit
message (where XXXX is the issue number).
-### [](#checkstyle)[3.4. Checkstyle](#checkstyle) ###
+### [](#checkstyle)[3.4. Checkstyle](#checkstyle)
Spring Cloud Build comes with a set of checkstyle rules. You can find them in the `spring-cloud-build-tools` module. The most notable files under the module are:
@@ -408,7 +467,7 @@ spring-cloud-build-tools/
|**2**| File header setup |
|**3**|Default suppression rules|
-#### [](#checkstyle-configuration)[3.4.1. Checkstyle configuration](#checkstyle-configuration) ####
+#### [](#checkstyle-configuration)[3.4.1. Checkstyle configuration](#checkstyle-configuration)
Checkstyle rules are **disabled by default**. To add checkstyle to your project just define the following properties and plugins.
@@ -475,9 +534,9 @@ $ curl https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/
$ touch .springformat
```
-### [](#ide-setup)[3.5. IDE setup](#ide-setup) ###
+### [](#ide-setup)[3.5. IDE setup](#ide-setup)
-#### [](#intellij-idea)[3.5.1. Intellij IDEA](#intellij-idea) ####
+#### [](#intellij-idea)[3.5.1. Intellij IDEA](#intellij-idea)
In order to setup Intellij you should import our coding conventions, inspection profiles and set up the checkstyle plugin.
The following files can be found in the [Spring Cloud Build](https://github.com/spring-cloud/spring-cloud-build/tree/master/spring-cloud-build-tools) project.
@@ -533,11 +592,11 @@ Go to `File` → `Settings` → `Other settings` → `Checkstyle`. There click o
| |Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources.|
|---|------------------------------------------------------------------------------------------------------------------|
-### [](#duplicate-finder)[3.6. Duplicate Finder](#duplicate-finder) ###
+### [](#duplicate-finder)[3.6. Duplicate Finder](#duplicate-finder)
Spring Cloud Build brings along the `basepom:duplicate-finder-maven-plugin`, that enables flagging duplicate and conflicting classes and resources on the java classpath.
-#### [](#duplicate-finder-configuration)[3.6.1. Duplicate Finder configuration](#duplicate-finder-configuration) ####
+#### [](#duplicate-finder-configuration)[3.6.1. Duplicate Finder configuration](#duplicate-finder-configuration)
Duplicate finder is **enabled by default** and will run in the `verify` phase of your Maven build, but it will only take effect in your project if you add the `duplicate-finder-maven-plugin` to the `build` section of the projecst’s `pom.xml`.
@@ -580,3 +639,4 @@ If you need to add `ignoredClassPatterns` or `ignoredResourcePatterns` to your s
```
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-cli.md b/docs/en/spring-cloud/spring-cloud-cli.md
index a9618c412a0e9f6af9a0800dff7bbe96423618b1..ef0e718b425fce54b7968ed69ff63927a85feb35 100644
--- a/docs/en/spring-cloud/spring-cloud-cli.md
+++ b/docs/en/spring-cloud/spring-cloud-cli.md
@@ -1,6 +1,29 @@
-Spring Boot Cloud CLI
-==========
-
+Spring Boot Cloud CLI.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Boot Cloud CLI
+
+Table of Contents
+
+* [Installation](#_installation)
+* [Running Spring Cloud Services in Development](#_running_spring_cloud_services_in_development)
+ * [Adding Additional Applications](#_adding_additional_applications)
+
+* [Writing Groovy Scripts and Running Applications](#_writing_groovy_scripts_and_running_applications)
+* [Encryption and Decryption](#_encryption_and_decryption)
Spring Boot CLI provides [Spring
Boot](https://projects.spring.io/spring-boot) command line features for [Spring
@@ -15,8 +38,7 @@ development time).
| |Spring Cloud is released under the non-restrictive Apache 2.0 license. If you would like to contribute to this section of the documentation or if you find an error, please find the source code and issue trackers in the project at [github](https://github.com/spring-cloud/spring-cloud-cli).|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[Installation](#_installation)
-----------
+## [Installation](#_installation)
To install, make
sure you have[Spring Boot CLI](https://github.com/spring-projects/spring-boot)(2.0.0 or better):
@@ -43,8 +65,7 @@ $ spring install org.springframework.cloud:spring-cloud-cli:2.2.0.RELEASE
| |**Prerequisites:** to use the encryption and decryption features
you need the full-strength JCE installed in your JVM (it’s not there by default).
You can download the "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files"
from Oracle, and follow instructions for installation (essentially replace the 2 policy files
in the JRE lib/security directory with the ones that you downloaded).|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[Running Spring Cloud Services in Development](#_running_spring_cloud_services_in_development)
-----------
+## [Running Spring Cloud Services in Development](#_running_spring_cloud_services_in_development)
The Launcher CLI can be used to run common services like Eureka,
Config Server etc. from the command line. To list the available
@@ -96,7 +117,7 @@ stubrunner:
- com.example:beer-api-producer:+:9876
```
-### [Adding Additional Applications](#_adding_additional_applications) ###
+### [Adding Additional Applications](#_adding_additional_applications)
Additional applications can be added to `./config/cloud.yml` (not`./config.yml` because that would replace the defaults), e.g. with
@@ -124,8 +145,7 @@ source sink configserver dataflow eureka h2 kafka stubrunner zipkin
(notice the additional apps at the start of the list).
-[Writing Groovy Scripts and Running Applications](#_writing_groovy_scripts_and_running_applications)
-----------
+## [Writing Groovy Scripts and Running Applications](#_writing_groovy_scripts_and_running_applications)
Spring Cloud CLI has support for most of the Spring Cloud declarative
features, such as the `@Enable*` class of annotations. For example,
@@ -162,8 +182,7 @@ class Service {
}
```
-[Encryption and Decryption](#_encryption_and_decryption)
-----------
+## [Encryption and Decryption](#_encryption_and_decryption)
The Spring Cloud CLI comes with an "encrypt" and a "decrypt"
command. Both accept arguments in the same form with a key specified
@@ -183,3 +202,5 @@ the key value with "@" and provide the file path, e.g.
$ spring encrypt mysecret --key @${HOME}/.ssh/id_rsa.pub
AQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+...
```
+
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-cloudfoundry.md b/docs/en/spring-cloud/spring-cloud-cloudfoundry.md
index a65144335b87d2a9fdb71acb05ea590f19cd18fb..d52f61438381aaea846ecf2fac99843f363b6778 100644
--- a/docs/en/spring-cloud/spring-cloud-cloudfoundry.md
+++ b/docs/en/spring-cloud/spring-cloud-cloudfoundry.md
@@ -1,6 +1,26 @@
-Spring Cloud for Cloud Foundry
-==========
-
+Spring Cloud for Cloud Foundry.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud for Cloud Foundry
+
+Table of Contents
+
+* [1. Discovery](#discovery)
+* [2. Single Sign On](#single-sign-on)
+* [3. Configuration](#configuration)
Spring Cloud for Cloudfoundry makes it easy to run[Spring Cloud](https://github.com/spring-cloud) apps in[Cloud Foundry](https://github.com/cloudfoundry) (the Platform as a
Service). Cloud Foundry has the notion of a "service", which is
@@ -23,8 +43,7 @@ can use the `DiscoveryClient` directly or via a `LoadBalancerClient`.
The first time you use it the discovery client might be slow owing to
the fact that it has to get an access token from Cloud Foundry.
-[](#discovery)[1. Discovery](#discovery)
-----------
+## [](#discovery)[1. Discovery](#discovery)
Here’s a Spring Cloud app with Cloud Foundry discovery:
@@ -61,8 +80,7 @@ the credentials it is authenticated with, where the space defaults to
the one the client is running in (if any). If neither org nor space
are configured, they default per the user’s profile in Cloud Foundry.
-[](#single-sign-on)[2. Single Sign On](#single-sign-on)
-----------
+## [](#single-sign-on)[2. Single Sign On](#single-sign-on)
| |All of the OAuth2 SSO and resource server features moved to Spring Boot
in version 1.3. You can find documentation in the[Spring Boot user guide](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/).|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
@@ -74,8 +92,8 @@ service called "sso", for instance, with credentials containing
automatically to the Spring OAuth2 client that you enable with`@EnableOAuth2Sso` (from Spring Boot). The name of the service can be
parameterized using `spring.oauth2.sso.serviceId`.
-[](#configuration)[3. Configuration](#configuration)
-----------
+## [](#configuration)[3. Configuration](#configuration)
To see the list of all Spring Cloud Sloud Foundry related configuration properties please check [the Appendix page](appendix.html).
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-commons.md b/docs/en/spring-cloud/spring-cloud-commons.md
index c790479244c4e35277a14ddaf4bca868a4b9cb7e..99a079ec8a2c4af9085af33ff791cd9edd881efe 100644
--- a/docs/en/spring-cloud/spring-cloud-commons.md
+++ b/docs/en/spring-cloud/spring-cloud-commons.md
@@ -1,5 +1,106 @@
-Cloud Native Applications
-==========
+Cloud Native Applications.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Cloud Native Applications
+
+Table of Contents
+
+* [1. Spring Cloud Context: Application Context Services](#spring-cloud-context-application-context-services)
+ * [1.1. The Bootstrap Application Context](#the-bootstrap-application-context)
+ * [1.2. Application Context Hierarchies](#application-context-hierarchies)
+ * [1.3. Changing the Location of Bootstrap Properties](#customizing-bootstrap-properties)
+ * [1.4. Overriding the Values of Remote Properties](#overriding-bootstrap-properties)
+ * [1.5. Customizing the Bootstrap Configuration](#customizing-the-bootstrap-configuration)
+ * [1.6. Customizing the Bootstrap Property Sources](#customizing-bootstrap-property-sources)
+ * [1.7. Logging Configuration](#logging-configuration)
+ * [1.8. Environment Changes](#environment-changes)
+ * [1.9. Refresh Scope](#refresh-scope)
+ * [1.10. Encryption and Decryption](#encryption-and-decryption)
+ * [1.11. Endpoints](#endpoints)
+
+* [2. Spring Cloud Commons: Common Abstractions](#spring-cloud-commons-common-abstractions)
+ * [2.1. The `@EnableDiscoveryClient` Annotation](#discovery-client)
+ * [2.1.1. Health Indicators](#health-indicators)
+ * [DiscoveryClientHealthIndicator](#discoveryclienthealthindicator)
+ * [DiscoveryCompositeHealthContributor](#discoverycompositehealthcontributor)
+
+ * [2.1.2. Ordering `DiscoveryClient` instances](#ordering-discoveryclient-instances)
+ * [2.1.3. SimpleDiscoveryClient](#simplediscoveryclient)
+
+ * [2.2. ServiceRegistry](#serviceregistry)
+ * [2.2.1. ServiceRegistry Auto-Registration](#serviceregistry-auto-registration)
+ * [ServiceRegistry Auto-Registration Events](#serviceregistry-auto-registration-events)
+
+ * [2.2.2. Service Registry Actuator Endpoint](#service-registry-actuator-endpoint)
+
+ * [2.3. Spring RestTemplate as a Load Balancer Client](#rest-template-loadbalancer-client)
+ * [2.4. Spring WebClient as a Load Balancer Client](#webclinet-loadbalancer-client)
+ * [2.4.1. Retrying Failed Requests](#retrying-failed-requests)
+
+ * [2.5. Multiple `RestTemplate` Objects](#multiple-resttemplate-objects)
+ * [2.6. Multiple WebClient Objects](#multiple-webclient-objects)
+ * [2.7. Spring WebFlux `WebClient` as a Load Balancer Client](#loadbalanced-webclient)
+ * [2.7.1. Spring WebFlux `WebClient` with `ReactorLoadBalancerExchangeFilterFunction`](#webflux-with-reactive-loadbalancer)
+ * [2.7.2. Spring WebFlux `WebClient` with a Non-reactive Load Balancer Client](#load-balancer-exchange-filter-function)
+
+ * [2.8. Ignore Network Interfaces](#ignore-network-interfaces)
+ * [2.9. HTTP Client Factories](#http-clients)
+ * [2.10. Enabled Features](#enabled-features)
+ * [2.10.1. Feature types](#feature-types)
+ * [2.10.2. Declaring features](#declaring-features)
+
+ * [2.11. Spring Cloud Compatibility Verification](#spring-cloud-compatibility-verification)
+
+* [3. Spring Cloud LoadBalancer](#spring-cloud-loadbalancer)
+ * [3.1. Switching between the load-balancing algorithms](#switching-between-the-load-balancing-algorithms)
+ * [3.2. Spring Cloud LoadBalancer integrations](#spring-cloud-loadbalancer-integrations)
+ * [3.3. Spring Cloud LoadBalancer Caching](#loadbalancer-caching)
+ * [3.3.1. Caffeine-backed LoadBalancer Cache Implementation](#caffeine-backed-loadbalancer-cache-implementation)
+ * [3.3.2. Default LoadBalancer Cache Implementation](#default-loadbalancer-cache-implementation)
+ * [3.3.3. LoadBalancer Cache Configuration](#loadbalancer-cache-configuration)
+
+ * [3.4. Zone-Based Load-Balancing](#zone-based-load-balancing)
+ * [3.5. Instance Health-Check for LoadBalancer](#instance-health-check-for-loadbalancer)
+ * [3.6. Same instance preference for LoadBalancer](#same-instance-preference-for-loadbalancer)
+ * [3.7. Request-based Sticky Session for LoadBalancer](#request-based-sticky-session-for-loadbalancer)
+ * [3.8. Spring Cloud LoadBalancer Hints](#spring-cloud-loadbalancer-hints)
+ * [3.9. Hint-Based Load-Balancing](#hints-based-loadbalancing)
+ * [3.10. Transform the load-balanced HTTP request](#transform-the-load-balanced-http-request)
+ * [3.11. Spring Cloud LoadBalancer Starter](#spring-cloud-loadbalancer-starter)
+ * [3.12. Passing Your Own Spring Cloud LoadBalancer Configuration](#custom-loadbalancer-configuration)
+ * [3.13. Spring Cloud LoadBalancer Lifecycle](#loadbalancer-lifecycle)
+ * [3.14. Spring Cloud LoadBalancer Statistics](#loadbalancer-micrometer-stats-lifecycle)
+ * [3.15. Configuring Individual LoadBalancerClients](#configuring-individual-loadbalancerclients)
+
+* [4. Spring Cloud Circuit Breaker](#spring-cloud-circuit-breaker)
+ * [4.1. Introduction](#introduction)
+ * [4.1.1. Supported Implementations](#supported-implementations)
+
+ * [4.2. Core Concepts](#core-concepts)
+ * [4.2.1. Circuit Breakers In Reactive Code](#circuit-breakers-in-reactive-code)
+
+ * [4.3. Configuration](#configuration)
+
+* [5. CachedRandomPropertySource](#cachedrandompropertysource)
+* [6. Security](#spring-cloud-security)
+ * [6.1. Single Sign On](#spring-cloud-security-single-sign-on)
+ * [6.1.1. Client Token Relay](#spring-cloud-security-client-token-relay)
+ * [6.1.2. Resource Server Token Relay](#spring-cloud-security-resource-server-token-relay)
+
+* [7. Configuration Properties](#configuration-properties)
[Cloud Native](https://pivotal.io/platform-as-a-service/migrating-to-cloud-native-application-architectures-ebook) 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 [12-factor Applications](https://12factor.net/), in which development practices are aligned with delivery and operations goals — for instance, by using declarative programming and management and monitoring.
@@ -23,14 +124,13 @@ Extract the files into the JDK/jre/lib/security folder for whichever version of
| |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 {docslink}[github].|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#spring-cloud-context-application-context-services)[1. Spring Cloud Context: Application Context Services](#spring-cloud-context-application-context-services)
-----------
+## [](#spring-cloud-context-application-context-services)[1. Spring Cloud Context: Application Context Services](#spring-cloud-context-application-context-services)
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 many components in a system would use or occasionally need.
-### [](#the-bootstrap-application-context)[1.1. The Bootstrap Application Context](#the-bootstrap-application-context) ###
+### [](#the-bootstrap-application-context)[1.1. The Bootstrap Application Context](#the-bootstrap-application-context)
A Spring Cloud application operates by creating a “bootstrap” context, which is a parent context for the main application.
This context is responsible for loading configuration properties from the external sources and for decrypting properties in the local external configuration files.
@@ -59,7 +159,7 @@ If you want to retrieve specific profile configuration, you should also set `spr
You can disable the bootstrap process completely by setting `spring.cloud.bootstrap.enabled=false` (for example, in system properties).
-### [](#application-context-hierarchies)[1.2. Application Context Hierarchies](#application-context-hierarchies) ###
+### [](#application-context-hierarchies)[1.2. Application Context Hierarchies](#application-context-hierarchies)
If you build an application context from `SpringApplication` or `SpringApplicationBuilder`, 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 “main” application context contains additional property sources, compared to building the same context without Spring Cloud Config.
@@ -88,7 +188,7 @@ the parent, by name and also by property source name.
Note that the `SpringApplicationBuilder` lets you share an `Environment` 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.
-### [](#customizing-bootstrap-properties)[1.3. Changing the Location of Bootstrap Properties](#customizing-bootstrap-properties) ###
+### [](#customizing-bootstrap-properties)[1.3. Changing the Location of Bootstrap Properties](#customizing-bootstrap-properties)
The `bootstrap.yml` (or `.properties`) location can be specified by setting `spring.cloud.bootstrap.name` (default: `bootstrap`), `spring.cloud.bootstrap.location` (default: empty) or `spring.cloud.bootstrap.additional-location` (default: empty) — for example, in System properties.
@@ -98,7 +198,7 @@ To add locations to the list of default ones, `spring.cloud.bootstrap.additional
In fact, they are used to set up the bootstrap `ApplicationContext` by setting those properties in its `Environment`.
If there is an active profile (from `spring.profiles.active` or through the `Environment` 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 `bootstrap-development.properties` for a `development` profile.
-### [](#overriding-bootstrap-properties)[1.4. Overriding the Values of Remote Properties](#overriding-bootstrap-properties) ###
+### [](#overriding-bootstrap-properties)[1.4. Overriding the Values of Remote Properties](#overriding-bootstrap-properties)
The property sources that are added to your application by the bootstrap context are often “remote” (from example, from Spring Cloud Config Server).
By default, they cannot be overridden locally.
@@ -109,7 +209,7 @@ Once that flag is set, two finer-grained settings control the location of the re
* `spring.cloud.config.overrideSystemProperties=false`: Only system properties, command line arguments, and environment variables (but not the local config files) should override the remote settings.
-### [](#customizing-the-bootstrap-configuration)[1.5. Customizing the Bootstrap Configuration](#customizing-the-bootstrap-configuration) ###
+### [](#customizing-the-bootstrap-configuration)[1.5. Customizing the Bootstrap Configuration](#customizing-the-bootstrap-configuration)
The bootstrap context can be set to do anything you like by adding entries to `/META-INF/spring.factories` under a key named `org.springframework.cloud.bootstrap.BootstrapConfiguration`.
This holds a comma-separated list of Spring `@Configuration` classes that are used to create the context.
@@ -124,7 +224,7 @@ The bootstrap process ends by injecting initializers into the main `SpringApplic
First, a bootstrap context is created from the classes found in `spring.factories`.
Then, all `@Beans` of type `ApplicationContextInitializer` are added to the main `SpringApplication` before it is started.
-### [](#customizing-bootstrap-property-sources)[1.6. Customizing the Bootstrap Property Sources](#customizing-bootstrap-property-sources) ###
+### [](#customizing-bootstrap-property-sources)[1.6. Customizing the Bootstrap Property Sources](#customizing-bootstrap-property-sources)
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 `PropertySourceLocator` to the bootstrap context (through `spring.factories`).
For instance, you can insert additional properties from a different server or from a database.
@@ -153,14 +253,14 @@ If you create a jar with this class in it and then add a `META-INF/spring.factor
org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator
```
-### [](#logging-configuration)[1.7. Logging Configuration](#logging-configuration) ###
+### [](#logging-configuration)[1.7. Logging Configuration](#logging-configuration)
If you use Spring Boot to configure log settings, you should place this configuration in `bootstrap.[yml | properties]` if you would like it to apply to all events.
| |For Spring Cloud to initialize logging configuration properly, you cannot use a custom prefix.
For example, using `custom.loggin.logpath` is not recognized by Spring Cloud when initializing the logging system.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#environment-changes)[1.8. Environment Changes](#environment-changes) ###
+### [](#environment-changes)[1.8. Environment Changes](#environment-changes)
The application listens for an `EnvironmentChangeEvent` and reacts to the change in a couple of standard ways (additional `ApplicationListeners` can be added as `@Beans` in the normal way).
When an `EnvironmentChangeEvent` is observed, it has a list of key values that have changed, and the application uses those to:
@@ -180,7 +280,7 @@ For instance, a `DataSource` can have its `maxPoolSize` changed at runtime (the
Re-binding `@ConfigurationProperties` 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 `ApplicationContext`.
To address those concerns, we have `@RefreshScope`.
-### [](#refresh-scope)[1.9. Refresh Scope](#refresh-scope) ###
+### [](#refresh-scope)[1.9. Refresh Scope](#refresh-scope)
When there is a configuration change, a Spring `@Bean` that is marked as `@RefreshScope` gets special treatment.
This feature addresses the problem of stateful beans that get their configuration injected only when they are initialized.
@@ -213,7 +313,7 @@ management:
| |`@RefreshScope` works (technically) on a `@Configuration` class, but it might lead to surprising behavior.
For example, it does not mean that all the `@Beans` defined in that class are themselves in `@RefreshScope`.
Specifically, anything that depends on those beans cannot rely on them being updated when a refresh is initiated, unless it is itself in `@RefreshScope`.
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 `@Configuration`).|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#encryption-and-decryption)[1.10. Encryption and Decryption](#encryption-and-decryption) ###
+### [](#encryption-and-decryption)[1.10. Encryption and Decryption](#encryption-and-decryption)
Spring Cloud has an `Environment` pre-processor for decrypting property values locally.
It follows the same rules as the Spring Cloud Config Server and has the same external configuration through `encrypt.*`.
@@ -231,7 +331,7 @@ See the following links for more information:
Extract the files into the JDK/jre/lib/security folder for whichever version of JRE/JDK x64/x86 you use.
-### [](#endpoints)[1.11. Endpoints](#endpoints) ###
+### [](#endpoints)[1.11. Endpoints](#endpoints)
For a Spring Boot Actuator application, some additional management endpoints are available. You can use:
@@ -247,12 +347,11 @@ For a Spring Boot Actuator application, some additional management endpoints are
| |If you disable the `/actuator/restart` endpoint then the `/actuator/pause` and `/actuator/resume` endpoints
will also be disabled since they are just a special case of `/actuator/restart`.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#spring-cloud-commons-common-abstractions)[2. Spring Cloud Commons: Common Abstractions](#spring-cloud-commons-common-abstractions)
-----------
+## [](#spring-cloud-commons-common-abstractions)[2. Spring Cloud Commons: Common Abstractions](#spring-cloud-commons-common-abstractions)
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).
-### [](#discovery-client)[2.1. The `@EnableDiscoveryClient` Annotation](#discovery-client) ###
+### [](#discovery-client)[2.1. The `@EnableDiscoveryClient` Annotation](#discovery-client)
Spring Cloud Commons provides the `@EnableDiscoveryClient` annotation.
This looks for implementations of the `DiscoveryClient` and `ReactiveDiscoveryClient` interfaces with `META-INF/spring.factories`.
@@ -269,11 +368,11 @@ This behavior can be disabled by setting `autoRegister=false` in `@EnableDiscove
| |`@EnableDiscoveryClient` is no longer required.
You can put a `DiscoveryClient` implementation on the classpath to cause the Spring Boot application to register with the service discovery server.|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [](#health-indicators)[2.1.1. Health Indicators](#health-indicators) ####
+#### [](#health-indicators)[2.1.1. Health Indicators](#health-indicators)
Commons auto-configures the following Spring Boot health indicators.
-##### [](#discoveryclienthealthindicator)[DiscoveryClientHealthIndicator](#discoveryclienthealthindicator) #####
+##### [](#discoveryclienthealthindicator)[DiscoveryClientHealthIndicator](#discoveryclienthealthindicator)
This health indicator is based on the currently registered `DiscoveryClient` implementation.
@@ -286,12 +385,12 @@ This health indicator is based on the currently registered `DiscoveryClient` imp
By default, the indicator invokes the client’s `getServices` method. In deployments with many registered services it may too
costly to retrieve all services during every check. This will skip the service retrieval and instead use the client’s `probe` method.
-##### [](#discoverycompositehealthcontributor)[DiscoveryCompositeHealthContributor](#discoverycompositehealthcontributor) #####
+##### [](#discoverycompositehealthcontributor)[DiscoveryCompositeHealthContributor](#discoverycompositehealthcontributor)
This composite health indicator is based on all registered `DiscoveryHealthIndicator` beans. To disable,
set `spring.cloud.discovery.client.composite-indicator.enabled=false`.
-#### [](#ordering-discoveryclient-instances)[2.1.2. Ordering `DiscoveryClient` instances](#ordering-discoveryclient-instances) ####
+#### [](#ordering-discoveryclient-instances)[2.1.2. Ordering `DiscoveryClient` instances](#ordering-discoveryclient-instances)
`DiscoveryClient` interface extends `Ordered`. This is useful when using multiple discovery
clients, as it allows you to define the order of the returned discovery clients, similar to
@@ -299,7 +398,7 @@ how you can order the beans loaded by a Spring application. By default, the orde
the `getOrder()` 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 `DiscoveryClient`implementations provided by Spring Cloud, among others `ConsulDiscoveryClient`, `EurekaDiscoveryClient` and`ZookeeperDiscoveryClient`. In order to do it, you just need to set the`spring.cloud.{clientIdentifier}.discovery.order` (or `eureka.client.order` for Eureka) property to the desired value.
-#### [](#simplediscoveryclient)[2.1.3. SimpleDiscoveryClient](#simplediscoveryclient) ####
+#### [](#simplediscoveryclient)[2.1.3. SimpleDiscoveryClient](#simplediscoveryclient)
If there is no Service-Registry-backed `DiscoveryClient` in the classpath, `SimpleDiscoveryClient`instance, that uses properties to get information on service and instances, will be used.
@@ -308,7 +407,7 @@ for the ID of the service in question, while `[0]` indicates the index number of
(as visible in the example, indexes start with `0`), and then the value of `uri` is
the actual URI under which the instance is available.
-### [](#serviceregistry)[2.2. ServiceRegistry](#serviceregistry) ###
+### [](#serviceregistry)[2.2. ServiceRegistry](#serviceregistry)
Commons now provides a `ServiceRegistry` interface that provides methods such as `register(Registration)` and `deregister(Registration)`, which let you provide custom registered services.`Registration` is a marker interface.
@@ -344,14 +443,14 @@ If you are using the `ServiceRegistry` interface, you are going to need to pass
correct `Registry` implementation for the `ServiceRegistry` implementation you
are using.
-#### [](#serviceregistry-auto-registration)[2.2.1. ServiceRegistry Auto-Registration](#serviceregistry-auto-registration) ####
+#### [](#serviceregistry-auto-registration)[2.2.1. ServiceRegistry Auto-Registration](#serviceregistry-auto-registration)
By default, the `ServiceRegistry` implementation auto-registers the running service.
To disable that behavior, you can set:
\* `@EnableDiscoveryClient(autoRegister=false)` to permanently disable auto-registration.
\* `spring.cloud.service-registry.auto-registration.enabled=false` to disable the behavior through configuration.
-##### [](#serviceregistry-auto-registration-events)[ServiceRegistry Auto-Registration Events](#serviceregistry-auto-registration-events) #####
+##### [](#serviceregistry-auto-registration-events)[ServiceRegistry Auto-Registration Events](#serviceregistry-auto-registration-events)
There are two events that will be fired when a service auto-registers. The first event, called`InstancePreRegisteredEvent`, is fired before the service is registered. The second
event, called `InstanceRegisteredEvent`, is fired after the service is registered. You can register an`ApplicationListener`(s) to listen to and react to these events.
@@ -359,7 +458,7 @@ event, called `InstanceRegisteredEvent`, is fired after the service is registere
| |These events will not be fired if the `spring.cloud.service-registry.auto-registration.enabled` property is set to `false`.|
|---|---------------------------------------------------------------------------------------------------------------------------|
-#### [](#service-registry-actuator-endpoint)[2.2.2. Service Registry Actuator Endpoint](#service-registry-actuator-endpoint) ####
+#### [](#service-registry-actuator-endpoint)[2.2.2. Service Registry Actuator Endpoint](#service-registry-actuator-endpoint)
Spring Cloud Commons provides a `/service-registry` actuator endpoint.
This endpoint relies on a `Registration` bean in the Spring Application Context.
@@ -369,7 +468,7 @@ The JSON body has to include the `status` field with the preferred value.
Please see the documentation of the `ServiceRegistry` 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 `UP`, `DOWN`, `OUT_OF_SERVICE`, and `UNKNOWN`.
-### [](#rest-template-loadbalancer-client)[2.3. Spring RestTemplate as a Load Balancer Client](#rest-template-loadbalancer-client) ###
+### [](#rest-template-loadbalancer-client)[2.3. Spring RestTemplate as a Load Balancer Client](#rest-template-loadbalancer-client)
You can configure a `RestTemplate` to use a Load-balancer client.
To create a load-balanced `RestTemplate`, create a `RestTemplate` `@Bean` and use the `@LoadBalanced` qualifier, as the following example shows:
@@ -405,7 +504,7 @@ The BlockingLoadBalancerClient is used to create a full physical address.
| |To use a load-balanced `RestTemplate`, you need to have a load-balancer implementation in your classpath.
Add [Spring Cloud LoadBalancer starter](#spring-cloud-loadbalancer-starter) to your project in order to use it.|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#webclinet-loadbalancer-client)[2.4. Spring WebClient as a Load Balancer Client](#webclinet-loadbalancer-client) ###
+### [](#webclinet-loadbalancer-client)[2.4. Spring WebClient as a Load Balancer Client](#webclinet-loadbalancer-client)
You can configure `WebClient` to automatically use a load-balancer client.
To create a load-balanced `WebClient`, create a `WebClient.Builder` `@Bean` and use the `@LoadBalanced` qualifier, as follows:
@@ -438,7 +537,7 @@ The Spring Cloud LoadBalancer is used to create a full physical address.
| |If you want to use a `@LoadBalanced WebClient.Builder`, you need to have a load balancer
implementation in the classpath. We recommend that you add the[Spring Cloud LoadBalancer starter](#spring-cloud-loadbalancer-starter) to your project.
Then, `ReactiveLoadBalancer` is used underneath.|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [](#retrying-failed-requests)[2.4.1. Retrying Failed Requests](#retrying-failed-requests) ####
+#### [](#retrying-failed-requests)[2.4.1. Retrying Failed Requests](#retrying-failed-requests)
A load-balanced `RestTemplate` can be configured to retry failed requests.
By default, this logic is disabled.
@@ -521,7 +620,7 @@ public class MyConfiguration {
}
```
-### [](#multiple-resttemplate-objects)[2.5. Multiple `RestTemplate` Objects](#multiple-resttemplate-objects) ###
+### [](#multiple-resttemplate-objects)[2.5. Multiple `RestTemplate` Objects](#multiple-resttemplate-objects)
If you want a `RestTemplate` that is not load-balanced, create a `RestTemplate` bean and inject it.
To access the load-balanced `RestTemplate`, use the `@LoadBalanced` qualifier when you create your `@Bean`, as the following example shows:
@@ -567,7 +666,7 @@ private RestTemplate restTemplate;
| |If you see errors such as `java.lang.IllegalArgumentException: Can not set org.springframework.web.client.RestTemplate field com.my.app.Foo.restTemplate to com.sun.proxy.$Proxy89`, try injecting `RestOperations` or setting `spring.aop.proxyTargetClass=true`.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#multiple-webclient-objects)[2.6. Multiple WebClient Objects](#multiple-webclient-objects) ###
+### [](#multiple-webclient-objects)[2.6. Multiple WebClient Objects](#multiple-webclient-objects)
If you want a `WebClient` that is not load-balanced, create a `WebClient` bean and inject it.
To access the load-balanced `WebClient`, use the `@LoadBalanced` qualifier when you create your `@Bean`, as the following example shows:
@@ -609,7 +708,7 @@ public class MyClass {
}
```
-### [](#loadbalanced-webclient)[2.7. Spring WebFlux `WebClient` as a Load Balancer Client](#loadbalanced-webclient) ###
+### [](#loadbalanced-webclient)[2.7. Spring WebFlux `WebClient` as a Load Balancer Client](#loadbalanced-webclient)
The Spring WebFlux can work with both reactive and non-reactive `WebClient` configurations, as the topics describe:
@@ -617,7 +716,7 @@ The Spring WebFlux can work with both reactive and non-reactive `WebClient` conf
* [[load-balancer-exchange-filter-functionload-balancer-exchange-filter-function]](#load-balancer-exchange-filter-functionload-balancer-exchange-filter-function)
-#### [](#webflux-with-reactive-loadbalancer)[2.7.1. Spring WebFlux `WebClient` with `ReactorLoadBalancerExchangeFilterFunction`](#webflux-with-reactive-loadbalancer) ####
+#### [](#webflux-with-reactive-loadbalancer)[2.7.1. Spring WebFlux `WebClient` with `ReactorLoadBalancerExchangeFilterFunction`](#webflux-with-reactive-loadbalancer)
You can configure `WebClient` to use the `ReactiveLoadBalancer`.
If you add [Spring Cloud LoadBalancer starter](#spring-cloud-loadbalancer-starter) to your project
@@ -644,7 +743,7 @@ public class MyClass {
The URI needs to use a virtual host name (that is, a service name, not a host name).
The `ReactorLoadBalancer` is used to create a full physical address.
-#### [](#load-balancer-exchange-filter-function)[2.7.2. Spring WebFlux `WebClient` with a Non-reactive Load Balancer Client](#load-balancer-exchange-filter-function) ####
+#### [](#load-balancer-exchange-filter-function)[2.7.2. Spring WebFlux `WebClient` with a Non-reactive Load Balancer Client](#load-balancer-exchange-filter-function)
If `spring-webflux` is on the classpath, `LoadBalancerExchangeFilterFunction`is auto-configured. Note, however, that this
uses a non-reactive client under the hood.
@@ -673,7 +772,7 @@ The `LoadBalancerClient` is used to create a full physical address.
WARN: This approach is now deprecated.
We suggest that you use [WebFlux with reactive Load-Balancer](#webflux-with-reactive-loadbalancer)instead.
-### [](#ignore-network-interfaces)[2.8. Ignore Network Interfaces](#ignore-network-interfaces) ###
+### [](#ignore-network-interfaces)[2.8. Ignore Network Interfaces](#ignore-network-interfaces)
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.
@@ -716,7 +815,7 @@ spring:
See [Inet4Address.html.isSiteLocalAddress()](https://docs.oracle.com/javase/8/docs/api/java/net/Inet4Address.html#isSiteLocalAddress--) for more details about what constitutes a site-local address.
-### [](#http-clients)[2.9. HTTP Client Factories](#http-clients) ###
+### [](#http-clients)[2.9. HTTP Client Factories](#http-clients)
Spring Cloud Commons provides beans for creating both Apache HTTP clients (`ApacheHttpClientFactory`) and OK HTTP clients (`OkHttpClientFactory`).
The `OkHttpClientFactory` bean is created only if the OK HTTP jar is on the classpath.
@@ -725,13 +824,13 @@ If you would like to customize how the HTTP clients are created in downstream pr
In addition, if you provide a bean of type `HttpClientBuilder` or `OkHttpClient.Builder`, 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 `spring.cloud.httpclientfactories.apache.enabled` or `spring.cloud.httpclientfactories.ok.enabled` to `false`.
-### [](#enabled-features)[2.10. Enabled Features](#enabled-features) ###
+### [](#enabled-features)[2.10. Enabled Features](#enabled-features)
Spring Cloud Commons provides a `/features` 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.
-#### [](#feature-types)[2.10.1. Feature types](#feature-types) ####
+#### [](#feature-types)[2.10.1. Feature types](#feature-types)
There are two types of 'features': abstract and named.
@@ -741,7 +840,7 @@ The version displayed is `bean.getClass().getPackage().getImplementationVersion(
Named features are features that do not have a particular class they implement. These features include “Circuit Breaker”, “API Gateway”, “Spring Cloud Bus”, and others. These features require a name and a bean type.
-#### [](#declaring-features)[2.10.2. Declaring features](#declaring-features) ####
+#### [](#declaring-features)[2.10.2. Declaring features](#declaring-features)
Any module can declare any number of `HasFeature` beans, as the following examples show:
@@ -770,7 +869,7 @@ HasFeatures localFeatures() {
Each of these beans should go in an appropriately guarded `@Configuration`.
-### [](#spring-cloud-compatibility-verification)[2.11. Spring Cloud Compatibility Verification](#spring-cloud-compatibility-verification) ###
+### [](#spring-cloud-compatibility-verification)[2.11. Spring Cloud Compatibility Verification](#spring-cloud-compatibility-verification)
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
@@ -804,8 +903,7 @@ In order to disable this feature, set `spring.cloud.compatibility-verifier.enabl
If you want to override the compatible Spring Boot versions, just set the`spring.cloud.compatibility-verifier.compatible-boot-versions` property with a comma separated list
of compatible Spring Boot versions.
-[](#spring-cloud-loadbalancer)[3. Spring Cloud LoadBalancer](#spring-cloud-loadbalancer)
-----------
+## [](#spring-cloud-loadbalancer)[3. Spring Cloud LoadBalancer](#spring-cloud-loadbalancer)
Spring Cloud provides its own client-side load-balancer abstraction and implementation. For the load-balancing
mechanism, `ReactiveLoadBalancer` interface has been added and a **Round-Robin-based** and **Random** implementations
@@ -814,7 +912,7 @@ have been provided for it. In order to get instances to select from reactive `Se
| |It is possible to disable Spring Cloud LoadBalancer by setting the value of `spring.cloud.loadbalancer.enabled` to `false`.|
|---|---------------------------------------------------------------------------------------------------------------------------|
-### [](#switching-between-the-load-balancing-algorithms)[3.1. Switching between the load-balancing algorithms](#switching-between-the-load-balancing-algorithms) ###
+### [](#switching-between-the-load-balancing-algorithms)[3.1. Switching between the load-balancing algorithms](#switching-between-the-load-balancing-algorithms)
The `ReactiveLoadBalancer` implementation that is used by default is `RoundRobinLoadBalancer`. To switch to a different implementation, either for selected services or all of them, you can use the [custom LoadBalancer configurations mechanism](#custom-loadbalancer-configuration).
@@ -837,7 +935,7 @@ public class CustomLoadBalancerConfiguration {
| |The classes you pass as `@LoadBalancerClient` or `@LoadBalancerClients` configuration arguments should either not be annotated with `@Configuration` or be outside component scan scope.|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#spring-cloud-loadbalancer-integrations)[3.2. Spring Cloud LoadBalancer integrations](#spring-cloud-loadbalancer-integrations) ###
+### [](#spring-cloud-loadbalancer-integrations)[3.2. Spring Cloud LoadBalancer integrations](#spring-cloud-loadbalancer-integrations)
In order to make it easy to use Spring Cloud LoadBalancer, we provide `ReactorLoadBalancerExchangeFilterFunction` that can be used with `WebClient` and `BlockingLoadBalancerClient` that works with `RestTemplate`.
You can see more information and examples of usage in the following sections:
@@ -848,11 +946,11 @@ You can see more information and examples of usage in the following sections:
* [Spring WebFlux WebClient with `ReactorLoadBalancerExchangeFilterFunction`](#webflux-with-reactive-loadbalancer)
-### [](#loadbalancer-caching)[3.3. Spring Cloud LoadBalancer Caching](#loadbalancer-caching) ###
+### [](#loadbalancer-caching)[3.3. Spring Cloud LoadBalancer Caching](#loadbalancer-caching)
Apart from the basic `ServiceInstanceListSupplier` implementation that retrieves instances via `DiscoveryClient` each time it has to choose an instance, we provide two caching implementations.
-#### [](#caffeine-backed-loadbalancer-cache-implementation)[3.3.1. ](#caffeine-backed-loadbalancer-cache-implementation)[Caffeine](https://github.com/ben-manes/caffeine)-backed LoadBalancer Cache Implementation ####
+#### [](#caffeine-backed-loadbalancer-cache-implementation)[3.3.1. ](#caffeine-backed-loadbalancer-cache-implementation)[Caffeine](https://github.com/ben-manes/caffeine)-backed LoadBalancer Cache Implementation
If you have `com.github.ben-manes.caffeine:caffeine` in the classpath, Caffeine-based implementation will be used.
See the [LoadBalancerCacheConfiguration](#loadbalancer-cache-configuration) section for information on how to configure it.
@@ -861,7 +959,7 @@ If you are using Caffeine, you can also override the default Caffeine Cache setu
WARN: Passing your own Caffeine specification will override any other LoadBalancerCache settings, including [General LoadBalancer Cache Configuration](#loadbalancer-cache-configuration) fields, such as `ttl` and `capacity`.
-#### [](#default-loadbalancer-cache-implementation)[3.3.2. Default LoadBalancer Cache Implementation](#default-loadbalancer-cache-implementation) ####
+#### [](#default-loadbalancer-cache-implementation)[3.3.2. Default LoadBalancer Cache Implementation](#default-loadbalancer-cache-implementation)
If you do not have Caffeine in the classpath, the `DefaultLoadBalancerCache`, which comes automatically with `spring-cloud-starter-loadbalancer`, will be used.
See the [LoadBalancerCacheConfiguration](#loadbalancer-cache-configuration) section for information on how to configure it.
@@ -869,7 +967,7 @@ See the [LoadBalancerCacheConfiguration](#loadbalancer-cache-configuration) sect
| |To use Caffeine instead of the default cache, add the `com.github.ben-manes.caffeine:caffeine` dependency to classpath.|
|---|-----------------------------------------------------------------------------------------------------------------------|
-#### [](#loadbalancer-cache-configuration)[3.3.3. LoadBalancer Cache Configuration](#loadbalancer-cache-configuration) ####
+#### [](#loadbalancer-cache-configuration)[3.3.3. LoadBalancer Cache Configuration](#loadbalancer-cache-configuration)
You can set your own `ttl` value (the time after write after which entries should be expired), expressed as `Duration`, by passing a `String` compliant with the [Spring Boot `String` to `Duration` converter syntax](https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-conversion-duration).
as the value of the `spring.cloud.loadbalancer.cache.ttl` property.
@@ -882,7 +980,7 @@ You can also altogether disable loadBalancer caching by setting the value of `sp
| |Although the basic, non-cached, implementation is useful for prototyping and testing, it’s much less efficient than the cached versions, so we recommend always using the cached version in production. If the caching is already done by the `DiscoveryClient` implementation, for example `EurekaDiscoveryClient`, the load-balancer caching should be disabled to prevent double caching.|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#zone-based-load-balancing)[3.4. Zone-Based Load-Balancing](#zone-based-load-balancing) ###
+### [](#zone-based-load-balancing)[3.4. Zone-Based Load-Balancing](#zone-based-load-balancing)
To enable zone-based load-balancing, we provide the `ZonePreferenceServiceInstanceListSupplier`.
We use `DiscoveryClient`-specific `zone` configuration (for example, `eureka.instance.metadata-map.zone`) to pick the zone that the client tries to filter available service instances for.
@@ -921,7 +1019,7 @@ public class CustomLoadBalancerConfiguration {
}
```
-### [](#instance-health-check-for-loadbalancer)[3.5. Instance Health-Check for LoadBalancer](#instance-health-check-for-loadbalancer) ###
+### [](#instance-health-check-for-loadbalancer)[3.5. Instance Health-Check for LoadBalancer](#instance-health-check-for-loadbalancer)
It is possible to enable a scheduled HealthCheck for the LoadBalancer. The `HealthCheckServiceInstanceListSupplier`is provided for that. It regularly verifies if the instances provided by a delegate`ServiceInstanceListSupplier` are still alive and only returns the healthy instances,
unless there are none - then it returns all the retrieved instances.
@@ -971,7 +1069,7 @@ public class CustomLoadBalancerConfiguration {
| |`HealthCheckServiceInstanceListSupplier` has its own caching mechanism based on Reactor Flux `replay()`. Therefore, if it’s being used, you may want to skip wrapping that supplier with `CachingServiceInstanceListSupplier`.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#same-instance-preference-for-loadbalancer)[3.6. Same instance preference for LoadBalancer](#same-instance-preference-for-loadbalancer) ###
+### [](#same-instance-preference-for-loadbalancer)[3.6. Same instance preference for LoadBalancer](#same-instance-preference-for-loadbalancer)
You can set up the LoadBalancer in such a way that it prefers the instance that was previously selected, if that instance is available.
@@ -994,7 +1092,7 @@ public class CustomLoadBalancerConfiguration {
| |This is also a replacement for Zookeeper `StickyRule`.|
|---|------------------------------------------------------|
-### [](#request-based-sticky-session-for-loadbalancer)[3.7. Request-based Sticky Session for LoadBalancer](#request-based-sticky-session-for-loadbalancer) ###
+### [](#request-based-sticky-session-for-loadbalancer)[3.7. Request-based Sticky Session for LoadBalancer](#request-based-sticky-session-for-loadbalancer)
You can set up the LoadBalancer in such a way that it prefers the instance with `instanceId` provided in a request cookie. We currently support this if the request is being passed to the LoadBalancer through either `ClientRequestContext` or `ServerHttpRequestContext`, which are used by the SC LoadBalancer exchange filter functions and filters.
@@ -1021,14 +1119,14 @@ By default, the name of the cookie is `sc-lb-instance-id`. You can modify it by
| |This feature is currently supported for WebClient-backed load-balancing.|
|---|------------------------------------------------------------------------|
-### [](#spring-cloud-loadbalancer-hints)[3.8. Spring Cloud LoadBalancer Hints](#spring-cloud-loadbalancer-hints) ###
+### [](#spring-cloud-loadbalancer-hints)[3.8. Spring Cloud LoadBalancer Hints](#spring-cloud-loadbalancer-hints)
Spring Cloud LoadBalancer lets you set `String` hints that are passed to the LoadBalancer within the `Request` object and that can later be used in `ReactiveLoadBalancer` implementations that can handle them.
You can set a default hint for all services by setting the value of the `spring.cloud.loadbalancer.hint.default` property. You can also set a specific value
for any given service by setting the value of the `spring.cloud.loadbalancer.hint.[SERVICE_ID]` property, substituting `[SERVICE_ID]` with the correct ID of your service. If the hint is not set by the user, `default` is used.
-### [](#hints-based-loadbalancing)[3.9. Hint-Based Load-Balancing](#hints-based-loadbalancing) ###
+### [](#hints-based-loadbalancing)[3.9. Hint-Based Load-Balancing](#hints-based-loadbalancing)
We also provide a `HintBasedServiceInstanceListSupplier`, which is a `ServiceInstanceListSupplier` implementation for hint-based instance selection.
@@ -1057,7 +1155,7 @@ public class CustomLoadBalancerConfiguration {
}
```
-### [](#transform-the-load-balanced-http-request)[3.10. Transform the load-balanced HTTP request](#transform-the-load-balanced-http-request) ###
+### [](#transform-the-load-balanced-http-request)[3.10. Transform the load-balanced HTTP request](#transform-the-load-balanced-http-request)
You can use the selected `ServiceInstance` to transform the load-balanced HTTP Request.
@@ -1102,7 +1200,7 @@ public LoadBalancerClientRequestTransformer transformer() {
If multiple transformers are defined, they are applied in the order in which Beans are defined.
Alternatively, you can use `LoadBalancerRequestTransformer.DEFAULT_ORDER` or `LoadBalancerClientRequestTransformer.DEFAULT_ORDER` to specify the order.
-### [](#spring-cloud-loadbalancer-starter)[3.11. Spring Cloud LoadBalancer Starter](#spring-cloud-loadbalancer-starter) ###
+### [](#spring-cloud-loadbalancer-starter)[3.11. Spring Cloud LoadBalancer Starter](#spring-cloud-loadbalancer-starter)
We also provide a starter that allows you to easily add Spring Cloud LoadBalancer in a Spring Boot app.
In order to use it, just add `org.springframework.cloud:spring-cloud-starter-loadbalancer` to your Spring Cloud dependencies in your build file.
@@ -1110,7 +1208,7 @@ In order to use it, just add `org.springframework.cloud:spring-cloud-starter-loa
| |Spring Cloud LoadBalancer starter includes[Spring Boot Caching](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-caching.html)and [Evictor](https://github.com/stoyanr/Evictor).|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#custom-loadbalancer-configuration)[3.12. Passing Your Own Spring Cloud LoadBalancer Configuration](#custom-loadbalancer-configuration) ###
+### [](#custom-loadbalancer-configuration)[3.12. Passing Your Own Spring Cloud LoadBalancer Configuration](#custom-loadbalancer-configuration)
You can also use the `@LoadBalancerClient` annotation to pass your own load-balancer client configuration, passing the name of the load-balancer client and the configuration class, as follows:
@@ -1160,7 +1258,7 @@ public class MyConfiguration {
| |The classes you pass as `@LoadBalancerClient` or `@LoadBalancerClients` configuration arguments should either not be annotated with `@Configuration` or be outside component scan scope.|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#loadbalancer-lifecycle)[3.13. Spring Cloud LoadBalancer Lifecycle](#loadbalancer-lifecycle) ###
+### [](#loadbalancer-lifecycle)[3.13. Spring Cloud LoadBalancer Lifecycle](#loadbalancer-lifecycle)
One type of bean that it may be useful to register using [Custom LoadBalancer configuration](#custom-loadbalancer-configuration) is `LoadBalancerLifecycle`.
@@ -1174,7 +1272,7 @@ Class serverTypeClass)` method can be used to determine whether the processor in
| |In the preceding method calls, `RC` means `RequestContext` type, `RES` means client response type, and `T` means returned server type.|
|---|--------------------------------------------------------------------------------------------------------------------------------------|
-### [](#loadbalancer-micrometer-stats-lifecycle)[3.14. Spring Cloud LoadBalancer Statistics](#loadbalancer-micrometer-stats-lifecycle) ###
+### [](#loadbalancer-micrometer-stats-lifecycle)[3.14. Spring Cloud LoadBalancer Statistics](#loadbalancer-micrometer-stats-lifecycle)
We provide a `LoadBalancerLifecycle` bean called `MicrometerStatsLoadBalancerLifecycle`, which uses Micrometer to provide statistics for load-balanced calls.
@@ -1202,7 +1300,7 @@ Additional information regarding the service instances, request data, and respon
| |You can further configure the behavior of those metrics (for example, add [publishing percentiles and histograms](https://micrometer.io/docs/concepts#_histograms_and_percentiles)) by [adding `MeterFilters`](https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-metrics-per-meter-properties).|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#configuring-individual-loadbalancerclients)[3.15. Configuring Individual LoadBalancerClients](#configuring-individual-loadbalancerclients) ###
+### [](#configuring-individual-loadbalancerclients)[3.15. Configuring Individual LoadBalancerClients](#configuring-individual-loadbalancerclients)
Individual Loadbalancer clients may be configured individually with a different prefix `spring.cloud.loadbalancer.clients..` **where `clientId` is the name of the loadbalancer. Default configuration values may be set in the `spring.cloud.loadbalancer.`** namespace and will be merged with the client specific values taking precedence
@@ -1235,15 +1333,14 @@ The per-client configuration properties work for most of the properties, apart f
| |For the properties where maps where already used, where you could specify a different value per-client without using the `clients` keyword (for example, `hints`, `health-check.path`), we have kept that behaviour in order to keep the library backwards compatible. It will be modified in the next major release.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#spring-cloud-circuit-breaker)[4. Spring Cloud Circuit Breaker](#spring-cloud-circuit-breaker)
-----------
+## [](#spring-cloud-circuit-breaker)[4. Spring Cloud Circuit Breaker](#spring-cloud-circuit-breaker)
-### [](#introduction)[4.1. Introduction](#introduction) ###
+### [](#introduction)[4.1. Introduction](#introduction)
Spring Cloud Circuit breaker provides an abstraction across different circuit breaker implementations.
It provides a consistent API to use in your applications, letting you, the developer, choose the circuit breaker implementation that best fits your needs for your application.
-#### [](#supported-implementations)[4.1.1. Supported Implementations](#supported-implementations) ####
+#### [](#supported-implementations)[4.1.1. Supported Implementations](#supported-implementations)
Spring Cloud supports the following circuit-breaker implementations:
@@ -1253,7 +1350,7 @@ Spring Cloud supports the following circuit-breaker implementations:
* [Spring Retry](https://github.com/spring-projects/spring-retry)
-### [](#core-concepts)[4.2. Core Concepts](#core-concepts) ###
+### [](#core-concepts)[4.2. Core Concepts](#core-concepts)
To create a circuit breaker in your code, you can use the `CircuitBreakerFactory` API. When you include a Spring Cloud Circuit Breaker starter on your classpath, a bean that implements this API is automatically created for you.
The following example shows a simple example of how to use this API:
@@ -1283,7 +1380,7 @@ The `Function` is the fallback that is run if the circuit breaker is tripped.
The function is passed the `Throwable` that caused the fallback to be triggered.
You can optionally exclude the fallback if you do not want to provide one.
-#### [](#circuit-breakers-in-reactive-code)[4.2.1. Circuit Breakers In Reactive Code](#circuit-breakers-in-reactive-code) ####
+#### [](#circuit-breakers-in-reactive-code)[4.2.1. Circuit Breakers In Reactive Code](#circuit-breakers-in-reactive-code)
If Project Reactor is on the class path, you can also use `ReactiveCircuitBreakerFactory` for your reactive code.
The following example shows how to do so:
@@ -1310,7 +1407,7 @@ The `ReactiveCircuitBreakerFactory.create` API creates an instance of a class ca
The `run` method takes a `Mono` or a `Flux` and wraps it in a circuit breaker.
You can optionally profile a fallback `Function`, which will be called if the circuit breaker is tripped and is passed the `Throwable`that caused the failure.
-### [](#configuration)[4.3. Configuration](#configuration) ###
+### [](#configuration)[4.3. Configuration](#configuration)
You can configure your circuit breakers by creating beans of type `Customizer`.
The `Customizer` interface has a single method (called `customize`) that takes the `Object` to customize.
@@ -1337,8 +1434,7 @@ Customizer.once(circuitBreaker -> {
}, CircuitBreaker::getName)
```
-[](#cachedrandompropertysource)[5. CachedRandomPropertySource](#cachedrandompropertysource)
-----------
+## [](#cachedrandompropertysource)[5. CachedRandomPropertySource](#cachedrandompropertysource)
Spring Cloud Context provides a `PropertySource` that caches random values based on a key. Outside of the caching
functionality it works the same as Spring Boot’s [`RandomValuePropertySource`](https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/RandomValuePropertySource.java).
@@ -1350,15 +1446,14 @@ be any type supported by Spring Boot’s `RandomValuePropertySource`.
myrandom=${cachedrandom.appname.value}
```
-[](#spring-cloud-security)[6. Security](#spring-cloud-security)
-----------
+## [](#spring-cloud-security)[6. Security](#spring-cloud-security)
-### [](#spring-cloud-security-single-sign-on)[6.1. Single Sign On](#spring-cloud-security-single-sign-on) ###
+### [](#spring-cloud-security-single-sign-on)[6.1. Single Sign On](#spring-cloud-security-single-sign-on)
| |All of the OAuth2 SSO and resource server features moved to Spring Boot
in version 1.3. You can find documentation in the[Spring Boot user guide](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/).|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [](#spring-cloud-security-client-token-relay)[6.1.1. Client Token Relay](#spring-cloud-security-client-token-relay) ####
+#### [](#spring-cloud-security-client-token-relay)[6.1.1. Client Token Relay](#spring-cloud-security-client-token-relay)
If your app is a user facing OAuth2 client (i.e. has declared`@EnableOAuth2Sso` or `@EnableOAuth2Client`) then it has an`OAuth2ClientContext` in request scope from Spring Boot. You can
create your own `OAuth2RestTemplate` from this context and an
@@ -1367,7 +1462,7 @@ always forward the access token downstream, also refreshing the access
token automatically if it expires. (These are features of Spring
Security and Spring Boot.)
-#### [](#spring-cloud-security-resource-server-token-relay)[6.1.2. Resource Server Token Relay](#spring-cloud-security-resource-server-token-relay) ####
+#### [](#spring-cloud-security-resource-server-token-relay)[6.1.2. Resource Server Token Relay](#spring-cloud-security-resource-server-token-relay)
If your app has `@EnableResourceServer` you might want to relay the
incoming token downstream to other services. If you use a`RestTemplate` to contact the downstream services then this is just a
@@ -1425,8 +1520,8 @@ client that sent you the token), then you only need to create your own`OAuth2Con
Feign clients will also pick up an interceptor that uses the`OAuth2ClientContext` if it is available, so they should also do a
token relay anywhere where a `RestTemplate` would.
-[](#configuration-properties)[7. Configuration Properties](#configuration-properties)
-----------
+## [](#configuration-properties)[7. Configuration Properties](#configuration-properties)
To see the list of all Spring Cloud Commons related configuration properties please check [the Appendix page](appendix.html).
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-config.md b/docs/en/spring-cloud/spring-cloud-config.md
index a7380542bfe3a309060a6cd0ac3481eb79da936c..30bf2ab87a0fa3b0c09f529a3ae0f58346bd91b8 100644
--- a/docs/en/spring-cloud/spring-cloud-config.md
+++ b/docs/en/spring-cloud/spring-cloud-config.md
@@ -1,5 +1,58 @@
-Spring Cloud Config
-==========
+Spring Cloud Config.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Config
+
+Table of Contents
+
+* [Quick Start](#_quick_start)
+ * [Client Side Usage](#_client_side_usage)
+
+* [Spring Cloud Config Server](#_spring_cloud_config_server)
+ * [Environment Repository](#_environment_repository)
+ * [Health Indicator](#_health_indicator)
+ * [Security](#_security)
+ * [Actuator and Security](#_actuator_and_security)
+ * [Encryption and Decryption](#_encryption_and_decryption)
+ * [Key Management](#_key_management)
+ * [Creating a Key Store for Testing](#_creating_a_key_store_for_testing)
+ * [Using Multiple Keys and Key Rotation](#_using_multiple_keys_and_key_rotation)
+ * [Serving Encrypted Properties](#_serving_encrypted_properties)
+
+* [Serving Alternative Formats](#_serving_alternative_formats)
+* [Serving Plain Text](#_serving_plain_text)
+ * [Git, SVN, and Native Backends](#spring-cloud-config-serving-plain-text-git-svn-native-backends)
+ * [AWS S3](#spring-cloud-config-serving-plain-text-aws-s3)
+ * [Decrypting Plain Text](#_decrypting_plain_text)
+
+* [Embedding the Config Server](#_embedding_the_config_server)
+* [Push Notifications and Spring Cloud Bus](#_push_notifications_and_spring_cloud_bus)
+* [Spring Cloud Config Client](#_spring_cloud_config_client)
+ * [Spring Boot Config Data Import](#config-data-import)
+ * [Config First Bootstrap](#config-first-bootstrap)
+ * [Config Client Fail Fast](#config-client-fail-fast)
+ * [Config Client Retry](#config-client-retry)
+ * [Config Client Retry with spring.config.import](#_config_client_retry_with_spring_config_import)
+ * [Locating Remote Configuration Resources](#_locating_remote_configuration_resources)
+ * [Specifying Multiple Urls for the Config Server](#_specifying_multiple_urls_for_the_config_server)
+ * [Configuring Timeouts](#_configuring_timeouts)
+ * [Security](#_security_2)
+ * [Nested Keys In Vault](#_nested_keys_in_vault)
+
+**3.1.1**
Spring Cloud Config provides server-side and client-side support for externalized configuration in a distributed system. With the Config Server, you have a central place to manage external properties for applications across all environments.
The concepts on both client and server map identically to the Spring `Environment` and `PropertySource` abstractions, so they fit very well with Spring applications but can be used with any application running in any language.
@@ -7,8 +60,7 @@ As an application moves through the deployment pipeline from dev to test and int
The default implementation of the server storage backend uses git, so it easily supports labelled versions of configuration environments as well as being accessible to a wide range of tooling for managing the content.
It is easy to add alternative implementations and plug them in with Spring configuration.
-[Quick Start](#_quick_start)
-----------
+## [Quick Start](#_quick_start)
This quick start walks through using both the server and the client of Spring Cloud Config Server.
@@ -88,7 +140,7 @@ spring:
Other sources are any JDBC compatible database, Subversion, Hashicorp Vault, Credhub and local filesystems.
-### [Client Side Usage](#_client_side_usage) ###
+### [Client Side Usage](#_client_side_usage)
To use these features in an application, you can build it as a Spring Boot application that depends on spring-cloud-config-client (for an example, see the test cases for the config-client or the sample application).
The most convenient way to add the dependency is with a Spring Boot starter `org.springframework.cloud:spring-cloud-starter-config`.
@@ -206,8 +258,7 @@ A property source called `configserver:/` c
| |If you use Spring Cloud Config Client, you need to set the `spring.config.import` property in order to bind to Config Server. You can read more about it [in the Spring Cloud Config Reference Guide](https://docs.spring.io/spring-cloud-config/docs/current/reference/html/#config-data-import).|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[Spring Cloud Config Server](#_spring_cloud_config_server)
-----------
+## [Spring Cloud Config Server](#_spring_cloud_config_server)
Spring Cloud Config Server provides an HTTP resource-based API for external configuration (name-value pairs or equivalent YAML content).
The server is embeddable in a Spring Boot application, by using the `@EnableConfigServer` annotation.
@@ -250,7 +301,7 @@ where `${user.home}/config-repo` is a git repository containing YAML and propert
| |The initial clone of your configuration repository can be quick and efficient if you keep only text files in it.
If you store binary files, especially large ones, you may experience delays on the first request for configuration or encounter out of memory errors in the server.|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [Environment Repository](#_environment_repository) ###
+### [Environment Repository](#_environment_repository)
Where should you store the configuration data for the Config Server?
The strategy that governs this behaviour is the `EnvironmentRepository`, serving `Environment` objects.
@@ -286,7 +337,7 @@ Higher precedence translates to a `PropertySource` listed earlier in the `Enviro
You can set spring.cloud.config.server.accept-empty to false so that Server would return a HTTP 404 status, if the application is not found.By default, this flag is set to true.
-#### [Git Backend](#_git_backend) ####
+#### [Git Backend](#_git_backend)
The default implementation of `EnvironmentRepository` uses a Git backend, which is very convenient for managing upgrades and physical environments and for auditing changes.
To change the location of the repository, you can set the `spring.cloud.config.server.git.uri` configuration property in the Config Server (for example in `application.yml`).
@@ -300,7 +351,7 @@ For example, if the label is `foo/bar`, replacing the slash would result in the
The inclusion of the special string `(_)` can also be applied to the `{application}` parameter.
If you use a command-line client such as curl, be careful with the brackets in the URL — you should escape them from the shell with single quotes ('').
-##### [Skipping SSL Certificate Validation](#_skipping_ssl_certificate_validation) #####
+##### [Skipping SSL Certificate Validation](#_skipping_ssl_certificate_validation)
The configuration server’s validation of the Git server’s SSL certificate can be disabled by setting the `git.skipSslValidation` property to `true` (default is `false`).
@@ -314,7 +365,7 @@ spring:
skipSslValidation: true
```
-##### [Setting HTTP Connection Timeout](#_setting_http_connection_timeout) #####
+##### [Setting HTTP Connection Timeout](#_setting_http_connection_timeout)
You can configure the time, in seconds, that the configuration server will wait to acquire an HTTP connection. Use the `git.timeout` property.
@@ -328,7 +379,7 @@ spring:
timeout: 4
```
-##### [Placeholders in Git URI](#_placeholders_in_git_uri) #####
+##### [Placeholders in Git URI](#_placeholders_in_git_uri)
Spring Cloud Config Server supports a git repository URL with placeholders for the `{application}` and `{profile}` (and `{label}` if you need it, but remember that the label is applied as a git label anyway).
So you can support a “one repository per application” policy by using a structure similar to the following:
@@ -358,7 +409,7 @@ spring:
where `{application}` is provided at request time in the following format: `organization(_)application`.
-##### [Pattern Matching and Multiple Repositories](#_pattern_matching_and_multiple_repositories) #####
+##### [Pattern Matching and Multiple Repositories](#_pattern_matching_and_multiple_repositories)
Spring Cloud Config also includes support for more complex requirements with pattern
matching on the application and profile name.
@@ -462,7 +513,7 @@ All other repositories are not cloned until configuration from the repository is
| |Setting a repository to be cloned when the Config Server starts up can help to identify a misconfigured configuration source (such as an invalid repository URI) quickly, while the Config Server is starting up.
With `cloneOnStart` not enabled for a configuration source, the Config Server may start successfully with a misconfigured or invalid configuration source and not detect an error until an application requests configuration from that configuration source.|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-##### [Authentication](#_authentication) #####
+##### [Authentication](#_authentication)
To use HTTP basic authentication on the remote repository, add the `username` and `password` properties separately (not in the URL), as shown in the following example:
@@ -503,7 +554,7 @@ Warning: When working with SSH keys, the expected ssh private-key must begin wit
To correct the above error the RSA key must be converted to PEM format. An example using openssh is provided above for generating a new key in the appropriate format.
-##### [Authentication with AWS CodeCommit](#_authentication_with_aws_codecommit) #####
+##### [Authentication with AWS CodeCommit](#_authentication_with_aws_codecommit)
Spring Cloud Config Server also supports [AWS CodeCommit](https://docs.aws.amazon.com/codecommit/latest/userguide/welcome.html) authentication.
AWS CodeCommit uses an authentication helper when using Git from the command line.
@@ -523,7 +574,7 @@ AWS EC2 instances may use [IAM Roles for EC2 Instances](https://docs.aws.amazon.
| |The `aws-java-sdk-core` jar is an optional dependency.
If the `aws-java-sdk-core` jar is not on your classpath, the AWS Code Commit credential provider is not created, regardless of the git server URI.|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-##### [Authentication with Google Cloud Source](#_authentication_with_google_cloud_source) #####
+##### [Authentication with Google Cloud Source](#_authentication_with_google_cloud_source)
Spring Cloud Config Server also supports authenticating against [Google Cloud Source](https://cloud.google.com/source-repositories/) repositories.
@@ -534,7 +585,7 @@ The Google Cloud Source credentials provider will use Google Cloud Platform appl
| |`com.google.auth:google-auth-library-oauth2-http` is an optional dependency.
If the `google-auth-library-oauth2-http` jar is not on your classpath, the Google Cloud Source credential provider is not created, regardless of the git server URI.|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-##### [Git SSH configuration using properties](#_git_ssh_configuration_using_properties) #####
+##### [Git SSH configuration using properties](#_git_ssh_configuration_using_properties)
By default, the JGit library used by Spring Cloud Config Server uses SSH configuration files such as `~/.ssh/known_hosts` and `/etc/ssh/ssh_config` when connecting to Git repositories by using an SSH URI.
In cloud environments such as Cloud Foundry, the local filesystem may be ephemeral or not easily accessible.
@@ -593,7 +644,7 @@ The following table describes the SSH configuration properties.
| **knownHostsFile** | Location of custom `.known_hosts` file. |
|**preferredAuthentications**| Override server authentication method order. This should allow for evading login prompts if server has keyboard-interactive authentication before the `publickey` method. |
-##### [Placeholders in Git Search Paths](#_placeholders_in_git_search_paths) #####
+##### [Placeholders in Git Search Paths](#_placeholders_in_git_search_paths)
Spring Cloud Config Server also supports a search path with placeholders for the `{application}` and `{profile}` (and `{label}` if
you need it), as shown in the following example:
@@ -611,7 +662,7 @@ spring:
The preceding listing causes a search of the repository for files in the same name as the directory (as well as the top level).
Wildcards are also valid in a search path with placeholders (any matching directory is included in the search).
-##### [Force pull in Git Repositories](#_force_pull_in_git_repositories) #####
+##### [Force pull in Git Repositories](#_force_pull_in_git_repositories)
As mentioned earlier, Spring Cloud Config Server makes a clone of the remote git repository in case the local copy gets dirty (for example,
folder content changes by an OS process) such that Spring Cloud Config Server cannot update the local copy from remote repository.
@@ -655,7 +706,7 @@ spring:
| |The default value for `force-pull` property is `false`.|
|---|-------------------------------------------------------|
-##### [Deleting untracked branches in Git Repositories](#_deleting_untracked_branches_in_git_repositories) #####
+##### [Deleting untracked branches in Git Repositories](#_deleting_untracked_branches_in_git_repositories)
As Spring Cloud Config Server has a clone of the remote git repository
after check-outing branch to local repo (e.g fetching properties by label) it will keep this branch
@@ -680,7 +731,7 @@ spring:
| |The default value for `deleteUntrackedBranches` property is `false`.|
|---|--------------------------------------------------------------------|
-##### [Git Refresh Rate](#_git_refresh_rate) #####
+##### [Git Refresh Rate](#_git_refresh_rate)
You can control how often the config server will fetch updated configuration data
from your Git backend by using `spring.cloud.config.server.git.refreshRate`. The
@@ -688,17 +739,17 @@ value of this property is specified in seconds. By default the value is 0, meani
the config server will fetch updated configuration from the Git repo every time it
is requested.
-##### [Default Label](#_default_label) #####
+##### [Default Label](#_default_label)
The default label used for Git is `main`. If you do not set `spring.cloud.config.server.git.defaultLabel` and a branch named `main`does not exist, the config server will by default also try to checkout a branch named `master`. If
you would like to disable to the fallback branch behavior you can set`spring.cloud.config.server.git.tryMasterBranch` to `false`.
-#### [Version Control Backend Filesystem Use](#_version_control_backend_filesystem_use) ####
+#### [Version Control Backend Filesystem Use](#_version_control_backend_filesystem_use)
| |With VCS-based backends (git, svn), files are checked out or cloned to the local filesystem.
By default, they are put in the system temporary directory with a prefix of `config-repo-`.
On linux, for example, it could be `/tmp/config-repo-`.
Some operating systems [routinely clean out](https://serverfault.com/questions/377348/when-does-tmp-get-cleared/377349#377349) temporary directories.
This can lead to unexpected behavior, such as missing properties.
To avoid this problem, change the directory that Config Server uses by setting `spring.cloud.config.server.git.basedir` or `spring.cloud.config.server.svn.basedir` to a directory that does not reside in the system temp structure.|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [File System Backend](#_file_system_backend) ####
+#### [File System Backend](#_file_system_backend)
There is also a “native” profile in the Config Server that does not use Git but loads the config files from the local classpath or file system (any static URL you want to point to with `spring.cloud.config.server.native.searchLocations`).
To use the native profile, launch the Config Server with `spring.profiles.active=native`.
@@ -720,7 +771,7 @@ Thus, the default behaviour with no placeholders is the same as adding a search
For example, `file:/tmp/config` is the same as `file:/tmp/config,file:/tmp/config/{label}`.
This behavior can be disabled by setting `spring.cloud.config.server.native.addLabelLocations=false`.
-#### [Vault Backend](#vault-backend) ####
+#### [Vault Backend](#vault-backend)
Spring Cloud Config Server also supports [Vault](https://www.vaultproject.io) as a backend.
@@ -837,7 +888,7 @@ See the [Spring Cloud Vault Reference Guide](https://cloud.spring.io/spring-clou
| |If you omit the X-Config-Token header and use a server property to set the authentication, the Config Server application needs an additional dependency on Spring Vault to enable the additional authentication options.
See the [Spring Vault Reference Guide](https://docs.spring.io/spring-vault/docs/current/reference/html/#dependencies) for how to add that dependency.|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-##### [Multiple Properties Sources](#_multiple_properties_sources) #####
+##### [Multiple Properties Sources](#_multiple_properties_sources)
When using Vault, you can provide your applications with multiple properties sources.
For example, assume you have written data to the following paths in Vault:
@@ -853,7 +904,7 @@ Properties written to `secret/application` are available to [all applications us
An application with the name, `myApp`, would have any properties written to `secret/myApp` and `secret/application` available to it.
When `myApp` has the `dev` profile enabled, properties written to all of the above paths would be available to it, with properties in the first path in the list taking priority over the others.
-#### [Accessing Backends Through a Proxy](#_accessing_backends_through_a_proxy) ####
+#### [Accessing Backends Through a Proxy](#_accessing_backends_through_a_proxy)
The configuration server can access a Git or Vault backend through an HTTP or HTTPS proxy. This behavior is controlled for either Git or Vault by settings under `proxy.http` and `proxy.https`. These settings are per repository, so if you are using a [composite environment repository](#composite-environment-repositories) you must configure proxy settings for each backend in the composite individually. If using a network which requires separate proxy servers for HTTP and HTTPS URLs, you can configure both the HTTP and the HTTPS proxy settings for a single backend.
@@ -887,7 +938,7 @@ spring:
nonProxyHosts: example.com
```
-#### [Sharing Configuration With All Applications](#_sharing_configuration_with_all_applications) ####
+#### [Sharing Configuration With All Applications](#_sharing_configuration_with_all_applications)
Sharing configuration between all applications varies according to which approach you take, as described in the following topics:
@@ -895,7 +946,7 @@ Sharing configuration between all applications varies according to which approac
* [Vault Server](#spring-cloud-config-server-vault-server)
-##### [File Based Repositories](#spring-cloud-config-server-file-based-repositories) #####
+##### [File Based Repositories](#spring-cloud-config-server-file-based-repositories)
With file-based (git, svn, and native) repositories, resources with file names in `application*` (`application.properties`, `application.yml`, `application-*.properties`, and so on) are shared between all client applications.
You can use resources with these file names to configure global defaults and have them be overridden by application-specific files as necessary.
@@ -906,7 +957,7 @@ allowed to override them locally.
| |With the “native” profile (a local file system backend) , you should use an explicit search location that is not part of the server’s own configuration.
Otherwise, the `application*` resources in the default search locations get removed because they are part of the server.|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-##### [Vault Server](#spring-cloud-config-server-vault-server) #####
+##### [Vault Server](#spring-cloud-config-server-vault-server)
When using Vault as a backend, you can share configuration with all applications by placing configuration in `secret/application`.
For example, if you run the following Vault command, all applications using the config server will have the properties `foo` and `baz` available to them:
@@ -915,7 +966,7 @@ For example, if you run the following Vault command, all applications using the
$ vault write secret/application foo=bar baz=bam
```
-##### [CredHub Server](#_credhub_server) #####
+##### [CredHub Server](#_credhub_server)
When using CredHub as a backend, you can share configuration with all applications by placing configuration in `/application/` or by placing it in the `default` profile for the application.
For example, if you run the following CredHub command, all applications using the config server will have the properties `shared.color1` and `shared.color2` available to them:
@@ -930,7 +981,7 @@ credhub set --name "/my-app/default/master/more-shared" --type=json
value: {"shared.word1": "hello", "shared.word2": "world"}
```
-#### [AWS Secrets Manager](#_aws_secrets_manager) ####
+#### [AWS Secrets Manager](#_aws_secrets_manager)
When using AWS Secrets Manager as a backend, you can share configuration with all applications by placing configuration in `/application/` or by placing it in the `default` profile for the application.
For example, if you add secrets with the following keys, all application using the config server will have the properties `shared.foo` and `shared.bar` available to them:
@@ -961,7 +1012,7 @@ secret value =
}
```
-##### [AWS Parameter Store](#_aws_parameter_store) #####
+##### [AWS Parameter Store](#_aws_parameter_store)
When using AWS Parameter Store as a backend, you can share configuration with all applications by placing properties within the `/application` hierarchy.
@@ -972,7 +1023,7 @@ For example, if you add parameters with the following names, all applications us
/config/application-default/fred.baz
```
-#### [JDBC Backend](#_jdbc_backend) ####
+#### [JDBC Backend](#_jdbc_backend)
Spring Cloud Config Server supports JDBC (relational database) as a backend for configuration properties.
You can enable this feature by adding `spring-jdbc` to the classpath and using the `jdbc` profile or by adding a bean of type `JdbcEnvironmentRepository`.
@@ -984,7 +1035,7 @@ The database needs to have a table called `PROPERTIES` with columns called `APPL
All fields are of type String in Java, so you can make them `VARCHAR` of whatever length you need.
Property values behave in the same way as they would if they came from Spring Boot properties files named `{application}-{profile}.properties`, including all the encryption and decryption, which will be applied as post-processing steps (that is, not in the repository implementation directly).
-#### [Redis Backend](#_redis_backend) ####
+#### [Redis Backend](#_redis_backend)
Spring Cloud Config Server supports Redis as a backend for configuration properties.
You can enable this feature by adding a dependency to [Spring Data Redis](https://spring.io/projects/spring-data-redis).
@@ -1031,7 +1082,7 @@ HGETALL sample-app
| |When no profile is specified `default` will be used.|
|---|----------------------------------------------------|
-#### [AWS S3 Backend](#_aws_s3_backend) ####
+#### [AWS S3 Backend](#_aws_s3_backend)
Spring Cloud Config Server supports AWS S3 as a backend for configuration properties.
You can enable this feature by adding a dependency to the [AWS Java SDK For Amazon S3](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/examples-s3.html).
@@ -1070,7 +1121,7 @@ Configuration files are stored in your bucket as `{application}-{profile}.proper
| |When no profile is specified `default` will be used.|
|---|----------------------------------------------------|
-#### [AWS Parameter Store Backend](#_aws_parameter_store_backend) ####
+#### [AWS Parameter Store Backend](#_aws_parameter_store_backend)
Spring Cloud Config Server supports AWS Parameter Store as a backend for configuration properties. You can enable this feature by adding a dependency to the [AWS Java SDK for SSM](https://github.com/aws/aws-sdk-java/tree/master/aws-java-sdk-ssm).
@@ -1122,7 +1173,7 @@ Versioned parameters are already supported with the default behaviour of returni
| |* When no application is specified `application` is the default, and when no profile is specified `default` is used.
* Valid values for `awsparamstore.prefix` must start with a forward slash followed by one or more valid path segments or be empty.
* Valid values for `awsparamstore.profile-separator` can only contain dots, dashes and underscores.
* Valid values for `awsparamstore.max-results` must be within the **[1, 10]** range.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [AWS Secrets Manager Backend](#_aws_secrets_manager_backend) ####
+#### [AWS Secrets Manager Backend](#_aws_secrets_manager_backend)
Spring Cloud Config Server supports [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) as a backend for configuration properties.
You can enable this feature by adding a dependency to [AWS Java SDK for Secrets Manager](https://github.com/aws/aws-sdk-java/tree/master/aws-java-sdk-secretsmanager).
@@ -1158,7 +1209,7 @@ AWS Secrets Manager API credentials are determined using [Default Credential Pro
| |* When no application is specified `application` is the default, and when no profile is specified `default` is used.|
|---|--------------------------------------------------------------------------------------------------------------------|
-#### [CredHub Backend](#_credhub_backend) ####
+#### [CredHub Backend](#_credhub_backend)
Spring Cloud Config Server supports [CredHub](https://docs.cloudfoundry.org/credhub) as a backend for configuration properties.
You can enable this feature by adding a dependency to [Spring CredHub](https://spring.io/projects/spring-credhub).
@@ -1213,7 +1264,7 @@ All client applications with the name `spring.cloud.config.name=demo-app` will h
| |When no profile is specified `default` will be used and when no label is specified `master` will be used as a default value.
NOTE: Values added to `application` will be shared by all the applications.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-##### [OAuth 2.0](#_oauth_2_0) #####
+##### [OAuth 2.0](#_oauth_2_0)
You can authenticate with [OAuth 2.0](https://oauth.net/2/) using [UAA](https://docs.cloudfoundry.org/concepts/architecture/uaa.html) as a provider.
@@ -1262,7 +1313,7 @@ spring:
| |The used UAA client-id should have `credhub.read` as scope.|
|---|-----------------------------------------------------------|
-#### [Composite Environment Repositories](#composite-environment-repositories) ####
+#### [Composite Environment Repositories](#composite-environment-repositories)
In some scenarios, you may wish to pull configuration data from multiple environment repositories.
To do so, you can enable the `composite` profile in your configuration server’s application properties or YAML file.
@@ -1324,14 +1375,14 @@ The priority order of a repository helps resolve any potential conflicts between
| |When using a composite environment, it is important that all repositories contain the same labels.
If you have an environment similar to those in the preceding examples and you request configuration data with the `master` label but the Subversion repository does not contain a branch called `master`, the entire request fails.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-##### [Custom Composite Environment Repositories](#_custom_composite_environment_repositories) #####
+##### [Custom Composite Environment Repositories](#_custom_composite_environment_repositories)
In addition to using one of the environment repositories from Spring Cloud, you can also provide your own `EnvironmentRepository` bean to be included as part of a composite environment.
To do so, your bean must implement the `EnvironmentRepository` interface.
If you want to control the priority of your custom `EnvironmentRepository` within the composite environment, you should also implement the `Ordered` interface and override the `getOrdered` method.
If you do not implement the `Ordered` interface, your `EnvironmentRepository` is given the lowest priority.
-#### [Property Overrides](#property-overrides) ####
+#### [Property Overrides](#property-overrides)
The Config Server has an “overrides” feature that lets the operator provide configuration properties to all applications.
The overridden properties cannot be accidentally changed by the application with the normal Spring Boot hooks.
@@ -1359,7 +1410,7 @@ The preceding examples causes all applications that are config clients to read `
You can change the priority of all overrides in the client to be more like default values, letting applications supply their own values in environment variables or System properties, by setting the `spring.cloud.config.overrideNone=true` flag (the default is false) in the remote repository.
-### [Health Indicator](#_health_indicator) ###
+### [Health Indicator](#_health_indicator)
Config Server comes with a Health Indicator that checks whether the configured `EnvironmentRepository` is working.
By default, it asks the `EnvironmentRepository` for an application named `app`, the `default` profile, and the default label provided by the `EnvironmentRepository` implementation.
@@ -1382,19 +1433,19 @@ spring:
You can disable the Health Indicator by setting `management.health.config.enabled=false`.
-### [Security](#_security) ###
+### [Security](#_security)
You can secure your Config Server in any way that makes sense to you (from physical network security to OAuth2 bearer tokens), because Spring Security and Spring Boot offer support for many security arrangements.
To use the default Spring Boot-configured HTTP Basic security, include Spring Security on the classpath (for example, through `spring-boot-starter-security`).
The default is a username of `user` and a randomly generated password. A random password is not useful in practice, so we recommend you configure the password (by setting `spring.security.user.password`) and encrypt it (see below for instructions on how to do that).
-### [Actuator and Security](#_actuator_and_security) ###
+### [Actuator and Security](#_actuator_and_security)
| |Some platforms configure health checks or something similar and point to `/actuator/health` or other actuator endpoints. If actuator is not a dependency of config server, requests to `/actuator/` **would match the config server API `/{application}/{label}` possibly leaking secure information. Remember to add the `spring-boot-starter-actuator` dependency in this case and configure the users such that the user that makes calls to `/actuator/`** does not have access to the config server API at `/{application}/{label}`.|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [Encryption and Decryption](#_encryption_and_decryption) ###
+### [Encryption and Decryption](#_encryption_and_decryption)
| |To use the encryption and decryption features you need the full-strength JCE installed in your JVM (it is not included by default).
You can download the “Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files” from Oracle and follow the installation instructions (essentially, you need to replace the two policy files in the JRE lib/security directory with the ones that you downloaded).|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
@@ -1476,7 +1527,7 @@ AQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+...
| |The `--key` argument is mandatory (despite having a `--` prefix).|
|---|-----------------------------------------------------------------|
-### [Key Management](#_key_management) ###
+### [Key Management](#_key_management)
The Config Server can use a symmetric (shared) key or an asymmetric one (RSA key pair).
The asymmetric choice is superior in terms of security, but it is often more convenient to use a symmetric key since it is a single property value to configure in the `bootstrap.properties`.
@@ -1504,7 +1555,7 @@ In practice, you might not want to do decrypt locally, because it spreads the ke
concentrating it in the server.
On the other hand, it can be a useful option if your config server is relatively insecure and only a handful of clients need the encrypted properties.
-### [Creating a Key Store for Testing](#_creating_a_key_store_for_testing) ###
+### [Creating a Key Store for Testing](#_creating_a_key_store_for_testing)
To create a keystore for testing, you can use a command resembling the following:
@@ -1533,7 +1584,7 @@ encrypt:
secret: changeme
```
-### [Using Multiple Keys and Key Rotation](#_using_multiple_keys_and_key_rotation) ###
+### [Using Multiple Keys and Key Rotation](#_using_multiple_keys_and_key_rotation)
In addition to the `{cipher}` prefix in encrypted property values, the Config Server looks for zero or more `{name:value}` prefixes before the start of the (Base64 encoded) cipher text.
The keys are passed to a `TextEncryptorLocator`, which can do whatever logic it needs to locate a `TextEncryptor` for the cipher.
@@ -1557,14 +1608,13 @@ Note that the clients need to first check that the key alias is available in the
| |If you want to let the Config Server handle all encryption as well as decryption, the `{name:value}` prefixes can also be added as plain text posted to the `/encrypt` endpoint, .|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [Serving Encrypted Properties](#_serving_encrypted_properties) ###
+### [Serving Encrypted Properties](#_serving_encrypted_properties)
Sometimes you want the clients to decrypt the configuration locally, instead of doing it in the server.
In that case, if you provide the `encrypt.*` configuration to locate a key, you can still have `/encrypt` and `/decrypt` endpoints, but you need to explicitly switch off the decryption of outgoing properties by placing `spring.cloud.config.server.encrypt.enabled=false` in `bootstrap.[yml|properties]`.
If you do not care about the endpoints, it should work if you do not configure either the key or the enabled flag.
-[Serving Alternative Formats](#_serving_alternative_formats)
-----------
+## [Serving Alternative Formats](#_serving_alternative_formats)
The default JSON format from the environment endpoints is perfect for consumption by Spring applications, because it maps directly onto the `Environment` abstraction.
If you prefer, you can consume the same data as YAML or Java properties by adding a suffix (".yml", ".yaml" or ".properties") to the resource path.
@@ -1576,8 +1626,7 @@ This is a useful feature for consumers that do not know about the Spring placeho
| |There are limitations in using the YAML or properties formats, mainly in relation to the loss of metadata.
For example, the JSON is structured as an ordered list of property sources, with names that correlate with the source.
The YAML and properties forms are coalesced into a single map, even if the origin of the values has multiple sources, and the names of the original source files are lost.
Also, the YAML representation is not necessarily a faithful representation of the YAML source in a backing repository either. It is constructed from a list of flat property sources, and assumptions have to be made about the form of the keys.|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[Serving Plain Text](#_serving_plain_text)
-----------
+## [Serving Plain Text](#_serving_plain_text)
Instead of using the `Environment` abstraction (or one of the alternative representations of it in YAML or properties format), your applications might need generic plain-text configuration files that are tailored to their environment.
The Config Server provides these through an additional endpoint at `/{application}/{profile}/{label}/{path}`, where `application`, `profile`, and `label` have the same meaning as the regular environment endpoint, but `path` is a path to a file name (such as `log.xml`).
@@ -1602,7 +1651,7 @@ The following sections show how each one works:
* [AWS S3](#spring-cloud-config-serving-plain-text-aws-s3)
-### [Git, SVN, and Native Backends](#spring-cloud-config-serving-plain-text-git-svn-native-backends) ###
+### [Git, SVN, and Native Backends](#spring-cloud-config-serving-plain-text-git-svn-native-backends)
Consider the following example for a GIT or SVN repository or a native backend:
@@ -1652,13 +1701,13 @@ server {
}
```
-### [AWS S3](#spring-cloud-config-serving-plain-text-aws-s3) ###
+### [AWS S3](#spring-cloud-config-serving-plain-text-aws-s3)
To enable serving plain text for AWS s3, the Config Server application needs to include a dependency on Spring Cloud AWS.
For details on how to set up that dependency, see the[Spring Cloud AWS Reference Guide](https://cloud.spring.io/spring-cloud-static/spring-cloud-aws/2.1.3.RELEASE/single/spring-cloud-aws.html#_spring_cloud_aws_maven_dependency_management).
Then you need to configure Spring Cloud AWS, as described in the[Spring Cloud AWS Reference Guide](https://cloud.spring.io/spring-cloud-static/spring-cloud-aws/2.1.3.RELEASE/single/spring-cloud-aws.html#_configuring_credentials).
-### [Decrypting Plain Text](#_decrypting_plain_text) ###
+### [Decrypting Plain Text](#_decrypting_plain_text)
By default, encrypted values in plain text files are not decrypted. In order to enable decryption for plain text files, set `spring.cloud.config.server.encrypt.enabled=true` and `spring.cloud.config.server.encrypt.plainTextEncrypt=true` in `bootstrap.[yml|properties]`
@@ -1667,8 +1716,7 @@ By default, encrypted values in plain text files are not decrypted. In order to
If this feature is enabled, and an unsupported file extention is requested, any encrypted values in the file will not be decrypted.
-[Embedding the Config Server](#_embedding_the_config_server)
-----------
+## [Embedding the Config Server](#_embedding_the_config_server)
The Config Server runs best as a standalone application.
However, if need be, you can embed it in another application.
@@ -1706,8 +1754,7 @@ If you want to read the configuration for an application directly from the backe
basically want an embedded config server with no endpoints.
You can switch off the endpoints entirely by not using the `@EnableConfigServer` annotation (set `spring.cloud.config.server.bootstrap=true`).
-[Push Notifications and Spring Cloud Bus](#_push_notifications_and_spring_cloud_bus)
-----------
+## [Push Notifications and Spring Cloud Bus](#_push_notifications_and_spring_cloud_bus)
Many source code repository providers (such as Github, Gitlab, Gitea, Gitee, Gogs, or Bitbucket) notify you of changes in a repository through a webhook.
You can configure the webhook through the provider’s user interface as a URL and a set of events in which you are interested.
@@ -1729,13 +1776,12 @@ Doing so broadcasts to applications matching the `{application}` pattern (which
| |The default configuration also detects filesystem changes in local git repositories. In that case, the webhook is not used. However, as soon as you edit a config file, a refresh is broadcast.|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[Spring Cloud Config Client](#_spring_cloud_config_client)
-----------
+## [Spring Cloud Config Client](#_spring_cloud_config_client)
A Spring Boot application can take immediate advantage of the Spring Config Server (or other external property sources provided by the application developer).
It also picks up some additional useful features related to `Environment` change events.
-### [Spring Boot Config Data Import](#config-data-import) ###
+### [Spring Boot Config Data Import](#config-data-import)
Spring Boot 2.4 introduced a new way to import configuration data via the `spring.config.import` property. This is now the default way to bind to Config Server.
@@ -1752,7 +1798,7 @@ This will connect to the Config Server at the default location of "http://localh
| |A `bootstrap` file (properties or yaml) is **not** needed for the Spring Boot Config Data method of import via `spring.config.import`.|
|---|--------------------------------------------------------------------------------------------------------------------------------------|
-### [Config First Bootstrap](#config-first-bootstrap) ###
+### [Config First Bootstrap](#config-first-bootstrap)
To use the legacy bootstrap way of connecting to Config Server, bootstrap must be enabled via a property or the `spring-cloud-starter-bootstrap` starter. The property is `spring.cloud.bootstrap.enabled=true`. It must be set as a System Property or environment variable.
Once bootstrap has been enabled any application with Spring Cloud Config Client on the classpath will connect to Config Server as follows:
@@ -1760,7 +1806,7 @@ When a config client starts, it binds to the Config Server (through the `spring.
The net result of this behavior is that all client applications that want to consume the Config Server need a `bootstrap.yml` (or an environment variable) with the server address set in `spring.cloud.config.uri` (it defaults to "http://localhost:8888").
-#### [Discovery First Lookup](#discovery-first-bootstrap) ####
+#### [Discovery First Lookup](#discovery-first-bootstrap)
| |Unless you are using [config first bootstrap](#config-first-bootstrap), you will need to have a `spring.config.import` property in your configuration properties with an `optional:` prefix.
For example, `spring.config.import=optional:configserver:`.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
@@ -1789,12 +1835,12 @@ eureka:
configPath: /config
```
-#### [Discovery First Bootstrap Using Eureka And WebClient](#_discovery_first_bootstrap_using_eureka_and_webclient) ####
+#### [Discovery First Bootstrap Using Eureka And WebClient](#_discovery_first_bootstrap_using_eureka_and_webclient)
If you use the Eureka `DiscoveryClient` from Spring Cloud Netflix and also want to use `WebClient` instead of Jersey or `RestTemplate`,
you need to include `WebClient` on your classpath as well as set `eureka.client.webclient.enabled=true`.
-### [Config Client Fail Fast](#config-client-fail-fast) ###
+### [Config Client Fail Fast](#config-client-fail-fast)
In some cases, you may want to fail startup of a service if it cannot connect to the Config Server.
If this is the desired behavior, set the bootstrap configuration property `spring.cloud.config.fail-fast=true` to make the client halt with an Exception.
@@ -1802,7 +1848,7 @@ If this is the desired behavior, set the bootstrap configuration property `sprin
| |To get similar functionality using `spring.config.import`, simply omit the `optional:` prefix.|
|---|----------------------------------------------------------------------------------------------|
-### [Config Client Retry](#config-client-retry) ###
+### [Config Client Retry](#config-client-retry)
If you expect that the config server may occasionally be unavailable when your application starts, you can make it keep trying after a failure.
First, you need to set `spring.cloud.config.fail-fast=true`.
@@ -1813,7 +1859,7 @@ You can configure these properties (and others) by setting the `spring.cloud.con
| |To take full control of the retry behavior and are using legacy bootstrap, add a `@Bean` of type `RetryOperationsInterceptor` with an ID of `configServerRetryInterceptor`.
Spring Retry has a `RetryInterceptorBuilder` that supports creating one.|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [Config Client Retry with spring.config.import](#_config_client_retry_with_spring_config_import) ###
+### [Config Client Retry with spring.config.import](#_config_client_retry_with_spring_config_import)
Retry works with the Spring Boot `spring.config.import` statement and the normal properties work. However, if the import statement is in a profile, such as `application-prod.properties`, then you need a different way to configure retry. Configuration needs to be placed as url parameters on the import statement.
@@ -1825,7 +1871,7 @@ spring.config.import=configserver:http://configserver.example.com?fail-fast=true
This sets `spring.cloud.config.fail-fast=true` (notice the missing prefix above) and all the available `spring.cloud.config.retry.*` configuration properties.
-### [Locating Remote Configuration Resources](#_locating_remote_configuration_resources) ###
+### [Locating Remote Configuration Resources](#_locating_remote_configuration_resources)
The Config Service serves property sources from `/{application}/{profile}/{label}`, where the default bindings in the client app are as follows:
@@ -1846,13 +1892,13 @@ In that case, the items in the list are tried one by one until one succeeds.
This behavior can be useful when working on a feature branch.
For instance, you might want to align the config label with your branch but make it optional (in that case, use `spring.cloud.config.label=myfeature,develop`).
-### [Specifying Multiple Urls for the Config Server](#_specifying_multiple_urls_for_the_config_server) ###
+### [Specifying Multiple Urls for the Config Server](#_specifying_multiple_urls_for_the_config_server)
To ensure high availability when you have multiple instances of Config Server deployed and expect one or more instances to be unavailable from time to time, you can either specify multiple URLs (as a comma-separated list under the `spring.cloud.config.uri` property) or have all your instances register in a Service Registry like Eureka ( if using Discovery-First Bootstrap mode ). Note that doing so ensures high availability only when the Config Server is not running (that is, when the application has exited) or when a connection timeout has occurred. For example, if the Config Server returns a 500 (Internal Server Error) response or the Config Client receives a 401 from the Config Server (due to bad credentials or other causes), the Config Client does not try to fetch properties from other URLs. An error of that kind indicates a user issue rather than an availability problem.
If you use HTTP basic security on your Config Server, it is currently possible to support per-Config Server auth credentials only if you embed the credentials in each URL you specify under the `spring.cloud.config.uri` property. If you use any other kind of security mechanism, you cannot (currently) support per-Config Server authentication and authorization.
-### [Configuring Timeouts](#_configuring_timeouts) ###
+### [Configuring Timeouts](#_configuring_timeouts)
If you want to configure timeout thresholds:
@@ -1860,7 +1906,7 @@ If you want to configure timeout thresholds:
* Connection timeouts can be configured by using the property `spring.cloud.config.request-connect-timeout`.
-### [Security](#_security_2) ###
+### [Security](#_security_2)
If you use HTTP Basic security on the server, clients need to know the password (and username if it is not the default).
You can specify the username and password through the config server URI or via separate username and password properties, as shown in the following example:
@@ -1917,7 +1963,7 @@ The `spring.cloud.config.tls.enabled` needs to be true to enable config client s
If you use another form of security, you might need to [provide a `RestTemplate`](#custom-rest-template) to the `ConfigServicePropertySourceLocator` (for example, by grabbing it in the bootstrap context and injecting it).
-#### [Health Indicator](#_health_indicator_2) ####
+#### [Health Indicator](#_health_indicator_2)
The Config Client supplies a Spring Boot Health Indicator that attempts to load configuration from the Config Server.
The health indicator can be disabled by setting `health.config.enabled=false`.
@@ -1925,7 +1971,7 @@ The response is also cached for performance reasons.
The default cache time to live is 5 minutes.
To change that value, set the `health.config.time-to-live` property (in milliseconds).
-#### [Providing A Custom RestTemplate](#custom-rest-template) ####
+#### [Providing A Custom RestTemplate](#custom-rest-template)
In some cases, you might need to customize the requests made to the config server from the client.
Typically, doing so involves passing special `Authorization` headers to authenticate requests to the server.
@@ -1959,7 +2005,7 @@ spring.factories
org.springframework.cloud.bootstrap.BootstrapConfiguration = com.my.config.client.CustomConfigServiceBootstrapConfiguration
```
-#### [Vault](#_vault) ####
+#### [Vault](#_vault)
When using Vault as a backend to your config server, the client needs to supply a token for the server to retrieve values from Vault.
This token can be provided within the client by setting `spring.cloud.config.token`in `bootstrap.yml`, as shown in the following example:
@@ -1971,7 +2017,7 @@ spring:
token: YourVaultToken
```
-### [Nested Keys In Vault](#_nested_keys_in_vault) ###
+### [Nested Keys In Vault](#_nested_keys_in_vault)
Vault supports the ability to nest keys in a value stored in Vault, as shown in the following example:
@@ -1987,3 +2033,4 @@ String name = "World";
The preceding code would sets the value of the `name` variable to `appAsecret`.
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-consul.md b/docs/en/spring-cloud/spring-cloud-consul.md
index 0179fe36eda7f51d77faaa5f64f74f3098ff77d5..5436fdf6769ab1830571cb609de7c4d2c9576d06 100644
--- a/docs/en/spring-cloud/spring-cloud-consul.md
+++ b/docs/en/spring-cloud/spring-cloud-consul.md
@@ -1,5 +1,69 @@
-Spring Cloud Consul
-==========
+Spring Cloud Consul.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Consul
+
+Table of Contents
+
+* [1. Quick Start](#quick-start)
+ * [1.1. Discovery Client Usage](#discovery-client-usage)
+ * [1.2. Distributed Configuration Usage](#distributed-configuration-usage)
+
+* [2. Install Consul](#spring-cloud-consul-install)
+* [3. Consul Agent](#spring-cloud-consul-agent)
+* [4. Service Discovery with Consul](#spring-cloud-consul-discovery)
+ * [4.1. How to activate](#how-to-activate)
+ * [4.2. Registering with Consul](#registering-with-consul)
+ * [4.2.1. Registering Management as a Separate Service](#registering-management-as-a-separate-service)
+ * [4.2.2. HTTP Health Check](#http-health-check)
+ * [Applying Headers](#applying-headers)
+
+ * [4.2.3. Actuator Health Indicator(s)](#actuator-health-indicators)
+ * [DiscoveryClientHealthIndicator](#discoveryclienthealthindicator)
+ * [ConsulHealthIndicator](#consulhealthindicator)
+
+ * [4.2.4. Metadata](#metadata)
+ * [Generated Metadata](#generated-metadata)
+
+ * [4.2.5. Making the Consul Instance ID Unique](#making-the-consul-instance-id-unique)
+
+ * [4.3. Looking up services](#looking-up-services)
+ * [4.3.1. Using Load-balancer](#using-load-balancer)
+ * [4.3.2. Using the DiscoveryClient](#using-the-discoveryclient)
+
+ * [4.4. Consul Catalog Watch](#consul-catalog-watch)
+
+* [5. Distributed Configuration with Consul](#spring-cloud-consul-config)
+ * [5.1. How to activate](#how-to-activate-2)
+ * [5.2. Spring Boot Config Data Import](#config-data-import)
+ * [5.3. Customizing](#customizing)
+ * [5.4. Config Watch](#spring-cloud-consul-config-watch)
+ * [5.5. YAML or Properties with Config](#spring-cloud-consul-config-format)
+ * [5.6. git2consul with Config](#spring-cloud-consul-config-git2consul)
+ * [5.7. Fail Fast](#spring-cloud-consul-failfast)
+
+* [6. Consul Retry](#spring-cloud-consul-retry)
+* [7. Spring Cloud Bus with Consul](#spring-cloud-consul-bus)
+ * [7.1. How to activate](#how-to-activate-3)
+
+* [8. Circuit Breaker with Hystrix](#spring-cloud-consul-hystrix)
+* [9. Hystrix metrics aggregation with Turbine and Consul](#spring-cloud-consul-turbine)
+* [10. Configuration Properties](#configuration-properties)
+
+**3.1.0**
This project provides Consul integrations for Spring Boot apps through autoconfiguration
and binding to the Spring Environment and other Spring programming model idioms. With a few
@@ -9,14 +73,13 @@ patterns provided include Service Discovery, Control Bus and Configuration.
Intelligent Routing and Client Side Load Balancing, Circuit Breaker
are provided by integration with other Spring Cloud projects.
-[](#quick-start)[1. Quick Start](#quick-start)
-----------
+## [](#quick-start)[1. Quick Start](#quick-start)
This quick start walks through using Spring Cloud Consul for Service Discovery and Distributed Configuration.
First, run Consul Agent on your machine. Then you can access it and use it as a Service Registry and Configuration source with Spring Cloud Consul.
-### [](#discovery-client-usage)[1.1. Discovery Client Usage](#discovery-client-usage) ###
+### [](#discovery-client-usage)[1.1. Discovery Client Usage](#discovery-client-usage)
To use these features in an application, you can build it as a Spring Boot application that depends on `spring-cloud-consul-core`.
The most convenient way to add the dependency is with a Spring Boot starter: `org.springframework.cloud:spring-cloud-starter-consul-discovery`.
@@ -138,7 +201,7 @@ public String serviceUrl() {
}
```
-### [](#distributed-configuration-usage)[1.2. Distributed Configuration Usage](#distributed-configuration-usage) ###
+### [](#distributed-configuration-usage)[1.2. Distributed Configuration Usage](#distributed-configuration-usage)
To use these features in an application, you can build it as a Spring Boot application that depends on `spring-cloud-consul-core` and `spring-cloud-consul-config`.
The most convenient way to add the dependency is with a Spring Boot starter: `org.springframework.cloud:spring-cloud-starter-consul-config`.
@@ -239,13 +302,11 @@ The application retrieves configuration data from Consul.
| |If you use Spring Cloud Consul Config, you need to set the `spring.config.import` property in order to bind to Consul.
You can read more about it in the [Spring Boot Config Data Import section](#config-data-import).|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#spring-cloud-consul-install)[2. Install Consul](#spring-cloud-consul-install)
-----------
+## [](#spring-cloud-consul-install)[2. Install Consul](#spring-cloud-consul-install)
Please see the [installation documentation](https://www.consul.io/intro/getting-started/install.html) for instructions on how to install Consul.
-[](#spring-cloud-consul-agent)[3. Consul Agent](#spring-cloud-consul-agent)
-----------
+## [](#spring-cloud-consul-agent)[3. Consul Agent](#spring-cloud-consul-agent)
A Consul Agent client must be available to all Spring Cloud Consul applications. By default, the Agent client is expected to be at `localhost:8500`. See the [Agent documentation](https://consul.io/docs/agent/basics.html) for specifics on how to start an Agent client and how to connect to a cluster of Consul Agent Servers. For development, after you have installed consul, you may start a Consul Agent using the following command:
@@ -255,16 +316,15 @@ A Consul Agent client must be available to all Spring Cloud Consul applications.
This will start an agent in server mode on port 8500, with the ui available at [localhost:8500](http://localhost:8500)
-[](#spring-cloud-consul-discovery)[4. Service Discovery with Consul](#spring-cloud-consul-discovery)
-----------
+## [](#spring-cloud-consul-discovery)[4. Service Discovery with Consul](#spring-cloud-consul-discovery)
Service Discovery is one of the key tenets of a microservice based architecture. Trying to hand configure each client or some form of convention can be very difficult to do and can be very brittle. Consul provides Service Discovery services via an [HTTP API](https://www.consul.io/docs/agent/http.html) and [DNS](https://www.consul.io/docs/agent/dns.html). Spring Cloud Consul leverages the HTTP API for service registration and discovery. This does not prevent non-Spring Cloud applications from leveraging the DNS interface. Consul Agents servers are run in a [cluster](https://www.consul.io/docs/internals/architecture.html) that communicates via a [gossip protocol](https://www.consul.io/docs/internals/gossip.html) and uses the [Raft consensus protocol](https://www.consul.io/docs/internals/consensus.html).
-### [](#how-to-activate)[4.1. How to activate](#how-to-activate) ###
+### [](#how-to-activate)[4.1. How to activate](#how-to-activate)
To activate Consul Service Discovery use the starter with group `org.springframework.cloud` and artifact id `spring-cloud-starter-consul-discovery`. See the [Spring Cloud Project page](https://projects.spring.io/spring-cloud/) for details on setting up your build system with the current Spring Cloud Release Train.
-### [](#registering-with-consul)[4.2. Registering with Consul](#registering-with-consul) ###
+### [](#registering-with-consul)[4.2. Registering with Consul](#registering-with-consul)
When a client registers with Consul, it provides meta-data about itself such as host and port, id, name and tags. An HTTP [Check](https://www.consul.io/docs/agent/checks.html) is created by default that Consul hits the `/actuator/health` endpoint every 10 seconds. If the health check fails, the service instance is marked as critical.
@@ -308,7 +368,7 @@ To disable the Consul Discovery Client you can set `spring.cloud.consul.discover
To disable the service registration you can set `spring.cloud.consul.discovery.register` to `false`.
-#### [](#registering-management-as-a-separate-service)[4.2.1. Registering Management as a Separate Service](#registering-management-as-a-separate-service) ####
+#### [](#registering-management-as-a-separate-service)[4.2.1. Registering Management as a Separate Service](#registering-management-as-a-separate-service)
When management server port is set to something different than the application port, by setting `management.server.port` property, management service will be registered as a separate service than the application service. For example:
@@ -387,7 +447,7 @@ spring.cloud.consul.discovery.management-suffix
spring.cloud.consul.discovery.management-tags
```
-#### [](#http-health-check)[4.2.2. HTTP Health Check](#http-health-check) ####
+#### [](#http-health-check)[4.2.2. HTTP Health Check](#http-health-check)
The health check for a Consul instance defaults to "/actuator/health", which is the default location of the health endpoint in a Spring Boot Actuator application. You need to change this, even for an Actuator application, if you use a non-default context path or servlet path (e.g. `server.servletPath=/foo`) or management endpoint path (e.g. `management.server.servlet.context-path=/admin`).
@@ -408,7 +468,7 @@ spring:
You can disable the HTTP health check entirely by setting `spring.cloud.consul.discovery.register-health-check=false`.
-##### [](#applying-headers)[Applying Headers](#applying-headers) #####
+##### [](#applying-headers)[Applying Headers](#applying-headers)
Headers can be applied to health check requests. For example, if you’re trying to register a [Spring Cloud Config](https://cloud.spring.io/spring-cloud-config/) server that uses [Vault Backend](https://github.com/spring-cloud/spring-cloud-config/blob/master/docs/src/main/asciidoc/spring-cloud-config.adoc#vault-backend):
@@ -438,16 +498,16 @@ spring:
- "Some other value"
```
-#### [](#actuator-health-indicators)[4.2.3. Actuator Health Indicator(s)](#actuator-health-indicators) ####
+#### [](#actuator-health-indicators)[4.2.3. Actuator Health Indicator(s)](#actuator-health-indicators)
If the service instance is a Spring Boot Actuator application, it may be provided the following Actuator health indicators.
-##### [](#discoveryclienthealthindicator)[DiscoveryClientHealthIndicator](#discoveryclienthealthindicator) #####
+##### [](#discoveryclienthealthindicator)[DiscoveryClientHealthIndicator](#discoveryclienthealthindicator)
When Consul Service Discovery is active, a [DiscoverClientHealthIndicator](https://cloud.spring.io/spring-cloud-commons/2.2.x/reference/html/#health-indicator) is configured and made available to the Actuator health endpoint.
See [here](https://cloud.spring.io/spring-cloud-commons/2.2.x/reference/html/#health-indicator) for configuration options.
-##### [](#consulhealthindicator)[ConsulHealthIndicator](#consulhealthindicator) #####
+##### [](#consulhealthindicator)[ConsulHealthIndicator](#consulhealthindicator)
An indicator is configured that verifies the health of the `ConsulClient`.
@@ -460,7 +520,7 @@ To disable the indicator set `management.health.consul.enabled=false`.
| |When the application runs in [bootstrap context mode](https://cloud.spring.io/spring-cloud-commons/2.2.x/reference/html/#the-bootstrap-application-context) (the default),
this indicator is loaded into the bootstrap context and is not made available to the Actuator health endpoint.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [](#metadata)[4.2.4. Metadata](#metadata) ####
+#### [](#metadata)[4.2.4. Metadata](#metadata)
Consul supports metadata on services. Spring Cloud’s `ServiceInstance` has a `Map metadata` field which is populated from a services `meta` field. To populate the `meta` field set values on `spring.cloud.consul.discovery.metadata` or `spring.cloud.consul.discovery.management-metadata` properties.
@@ -478,7 +538,7 @@ spring:
The above configuration will result in a service who’s meta field contains `myfield→myvalue` and `anotherfield→anothervalue`.
-##### [](#generated-metadata)[Generated Metadata](#generated-metadata) #####
+##### [](#generated-metadata)[Generated Metadata](#generated-metadata)
The Consul Auto Registration will generate a few entries automatically.
@@ -491,7 +551,7 @@ The Consul Auto Registration will generate a few entries automatically.
| |Older versions of Spring Cloud Consul populated the `ServiceInstance.getMetadata()` method from Spring Cloud Commons by parsing the `spring.cloud.consul.discovery.tags` property. This is no longer supported, please migrate to using the `spring.cloud.consul.discovery.metadata` map.|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [](#making-the-consul-instance-id-unique)[4.2.5. Making the Consul Instance ID Unique](#making-the-consul-instance-id-unique) ####
+#### [](#making-the-consul-instance-id-unique)[4.2.5. Making the Consul Instance ID Unique](#making-the-consul-instance-id-unique)
By default a consul instance is registered with an ID that is equal to its Spring Application Context ID. By default, the Spring Application Context ID is `${spring.application.name}:comma,separated,profiles:${server.port}`. For most cases, this will allow multiple instances of one service to run on one machine. If further uniqueness is required, Using Spring Cloud you can override this by providing a unique identifier in `spring.cloud.consul.discovery.instanceId`. For example:
@@ -507,9 +567,9 @@ spring:
With this metadata, and multiple service instances deployed on localhost, the random value will kick in there to make the instance unique. In Cloudfoundry the `vcap.application.instance_id` will be populated automatically in a Spring Boot application, so the random value will not be needed.
-### [](#looking-up-services)[4.3. Looking up services](#looking-up-services) ###
+### [](#looking-up-services)[4.3. Looking up services](#looking-up-services)
-#### [](#using-load-balancer)[4.3.1. Using Load-balancer](#using-load-balancer) ####
+#### [](#using-load-balancer)[4.3.1. Using Load-balancer](#using-load-balancer)
Spring Cloud has support for [Feign](https://github.com/spring-cloud/spring-cloud-netflix/blob/master/docs/src/main/asciidoc/spring-cloud-netflix.adoc#spring-cloud-feign) (a REST client builder) and also [Spring `RestTemplate`](https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#rest-template-loadbalancer-client)for looking up services using the logical service names/ids instead of physical URLs. Both Feign and the discovery-aware RestTemplate utilize [Spring Cloud LoadBalancer](https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer) for client-side load balancing.
@@ -541,7 +601,7 @@ where the STORES service lives.
| |Spring Cloud now also offers support for[Spring Cloud LoadBalancer](https://cloud.spring.io/spring-cloud-commons/reference/html/#_spring_resttemplate_as_a_load_balancer_client).|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [](#using-the-discoveryclient)[4.3.2. Using the DiscoveryClient](#using-the-discoveryclient) ####
+#### [](#using-the-discoveryclient)[4.3.2. Using the DiscoveryClient](#using-the-discoveryclient)
You can also use the `org.springframework.cloud.client.discovery.DiscoveryClient` which provides a simple API for discovery clients that is not specific to Netflix, e.g.
@@ -558,7 +618,7 @@ public String serviceUrl() {
}
```
-### [](#consul-catalog-watch)[4.4. Consul Catalog Watch](#consul-catalog-watch) ###
+### [](#consul-catalog-watch)[4.4. Consul Catalog Watch](#consul-catalog-watch)
The Consul Catalog Watch takes advantage of the ability of consul to [watch services](https://www.consul.io/docs/agent/watches.html#services). The Catalog Watch makes a blocking Consul HTTP API call to determine if any services have changed. If there is new service data a Heartbeat Event is published.
@@ -568,8 +628,7 @@ To disable the Catalog Watch set `spring.cloud.consul.discovery.catalogServicesW
The watch uses a Spring `TaskScheduler` to schedule the call to consul. By default it is a `ThreadPoolTaskScheduler` with a `poolSize` of 1. To change the `TaskScheduler`, create a bean of type `TaskScheduler` named with the `ConsulDiscoveryClientConfiguration.CATALOG_WATCH_TASK_SCHEDULER_NAME` constant.
-[](#spring-cloud-consul-config)[5. Distributed Configuration with Consul](#spring-cloud-consul-config)
-----------
+## [](#spring-cloud-consul-config)[5. Distributed Configuration with Consul](#spring-cloud-consul-config)
Consul provides a [Key/Value Store](https://consul.io/docs/agent/http/kv.html) for storing configuration and other metadata. Spring Cloud Consul Config is an alternative to the [Config Server and Client](https://github.com/spring-cloud/spring-cloud-config). Configuration is loaded into the Spring Environment during the special "bootstrap" phase. Configuration is stored in the `/config` folder by default. Multiple `PropertySource` instances are created based on the application’s name and the active profiles that mimics the Spring Cloud Config order of resolving properties. For example, an application with the name "testApp" and with the "dev" profile will have the following property sources created:
@@ -584,11 +643,11 @@ The most specific property source is at the top, with the least specific at the
Configuration is currently read on startup of the application. Sending a HTTP POST to `/refresh` will cause the configuration to be reloaded. [Config Watch](#spring-cloud-consul-config-watch) will also automatically detect changes and reload the application context.
-### [](#how-to-activate-2)[5.1. How to activate](#how-to-activate-2) ###
+### [](#how-to-activate-2)[5.1. How to activate](#how-to-activate-2)
To get started with Consul Configuration use the starter with group `org.springframework.cloud` and artifact id `spring-cloud-starter-consul-config`. See the [Spring Cloud Project page](https://projects.spring.io/spring-cloud/) for details on setting up your build system with the current Spring Cloud Release Train.
-### [](#config-data-import)[5.2. Spring Boot Config Data Import](#config-data-import) ###
+### [](#config-data-import)[5.2. Spring Boot Config Data Import](#config-data-import)
Spring Boot 2.4 introduced a new way to import configuration data via the `spring.config.import` property. This is now the default way to get configuration from Consul.
@@ -615,7 +674,7 @@ This will optionally load configuration only from `/contextone` and `/context/tw
| |A `bootstrap` file (properties or yaml) is **not** needed for the Spring Boot Config Data method of import via `spring.config.import`.|
|---|--------------------------------------------------------------------------------------------------------------------------------------|
-### [](#customizing)[5.3. Customizing](#customizing) ###
+### [](#customizing)[5.3. Customizing](#customizing)
Consul Config may be customized using the following properties:
@@ -641,7 +700,7 @@ spring:
* `profileSeparator` sets the value of the separator used to separate the profile name in property sources with profiles
-### [](#spring-cloud-consul-config-watch)[5.4. Config Watch](#spring-cloud-consul-config-watch) ###
+### [](#spring-cloud-consul-config-watch)[5.4. Config Watch](#spring-cloud-consul-config-watch)
The Consul Config Watch takes advantage of the ability of consul to [watch a key prefix](https://www.consul.io/docs/agent/watches.html#keyprefix). The Config Watch makes a blocking Consul HTTP API call to determine if any relevant configuration data has changed for the current application. If there is new configuration data a Refresh Event is published. This is equivalent to calling the `/refresh` actuator endpoint.
@@ -651,7 +710,7 @@ To disable the Config Watch set `spring.cloud.consul.config.watch.enabled=false`
The watch uses a Spring `TaskScheduler` to schedule the call to consul. By default it is a `ThreadPoolTaskScheduler` with a `poolSize` of 1. To change the `TaskScheduler`, create a bean of type `TaskScheduler` named with the `ConsulConfigAutoConfiguration.CONFIG_WATCH_TASK_SCHEDULER_NAME` constant.
-### [](#spring-cloud-consul-config-format)[5.5. YAML or Properties with Config](#spring-cloud-consul-config-format) ###
+### [](#spring-cloud-consul-config-format)[5.5. YAML or Properties with Config](#spring-cloud-consul-config-format)
It may be more convenient to store a blob of properties in YAML or Properties format as opposed to individual key/value pairs. Set the `spring.cloud.consul.config.format` property to `YAML` or `PROPERTIES`. For example to use YAML:
@@ -679,7 +738,7 @@ You could store a YAML document in any of the keys listed above.
You can change the data key using `spring.cloud.consul.config.data-key`.
-### [](#spring-cloud-consul-config-git2consul)[5.6. git2consul with Config](#spring-cloud-consul-config-git2consul) ###
+### [](#spring-cloud-consul-config-git2consul)[5.6. git2consul with Config](#spring-cloud-consul-config-git2consul)
git2consul is a Consul community project that loads files from a git repository to individual keys into Consul. By default the names of the keys are names of the files. YAML and Properties files are supported with file extensions of `.yml` and `.properties` respectively. Set the `spring.cloud.consul.config.format` property to `FILES`. For example:
@@ -715,15 +774,14 @@ config/application.yml
The value of each key needs to be a properly formatted YAML or Properties file.
-### [](#spring-cloud-consul-failfast)[5.7. Fail Fast](#spring-cloud-consul-failfast) ###
+### [](#spring-cloud-consul-failfast)[5.7. Fail Fast](#spring-cloud-consul-failfast)
It may be convenient in certain circumstances (like local development or certain test scenarios) to not fail if consul isn’t available for configuration. Setting `spring.cloud.consul.config.fail-fast=false` will cause the configuration module to log a warning rather than throw an exception. This will allow the application to continue startup normally.
| |If you have set `spring.cloud.bootstrap.enabled=true` or `spring.config.use-legacy-processing=true`, or included `spring-cloud-starter-bootstrap`, then the above values will need to be placed in `bootstrap.yml` instead of `application.yml`.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#spring-cloud-consul-retry)[6. Consul Retry](#spring-cloud-consul-retry)
-----------
+## [](#spring-cloud-consul-retry)[6. Consul Retry](#spring-cloud-consul-retry)
If you expect that the consul agent may occasionally be unavailable when
your app starts, you can ask it to keep trying after a failure. You need to add`spring-retry` and `spring-boot-starter-aop` to your classpath. The default
@@ -735,22 +793,19 @@ This works with both Spring Cloud Consul Config and Discovery registration.
| |To take full control of the retry add a `@Bean` of type`RetryOperationsInterceptor` with id "consulRetryInterceptor". Spring
Retry has a `RetryInterceptorBuilder` that makes it easy to create one.|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#spring-cloud-consul-bus)[7. Spring Cloud Bus with Consul](#spring-cloud-consul-bus)
-----------
+## [](#spring-cloud-consul-bus)[7. Spring Cloud Bus with Consul](#spring-cloud-consul-bus)
-### [](#how-to-activate-3)[7.1. How to activate](#how-to-activate-3) ###
+### [](#how-to-activate-3)[7.1. How to activate](#how-to-activate-3)
To get started with the Consul Bus use the starter with group `org.springframework.cloud` and artifact id `spring-cloud-starter-consul-bus`. See the [Spring Cloud Project page](https://projects.spring.io/spring-cloud/) for details on setting up your build system with the current Spring Cloud Release Train.
See the [Spring Cloud Bus](https://cloud.spring.io/spring-cloud-bus/) documentation for the available actuator endpoints and howto send custom messages.
-[](#spring-cloud-consul-hystrix)[8. Circuit Breaker with Hystrix](#spring-cloud-consul-hystrix)
-----------
+## [](#spring-cloud-consul-hystrix)[8. Circuit Breaker with Hystrix](#spring-cloud-consul-hystrix)
Applications can use the Hystrix Circuit Breaker provided by the Spring Cloud Netflix project by including this starter in the projects pom.xml: `spring-cloud-starter-hystrix`. Hystrix doesn’t depend on the Netflix Discovery Client. The `@EnableHystrix` annotation should be placed on a configuration class (usually the main class). Then methods can be annotated with `@HystrixCommand` to be protected by a circuit breaker. See [the documentation](https://projects.spring.io/spring-cloud/spring-cloud.html#_circuit_breaker_hystrix_clients) for more details.
-[](#spring-cloud-consul-turbine)[9. Hystrix metrics aggregation with Turbine and Consul](#spring-cloud-consul-turbine)
-----------
+## [](#spring-cloud-consul-turbine)[9. Hystrix metrics aggregation with Turbine and Consul](#spring-cloud-consul-turbine)
Turbine (provided by the Spring Cloud Netflix project), aggregates multiple instances Hystrix metrics streams, so the dashboard can display an aggregate view. Turbine uses the `DiscoveryClient` interface to lookup relevant instances. To use Turbine with Spring Cloud Consul, configure the Turbine application in a manner similar to the following examples:
@@ -794,7 +849,8 @@ public class Turbine {
}
```
-[](#configuration-properties)[10. Configuration Properties](#configuration-properties)
-----------
+## [](#configuration-properties)[10. Configuration Properties](#configuration-properties)
To see the list of all Consul related configuration properties please check [the Appendix page](appendix.html).
+
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-contract.md b/docs/en/spring-cloud/spring-cloud-contract.md
index d4bc8b53d1ab0c7a549ad48f17baa3399076177a..7d48ddb31d6f12f958226fe68d2994c3241f31a0 100644
--- a/docs/en/spring-cloud/spring-cloud-contract.md
+++ b/docs/en/spring-cloud/spring-cloud-contract.md
@@ -1,5 +1,20 @@
-Spring Cloud Contract Reference Documentation
-==========
+Spring Cloud Contract Reference Documentation.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Contract Reference Documentation
Adam Dudczak, Mathias Düsterhöft, Marcin Grzejszczak, Dennis Kieselhorst, Jakub Kubryński, Karol Lassak, Olga Maciaszek-Sharma, Mariusz Smykuła, Dave Syer, Jay Bryant
@@ -15,3 +30,4 @@ The reference documentation consists of the following sections:
| [“How-to” Guides](howto.html#howto) | Stubs versioning, Pact integration, Debugging, and more. |
| [Appendices](appendix.html#appendix) | Properties, Metadata, Configuration, Dependencies, and more. |
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-function.md b/docs/en/spring-cloud/spring-cloud-function.md
index 7a851bc94620e4f9a9d2a01ef156c6f9838b1294..182589e4d920b4410f8069344072c9c766e3fe42 100644
--- a/docs/en/spring-cloud/spring-cloud-function.md
+++ b/docs/en/spring-cloud/spring-cloud-function.md
@@ -1,5 +1,20 @@
-Spring Cloud Function Reference Documentation
-==========
+Spring Cloud Function Reference Documentation.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Function Reference Documentation
Mark Fisher, Dave Syer, Oleg Zhurakousky, Anshul Mehra
@@ -20,3 +35,4 @@ Relevant Links:
|[Reactor](https://projectreactor.io/)|Project Reactor|
|-------------------------------------|---------------|
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-gateway.md b/docs/en/spring-cloud/spring-cloud-gateway.md
index f9a4e0a096895ff2cd8b84e8c6d7a8ef35a847b5..f8eca1d5bd3fa11441b80e72f54da4e59990a7f0 100644
--- a/docs/en/spring-cloud/spring-cloud-gateway.md
+++ b/docs/en/spring-cloud/spring-cloud-gateway.md
@@ -1,11 +1,148 @@
-Spring Cloud Gateway
-==========
-
+Spring Cloud Gateway.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Gateway
+
+Table of Contents
+
+* [1. How to Include Spring Cloud Gateway](#gateway-starter)
+* [2. Glossary](#glossary)
+* [3. How It Works](#gateway-how-it-works)
+* [4. Configuring Route Predicate Factories and Gateway Filter Factories](#configuring-route-predicate-factories-and-gateway-filter-factories)
+ * [4.1. Shortcut Configuration](#shortcut-configuration)
+ * [4.2. Fully Expanded Arguments](#fully-expanded-arguments)
+
+* [5. Route Predicate Factories](#gateway-request-predicates-factories)
+ * [5.1. The After Route Predicate Factory](#the-after-route-predicate-factory)
+ * [5.2. The Before Route Predicate Factory](#the-before-route-predicate-factory)
+ * [5.3. The Between Route Predicate Factory](#the-between-route-predicate-factory)
+ * [5.4. The Cookie Route Predicate Factory](#the-cookie-route-predicate-factory)
+ * [5.5. The Header Route Predicate Factory](#the-header-route-predicate-factory)
+ * [5.6. The Host Route Predicate Factory](#the-host-route-predicate-factory)
+ * [5.7. The Method Route Predicate Factory](#the-method-route-predicate-factory)
+ * [5.8. The Path Route Predicate Factory](#the-path-route-predicate-factory)
+ * [5.9. The Query Route Predicate Factory](#the-query-route-predicate-factory)
+ * [5.10. The RemoteAddr Route Predicate Factory](#the-remoteaddr-route-predicate-factory)
+ * [5.10.1. Modifying the Way Remote Addresses Are Resolved](#modifying-the-way-remote-addresses-are-resolved)
+
+ * [5.11. The Weight Route Predicate Factory](#the-weight-route-predicate-factory)
+ * [5.12. The XForwarded Remote Addr Route Predicate Factory](#the-xforwarded-remote-addr-route-predicate-factory)
+
+* [6. `GatewayFilter` Factories](#gatewayfilter-factories)
+ * [6.1. The `AddRequestHeader` `GatewayFilter` Factory](#the-addrequestheader-gatewayfilter-factory)
+ * [6.2. The `AddRequestParameter` `GatewayFilter` Factory](#the-addrequestparameter-gatewayfilter-factory)
+ * [6.3. The `AddResponseHeader` `GatewayFilter` Factory](#the-addresponseheader-gatewayfilter-factory)
+ * [6.4. The `DedupeResponseHeader` `GatewayFilter` Factory](#the-deduperesponseheader-gatewayfilter-factory)
+ * [6.5. Spring Cloud CircuitBreaker GatewayFilter Factory](#spring-cloud-circuitbreaker-filter-factory)
+ * [6.5.1. Tripping The Circuit Breaker On Status Codes](#circuit-breaker-status-codes)
+
+ * [6.6. The `FallbackHeaders` `GatewayFilter` Factory](#fallback-headers)
+ * [6.7. The `MapRequestHeader` `GatewayFilter` Factory](#the-maprequestheader-gatewayfilter-factory)
+ * [6.8. The `PrefixPath` `GatewayFilter` Factory](#the-prefixpath-gatewayfilter-factory)
+ * [6.9. The `PreserveHostHeader` `GatewayFilter` Factory](#the-preservehostheader-gatewayfilter-factory)
+ * [6.10. The `RequestRateLimiter` `GatewayFilter` Factory](#the-requestratelimiter-gatewayfilter-factory)
+ * [6.10.1. The Redis `RateLimiter`](#the-redis-ratelimiter)
+
+ * [6.11. The `RedirectTo` `GatewayFilter` Factory](#the-redirectto-gatewayfilter-factory)
+ * [6.12. The `RemoveRequestHeader` GatewayFilter Factory](#the-removerequestheader-gatewayfilter-factory)
+ * [6.13. `RemoveResponseHeader` `GatewayFilter` Factory](#removeresponseheader-gatewayfilter-factory)
+ * [6.14. The `RemoveRequestParameter` `GatewayFilter` Factory](#the-removerequestparameter-gatewayfilter-factory)
+ * [6.15. The `RewritePath` `GatewayFilter` Factory](#the-rewritepath-gatewayfilter-factory)
+ * [6.16. `RewriteLocationResponseHeader` `GatewayFilter` Factory](#rewritelocationresponseheader-gatewayfilter-factory)
+ * [6.17. The `RewriteResponseHeader` `GatewayFilter` Factory](#the-rewriteresponseheader-gatewayfilter-factory)
+ * [6.18. The `SaveSession` `GatewayFilter` Factory](#the-savesession-gatewayfilter-factory)
+ * [6.19. The `SecureHeaders` `GatewayFilter` Factory](#the-secureheaders-gatewayfilter-factory)
+ * [6.20. The `SetPath` `GatewayFilter` Factory](#the-setpath-gatewayfilter-factory)
+ * [6.21. The `SetRequestHeader` `GatewayFilter` Factory](#the-setrequestheader-gatewayfilter-factory)
+ * [6.22. The `SetResponseHeader` `GatewayFilter` Factory](#the-setresponseheader-gatewayfilter-factory)
+ * [6.23. The `SetStatus` `GatewayFilter` Factory](#the-setstatus-gatewayfilter-factory)
+ * [6.24. The `StripPrefix` `GatewayFilter` Factory](#the-stripprefix-gatewayfilter-factory)
+ * [6.25. The Retry `GatewayFilter` Factory](#the-retry-gatewayfilter-factory)
+ * [6.26. The `RequestSize` `GatewayFilter` Factory](#the-requestsize-gatewayfilter-factory)
+ * [6.27. The `SetRequestHostHeader` `GatewayFilter` Factory](#the-setrequesthostheader-gatewayfilter-factory)
+ * [6.28. Modify a Request Body `GatewayFilter` Factory](#modify-a-request-body-gatewayfilter-factory)
+ * [6.29. Modify a Response Body `GatewayFilter` Factory](#modify-a-response-body-gatewayfilter-factory)
+ * [6.30. Token Relay `GatewayFilter` Factory](#token-relay-gatewayfilter-factory)
+ * [6.31. The `CacheRequestBody` `GatewayFilter` Factory](#the-cacherequestbody-gatewayfilter-factory)
+ * [6.32. Default Filters](#default-filters)
+
+* [7. Global Filters](#global-filters)
+ * [7.1. Combined Global Filter and `GatewayFilter` Ordering](#gateway-combined-global-filter-and-gatewayfilter-ordering)
+ * [7.2. Forward Routing Filter](#forward-routing-filter)
+ * [7.3. The `ReactiveLoadBalancerClientFilter`](#reactive-loadbalancer-client-filter)
+ * [7.4. The Netty Routing Filter](#the-netty-routing-filter)
+ * [7.5. The Netty Write Response Filter](#the-netty-write-response-filter)
+ * [7.6. The `RouteToRequestUrl` Filter](#the-routetorequesturl-filter)
+ * [7.7. The Websocket Routing Filter](#the-websocket-routing-filter)
+ * [7.8. The Gateway Metrics Filter](#the-gateway-metrics-filter)
+ * [7.9. Marking An Exchange As Routed](#marking-an-exchange-as-routed)
+
+* [8. HttpHeadersFilters](#httpheadersfilters)
+ * [8.1. Forwarded Headers Filter](#forwarded-headers-filter)
+ * [8.2. RemoveHopByHop Headers Filter](#removehopbyhop-headers-filter)
+ * [8.3. XForwarded Headers Filter](#xforwarded-headers-filter)
+
+* [9. TLS and SSL](#tls-and-ssl)
+ * [9.1. TLS Handshake](#tls-handshake)
+
+* [10. Configuration](#configuration)
+ * [10.1. RouteDefinition Metrics](#routedefinition-metrics)
+
+* [11. Route Metadata Configuration](#route-metadata-configuration)
+* [12. Http timeouts configuration](#http-timeouts-configuration)
+ * [12.1. Global timeouts](#global-timeouts)
+ * [12.2. Per-route timeouts](#per-route-timeouts)
+ * [12.3. Fluent Java Routes API](#fluent-java-routes-api)
+ * [12.4. The `DiscoveryClient` Route Definition Locator](#the-discoveryclient-route-definition-locator)
+ * [12.4.1. Configuring Predicates and Filters For `DiscoveryClient` Routes](#configuring-predicates-and-filters-for-discoveryclient-routes)
+
+* [13. Reactor Netty Access Logs](#reactor-netty-access-logs)
+* [14. CORS Configuration](#cors-configuration)
+* [15. Actuator API](#actuator-api)
+ * [15.1. Verbose Actuator Format](#verbose-actuator-format)
+ * [15.2. Retrieving Route Filters](#retrieving-route-filters)
+ * [15.2.1. Global Filters](#gateway-global-filters)
+ * [15.2.2. Route Filters](#gateway-route-filters)
+
+ * [15.3. Refreshing the Route Cache](#refreshing-the-route-cache)
+ * [15.4. Retrieving the Routes Defined in the Gateway](#retrieving-the-routes-defined-in-the-gateway)
+ * [15.5. Retrieving Information about a Particular Route](#gateway-retrieving-information-about-a-particular-route)
+ * [15.6. Creating and Deleting a Particular Route](#creating-and-deleting-a-particular-route)
+ * [15.7. Recap: The List of All endpoints](#recap-the-list-of-all-endpoints)
+ * [15.8. Sharing Routes between multiple Gateway instances](#sharing-routes-between-multiple-gateway-instances)
+
+* [16. Troubleshooting](#troubleshooting)
+ * [16.1. Log Levels](#log-levels)
+ * [16.2. Wiretap](#wiretap)
+
+* [17. Developer Guide](#developer-guide)
+ * [17.1. Writing Custom Route Predicate Factories](#writing-custom-route-predicate-factories)
+ * [17.2. Writing Custom GatewayFilter Factories](#writing-custom-gatewayfilter-factories)
+ * [17.2.1. Naming Custom Filters And References In Configuration](#naming-custom-filters-and-references-in-configuration)
+
+ * [17.3. Writing Custom Global Filters](#writing-custom-global-filters)
+
+* [18. Building a Simple Gateway by Using Spring MVC or Webflux](#building-a-simple-gateway-by-using-spring-mvc-or-webflux)
+* [19. Configuration properties](#configuration-properties)
+
+**3.1.1**
This project provides an API Gateway built on top of the Spring Ecosystem, including: Spring 5, Spring Boot 2 and Project Reactor. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency.
-[](#gateway-starter)[1. How to Include Spring Cloud Gateway](#gateway-starter)
-----------
+## [](#gateway-starter)[1. How to Include Spring Cloud Gateway](#gateway-starter)
To include Spring Cloud Gateway in your project, use the starter with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-starter-gateway`.
See the [Spring Cloud Project page](https://projects.spring.io/spring-cloud/) for details on setting up your build system with the current Spring Cloud Release Train.
@@ -18,8 +155,7 @@ If you include the starter, but you do not want the gateway to be enabled, set `
| |Spring Cloud Gateway requires the Netty runtime provided by Spring Boot and Spring Webflux.
It does not work in a traditional Servlet Container or when built as a WAR.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#glossary)[2. Glossary](#glossary)
-----------
+## [](#glossary)[2. Glossary](#glossary)
* **Route**: The basic building block of the gateway.
It is defined by an ID, a destination URI, a collection of predicates, and a collection of filters. A route is matched if the aggregate predicate is true.
@@ -30,8 +166,7 @@ If you include the starter, but you do not want the gateway to be enabled, set `
* **Filter**: These are instances of [`GatewayFilter`](https://github.com/spring-cloud/spring-cloud-gateway/tree/main/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/GatewayFilter.java) that have been constructed with a specific factory.
Here, you can modify requests and responses before or after sending the downstream request.
-[](#gateway-how-it-works)[3. How It Works](#gateway-how-it-works)
-----------
+## [](#gateway-how-it-works)[3. How It Works](#gateway-how-it-works)
The following diagram provides a high-level overview of how Spring Cloud Gateway works:
@@ -45,14 +180,13 @@ All “pre” filter logic is executed. Then the proxy request is made. After th
| |URIs defined in routes without a port get default port values of 80 and 443 for the HTTP and HTTPS URIs, respectively.|
|---|----------------------------------------------------------------------------------------------------------------------|
-[](#configuring-route-predicate-factories-and-gateway-filter-factories)[4. Configuring Route Predicate Factories and Gateway Filter Factories](#configuring-route-predicate-factories-and-gateway-filter-factories)
-----------
+## [](#configuring-route-predicate-factories-and-gateway-filter-factories)[4. Configuring Route Predicate Factories and Gateway Filter Factories](#configuring-route-predicate-factories-and-gateway-filter-factories)
There are two ways to configure predicates and filters: shortcuts and fully expanded arguments. Most examples below use the shortcut way.
The name and argument names will be listed as `code` in the first sentance or two of the each section. The arguments are typically listed in the order that would be needed for the shortcut configuration.
-### [](#shortcut-configuration)[4.1. Shortcut Configuration](#shortcut-configuration) ###
+### [](#shortcut-configuration)[4.1. Shortcut Configuration](#shortcut-configuration)
Shortcut configuration is recognized by the filter name, followed by an equals sign (`=`), followed by argument values separated by commas (`,`).
@@ -71,7 +205,7 @@ spring:
The previous sample defines the `Cookie` Route Predicate Factory with two arguments, the cookie name, `mycookie` and the value to match `mycookievalue`.
-### [](#fully-expanded-arguments)[4.2. Fully Expanded Arguments](#fully-expanded-arguments) ###
+### [](#fully-expanded-arguments)[4.2. Fully Expanded Arguments](#fully-expanded-arguments)
Fully expanded arguments appear more like standard yaml configuration with name/value pairs. Typically, there will be a `name` key and an `args` key. The `args` key is a map of key value pairs to configure the predicate or filter.
@@ -93,15 +227,14 @@ spring:
This is the full configuration of the shortcut configuration of the `Cookie` predicate shown above.
-[](#gateway-request-predicates-factories)[5. Route Predicate Factories](#gateway-request-predicates-factories)
-----------
+## [](#gateway-request-predicates-factories)[5. Route Predicate Factories](#gateway-request-predicates-factories)
Spring Cloud Gateway matches routes as part of the Spring WebFlux `HandlerMapping` infrastructure.
Spring Cloud Gateway includes many built-in route predicate factories.
All of these predicates match on different attributes of the HTTP request.
You can combine multiple route predicate factories with logical `and` statements.
-### [](#the-after-route-predicate-factory)[5.1. The After Route Predicate Factory](#the-after-route-predicate-factory) ###
+### [](#the-after-route-predicate-factory)[5.1. The After Route Predicate Factory](#the-after-route-predicate-factory)
The `After` route predicate factory takes one parameter, a `datetime` (which is a java `ZonedDateTime`).
This predicate matches requests that happen after the specified datetime.
@@ -122,7 +255,7 @@ spring:
This route matches any request made after Jan 20, 2017 17:42 Mountain Time (Denver).
-### [](#the-before-route-predicate-factory)[5.2. The Before Route Predicate Factory](#the-before-route-predicate-factory) ###
+### [](#the-before-route-predicate-factory)[5.2. The Before Route Predicate Factory](#the-before-route-predicate-factory)
The `Before` route predicate factory takes one parameter, a `datetime` (which is a java `ZonedDateTime`).
This predicate matches requests that happen before the specified `datetime`.
@@ -143,7 +276,7 @@ spring:
This route matches any request made before Jan 20, 2017 17:42 Mountain Time (Denver).
-### [](#the-between-route-predicate-factory)[5.3. The Between Route Predicate Factory](#the-between-route-predicate-factory) ###
+### [](#the-between-route-predicate-factory)[5.3. The Between Route Predicate Factory](#the-between-route-predicate-factory)
The `Between` route predicate factory takes two parameters, `datetime1` and `datetime2`which are java `ZonedDateTime` objects.
This predicate matches requests that happen after `datetime1` and before `datetime2`.
@@ -166,7 +299,7 @@ spring:
This route matches any request made after Jan 20, 2017 17:42 Mountain Time (Denver) and before Jan 21, 2017 17:42 Mountain Time (Denver).
This could be useful for maintenance windows.
-### [](#the-cookie-route-predicate-factory)[5.4. The Cookie Route Predicate Factory](#the-cookie-route-predicate-factory) ###
+### [](#the-cookie-route-predicate-factory)[5.4. The Cookie Route Predicate Factory](#the-cookie-route-predicate-factory)
The `Cookie` route predicate factory takes two parameters, the cookie `name` and a `regexp` (which is a Java regular expression).
This predicate matches cookies that have the given name and whose values match the regular expression.
@@ -187,7 +320,7 @@ spring:
This route matches requests that have a cookie named `chocolate` whose value matches the `ch.p` regular expression.
-### [](#the-header-route-predicate-factory)[5.5. The Header Route Predicate Factory](#the-header-route-predicate-factory) ###
+### [](#the-header-route-predicate-factory)[5.5. The Header Route Predicate Factory](#the-header-route-predicate-factory)
The `Header` route predicate factory takes two parameters, the `header` and a `regexp` (which is a Java regular expression).
This predicate matches with a header that has the given name whose value matches the regular expression.
@@ -208,7 +341,7 @@ spring:
This route matches if the request has a header named `X-Request-Id` whose value matches the `\d+` regular expression (that is, it has a value of one or more digits).
-### [](#the-host-route-predicate-factory)[5.6. The Host Route Predicate Factory](#the-host-route-predicate-factory) ###
+### [](#the-host-route-predicate-factory)[5.6. The Host Route Predicate Factory](#the-host-route-predicate-factory)
The `Host` route predicate factory takes one parameter: a list of host name `patterns`.
The pattern is an Ant-style pattern with `.` as the separator.
@@ -235,7 +368,7 @@ This route matches if the request has a `Host` header with a value of `www.someh
This predicate extracts the URI template variables (such as `sub`, defined in the preceding example) as a map of names and values and places it in the `ServerWebExchange.getAttributes()` with a key defined in `ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE`.
Those values are then available for use by [`GatewayFilter` factories](#gateway-route-filters)
-### [](#the-method-route-predicate-factory)[5.7. The Method Route Predicate Factory](#the-method-route-predicate-factory) ###
+### [](#the-method-route-predicate-factory)[5.7. The Method Route Predicate Factory](#the-method-route-predicate-factory)
The `Method` Route Predicate Factory takes a `methods` argument which is one or more parameters: the HTTP methods to match.
The following example configures a method route predicate:
@@ -255,7 +388,7 @@ spring:
This route matches if the request method was a `GET` or a `POST`.
-### [](#the-path-route-predicate-factory)[5.8. The Path Route Predicate Factory](#the-path-route-predicate-factory) ###
+### [](#the-path-route-predicate-factory)[5.8. The Path Route Predicate Factory](#the-path-route-predicate-factory)
The `Path` Route Predicate Factory takes two parameters: a list of Spring `PathMatcher` `patterns` and an optional flag called `matchTrailingSlash` (defaults to `true`).
The following example configures a path route predicate:
@@ -289,7 +422,7 @@ Map uriVariables = ServerWebExchangeUtils.getPathPredicateVariab
String segment = uriVariables.get("segment");
```
-### [](#the-query-route-predicate-factory)[5.9. The Query Route Predicate Factory](#the-query-route-predicate-factory) ###
+### [](#the-query-route-predicate-factory)[5.9. The Query Route Predicate Factory](#the-query-route-predicate-factory)
The `Query` route predicate factory takes two parameters: a required `param` and an optional `regexp` (which is a Java regular expression).
The following example configures a query route predicate:
@@ -324,7 +457,7 @@ spring:
The preceding route matches if the request contained a `red` query parameter whose value matched the `gree.` regexp, so `green` and `greet` would match.
-### [](#the-remoteaddr-route-predicate-factory)[5.10. The RemoteAddr Route Predicate Factory](#the-remoteaddr-route-predicate-factory) ###
+### [](#the-remoteaddr-route-predicate-factory)[5.10. The RemoteAddr Route Predicate Factory](#the-remoteaddr-route-predicate-factory)
The `RemoteAddr` route predicate factory takes a list (min size 1) of `sources`, which are CIDR-notation (IPv4 or IPv6) strings, such as `192.168.0.1/16` (where `192.168.0.1` is an IP address and `16` is a subnet mask).
The following example configures a RemoteAddr route predicate:
@@ -344,7 +477,7 @@ spring:
This route matches if the remote address of the request was, for example, `192.168.1.10`.
-#### [](#modifying-the-way-remote-addresses-are-resolved)[5.10.1. Modifying the Way Remote Addresses Are Resolved](#modifying-the-way-remote-addresses-are-resolved) ####
+#### [](#modifying-the-way-remote-addresses-are-resolved)[5.10.1. Modifying the Way Remote Addresses Are Resolved](#modifying-the-way-remote-addresses-are-resolved)
By default, the RemoteAddr route predicate factory uses the remote address from the incoming request.
This may not match the actual client IP address if Spring Cloud Gateway sits behind a proxy layer.
@@ -396,7 +529,7 @@ RemoteAddressResolver resolver = XForwardedRemoteAddressResolver
)
```
-### [](#the-weight-route-predicate-factory)[5.11. The Weight Route Predicate Factory](#the-weight-route-predicate-factory) ###
+### [](#the-weight-route-predicate-factory)[5.11. The Weight Route Predicate Factory](#the-weight-route-predicate-factory)
The `Weight` route predicate factory takes two arguments: `group` and `weight` (an int). The weights are calculated per group.
The following example configures a weight route predicate:
@@ -420,7 +553,7 @@ spring:
This route would forward \~80% of traffic to [weighthigh.org](https://weighthigh.org) and \~20% of traffic to [weighlow.org](https://weighlow.org)
-### [](#the-xforwarded-remote-addr-route-predicate-factory)[5.12. The XForwarded Remote Addr Route Predicate Factory](#the-xforwarded-remote-addr-route-predicate-factory) ###
+### [](#the-xforwarded-remote-addr-route-predicate-factory)[5.12. The XForwarded Remote Addr Route Predicate Factory](#the-xforwarded-remote-addr-route-predicate-factory)
The `XForwarded Remote Addr` route predicate factory takes a list (min size 1) of `sources`, which are CIDR-notation (IPv4 or IPv6) strings, such as `192.168.0.1/16` (where `192.168.0.1` is an IP address and `16` is a subnet mask).
@@ -447,8 +580,7 @@ spring:
This route matches if the `X-Forwarded-For` header contains, for example, `192.168.1.10`.
-[](#gatewayfilter-factories)[6. `GatewayFilter` Factories](#gatewayfilter-factories)
-----------
+## [](#gatewayfilter-factories)[6. `GatewayFilter` Factories](#gatewayfilter-factories)
Route filters allow the modification of the incoming HTTP request or outgoing HTTP response in some manner.
Route filters are scoped to a particular route.
@@ -457,7 +589,7 @@ Spring Cloud Gateway includes many built-in GatewayFilter Factories.
| |For more detailed examples of how to use any of the following filters, take a look at the [unit tests](https://github.com/spring-cloud/spring-cloud-gateway/tree/master/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/filter/factory).|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#the-addrequestheader-gatewayfilter-factory)[6.1. The `AddRequestHeader` `GatewayFilter` Factory](#the-addrequestheader-gatewayfilter-factory) ###
+### [](#the-addrequestheader-gatewayfilter-factory)[6.1. The `AddRequestHeader` `GatewayFilter` Factory](#the-addrequestheader-gatewayfilter-factory)
The `AddRequestHeader` `GatewayFilter` factory takes a `name` and `value` parameter.
The following example configures an `AddRequestHeader` `GatewayFilter`:
@@ -496,7 +628,7 @@ spring:
- AddRequestHeader=X-Request-Red, Blue-{segment}
```
-### [](#the-addrequestparameter-gatewayfilter-factory)[6.2. The `AddRequestParameter` `GatewayFilter` Factory](#the-addrequestparameter-gatewayfilter-factory) ###
+### [](#the-addrequestparameter-gatewayfilter-factory)[6.2. The `AddRequestParameter` `GatewayFilter` Factory](#the-addrequestparameter-gatewayfilter-factory)
The `AddRequestParameter` `GatewayFilter` Factory takes a `name` and `value` parameter.
The following example configures an `AddRequestParameter` `GatewayFilter`:
@@ -535,7 +667,7 @@ spring:
- AddRequestParameter=foo, bar-{segment}
```
-### [](#the-addresponseheader-gatewayfilter-factory)[6.3. The `AddResponseHeader` `GatewayFilter` Factory](#the-addresponseheader-gatewayfilter-factory) ###
+### [](#the-addresponseheader-gatewayfilter-factory)[6.3. The `AddResponseHeader` `GatewayFilter` Factory](#the-addresponseheader-gatewayfilter-factory)
The `AddResponseHeader` `GatewayFilter` Factory takes a `name` and `value` parameter.
The following example configures an `AddResponseHeader` `GatewayFilter`:
@@ -574,7 +706,7 @@ spring:
- AddResponseHeader=foo, bar-{segment}
```
-### [](#the-deduperesponseheader-gatewayfilter-factory)[6.4. The `DedupeResponseHeader` `GatewayFilter` Factory](#the-deduperesponseheader-gatewayfilter-factory) ###
+### [](#the-deduperesponseheader-gatewayfilter-factory)[6.4. The `DedupeResponseHeader` `GatewayFilter` Factory](#the-deduperesponseheader-gatewayfilter-factory)
The DedupeResponseHeader GatewayFilter factory takes a `name` parameter and an optional `strategy` parameter. `name` can contain a space-separated list of header names.
The following example configures a `DedupeResponseHeader` `GatewayFilter`:
@@ -597,7 +729,7 @@ This removes duplicate values of `Access-Control-Allow-Credentials` and `Access-
The `DedupeResponseHeader` filter also accepts an optional `strategy` parameter.
The accepted values are `RETAIN_FIRST` (default), `RETAIN_LAST`, and `RETAIN_UNIQUE`.
-### [](#spring-cloud-circuitbreaker-filter-factory)[6.5. Spring Cloud CircuitBreaker GatewayFilter Factory](#spring-cloud-circuitbreaker-filter-factory) ###
+### [](#spring-cloud-circuitbreaker-filter-factory)[6.5. Spring Cloud CircuitBreaker GatewayFilter Factory](#spring-cloud-circuitbreaker-filter-factory)
The Spring Cloud CircuitBreaker GatewayFilter factory uses the Spring Cloud CircuitBreaker APIs to wrap Gateway routes in
a circuit breaker. Spring Cloud CircuitBreaker supports multiple libraries that can be used with Spring Cloud Gateway. Spring Cloud supports Resilience4J out of the box.
@@ -698,7 +830,7 @@ It is added to the `ServerWebExchange` as the `ServerWebExchangeUtils.CIRCUITBRE
For the external controller/handler scenario, headers can be added with exception details.
You can find more information on doing so in the [FallbackHeaders GatewayFilter Factory section](#fallback-headers).
-#### [](#circuit-breaker-status-codes)[6.5.1. Tripping The Circuit Breaker On Status Codes](#circuit-breaker-status-codes) ####
+#### [](#circuit-breaker-status-codes)[6.5.1. Tripping The Circuit Breaker On Status Codes](#circuit-breaker-status-codes)
In some cases you might want to trip a circuit breaker based on the status code
returned from the route it wraps. The circuit breaker config object takes a list of
@@ -740,7 +872,7 @@ public RouteLocator routes(RouteLocatorBuilder builder) {
}
```
-### [](#fallback-headers)[6.6. The `FallbackHeaders` `GatewayFilter` Factory](#fallback-headers) ###
+### [](#fallback-headers)[6.6. The `FallbackHeaders` `GatewayFilter` Factory](#fallback-headers)
The `FallbackHeaders` factory lets you add Spring Cloud CircuitBreaker execution exception details in the headers of a request forwarded to a `fallbackUri` in an external application, as in the following scenario:
@@ -785,7 +917,7 @@ You can overwrite the names of the headers in the configuration by setting the v
For more information on circuit breakers and the gateway see the [Spring Cloud CircuitBreaker Factory section](#spring-cloud-circuitbreaker-filter-factory).
-### [](#the-maprequestheader-gatewayfilter-factory)[6.7. The `MapRequestHeader` `GatewayFilter` Factory](#the-maprequestheader-gatewayfilter-factory) ###
+### [](#the-maprequestheader-gatewayfilter-factory)[6.7. The `MapRequestHeader` `GatewayFilter` Factory](#the-maprequestheader-gatewayfilter-factory)
The `MapRequestHeader` `GatewayFilter` factory takes `fromHeader` and `toHeader` parameters.
It creates a new named header (`toHeader`), and the value is extracted out of an existing named header (`fromHeader`) from the incoming http request.
@@ -808,7 +940,7 @@ spring:
This adds `X-Request-Red:` header to the downstream request with updated values from the incoming HTTP request’s `Blue` header.
-### [](#the-prefixpath-gatewayfilter-factory)[6.8. The `PrefixPath` `GatewayFilter` Factory](#the-prefixpath-gatewayfilter-factory) ###
+### [](#the-prefixpath-gatewayfilter-factory)[6.8. The `PrefixPath` `GatewayFilter` Factory](#the-prefixpath-gatewayfilter-factory)
The `PrefixPath` `GatewayFilter` factory takes a single `prefix` parameter.
The following example configures a `PrefixPath` `GatewayFilter`:
@@ -829,7 +961,7 @@ spring:
This will prefix `/mypath` to the path of all matching requests.
So a request to `/hello` would be sent to `/mypath/hello`.
-### [](#the-preservehostheader-gatewayfilter-factory)[6.9. The `PreserveHostHeader` `GatewayFilter` Factory](#the-preservehostheader-gatewayfilter-factory) ###
+### [](#the-preservehostheader-gatewayfilter-factory)[6.9. The `PreserveHostHeader` `GatewayFilter` Factory](#the-preservehostheader-gatewayfilter-factory)
The `PreserveHostHeader` `GatewayFilter` factory has no parameters.
This filter sets a request attribute that the routing filter inspects to determine if the original host header should be sent, rather than the host header determined by the HTTP client.
@@ -848,7 +980,7 @@ spring:
- PreserveHostHeader
```
-### [](#the-requestratelimiter-gatewayfilter-factory)[6.10. The `RequestRateLimiter` `GatewayFilter` Factory](#the-requestratelimiter-gatewayfilter-factory) ###
+### [](#the-requestratelimiter-gatewayfilter-factory)[6.10. The `RequestRateLimiter` `GatewayFilter` Factory](#the-requestratelimiter-gatewayfilter-factory)
The `RequestRateLimiter` `GatewayFilter` factory uses a `RateLimiter` implementation to determine if the current request is allowed to proceed. If it is not, a status of `HTTP 429 - Too Many Requests` (by default) is returned.
@@ -877,7 +1009,7 @@ You can adjust this behavior by setting the `spring.cloud.gateway.filter.request
| |The `RequestRateLimiter` is not configurable with the "shortcut" notation. The following example below is *invalid*:
Example 32. application.properties
```
# INVALID SHORTCUT CONFIGURATION
spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}
```|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [](#the-redis-ratelimiter)[6.10.1. The Redis `RateLimiter`](#the-redis-ratelimiter) ####
+#### [](#the-redis-ratelimiter)[6.10.1. The Redis `RateLimiter`](#the-redis-ratelimiter)
The Redis implementation is based off of work done at [Stripe](https://stripe.com/blog/rate-limiters).
It requires the use of the `spring-boot-starter-data-redis-reactive` Spring Boot starter.
@@ -952,7 +1084,7 @@ spring:
key-resolver: "#{@userKeyResolver}"
```
-### [](#the-redirectto-gatewayfilter-factory)[6.11. The `RedirectTo` `GatewayFilter` Factory](#the-redirectto-gatewayfilter-factory) ###
+### [](#the-redirectto-gatewayfilter-factory)[6.11. The `RedirectTo` `GatewayFilter` Factory](#the-redirectto-gatewayfilter-factory)
The `RedirectTo` `GatewayFilter` factory takes two parameters, `status` and `url`.
The `status` parameter should be a 300 series redirect HTTP code, such as 301.
@@ -976,7 +1108,7 @@ spring:
This will send a status 302 with a `Location:https://acme.org` header to perform a redirect.
-### [](#the-removerequestheader-gatewayfilter-factory)[6.12. The `RemoveRequestHeader` GatewayFilter Factory](#the-removerequestheader-gatewayfilter-factory) ###
+### [](#the-removerequestheader-gatewayfilter-factory)[6.12. The `RemoveRequestHeader` GatewayFilter Factory](#the-removerequestheader-gatewayfilter-factory)
The `RemoveRequestHeader` `GatewayFilter` factory takes a `name` parameter.
It is the name of the header to be removed.
@@ -997,7 +1129,7 @@ spring:
This removes the `X-Request-Foo` header before it is sent downstream.
-### [](#removeresponseheader-gatewayfilter-factory)[6.13. `RemoveResponseHeader` `GatewayFilter` Factory](#removeresponseheader-gatewayfilter-factory) ###
+### [](#removeresponseheader-gatewayfilter-factory)[6.13. `RemoveResponseHeader` `GatewayFilter` Factory](#removeresponseheader-gatewayfilter-factory)
The `RemoveResponseHeader` `GatewayFilter` factory takes a `name` parameter.
It is the name of the header to be removed.
@@ -1021,7 +1153,7 @@ This will remove the `X-Response-Foo` header from the response before it is retu
To remove any kind of sensitive header, you should configure this filter for any routes for which you may want to do so.
In addition, you can configure this filter once by using `spring.cloud.gateway.default-filters` and have it applied to all routes.
-### [](#the-removerequestparameter-gatewayfilter-factory)[6.14. The `RemoveRequestParameter` `GatewayFilter` Factory](#the-removerequestparameter-gatewayfilter-factory) ###
+### [](#the-removerequestparameter-gatewayfilter-factory)[6.14. The `RemoveRequestParameter` `GatewayFilter` Factory](#the-removerequestparameter-gatewayfilter-factory)
The `RemoveRequestParameter` `GatewayFilter` factory takes a `name` parameter.
It is the name of the query parameter to be removed.
@@ -1042,7 +1174,7 @@ spring:
This will remove the `red` parameter before it is sent downstream.
-### [](#the-rewritepath-gatewayfilter-factory)[6.15. The `RewritePath` `GatewayFilter` Factory](#the-rewritepath-gatewayfilter-factory) ###
+### [](#the-rewritepath-gatewayfilter-factory)[6.15. The `RewritePath` `GatewayFilter` Factory](#the-rewritepath-gatewayfilter-factory)
The `RewritePath` `GatewayFilter` factory takes a path `regexp` parameter and a `replacement` parameter.
This uses Java regular expressions for a flexible way to rewrite the request path.
@@ -1065,7 +1197,7 @@ spring:
For a request path of `/red/blue`, this sets the path to `/blue` before making the downstream request. Note that the `$` should be replaced with `$\` because of the YAML specification.
-### [](#rewritelocationresponseheader-gatewayfilter-factory)[6.16. `RewriteLocationResponseHeader` `GatewayFilter` Factory](#rewritelocationresponseheader-gatewayfilter-factory) ###
+### [](#rewritelocationresponseheader-gatewayfilter-factory)[6.16. `RewriteLocationResponseHeader` `GatewayFilter` Factory](#rewritelocationresponseheader-gatewayfilter-factory)
The `RewriteLocationResponseHeader` `GatewayFilter` factory modifies the value of the `Location` response header, usually to get rid of backend-specific details.
It takes `stripVersionMode`, `locationHeaderName`, `hostValue`, and `protocolsRegex` parameters.
@@ -1101,7 +1233,7 @@ The `protocolsRegex` parameter must be a valid regex `String`, against which the
If it is not matched, the filter does nothing.
The default is `http|https|ftp|ftps`.
-### [](#the-rewriteresponseheader-gatewayfilter-factory)[6.17. The `RewriteResponseHeader` `GatewayFilter` Factory](#the-rewriteresponseheader-gatewayfilter-factory) ###
+### [](#the-rewriteresponseheader-gatewayfilter-factory)[6.17. The `RewriteResponseHeader` `GatewayFilter` Factory](#the-rewriteresponseheader-gatewayfilter-factory)
The `RewriteResponseHeader` `GatewayFilter` factory takes `name`, `regexp`, and `replacement` parameters.
It uses Java regular expressions for a flexible way to rewrite the response header value.
@@ -1123,7 +1255,7 @@ spring:
For a header value of `/42?user=ford&password=omg!what&flag=true`, it is set to `/42?user=ford&password=***&flag=true` after making the downstream request.
You must use `$\` to mean `$` because of the YAML specification.
-### [](#the-savesession-gatewayfilter-factory)[6.18. The `SaveSession` `GatewayFilter` Factory](#the-savesession-gatewayfilter-factory) ###
+### [](#the-savesession-gatewayfilter-factory)[6.18. The `SaveSession` `GatewayFilter` Factory](#the-savesession-gatewayfilter-factory)
The `SaveSession` `GatewayFilter` factory forces a `WebSession::save` operation *before* forwarding the call downstream.
This is of particular use when using something like [Spring Session](https://projects.spring.io/spring-session/) with a lazy data store and you need to ensure the session state has been saved before making the forwarded call.
@@ -1146,7 +1278,7 @@ spring:
If you integrate [Spring Security](https://projects.spring.io/spring-security/) with Spring Session and want to ensure security details have been forwarded to the remote process, this is critical.
-### [](#the-secureheaders-gatewayfilter-factory)[6.19. The `SecureHeaders` `GatewayFilter` Factory](#the-secureheaders-gatewayfilter-factory) ###
+### [](#the-secureheaders-gatewayfilter-factory)[6.19. The `SecureHeaders` `GatewayFilter` Factory](#the-secureheaders-gatewayfilter-factory)
The `SecureHeaders` `GatewayFilter` factory adds a number of headers to the response, per the recommendation made in [this blog post](https://blog.appcanary.com/2017/http-security-headers.html).
@@ -1197,7 +1329,7 @@ spring.cloud.gateway.filter.secure-headers.disable=x-frame-options,strict-transp
| |The lowercase full name of the secure header needs to be used to disable it..|
|---|-----------------------------------------------------------------------------|
-### [](#the-setpath-gatewayfilter-factory)[6.20. The `SetPath` `GatewayFilter` Factory](#the-setpath-gatewayfilter-factory) ###
+### [](#the-setpath-gatewayfilter-factory)[6.20. The `SetPath` `GatewayFilter` Factory](#the-setpath-gatewayfilter-factory)
The `SetPath` `GatewayFilter` factory takes a path `template` parameter.
It offers a simple way to manipulate the request path by allowing templated segments of the path.
@@ -1222,7 +1354,7 @@ spring:
For a request path of `/red/blue`, this sets the path to `/blue` before making the downstream request.
-### [](#the-setrequestheader-gatewayfilter-factory)[6.21. The `SetRequestHeader` `GatewayFilter` Factory](#the-setrequestheader-gatewayfilter-factory) ###
+### [](#the-setrequestheader-gatewayfilter-factory)[6.21. The `SetRequestHeader` `GatewayFilter` Factory](#the-setrequestheader-gatewayfilter-factory)
The `SetRequestHeader` `GatewayFilter` factory takes `name` and `value` parameters.
The following listing configures a `SetRequestHeader` `GatewayFilter`:
@@ -1262,7 +1394,7 @@ spring:
- SetRequestHeader=foo, bar-{segment}
```
-### [](#the-setresponseheader-gatewayfilter-factory)[6.22. The `SetResponseHeader` `GatewayFilter` Factory](#the-setresponseheader-gatewayfilter-factory) ###
+### [](#the-setresponseheader-gatewayfilter-factory)[6.22. The `SetResponseHeader` `GatewayFilter` Factory](#the-setresponseheader-gatewayfilter-factory)
The `SetResponseHeader` `GatewayFilter` factory takes `name` and `value` parameters.
The following listing configures a `SetResponseHeader` `GatewayFilter`:
@@ -1302,7 +1434,7 @@ spring:
- SetResponseHeader=foo, bar-{segment}
```
-### [](#the-setstatus-gatewayfilter-factory)[6.23. The `SetStatus` `GatewayFilter` Factory](#the-setstatus-gatewayfilter-factory) ###
+### [](#the-setstatus-gatewayfilter-factory)[6.23. The `SetStatus` `GatewayFilter` Factory](#the-setstatus-gatewayfilter-factory)
The `SetStatus` `GatewayFilter` factory takes a single parameter, `status`.
It must be a valid Spring `HttpStatus`.
@@ -1341,7 +1473,7 @@ spring:
original-status-header-name: original-http-status
```
-### [](#the-stripprefix-gatewayfilter-factory)[6.24. The `StripPrefix` `GatewayFilter` Factory](#the-stripprefix-gatewayfilter-factory) ###
+### [](#the-stripprefix-gatewayfilter-factory)[6.24. The `StripPrefix` `GatewayFilter` Factory](#the-stripprefix-gatewayfilter-factory)
The `StripPrefix` `GatewayFilter` factory takes one parameter, `parts`.
The `parts` parameter indicates the number of parts in the path to strip from the request before sending it downstream.
@@ -1364,7 +1496,7 @@ spring:
When a request is made through the gateway to `/name/blue/red`, the request made to `nameservice` looks like `[nameservice/red](https://nameservice/red)`.
-### [](#the-retry-gatewayfilter-factory)[6.25. The Retry `GatewayFilter` Factory](#the-retry-gatewayfilter-factory) ###
+### [](#the-retry-gatewayfilter-factory)[6.25. The Retry `GatewayFilter` Factory](#the-retry-gatewayfilter-factory)
The `Retry` `GatewayFilter` factory supports the following parameters:
@@ -1458,7 +1590,7 @@ spring:
- Retry=3,INTERNAL_SERVER_ERROR,GET,10ms,50ms,2,false
```
-### [](#the-requestsize-gatewayfilter-factory)[6.26. The `RequestSize` `GatewayFilter` Factory](#the-requestsize-gatewayfilter-factory) ###
+### [](#the-requestsize-gatewayfilter-factory)[6.26. The `RequestSize` `GatewayFilter` Factory](#the-requestsize-gatewayfilter-factory)
When the request size is greater than the permissible limit, the `RequestSize` `GatewayFilter` factory can restrict a request from reaching the downstream service.
The filter takes a `maxSize` parameter.
@@ -1492,7 +1624,7 @@ errorMessage : Request size is larger than permissible limit. Request size is 6.
| |The default request size is set to five MB if not provided as a filter argument in the route definition.|
|---|--------------------------------------------------------------------------------------------------------|
-### [](#the-setrequesthostheader-gatewayfilter-factory)[6.27. The `SetRequestHostHeader` `GatewayFilter` Factory](#the-setrequesthostheader-gatewayfilter-factory) ###
+### [](#the-setrequesthostheader-gatewayfilter-factory)[6.27. The `SetRequestHostHeader` `GatewayFilter` Factory](#the-setrequesthostheader-gatewayfilter-factory)
There are certain situation when the host header may need to be overridden. In this situation, the `SetRequestHostHeader` `GatewayFilter` factory can replace the existing host header with a specified vaue.
The filter takes a `host` parameter.
@@ -1517,7 +1649,7 @@ spring:
The `SetRequestHostHeader` `GatewayFilter` factory replaces the value of the host header with `example.org`.
-### [](#modify-a-request-body-gatewayfilter-factory)[6.28. Modify a Request Body `GatewayFilter` Factory](#modify-a-request-body-gatewayfilter-factory) ###
+### [](#modify-a-request-body-gatewayfilter-factory)[6.28. Modify a Request Body `GatewayFilter` Factory](#modify-a-request-body-gatewayfilter-factory)
You can use the `ModifyRequestBody` filter filter to modify the request body before it is sent downstream by the gateway.
@@ -1559,7 +1691,7 @@ static class Hello {
| |if the request has no body, the `RewriteFilter` will be passed `null`. `Mono.empty()` should be returned to assign a missing body in the request.|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#modify-a-response-body-gatewayfilter-factory)[6.29. Modify a Response Body `GatewayFilter` Factory](#modify-a-response-body-gatewayfilter-factory) ###
+### [](#modify-a-response-body-gatewayfilter-factory)[6.29. Modify a Response Body `GatewayFilter` Factory](#modify-a-response-body-gatewayfilter-factory)
You can use the `ModifyResponseBody` filter to modify the response body before it is sent back to the client.
@@ -1583,7 +1715,7 @@ public RouteLocator routes(RouteLocatorBuilder builder) {
| |if the response has no body, the `RewriteFilter` will be passed `null`. `Mono.empty()` should be returned to assign a missing body in the response.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#token-relay-gatewayfilter-factory)[6.30. Token Relay `GatewayFilter` Factory](#token-relay-gatewayfilter-factory) ###
+### [](#token-relay-gatewayfilter-factory)[6.30. Token Relay `GatewayFilter` Factory](#token-relay-gatewayfilter-factory)
A Token Relay is where an OAuth2 consumer acts as a Client and
forwards the incoming token to outgoing resource requests. The
@@ -1643,7 +1775,7 @@ For a full working sample see [this project](https://github.com/spring-cloud-sam
| |The default implementation of `ReactiveOAuth2AuthorizedClientService` used by `TokenRelayGatewayFilterFactory`uses an in-memory data store. You will need to provide your own implementation `ReactiveOAuth2AuthorizedClientService`if you need a more robust solution.|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#the-cacherequestbody-gatewayfilter-factory)[6.31. The `CacheRequestBody` `GatewayFilter` Factory](#the-cacherequestbody-gatewayfilter-factory) ###
+### [](#the-cacherequestbody-gatewayfilter-factory)[6.31. The `CacheRequestBody` `GatewayFilter` Factory](#the-cacherequestbody-gatewayfilter-factory)
There are certain situation need to read body.Since the request body stream can only be read once, we need to cache the request body.
You can use the `CacheRequestBody` filter to cache request body before it send to the downstream and get body from exchagne attribute.
@@ -1683,7 +1815,7 @@ spring:
| |This filter only works with http request (including https).|
|---|-----------------------------------------------------------|
-### [](#default-filters)[6.32. Default Filters](#default-filters) ###
+### [](#default-filters)[6.32. Default Filters](#default-filters)
To add a filter and apply it to all routes, you can use `spring.cloud.gateway.default-filters`.
This property takes a list of filters.
@@ -1700,8 +1832,7 @@ spring:
- PrefixPath=/httpbin
```
-[](#global-filters)[7. Global Filters](#global-filters)
-----------
+## [](#global-filters)[7. Global Filters](#global-filters)
The `GlobalFilter` interface has the same signature as `GatewayFilter`.
These are special filters that are conditionally applied to all routes.
@@ -1709,7 +1840,7 @@ These are special filters that are conditionally applied to all routes.
| |This interface and its usage are subject to change in future milestone releases.|
|---|--------------------------------------------------------------------------------|
-### [](#gateway-combined-global-filter-and-gatewayfilter-ordering)[7.1. Combined Global Filter and `GatewayFilter` Ordering](#gateway-combined-global-filter-and-gatewayfilter-ordering) ###
+### [](#gateway-combined-global-filter-and-gatewayfilter-ordering)[7.1. Combined Global Filter and `GatewayFilter` Ordering](#gateway-combined-global-filter-and-gatewayfilter-ordering)
When a request matches a route, the filtering web handler adds all instances of `GlobalFilter` and all route-specific instances of `GatewayFilter` to a filter chain.
This combined filter chain is sorted by the `org.springframework.core.Ordered` interface, which you can set by implementing the `getOrder()` method.
@@ -1741,14 +1872,14 @@ public class CustomGlobalFilter implements GlobalFilter, Ordered {
}
```
-### [](#forward-routing-filter)[7.2. Forward Routing Filter](#forward-routing-filter) ###
+### [](#forward-routing-filter)[7.2. Forward Routing Filter](#forward-routing-filter)
The `ForwardRoutingFilter` looks for a URI in the exchange attribute `ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR`.
If the URL has a `forward` scheme (such as `forward:///localendpoint`), it uses the Spring `DispatcherHandler` to handle the request.
The path part of the request URL is overridden with the path in the forward URL.
The unmodified original URL is appended to the list in the `ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR` attribute.
-### [](#reactive-loadbalancer-client-filter)[7.3. The `ReactiveLoadBalancerClientFilter`](#reactive-loadbalancer-client-filter) ###
+### [](#reactive-loadbalancer-client-filter)[7.3. The `ReactiveLoadBalancerClientFilter`](#reactive-loadbalancer-client-filter)
The `ReactiveLoadBalancerClientFilter` looks for a URI in the exchange attribute named `ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR`.
If the URL has a `lb` scheme (such as `lb://myservice`), it uses the Spring Cloud `ReactorLoadBalancer` to resolve the name (`myservice` in this example) to an actual host and port and replaces the URI in the same attribute.
@@ -1779,20 +1910,20 @@ spring:
| |Gateway supports all the LoadBalancer features. You can read more about them in the [Spring Cloud Commons documentation](https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer).|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#the-netty-routing-filter)[7.4. The Netty Routing Filter](#the-netty-routing-filter) ###
+### [](#the-netty-routing-filter)[7.4. The Netty Routing Filter](#the-netty-routing-filter)
The Netty routing filter runs if the URL located in the `ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR` exchange attribute has a `http` or `https` scheme.
It uses the Netty `HttpClient` to make the downstream proxy request.
The response is put in the `ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR` exchange attribute for use in a later filter.
(There is also an experimental `WebClientHttpRoutingFilter` that performs the same function but does not require Netty.)
-### [](#the-netty-write-response-filter)[7.5. The Netty Write Response Filter](#the-netty-write-response-filter) ###
+### [](#the-netty-write-response-filter)[7.5. The Netty Write Response Filter](#the-netty-write-response-filter)
The `NettyWriteResponseFilter` runs if there is a Netty `HttpClientResponse` in the `ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR` exchange attribute.
It runs after all other filters have completed and writes the proxy response back to the gateway client response.
(There is also an experimental `WebClientWriteResponseFilter` that performs the same function but does not require Netty.)
-### [](#the-routetorequesturl-filter)[7.6. The `RouteToRequestUrl` Filter](#the-routetorequesturl-filter) ###
+### [](#the-routetorequesturl-filter)[7.6. The `RouteToRequestUrl` Filter](#the-routetorequesturl-filter)
If there is a `Route` object in the `ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR` exchange attribute, the `RouteToRequestUrlFilter` runs.
It creates a new URI, based off of the request URI but updated with the URI attribute of the `Route` object.
@@ -1800,7 +1931,7 @@ The new URI is placed in the `ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR` e
If the URI has a scheme prefix, such as `lb:ws://serviceid`, the `lb` scheme is stripped from the URI and placed in the `ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR` for use later in the filter chain.
-### [](#the-websocket-routing-filter)[7.7. The Websocket Routing Filter](#the-websocket-routing-filter) ###
+### [](#the-websocket-routing-filter)[7.7. The Websocket Routing Filter](#the-websocket-routing-filter)
If the URL located in the `ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR` exchange attribute has a `ws` or `wss` scheme, the websocket routing filter runs. It uses the Spring WebSocket infrastructure to forward the websocket request downstream.
@@ -1830,7 +1961,7 @@ spring:
- Path=/websocket/**
```
-### [](#the-gateway-metrics-filter)[7.8. The Gateway Metrics Filter](#the-gateway-metrics-filter) ###
+### [](#the-gateway-metrics-filter)[7.8. The Gateway Metrics Filter](#the-gateway-metrics-filter)
To enable gateway metrics, add spring-boot-starter-actuator as a project dependency. Then, by default, the gateway metrics filter runs as long as the property `spring.cloud.gateway.metrics.enabled` is not set to `false`. This filter adds a timer metric named `spring.cloud.gateway.requests` with the following tags:
@@ -1855,7 +1986,7 @@ These metrics are then available to be scraped from `/actuator/metrics/spring.cl
| |To enable the prometheus endpoint, add `micrometer-registry-prometheus` as a project dependency.|
|---|------------------------------------------------------------------------------------------------|
-### [](#marking-an-exchange-as-routed)[7.9. Marking An Exchange As Routed](#marking-an-exchange-as-routed) ###
+### [](#marking-an-exchange-as-routed)[7.9. Marking An Exchange As Routed](#marking-an-exchange-as-routed)
After the gateway has routed a `ServerWebExchange`, it marks that exchange as “routed” by adding `gatewayAlreadyRouted`to the exchange attributes. Once a request has been marked as routed, other routing filters will not route the request again,
essentially skipping the filter. There are convenience methods that you can use to mark an exchange as routed
@@ -1865,16 +1996,15 @@ or check if an exchange has already been routed.
* `ServerWebExchangeUtils.setAlreadyRouted` takes a `ServerWebExchange` object and marks it as “routed”.
-[](#httpheadersfilters)[8. HttpHeadersFilters](#httpheadersfilters)
-----------
+## [](#httpheadersfilters)[8. HttpHeadersFilters](#httpheadersfilters)
HttpHeadersFilters are applied to requests before sending them downstream, such as in the `NettyRoutingFilter`.
-### [](#forwarded-headers-filter)[8.1. Forwarded Headers Filter](#forwarded-headers-filter) ###
+### [](#forwarded-headers-filter)[8.1. Forwarded Headers Filter](#forwarded-headers-filter)
The `Forwarded` Headers Filter creates a `Forwarded` header to send to the downstream service. It adds the `Host` header, scheme and port of the current request to any existing `Forwarded` header.
-### [](#removehopbyhop-headers-filter)[8.2. RemoveHopByHop Headers Filter](#removehopbyhop-headers-filter) ###
+### [](#removehopbyhop-headers-filter)[8.2. RemoveHopByHop Headers Filter](#removehopbyhop-headers-filter)
The `RemoveHopByHop` Headers Filter removes headers from forwarded requests. The default list of headers that is removed comes from the [IETF](https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-7.1.3).
@@ -1898,7 +2028,7 @@ The default removed headers are:
To change this, set the `spring.cloud.gateway.filter.remove-hop-by-hop.headers` property to the list of header names to remove.
-### [](#xforwarded-headers-filter)[8.3. XForwarded Headers Filter](#xforwarded-headers-filter) ###
+### [](#xforwarded-headers-filter)[8.3. XForwarded Headers Filter](#xforwarded-headers-filter)
The `XForwarded` Headers Filter creates various a `X-Forwarded-*` headers to send to the downstream service. It users the `Host` header, scheme, port and path of the current request to create the various headers.
@@ -1926,8 +2056,7 @@ Appending multiple headers can be controlled by the following boolean properties
* `spring.cloud.gateway.x-forwarded.prefix-append`
-[](#tls-and-ssl)[9. TLS and SSL](#tls-and-ssl)
-----------
+## [](#tls-and-ssl)[9. TLS and SSL](#tls-and-ssl)
The gateway can listen for requests on HTTPS by following the usual Spring server configuration.
The following example shows how to do so:
@@ -1976,7 +2105,7 @@ spring:
If the Spring Cloud Gateway is not provisioned with trusted certificates, the default trust store is used (which you can override by setting the `javax.net.ssl.trustStore` system property).
-### [](#tls-handshake)[9.1. TLS Handshake](#tls-handshake) ###
+### [](#tls-handshake)[9.1. TLS Handshake](#tls-handshake)
The gateway maintains a client pool that it uses to route to backends.
When communicating over HTTPS, the client initiates a TLS handshake.
@@ -1996,8 +2125,7 @@ spring:
close-notify-read-timeout-millis: 0
```
-[](#configuration)[10. Configuration](#configuration)
-----------
+## [](#configuration)[10. Configuration](#configuration)
Configuration for Spring Cloud Gateway is driven by a collection of `RouteDefinitionLocator` instances.
The following listing shows the definition of the `RouteDefinitionLocator` interface:
@@ -2036,12 +2164,11 @@ spring:
For some usages of the gateway, properties are adequate, but some production use cases benefit from loading configuration from an external source, such as a database. Future milestone versions will have `RouteDefinitionLocator` implementations based off of Spring Data Repositories, such as Redis, MongoDB, and Cassandra.
-### [](#routedefinition-metrics)[10.1. RouteDefinition Metrics](#routedefinition-metrics) ###
+### [](#routedefinition-metrics)[10.1. RouteDefinition Metrics](#routedefinition-metrics)
To enable `RouteDefinition` metrics, add spring-boot-starter-actuator as a project dependency. Then, by default, the metrics will be available as long as the property `spring.cloud.gateway.metrics.enabled` is set to `true`. A gauge metric named `spring.cloud.gateway.routes.count` will be added, whose value is the number of `RouteDefinitions`. This metric will be available from `/actuator/metrics/spring.cloud.gateway.routes.count`.
-[](#route-metadata-configuration)[11. Route Metadata Configuration](#route-metadata-configuration)
-----------
+## [](#route-metadata-configuration)[11. Route Metadata Configuration](#route-metadata-configuration)
You can configure additional parameters for each route by using metadata, as follows:
@@ -2071,12 +2198,11 @@ route.getMetadata();
route.getMetadata(someKey);
```
-[](#http-timeouts-configuration)[12. Http timeouts configuration](#http-timeouts-configuration)
-----------
+## [](#http-timeouts-configuration)[12. Http timeouts configuration](#http-timeouts-configuration)
Http timeouts (response and connect) can be configured for all routes and overridden for each specific route.
-### [](#global-timeouts)[12.1. Global timeouts](#global-timeouts) ###
+### [](#global-timeouts)[12.1. Global timeouts](#global-timeouts)
To configure Global http timeouts:
`connect-timeout` must be specified in milliseconds.
@@ -2093,7 +2219,7 @@ spring:
response-timeout: 5s
```
-### [](#per-route-timeouts)[12.2. Per-route timeouts](#per-route-timeouts) ###
+### [](#per-route-timeouts)[12.2. Per-route timeouts](#per-route-timeouts)
To configure per-route timeouts:
`connect-timeout` must be specified in milliseconds.
@@ -2146,7 +2272,7 @@ A per-route `response-timeout` with a negative value will disable the global `re
response-timeout: -1
```
-### [](#fluent-java-routes-api)[12.3. Fluent Java Routes API](#fluent-java-routes-api) ###
+### [](#fluent-java-routes-api)[12.3. Fluent Java Routes API](#fluent-java-routes-api)
To allow for simple configuration in Java, the `RouteLocatorBuilder` bean includes a fluent API.
The following listing shows how it works:
@@ -2186,13 +2312,13 @@ This style also allows for more custom predicate assertions.
The predicates defined by `RouteDefinitionLocator` beans are combined using logical `and`.
By using the fluent Java API, you can use the `and()`, `or()`, and `negate()` operators on the `Predicate` class.
-### [](#the-discoveryclient-route-definition-locator)[12.4. The `DiscoveryClient` Route Definition Locator](#the-discoveryclient-route-definition-locator) ###
+### [](#the-discoveryclient-route-definition-locator)[12.4. The `DiscoveryClient` Route Definition Locator](#the-discoveryclient-route-definition-locator)
You can configure the gateway to create routes based on services registered with a `DiscoveryClient` compatible service registry.
To enable this, set `spring.cloud.gateway.discovery.locator.enabled=true` and make sure a `DiscoveryClient` implementation (such as Netflix Eureka, Consul, or Zookeeper) is on the classpath and enabled.
-#### [](#configuring-predicates-and-filters-for-discoveryclient-routes)[12.4.1. Configuring Predicates and Filters For `DiscoveryClient` Routes](#configuring-predicates-and-filters-for-discoveryclient-routes) ####
+#### [](#configuring-predicates-and-filters-for-discoveryclient-routes)[12.4.1. Configuring Predicates and Filters For `DiscoveryClient` Routes](#configuring-predicates-and-filters-for-discoveryclient-routes)
By default, the gateway defines a single predicate and filter for routes created with a `DiscoveryClient`.
@@ -2220,8 +2346,7 @@ spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId
spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"
```
-[](#reactor-netty-access-logs)[13. Reactor Netty Access Logs](#reactor-netty-access-logs)
-----------
+## [](#reactor-netty-access-logs)[13. Reactor Netty Access Logs](#reactor-netty-access-logs)
To enable Reactor Netty access logs, set `-Dreactor.netty.http.server.accessLogEnabled=true`.
@@ -2248,8 +2373,7 @@ Example 70. logback.xml
```
-[](#cors-configuration)[14. CORS Configuration](#cors-configuration)
-----------
+## [](#cors-configuration)[14. CORS Configuration](#cors-configuration)
You can configure the gateway to control CORS behavior. The “global” CORS configuration is a map of URL patterns to [Spring Framework `CorsConfiguration`](https://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/cors/CorsConfiguration.html).
The following example configures CORS:
@@ -2273,8 +2397,7 @@ In the preceding example, CORS requests are allowed from requests that originate
To provide the same CORS configuration to requests that are not handled by some gateway route predicate, set the `spring.cloud.gateway.globalcors.add-to-simple-url-handler-mapping` property to `true`.
This is useful when you try to support CORS preflight requests and your route predicate does not evalute to `true` because the HTTP method is `options`.
-[](#actuator-api)[15. Actuator API](#actuator-api)
-----------
+## [](#actuator-api)[15. Actuator API](#actuator-api)
The `/gateway` actuator endpoint lets you monitor and interact with a Spring Cloud Gateway application.
To be remotely accessible, the endpoint has to be [enabled](https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html#production-ready-endpoints-enabling-endpoints) and [exposed over HTTP or JMX](https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html#production-ready-endpoints-exposing-endpoints) in the application properties.
@@ -2287,7 +2410,7 @@ management.endpoint.gateway.enabled=true # default value
management.endpoints.web.exposure.include=gateway
```
-### [](#verbose-actuator-format)[15.1. Verbose Actuator Format](#verbose-actuator-format) ###
+### [](#verbose-actuator-format)[15.1. Verbose Actuator Format](#verbose-actuator-format)
A new, more verbose format has been added to Spring Cloud Gateway.
It adds more detail to each route, letting you view the predicates and filters associated with each route along with any configuration that is available.
@@ -2319,7 +2442,7 @@ spring.cloud.gateway.actuator.verbose.enabled=false
This will default to `true` in a future release.
-### [](#retrieving-route-filters)[15.2. Retrieving Route Filters](#retrieving-route-filters) ###
+### [](#retrieving-route-filters)[15.2. Retrieving Route Filters](#retrieving-route-filters)
This section details how to retrieve route filters, including:
@@ -2327,7 +2450,7 @@ This section details how to retrieve route filters, including:
* [[gateway-route-filters]](#gateway-route-filters)
-#### [](#gateway-global-filters)[15.2.1. Global Filters](#gateway-global-filters) ####
+#### [](#gateway-global-filters)[15.2.1. Global Filters](#gateway-global-filters)
To retrieve the [global filters](#global-filters) applied to all routes, make a `GET` request to `/actuator/gateway/globalfilters`. The resulting response is similar to the following:
@@ -2347,7 +2470,7 @@ To retrieve the [global filters](#global-filters) applied to all routes, make a
The response contains the details of the global filters that are in place.
For each global filter, there is a string representation of the filter object (for example, `org.spring[[email protected]](/cdn-cgi/l/email-protection)77856cc5`) and the corresponding [order](#gateway-combined-global-filter-and-gatewayfilter-ordering) in the filter chain.}
-#### [](#gateway-route-filters)[15.2.2. Route Filters](#gateway-route-filters) ####
+#### [](#gateway-route-filters)[15.2.2. Route Filters](#gateway-route-filters)
To retrieve the [`GatewayFilter` factories](#gatewayfilter-factories) applied to routes, make a `GET` request to `/actuator/gateway/routefilters`.
The resulting response is similar to the following:
@@ -2364,12 +2487,12 @@ The response contains the details of the `GatewayFilter` factories applied to an
For each factory there is a string representation of the corresponding object (for example, `[[[email protected]](/cdn-cgi/l/email-protection) configClass = Object]`).
Note that the `null` value is due to an incomplete implementation of the endpoint controller, because it tries to set the order of the object in the filter chain, which does not apply to a `GatewayFilter` factory object.
-### [](#refreshing-the-route-cache)[15.3. Refreshing the Route Cache](#refreshing-the-route-cache) ###
+### [](#refreshing-the-route-cache)[15.3. Refreshing the Route Cache](#refreshing-the-route-cache)
To clear the routes cache, make a `POST` request to `/actuator/gateway/refresh`.
The request returns a 200 without a response body.
-### [](#retrieving-the-routes-defined-in-the-gateway)[15.4. Retrieving the Routes Defined in the Gateway](#retrieving-the-routes-defined-in-the-gateway) ###
+### [](#retrieving-the-routes-defined-in-the-gateway)[15.4. Retrieving the Routes Defined in the Gateway](#retrieving-the-routes-defined-in-the-gateway)
To retrieve the routes defined in the gateway, make a `GET` request to `/actuator/gateway/routes`.
The resulting response is similar to the following:
@@ -2405,7 +2528,7 @@ The following table describes the structure of each element (each is a route) of
| `route_object.filters` |Array |The [`GatewayFilter` factories](#gatewayfilter-factories) applied to the route.|
| `order` |Number| The route order. |
-### [](#gateway-retrieving-information-about-a-particular-route)[15.5. Retrieving Information about a Particular Route](#gateway-retrieving-information-about-a-particular-route) ###
+### [](#gateway-retrieving-information-about-a-particular-route)[15.5. Retrieving Information about a Particular Route](#gateway-retrieving-information-about-a-particular-route)
To retrieve information about a single route, make a `GET` request to `/actuator/gateway/routes/{id}` (for example, `/actuator/gateway/routes/first_route`).
The resulting response is similar to the following:
@@ -2433,13 +2556,13 @@ The following table describes the structure of the response:
| `uri` |String| The destination URI of the route. |
| `order` |Number| The route order. |
-### [](#creating-and-deleting-a-particular-route)[15.6. Creating and Deleting a Particular Route](#creating-and-deleting-a-particular-route) ###
+### [](#creating-and-deleting-a-particular-route)[15.6. Creating and Deleting a Particular Route](#creating-and-deleting-a-particular-route)
To create a route, make a `POST` request to `/gateway/routes/{id_route_to_create}` with a JSON body that specifies the fields of the route (see [Retrieving Information about a Particular Route](#gateway-retrieving-information-about-a-particular-route)).
To delete a route, make a `DELETE` request to `/gateway/routes/{id_route_to_delete}`.
-### [](#recap-the-list-of-all-endpoints)[15.7. Recap: The List of All endpoints](#recap-the-list-of-all-endpoints) ###
+### [](#recap-the-list-of-all-endpoints)[15.7. Recap: The List of All endpoints](#recap-the-list-of-all-endpoints)
The folloiwng table below summarizes the Spring Cloud Gateway actuator endpoints (note that each endpoint has `/actuator/gateway` as the base-path):
@@ -2453,7 +2576,7 @@ The folloiwng table below summarizes the Spring Cloud Gateway actuator endpoints
| `routes/{id}` | POST | Adds a new route to the gateway. |
| `routes/{id}` | DELETE | Removes an existing route from the gateway. |
-### [](#sharing-routes-between-multiple-gateway-instances)[15.8. Sharing Routes between multiple Gateway instances](#sharing-routes-between-multiple-gateway-instances) ###
+### [](#sharing-routes-between-multiple-gateway-instances)[15.8. Sharing Routes between multiple Gateway instances](#sharing-routes-between-multiple-gateway-instances)
Spring Cloud Gateway offers two `RouteDefinitionRepository` implementations. The first one is the`InMemoryRouteDefinitionRepository` which only lives within the memory of one Gateway instance.
This type of Repository is not suited to populate Routes across multiple Gateway instances.
@@ -2461,12 +2584,11 @@ This type of Repository is not suited to populate Routes across multiple Gateway
In order to share Routes across a cluster of Spring Cloud Gateway instances, `RedisRouteDefinitionRepository` can be used.
To enable this kind of repository, the following property has to set to true: `spring.cloud.gateway.redis-route-definition-repository.enabled`Likewise to the RedisRateLimiter Filter Factory it requires the use of the spring-boot-starter-data-redis-reactive Spring Boot starter.
-[](#troubleshooting)[16. Troubleshooting](#troubleshooting)
-----------
+## [](#troubleshooting)[16. Troubleshooting](#troubleshooting)
This section covers common problems that may arise when you use Spring Cloud Gateway.
-### [](#log-levels)[16.1. Log Levels](#log-levels) ###
+### [](#log-levels)[16.1. Log Levels](#log-levels)
The following loggers may contain valuable troubleshooting information at the `DEBUG` and `TRACE` levels:
@@ -2482,18 +2604,17 @@ The following loggers may contain valuable troubleshooting information at the `D
* `redisratelimiter`
-### [](#wiretap)[16.2. Wiretap](#wiretap) ###
+### [](#wiretap)[16.2. Wiretap](#wiretap)
The Reactor Netty `HttpClient` and `HttpServer` can have wiretap enabled.
When combined with setting the `reactor.netty` log level to `DEBUG` or `TRACE`, it enables the logging of information, such as headers and bodies sent and received across the wire.
To enable wiretap, set `spring.cloud.gateway.httpserver.wiretap=true` or `spring.cloud.gateway.httpclient.wiretap=true` for the `HttpServer` and `HttpClient`, respectively.
-[](#developer-guide)[17. Developer Guide](#developer-guide)
-----------
+## [](#developer-guide)[17. Developer Guide](#developer-guide)
These are basic guides to writing some custom components of the gateway.
-### [](#writing-custom-route-predicate-factories)[17.1. Writing Custom Route Predicate Factories](#writing-custom-route-predicate-factories) ###
+### [](#writing-custom-route-predicate-factories)[17.1. Writing Custom Route Predicate Factories](#writing-custom-route-predicate-factories)
In order to write a Route Predicate you will need to implement `RoutePredicateFactory` as a bean. There is an abstract class called `AbstractRoutePredicateFactory` which you can extend.
@@ -2526,7 +2647,7 @@ public class MyRoutePredicateFactory extends AbstractRoutePredicateFactoryreferenced as `AnotherThing` in configuration files. This is **not** a supported naming
convention and this syntax may be removed in future releases. Please update the filter
name to be compliant.|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#writing-custom-global-filters)[17.3. Writing Custom Global Filters](#writing-custom-global-filters) ###
+### [](#writing-custom-global-filters)[17.3. Writing Custom Global Filters](#writing-custom-global-filters)
To write a custom global filter, you must implement `GlobalFilter` interface as a bean.
This applies the filter to all requests.
@@ -2634,8 +2755,7 @@ public GlobalFilter customGlobalPostFilter() {
}
```
-[](#building-a-simple-gateway-by-using-spring-mvc-or-webflux)[18. Building a Simple Gateway by Using Spring MVC or Webflux](#building-a-simple-gateway-by-using-spring-mvc-or-webflux)
-----------
+## [](#building-a-simple-gateway-by-using-spring-mvc-or-webflux)[18. Building a Simple Gateway by Using Spring MVC or Webflux](#building-a-simple-gateway-by-using-spring-mvc-or-webflux)
| |The following describes an alternative style gateway. None of the prior documentation applies to what follows.|
|---|--------------------------------------------------------------------------------------------------------------|
@@ -2704,8 +2824,7 @@ The mapper is a `Function` that takes the incoming `ResponseEntity` and converts
First-class support is provided for “sensitive” headers (by default, `cookie` and `authorization`), which are not passed downstream, and for “proxy” (`x-forwarded-*`) headers.
-[](#configuration-properties)[19. Configuration properties](#configuration-properties)
-----------
+## [](#configuration-properties)[19. Configuration properties](#configuration-properties)
To see the list of all Spring Cloud Gateway related configuration properties, see [the appendix](appendix.html).
diff --git a/docs/en/spring-cloud/spring-cloud-kubernetes.md b/docs/en/spring-cloud/spring-cloud-kubernetes.md
index 11dd490ce12c6ff00af3166bd0c215fc0ec85ae8..7a4c44ca241d3a50326d11e79e8eedb4df5ae0f9 100644
--- a/docs/en/spring-cloud/spring-cloud-kubernetes.md
+++ b/docs/en/spring-cloud/spring-cloud-kubernetes.md
@@ -1,16 +1,105 @@
-Spring Cloud Kubernetes
-==========
-
+Spring Cloud Kubernetes.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Kubernetes
+
+Table of Contents
+
+* [1. Why do you need Spring Cloud Kubernetes?](#why-do-you-need-spring-cloud-kubernetes)
+* [2. Starters](#starters)
+* [3. DiscoveryClient for Kubernetes](#discoveryclient-for-kubernetes)
+* [4. Kubernetes native service discovery](#kubernetes-native-service-discovery)
+* [5. Kubernetes PropertySource implementations](#kubernetes-propertysource-implementations)
+ * [5.1. Using a `ConfigMap` `PropertySource`](#configmap-propertysource)
+ * [5.2. Secrets PropertySource](#secrets-propertysource)
+ * [5.3. Namespace resolution](#namespace-resolution)
+ * [5.4. `PropertySource` Reload](#propertysource-reload)
+
+* [6. Kubernetes Ecosystem Awareness](#kubernetes-ecosystem-awareness)
+ * [6.1. Kubernetes Profile Autoconfiguration](#kubernetes-profile-autoconfiguration)
+ * [6.2. Istio Awareness](#istio-awareness)
+
+* [7. Pod Health Indicator](#pod-health-indicator)
+* [8. Info Contributor](#info-contributor)
+* [9. Leader Election](#leader-election)
+* [10. LoadBalancer for Kubernetes](#loadbalancer-for-kubernetes)
+* [11. Security Configurations Inside Kubernetes](#security-configurations-inside-kubernetes)
+ * [11.1. Namespace](#namespace)
+ * [11.2. Service Account](#service-account)
+
+* [12. Service Registry Implementation](#service-registry-implementation)
+* [13. Spring Cloud Kubernetes Configuration Watcher](#spring-cloud-kubernetes-configuration-watcher)
+ * [13.1. Deployment YAML](#deployment-yaml)
+ * [13.2. Monitoring ConfigMaps and Secrets](#monitoring-configmaps-and-secrets)
+ * [13.3. HTTP Implementation](#http-implementation)
+ * [13.3.1. Non-Default Management Port and Actuator Path](#non-default-management-port-and-actuator-path)
+
+ * [13.4. Messaging Implementation](#messaging-implementation)
+ * [13.5. Configuring RabbitMQ](#configuring-rabbitmq)
+ * [13.6. Configuring Kafka](#configuring-kafka)
+
+* [14. Spring Cloud Kubernetes Config Server](#spring-cloud-kubernetes-configserver)
+ * [14.1. Configuration](#configuration)
+ * [14.1.1. Enabling The Kubernetes Environment Repository](#enabling-the-kubernetes-environment-repository)
+ * [14.1.2. Config Map and Secret PropertySources](#config-map-and-secret-propertysources)
+ * [14.1.3. Fetching Config Map and Secret Data From Additional Namespaces](#fetching-config-map-and-secret-data-from-additional-namespaces)
+ * [14.1.4. Kubernetes Access Controls](#kubernetes-access-controls)
+
+ * [14.2. Deployment Yaml](#deployment-yaml-2)
+
+* [15. Spring Cloud Kubernetes Discovery Server](#spring-cloud-kubernetes-discoveryserver)
+ * [15.1. Permissions](#permissions)
+ * [15.2. Endpoints](#endpoints)
+ * [15.2.1. `/apps`](#apps)
+ * [15.2.2. `/app/{name}`](#appname)
+ * [15.2.3. `/app/{name}/{instanceid}`](#appnameinstanceid)
+
+ * [15.3. Deployment YAML](#deployment-yaml-3)
+
+* [16. Examples](#examples)
+* [17. Other Resources](#other-resources)
+* [18. Configuration properties](#configuration-properties)
+* [19. Building](#building)
+ * [19.1. Basic Compile and Test](#basic-compile-and-test)
+ * [19.2. Documentation](#documentation)
+ * [19.3. Working with the code](#working-with-the-code)
+ * [19.3.1. Activate the Spring Maven profile](#activate-the-spring-maven-profile)
+ * [19.3.2. Importing into eclipse with m2eclipse](#importing-into-eclipse-with-m2eclipse)
+ * [19.3.3. Importing into eclipse without m2eclipse](#importing-into-eclipse-without-m2eclipse)
+
+* [20. Contributing](#contributing)
+ * [20.1. Sign the Contributor License Agreement](#sign-the-contributor-license-agreement)
+ * [20.2. Code of Conduct](#code-of-conduct)
+ * [20.3. Code Conventions and Housekeeping](#code-conventions-and-housekeeping)
+ * [20.4. Checkstyle](#checkstyle)
+ * [20.4.1. Checkstyle configuration](#checkstyle-configuration)
+
+ * [20.5. IDE setup](#ide-setup)
+ * [20.5.1. Intellij IDEA](#intellij-idea)
+
+ * [20.6. Duplicate Finder](#duplicate-finder)
+ * [20.6.1. Duplicate Finder configuration](#duplicate-finder-configuration)
This reference guide covers how to use Spring Cloud Kubernetes.
-[](#why-do-you-need-spring-cloud-kubernetes)[1. Why do you need Spring Cloud Kubernetes?](#why-do-you-need-spring-cloud-kubernetes)
-----------
+## [](#why-do-you-need-spring-cloud-kubernetes)[1. Why do you need Spring Cloud Kubernetes?](#why-do-you-need-spring-cloud-kubernetes)
Spring Cloud Kubernetes provides implementations of well known Spring Cloud interfaces allowing developers to build and run Spring Cloud applications on Kubernetes. While this project may be useful to you when building a cloud native application, it is also not a requirement in order to deploy a Spring Boot app on Kubernetes. If you are just getting started in your journey to running your Spring Boot app on Kubernetes you can accomplish a lot with nothing more than a basic Spring Boot app and Kubernetes itself. To learn more, you can get started by reading the [Spring Boot reference documentation for deploying to Kubernetes ](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#cloud-deployment-kubernetes) and also working through the workshop material [Spring and Kubernetes](https://hackmd.io/@ryanjbaxter/spring-on-k8s-workshop).
-[](#starters)[2. Starters](#starters)
-----------
+## [](#starters)[2. Starters](#starters)
Starters are convenient dependency descriptors you can include in your
application. Include a starter to get the dependencies and Spring Boot
@@ -23,8 +112,7 @@ Starters that begin with`spring-cloud-starter-kubernetes-client` provide impleme
|Fabric8 Dependency
```
org.springframework.cloud
spring-cloud-starter-kubernetes-fabric8-config
```
Kubernetes Client Dependency
```
org.springframework.cloud
spring-cloud-starter-kubernetes-client-config
```|Load application properties from Kubernetes[ConfigMaps](#configmap-propertysource) and [Secrets](#secrets-propertysource).[Reload](#propertysource-reload) application properties when a ConfigMap or
Secret changes.|
| Fabric8 Dependency
```
org.springframework.cloud
spring-cloud-starter-kubernetes-fabric8-all
```
Kubernetes Client Dependency
```
org.springframework.cloud
spring-cloud-starter-kubernetes-client-all
``` | All Spring Cloud Kubernetes features. |
-[](#discoveryclient-for-kubernetes)[3. DiscoveryClient for Kubernetes](#discoveryclient-for-kubernetes)
-----------
+## [](#discoveryclient-for-kubernetes)[3. DiscoveryClient for Kubernetes](#discoveryclient-for-kubernetes)
This project provides an implementation of [Discovery Client](https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/DiscoveryClient.java)for [Kubernetes](https://kubernetes.io).
This client lets you query Kubernetes endpoints (see [services](https://kubernetes.io/docs/user-guide/services/)) by name.
@@ -129,8 +217,7 @@ this to work, you need to align the Kubernetes service name with the `spring.app
Spring Cloud Kubernetes can also watch the Kubernetes service catalog for changes and update the`DiscoveryClient` implementation accordingly. In order to enable this functionality you need to add`@EnableScheduling` on a configuration class in your application.
-[](#kubernetes-native-service-discovery)[4. Kubernetes native service discovery](#kubernetes-native-service-discovery)
-----------
+## [](#kubernetes-native-service-discovery)[4. Kubernetes native service discovery](#kubernetes-native-service-discovery)
Kubernetes itself is capable of (server side) service discovery (see: [kubernetes.io/docs/concepts/services-networking/service/#discovering-services](https://kubernetes.io/docs/concepts/services-networking/service/#discovering-services)).
Using native kubernetes service discovery ensures compatibility with additional tooling, such as Istio ([istio.io](https://istio.io)), a service mesh that is capable of load balancing, circuit breaker, failover, and much more.
@@ -143,15 +230,14 @@ Additionally, you can use Hystrix for:
* Fallback functionality, by annotating the respective method with `@HystrixCommand(fallbackMethod=`
-[](#kubernetes-propertysource-implementations)[5. Kubernetes PropertySource implementations](#kubernetes-propertysource-implementations)
-----------
+## [](#kubernetes-propertysource-implementations)[5. Kubernetes PropertySource implementations](#kubernetes-propertysource-implementations)
The most common approach to configuring your Spring Boot application is to create an `application.properties` or `application.yaml` or
an `application-profile.properties` or `application-profile.yaml` file that contains key-value pairs that provide customization values to your
application or Spring Boot starters. You can override these properties by specifying system properties or environment
variables.
-### [](#configmap-propertysource)[5.1. Using a `ConfigMap` `PropertySource`](#configmap-propertysource) ###
+### [](#configmap-propertysource)[5.1. Using a `ConfigMap` `PropertySource`](#configmap-propertysource)
Kubernetes provides a resource named [`ConfigMap`](https://kubernetes.io/docs/user-guide/configmap/) to externalize the
parameters to pass to your application in the form of key-value pairs or embedded `application.properties` or `application.yaml` files.
@@ -567,7 +653,7 @@ the maximum number of attempts, backoff options like initial interval, multiplie
| `spring.cloud.kubernetes.config.retry.max-interval` | `Long` | `2000` | Maximum interval for backoff. |
| `spring.cloud.kubernetes.config.retry.multiplier` |`Double` | `1.1` | Multiplier for next interval. |
-### [](#secrets-propertysource)[5.2. Secrets PropertySource](#secrets-propertysource) ###
+### [](#secrets-propertysource)[5.2. Secrets PropertySource](#secrets-propertysource)
Kubernetes has the notion of [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) for storing
sensitive data such as passwords, OAuth tokens, and so on. This project provides integration with `Secrets` to make secrets
@@ -732,7 +818,7 @@ Notes:
You can find an example of an application that uses secrets (though it has not been updated to use the new `spring-cloud-kubernetes` project) at[spring-boot-camel-config](https://github.com/fabric8-quickstarts/spring-boot-camel-config)
-### [](#namespace-resolution)[5.3. Namespace resolution](#namespace-resolution) ###
+### [](#namespace-resolution)[5.3. Namespace resolution](#namespace-resolution)
Finding an application namespace happens on a best-effort basis. There are some steps that we iterate in order
to find it. The easiest and most common one, is to specify it in the proper configuration, for example:
@@ -771,7 +857,7 @@ Remember that the same can be done for config maps. If such a namespace is not s
Failure to find a namespace from the above steps will result in an Exception being raised.
-### [](#propertysource-reload)[5.4. `PropertySource` Reload](#propertysource-reload) ###
+### [](#propertysource-reload)[5.4. `PropertySource` Reload](#propertysource-reload)
| |This functionality has been deprecated in the 2020.0 release. Please see
the [Spring Cloud Kubernetes Configuration Watcher](#spring-cloud-kubernetes-configuration-watcher) controller for an alternative way
to achieve the same functionality.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
@@ -873,8 +959,7 @@ Notes:
\* You should not use properties under `spring.cloud.kubernetes.reload` in config maps or secrets. Changing such properties at runtime may lead to unexpected results.
\* Deleting a property or the whole config map does not restore the original state of the beans when you use the `refresh` level.
-[](#kubernetes-ecosystem-awareness)[6. Kubernetes Ecosystem Awareness](#kubernetes-ecosystem-awareness)
-----------
+## [](#kubernetes-ecosystem-awareness)[6. Kubernetes Ecosystem Awareness](#kubernetes-ecosystem-awareness)
All of the features described earlier in this guide work equally well, regardless of whether your application is running inside
Kubernetes. This is really helpful for development and troubleshooting.
@@ -888,13 +973,13 @@ Because of the way we set up a specific `EnvironmentPostProcessor` in `spring-cl
your application via `-DSPRING_CLOUD_KUBERNETES_ENABLED=false` (any form of relaxed binding will work too).
Also note that these properties: `spring.cloud.kubernetes.config.enabled` and `spring.cloud.kubernetes.secrets.enabled` only take effect when set in `bootstrap.{properties|yml}`
-### [](#kubernetes-profile-autoconfiguration)[6.1. Kubernetes Profile Autoconfiguration](#kubernetes-profile-autoconfiguration) ###
+### [](#kubernetes-profile-autoconfiguration)[6.1. Kubernetes Profile Autoconfiguration](#kubernetes-profile-autoconfiguration)
When the application runs as a pod inside Kubernetes, a Spring profile named `kubernetes` automatically gets activated.
This lets you customize the configuration, to define beans that are applied when the Spring Boot application is deployed
within the Kubernetes platform (for example, different development and production configuration).
-### [](#istio-awareness)[6.2. Istio Awareness](#istio-awareness) ###
+### [](#istio-awareness)[6.2. Istio Awareness](#istio-awareness)
When you include the `spring-cloud-kubernetes-fabric8-istio` module in the application classpath, a new profile is added to the application,
provided the application is running inside a Kubernetes Cluster with [Istio](https://istio.io) installed. You can then use
@@ -903,8 +988,7 @@ spring `@Profile("istio")` annotations in your Beans and `@Configuration` classe
The Istio awareness module uses `me.snowdrop:istio-client` to interact with Istio APIs, letting us discover traffic rules, circuit breakers, and so on,
making it easy for our Spring Boot applications to consume this data to dynamically configure themselves according to the environment.
-[](#pod-health-indicator)[7. Pod Health Indicator](#pod-health-indicator)
-----------
+## [](#pod-health-indicator)[7. Pod Health Indicator](#pod-health-indicator)
Spring Boot uses [`HealthIndicator`](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java) to expose info about the health of an application.
That makes it really useful for exposing health-related information to the user and makes it a good fit for use as [readiness probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/).
@@ -917,16 +1001,14 @@ The Kubernetes health indicator (which is part of the core module) exposes the f
You can disable this `HealthContributor` by setting `management.health.kubernetes.enabled`to `false` in `application.[properties | yaml]`.
-[](#info-contributor)[8. Info Contributor](#info-contributor)
-----------
+## [](#info-contributor)[8. Info Contributor](#info-contributor)
Spring Cloud Kubernetes includes an `InfoContributor` which adds Pod information to
Spring Boot’s `/info` Acturator endpoint.
You can disable this `InfoContributor` by setting `management.info.kubernetes.enabled`to `false` in `application.[properties | yaml]`.
-[](#leader-election)[9. Leader Election](#leader-election)
-----------
+## [](#leader-election)[9. Leader Election](#leader-election)
The Spring Cloud Kubernetes leader election mechanism implements the leader election API of Spring Integration using a Kubernetes ConfigMap.
@@ -954,8 +1036,7 @@ To specify the name of the configmap used for leader election use the following
spring.cloud.kubernetes.leader.config-map-name=leader
```
-[](#loadbalancer-for-kubernetes)[10. LoadBalancer for Kubernetes](#loadbalancer-for-kubernetes)
-----------
+## [](#loadbalancer-for-kubernetes)[10. LoadBalancer for Kubernetes](#loadbalancer-for-kubernetes)
This project includes Spring Cloud Load Balancer for load balancing based on Kubernetes Endpoints and provides implementation of load balancer based on Kubernetes Service.
To include it to your project add the following dependency.
@@ -992,10 +1073,9 @@ spring.cloud.kubernetes.discovery.all-namespaces=true
If a service needs to be accessed over HTTPS you need to add a label or annotation to your service definition with the name `secured` and the value `true` and the load balancer will then use HTTPS to make requests to the service.
-[](#security-configurations-inside-kubernetes)[11. Security Configurations Inside Kubernetes](#security-configurations-inside-kubernetes)
-----------
+## [](#security-configurations-inside-kubernetes)[11. Security Configurations Inside Kubernetes](#security-configurations-inside-kubernetes)
-### [](#namespace)[11.1. Namespace](#namespace) ###
+### [](#namespace)[11.1. Namespace](#namespace)
Most of the components provided in this project need to know the namespace. For Kubernetes (1.3+), the namespace is made available to the pod as part of the service account secret and is automatically detected by the client.
For earlier versions, it needs to be specified as an environment variable to the pod. A quick way to do this is as follows:
@@ -1008,7 +1088,7 @@ For earlier versions, it needs to be specified as an environment variable to the
fieldPath: "metadata.namespace"
```
-### [](#service-account)[11.2. Service Account](#service-account) ###
+### [](#service-account)[11.2. Service Account](#service-account)
For distributions of Kubernetes that support more fine-grained role-based access within the cluster, you need to make sure a pod that runs with `spring-cloud-kubernetes` has access to the Kubernetes API.
For any service accounts you assign to a deployment or pod, you need to make sure they have the correct roles.
@@ -1054,14 +1134,12 @@ roleRef:
apiGroup: ""
```
-[](#service-registry-implementation)[12. Service Registry Implementation](#service-registry-implementation)
-----------
+## [](#service-registry-implementation)[12. Service Registry Implementation](#service-registry-implementation)
In Kubernetes service registration is controlled by the platform, the application itself does not control
registration as it may do in other platforms. For this reason using `spring.cloud.service-registry.auto-registration.enabled`or setting `@EnableDiscoveryClient(autoRegister=false)` will have no effect in Spring Cloud Kubernetes.
-[](#spring-cloud-kubernetes-configuration-watcher)[13. Spring Cloud Kubernetes Configuration Watcher](#spring-cloud-kubernetes-configuration-watcher)
-----------
+## [](#spring-cloud-kubernetes-configuration-watcher)[13. Spring Cloud Kubernetes Configuration Watcher](#spring-cloud-kubernetes-configuration-watcher)
Kubernetes provides the ability to [mount a ConfigMap or Secret as a volume](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#add-configmap-data-to-a-volume)in the container of your application. When the contents of the ConfigMap or Secret changes, the [mounted volume will be updated with those changes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#mounted-configmaps-are-updated-automatically).
@@ -1080,7 +1158,7 @@ Spring Cloud Kubernetes Configuration Watcher can send refresh notifications to
2. Using Spring Cloud Bus, in which case you will need a message broker deployed to your custer for the application to use.
-### [](#deployment-yaml)[13.1. Deployment YAML](#deployment-yaml) ###
+### [](#deployment-yaml)[13.1. Deployment YAML](#deployment-yaml)
Below is a sample deployment YAML you can use to deploy the Kubernetes Configuration Watcher to Kubernetes.
@@ -1164,7 +1242,7 @@ items:
The Service Account and associated Role Binding is important for Spring Cloud Kubernetes Configuration to work properly.
The controller needs access to read data about ConfigMaps, Pods, Services, Endpoints and Secrets in the Kubernetes cluster.
-### [](#monitoring-configmaps-and-secrets)[13.2. Monitoring ConfigMaps and Secrets](#monitoring-configmaps-and-secrets) ###
+### [](#monitoring-configmaps-and-secrets)[13.2. Monitoring ConfigMaps and Secrets](#monitoring-configmaps-and-secrets)
Spring Cloud Kubernetes Configuration Watcher will react to changes in ConfigMaps with a label of `spring.cloud.kubernetes.config` with the value `true`or any Secret with a label of `spring.cloud.kubernetes.secret` with the value `true`. If the ConfigMap or Secret does not have either of those labels
or the values of those labels is not `true` then any changes will be ignored.
@@ -1174,13 +1252,13 @@ The labels Spring Cloud Kubernetes Configuration Watcher looks for on ConfigMaps
If a change is made to a ConfigMap or Secret with valid labels then Spring Cloud Kubernetes Configuration Watcher will take the name of the ConfigMap or Secret
and send a notification to the application with that name.
-### [](#http-implementation)[13.3. HTTP Implementation](#http-implementation) ###
+### [](#http-implementation)[13.3. HTTP Implementation](#http-implementation)
The HTTP implementation is what is used by default. When this implementation is used Spring Cloud Kubernetes Configuration Watcher and a
change to a ConfigMap or Secret occurs then the HTTP implementation will use the Spring Cloud Kubernetes Discovery Client to fetch all
instances of the application which match the name of the ConfigMap or Secret and send an HTTP POST request to the application’s actuator`/refresh` endpoint. By default it will send the post request to `/actuator/refresh` using the port registered in the discovery client.
-#### [](#non-default-management-port-and-actuator-path)[13.3.1. Non-Default Management Port and Actuator Path](#non-default-management-port-and-actuator-path) ####
+#### [](#non-default-management-port-and-actuator-path)[13.3.1. Non-Default Management Port and Actuator Path](#non-default-management-port-and-actuator-path)
If the application is using a non-default actuator path and/or using a different port for the management endpoints, the Kubernetes service for the application
can add an annotation called `boot.spring.io/actuator` and set its value to the path and port used by the application. For example
@@ -1205,12 +1283,12 @@ spec:
Another way you can choose to configure the actuator path and/or management port is by setting`spring.cloud.kubernetes.configuration.watcher.actuatorPath` and `spring.cloud.kubernetes.configuration.watcher.actuatorPort`.
-### [](#messaging-implementation)[13.4. Messaging Implementation](#messaging-implementation) ###
+### [](#messaging-implementation)[13.4. Messaging Implementation](#messaging-implementation)
The messaging implementation can be enabled by setting profile to either `bus-amqp` (RabbitMQ) or `bus-kafka` (Kafka) when the Spring Cloud Kubernetes Configuration Watcher
application is deployed to Kubernetes.
-### [](#configuring-rabbitmq)[13.5. Configuring RabbitMQ](#configuring-rabbitmq) ###
+### [](#configuring-rabbitmq)[13.5. Configuring RabbitMQ](#configuring-rabbitmq)
When the `bus-amqp` profile is enabled you will need to configure Spring RabbitMQ to point it to the location of the RabbitMQ
instance you would like to use as well as any credentials necessary to authenticate. This can be done
@@ -1224,7 +1302,7 @@ spring:
host: rabbitmq
```
-### [](#configuring-kafka)[13.6. Configuring Kafka](#configuring-kafka) ###
+### [](#configuring-kafka)[13.6. Configuring Kafka](#configuring-kafka)
When the `bus-kafka` profile is enabled you will need to configure Spring Kafka to point it to the location of the Kafka Broker
instance you would like to use. This can be done by setting the standard Spring Kafka properties, for example
@@ -1236,8 +1314,7 @@ spring:
bootstrap-servers: localhost:9092
```
-[](#spring-cloud-kubernetes-configserver)[14. Spring Cloud Kubernetes Config Server](#spring-cloud-kubernetes-configserver)
-----------
+## [](#spring-cloud-kubernetes-configserver)[14. Spring Cloud Kubernetes Config Server](#spring-cloud-kubernetes-configserver)
The Spring Cloud Kubernetes Config Server, is based on [Spring Cloud Config Server](https://spring.io/projects/spring-cloud-config) and adds an [environment repository](https://docs.spring.io/spring-cloud-config/docs/current/reference/html/#_environment_repository) for Kubernetes[Config Maps](https://kubernetes.io/docs/concepts/configuration/configmap/) and [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/).
@@ -1248,19 +1325,19 @@ A default image is located on [Docker Hub](https://hub.docker.com/r/springcloud/
the code and image yourself. However, if you need to customize the config server behavior you can easily build your own
image from the source code on GitHub and use that.
-### [](#configuration)[14.1. Configuration](#configuration) ###
+### [](#configuration)[14.1. Configuration](#configuration)
-#### [](#enabling-the-kubernetes-environment-repository)[14.1.1. Enabling The Kubernetes Environment Repository](#enabling-the-kubernetes-environment-repository) ####
+#### [](#enabling-the-kubernetes-environment-repository)[14.1.1. Enabling The Kubernetes Environment Repository](#enabling-the-kubernetes-environment-repository)
To enable the Kubernetes environment repository the `kubernetes` profile must be included in the list of active profiles.
You may activate other profiles as well to use other environment repository implementations.
-#### [](#config-map-and-secret-propertysources)[14.1.2. Config Map and Secret PropertySources](#config-map-and-secret-propertysources) ####
+#### [](#config-map-and-secret-propertysources)[14.1.2. Config Map and Secret PropertySources](#config-map-and-secret-propertysources)
By default, only Config Map data will be fetched. To enable Secrets as well you will need to set `spring.cloud.kubernetes.secrets.enableApi=true`.
You can disable the Config Map `PropertySource` by setting `spring.cloud.kubernetes.config.enableApi=false`.
-#### [](#fetching-config-map-and-secret-data-from-additional-namespaces)[14.1.3. Fetching Config Map and Secret Data From Additional Namespaces](#fetching-config-map-and-secret-data-from-additional-namespaces) ####
+#### [](#fetching-config-map-and-secret-data-from-additional-namespaces)[14.1.3. Fetching Config Map and Secret Data From Additional Namespaces](#fetching-config-map-and-secret-data-from-additional-namespaces)
By default, the Kubernetes environment repository will only fetch Config Map and Secrets from the namespace in which it is deployed.
If you want to include data from other namespaces you can set `spring.cloud.kubernetes.configserver.config-map-namespaces` and/or `spring.cloud.kubernetes.configserver.secrets-namespaces` to a comma separated
@@ -1269,12 +1346,12 @@ list of namespace values.
| |If you set `spring.cloud.kubernetes.configserver.config-map-namespaces` and/or `spring.cloud.kubernetes.configserver.secrets-namespaces`you will need to include the namespace in which the Config Server is deployed in order to continue to fetch Config Map and Secret data from that namespace.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [](#kubernetes-access-controls)[14.1.4. Kubernetes Access Controls](#kubernetes-access-controls) ####
+#### [](#kubernetes-access-controls)[14.1.4. Kubernetes Access Controls](#kubernetes-access-controls)
The Kubernetes Config Server uses the Kubernetes API server to fetch Config Map and Secret data. In order for it to do that
it needs ability to `get` and `list` Config Map and Secrets (depending on what you enable/disable).
-### [](#deployment-yaml-2)[14.2. Deployment Yaml](#deployment-yaml-2) ###
+### [](#deployment-yaml-2)[14.2. Deployment Yaml](#deployment-yaml-2)
Below is a sample deployment, service and permissions configuration you can use to deploy a basic Config Server to Kubernetes.
@@ -1358,26 +1435,25 @@ items:
- containerPort: 8888
```
-[](#spring-cloud-kubernetes-discoveryserver)[15. Spring Cloud Kubernetes Discovery Server](#spring-cloud-kubernetes-discoveryserver)
-----------
+## [](#spring-cloud-kubernetes-discoveryserver)[15. Spring Cloud Kubernetes Discovery Server](#spring-cloud-kubernetes-discoveryserver)
The Spring Cloud Kubernetes Discovery Server provides HTTP endpoints apps can use to gather information
about services available within a Kubernetes cluster. The Spring Cloud Kubernetes Discovery Server
can be used by apps using the `spring-cloud-starter-kubernetes-discoveryclient` to provide data to
the `DiscoveryClient` implementation provided by that starter.
-### [](#permissions)[15.1. Permissions](#permissions) ###
+### [](#permissions)[15.1. Permissions](#permissions)
The Spring Cloud Discovery server uses
the Kubernetes API server to get data about Service and Endpoint resrouces so it needs list, watch, and
get permissions to use those endpoints. See the below sample Kubernetes deployment YAML for an
examlpe of how to configure the Service Account on Kubernetes.
-### [](#endpoints)[15.2. Endpoints](#endpoints) ###
+### [](#endpoints)[15.2. Endpoints](#endpoints)
There are three endpoints exposed by the server.
-#### [](#apps)[15.2.1. `/apps`](#apps) ####
+#### [](#apps)[15.2.1. `/apps`](#apps)
A `GET` request sent to `/apps` will return a JSON array of available services. Each item contains
the name of the Kubernetes service and service instance information. Below is a sample response.
@@ -1427,7 +1503,7 @@ the name of the Kubernetes service and service instance information. Below is a
]
```
-#### [](#appname)[15.2.2. `/app/{name}`](#appname) ####
+#### [](#appname)[15.2.2. `/app/{name}`](#appname)
A `GET` request to `/app/{name}` can be used to get instance data for all instances of a given
service. Below is a sample response when a `GET` request is made to `/app/kubernetes`.
@@ -1452,7 +1528,7 @@ service. Below is a sample response when a `GET` request is made to `/app/kubern
]
```
-#### [](#appnameinstanceid)[15.2.3. `/app/{name}/{instanceid}`](#appnameinstanceid) ####
+#### [](#appnameinstanceid)[15.2.3. `/app/{name}/{instanceid}`](#appnameinstanceid)
A `GET` request made to `/app/{name}/{instanceid}` will return the instance data for a specific
instance of a given service. Below is a sample response when a `GET` request is made to `/app/kubernetes/1234`.
@@ -1475,7 +1551,7 @@ instance of a given service. Below is a sample response when a `GET` request is
}
```
-### [](#deployment-yaml-3)[15.3. Deployment YAML](#deployment-yaml-3) ###
+### [](#deployment-yaml-3)[15.3. Deployment YAML](#deployment-yaml-3)
An image of the Spring Cloud Discovery Server is hosted on [Docker Hub](https://hub.docker.com/r/springcloud/spring-cloud-kubernetes-discoveryserver).
@@ -1558,8 +1634,7 @@ items:
- containerPort: 8761
```
-[](#examples)[16. Examples](#examples)
-----------
+## [](#examples)[16. Examples](#examples)
Spring Cloud Kubernetes tries to make it transparent for your applications to consume Kubernetes Native Services by
following the Spring Cloud interfaces.
@@ -1583,8 +1658,7 @@ The following projects highlight the usage of these dependencies and demonstrate
* [Spring Boot Admin with Spring Cloud Kubernetes Discovery and Config](https://github.com/salaboy/showcase-admin-tool)
-[](#other-resources)[17. Other Resources](#other-resources)
-----------
+## [](#other-resources)[17. Other Resources](#other-resources)
This section lists other resources, such as presentations (slides) and videos about Spring Cloud Kubernetes.
@@ -1594,15 +1668,13 @@ This section lists other resources, such as presentations (slides) and videos ab
Please feel free to submit other resources through pull requests to [this repository](https://github.com/spring-cloud/spring-cloud-kubernetes).
-[](#configuration-properties)[18. Configuration properties](#configuration-properties)
-----------
+## [](#configuration-properties)[18. Configuration properties](#configuration-properties)
To see the list of all Kubernetes related configuration properties please check [the Appendix page](appendix.html).
-[](#building)[19. Building](#building)
-----------
+## [](#building)[19. Building](#building)
-### [](#basic-compile-and-test)[19.1. Basic Compile and Test](#basic-compile-and-test) ###
+### [](#basic-compile-and-test)[19.1. Basic Compile and Test](#basic-compile-and-test)
To build the source you will need to install JDK 17.
@@ -1623,7 +1695,7 @@ $ ./mvnw install
The projects that require middleware (i.e. Redis) for testing generally
require that a local instance of [Docker]([www.docker.com/get-started](https://www.docker.com/get-started)) is installed and running.
-### [](#documentation)[19.2. Documentation](#documentation) ###
+### [](#documentation)[19.2. Documentation](#documentation)
The spring-cloud-build module has a "docs" profile, and if you switch
that on it will try to build asciidoc sources from`src/main/asciidoc`. As part of that process it will look for a`README.adoc` and process it by loading all the includes, but not
@@ -1631,18 +1703,18 @@ parsing or rendering it, just copying it to `${main.basedir}`(defaults to `$/tmp
any changes in the README it will then show up after a Maven build as
a modified file in the correct place. Just commit it and push the change.
-### [](#working-with-the-code)[19.3. Working with the code](#working-with-the-code) ###
+### [](#working-with-the-code)[19.3. Working with the code](#working-with-the-code)
If you don’t have an IDE preference we would recommend that you use[Spring Tools Suite](https://www.springsource.com/developer/sts) or[Eclipse](https://eclipse.org) when working with the code. We use the[m2eclipse](https://eclipse.org/m2e/) eclipse plugin for maven support. Other IDEs and tools
should also work without issue as long as they use Maven 3.3.3 or better.
-#### [](#activate-the-spring-maven-profile)[19.3.1. Activate the Spring Maven profile](#activate-the-spring-maven-profile) ####
+#### [](#activate-the-spring-maven-profile)[19.3.1. Activate the Spring Maven profile](#activate-the-spring-maven-profile)
Spring Cloud projects require the 'spring' Maven profile to be activated to resolve
the spring milestone and snapshot repositories. Use your preferred IDE to set this
profile to be active, or you may experience build errors.
-#### [](#importing-into-eclipse-with-m2eclipse)[19.3.2. Importing into eclipse with m2eclipse](#importing-into-eclipse-with-m2eclipse) ####
+#### [](#importing-into-eclipse-with-m2eclipse)[19.3.2. Importing into eclipse with m2eclipse](#importing-into-eclipse-with-m2eclipse)
We recommend the [m2eclipse](https://eclipse.org/m2e/) eclipse plugin when working with
eclipse. If you don’t already have m2eclipse installed it is available from the "eclipse
@@ -1651,7 +1723,7 @@ marketplace".
| |Older versions of m2e do not support Maven 3.3, so once the
projects are imported into Eclipse you will also need to tell
m2eclipse to use the right profile for the projects. If you
see many different errors related to the POMs in the projects, check
that you have an up to date installation. If you can’t upgrade m2e,
add the "spring" profile to your `settings.xml`. Alternatively you can
copy the repository settings from the "spring" profile of the parent
pom into your `settings.xml`.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [](#importing-into-eclipse-without-m2eclipse)[19.3.3. Importing into eclipse without m2eclipse](#importing-into-eclipse-without-m2eclipse) ####
+#### [](#importing-into-eclipse-without-m2eclipse)[19.3.3. Importing into eclipse without m2eclipse](#importing-into-eclipse-without-m2eclipse)
If you prefer not to use m2eclipse you can generate eclipse project metadata using the
following command:
@@ -1662,8 +1734,7 @@ $ ./mvnw eclipse:eclipse
The generated eclipse projects can be imported by selecting `import existing projects`from the `file` menu.
-[](#contributing)[20. Contributing](#contributing)
-----------
+## [](#contributing)[20. Contributing](#contributing)
Spring Cloud is released under the non-restrictive Apache 2.0 license,
and follows a very standard Github development process, using Github
@@ -1671,7 +1742,7 @@ tracker for issues and merging pull requests into master. If you want
to contribute even something trivial please do not hesitate, but
follow the guidelines below.
-### [](#sign-the-contributor-license-agreement)[20.1. Sign the Contributor License Agreement](#sign-the-contributor-license-agreement) ###
+### [](#sign-the-contributor-license-agreement)[20.1. Sign the Contributor License Agreement](#sign-the-contributor-license-agreement)
Before we accept a non-trivial patch or pull request we will need you to sign the[Contributor License Agreement](https://cla.pivotal.io/sign/spring).
Signing the contributor’s agreement does not grant anyone commit rights to the main
@@ -1679,13 +1750,13 @@ repository, but it does mean that we can accept your contributions, and you will
author credit if we do. Active contributors might be asked to join the core team, and
given the ability to merge pull requests.
-### [](#code-of-conduct)[20.2. Code of Conduct](#code-of-conduct) ###
+### [](#code-of-conduct)[20.2. Code of Conduct](#code-of-conduct)
This project adheres to the Contributor Covenant [code of
conduct](https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report
-unacceptable behavior to [[email protected]](/cdn-cgi/l/email-protection#473437352e29206a242823226a28216a2428292332243307372e312833262b692e28).
+unacceptable behavior to [[email protected]](/cdn-cgi/l/email-protection#d4a7a4a6bdbab3f9b7bbb0b1f9bbb2f9b7bbbab0a1b7a094a4bda2bba0b5b8fabdbb).
-### [](#code-conventions-and-housekeeping)[20.3. Code Conventions and Housekeeping](#code-conventions-and-housekeeping) ###
+### [](#code-conventions-and-housekeeping)[20.3. Code Conventions and Housekeeping](#code-conventions-and-housekeeping)
None of these is essential for a pull request, but they will all help. They can also be
added after the original pull request but before a merge.
@@ -1715,7 +1786,7 @@ added after the original pull request but before a merge.
if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit
message (where XXXX is the issue number).
-### [](#checkstyle)[20.4. Checkstyle](#checkstyle) ###
+### [](#checkstyle)[20.4. Checkstyle](#checkstyle)
Spring Cloud Build comes with a set of checkstyle rules. You can find them in the `spring-cloud-build-tools` module. The most notable files under the module are:
@@ -1736,7 +1807,7 @@ spring-cloud-build-tools/
|**2**| File header setup |
|**3**|Default suppression rules|
-#### [](#checkstyle-configuration)[20.4.1. Checkstyle configuration](#checkstyle-configuration) ####
+#### [](#checkstyle-configuration)[20.4.1. Checkstyle configuration](#checkstyle-configuration)
Checkstyle rules are **disabled by default**. To add checkstyle to your project just define the following properties and plugins.
@@ -1803,9 +1874,9 @@ $ curl https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/
$ touch .springformat
```
-### [](#ide-setup)[20.5. IDE setup](#ide-setup) ###
+### [](#ide-setup)[20.5. IDE setup](#ide-setup)
-#### [](#intellij-idea)[20.5.1. Intellij IDEA](#intellij-idea) ####
+#### [](#intellij-idea)[20.5.1. Intellij IDEA](#intellij-idea)
In order to setup Intellij you should import our coding conventions, inspection profiles and set up the checkstyle plugin.
The following files can be found in the [Spring Cloud Build](https://github.com/spring-cloud/spring-cloud-build/tree/master/spring-cloud-build-tools) project.
@@ -1861,11 +1932,11 @@ Go to `File` → `Settings` → `Other settings` → `Checkstyle`. There click o
| |Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources.|
|---|------------------------------------------------------------------------------------------------------------------|
-### [](#duplicate-finder)[20.6. Duplicate Finder](#duplicate-finder) ###
+### [](#duplicate-finder)[20.6. Duplicate Finder](#duplicate-finder)
Spring Cloud Build brings along the `basepom:duplicate-finder-maven-plugin`, that enables flagging duplicate and conflicting classes and resources on the java classpath.
-#### [](#duplicate-finder-configuration)[20.6.1. Duplicate Finder configuration](#duplicate-finder-configuration) ####
+#### [](#duplicate-finder-configuration)[20.6.1. Duplicate Finder configuration](#duplicate-finder-configuration)
Duplicate finder is **enabled by default** and will run in the `verify` phase of your Maven build, but it will only take effect in your project if you add the `duplicate-finder-maven-plugin` to the `build` section of the projecst’s `pom.xml`.
@@ -1907,3 +1978,5 @@ If you need to add `ignoredClassPatterns` or `ignoredResourcePatterns` to your s
```
+
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-netflix.md b/docs/en/spring-cloud/spring-cloud-netflix.md
index 145b9679453d337f402c59a4d029f5bbce8fa2ce..01d0558765d19f1e0fbbc9f37e7cccc1272f8366 100644
--- a/docs/en/spring-cloud/spring-cloud-netflix.md
+++ b/docs/en/spring-cloud/spring-cloud-netflix.md
@@ -1,5 +1,57 @@
-Spring Cloud Netflix
-==========
+Spring Cloud Netflix.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Netflix
+
+Table of Contents
+
+* [1. Service Discovery: Eureka Clients](#service-discovery-eureka-clients)
+ * [1.1. How to Include Eureka Client](#netflix-eureka-client-starter)
+ * [1.2. Registering with Eureka](#registering-with-eureka)
+ * [1.3. Authenticating with the Eureka Server](#authenticating-with-the-eureka-server)
+ * [1.4. Status Page and Health Indicator](#status-page-and-health-indicator)
+ * [1.5. Registering a Secure Application](#registering-a-secure-application)
+ * [1.6. Eureka’s Health Checks](#eurekas-health-checks)
+ * [1.7. Eureka Metadata for Instances and Clients](#eureka-metadata-for-instances-and-clients)
+ * [1.7.1. Using Eureka on Cloud Foundry](#using-eureka-on-cloud-foundry)
+ * [1.7.2. Using Eureka on AWS](#using-eureka-on-aws)
+ * [1.7.3. Changing the Eureka Instance ID](#changing-the-eureka-instance-id)
+
+ * [1.8. Using the EurekaClient](#using-the-eurekaclient)
+ * [1.8.1. EurekaClient with Jersey](#eurekaclient-with-jersey)
+
+ * [1.9. Alternatives to the Native Netflix EurekaClient](#alternatives-to-the-native-netflix-eurekaclient)
+ * [1.10. Why Is It so Slow to Register a Service?](#why-is-it-so-slow-to-register-a-service)
+ * [1.11. Zones](#zones)
+ * [1.12. Refreshing Eureka Clients](#refreshing-eureka-clients)
+ * [1.13. Using Eureka with Spring Cloud LoadBalancer](#using-eureka-with-spring-cloud-loadbalancer)
+
+* [2. Service Discovery: Eureka Server](#spring-cloud-eureka-server)
+ * [2.1. How to Include Eureka Server](#netflix-eureka-server-starter)
+ * [2.2. How to Run a Eureka Server](#spring-cloud-running-eureka-server)
+ * [2.3. High Availability, Zones and Regions](#spring-cloud-eureka-server-zones-and-regions)
+ * [2.4. Standalone Mode](#spring-cloud-eureka-server-standalone-mode)
+ * [2.5. Peer Awareness](#spring-cloud-eureka-server-peer-awareness)
+ * [2.6. When to Prefer IP Address](#spring-cloud-eureka-server-prefer-ip-address)
+ * [2.7. Securing The Eureka Server](#securing-the-eureka-server)
+ * [2.8. JDK 11 Support](#jdk-11-support)
+
+* [3. Configuration properties](#configuration-properties)
+
+**3.1.1**
This project provides Netflix OSS integrations for Spring Boot apps through autoconfiguration
and binding to the Spring Environment and other Spring programming model idioms. With a few
@@ -7,20 +59,19 @@ simple annotations you can quickly enable and configure the common patterns insi
application and build large distributed systems with battle-tested Netflix components. The
patterns provided include Service Discovery (Eureka).
-[](#service-discovery-eureka-clients)[1. Service Discovery: Eureka Clients](#service-discovery-eureka-clients)
-----------
+## [](#service-discovery-eureka-clients)[1. Service Discovery: Eureka Clients](#service-discovery-eureka-clients)
Service Discovery is one of the key tenets of a microservice-based architecture.
Trying to hand-configure each client or some form of convention can be difficult to do and can be brittle.
Eureka is the Netflix Service Discovery Server and Client.
The server can be configured and deployed to be highly available, with each server replicating state about the registered services to the others.
-### [](#netflix-eureka-client-starter)[1.1. How to Include Eureka Client](#netflix-eureka-client-starter) ###
+### [](#netflix-eureka-client-starter)[1.1. How to Include Eureka Client](#netflix-eureka-client-starter)
To include the Eureka Client in your project, use the starter with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-starter-netflix-eureka-client`.
See the [Spring Cloud Project page](https://projects.spring.io/spring-cloud/) for details on setting up your build system with the current Spring Cloud Release Train.
-### [](#registering-with-eureka)[1.2. Registering with Eureka](#registering-with-eureka) ###
+### [](#registering-with-eureka)[1.2. Registering with Eureka](#registering-with-eureka)
When a client registers with Eureka, it provides meta-data about itself — such as host, port, health indicator URL, home page, and other details.
Eureka receives heartbeat messages from each instance belonging to a service.
@@ -71,7 +122,7 @@ See [EurekaInstanceConfigBean](https://github.com/spring-cloud/spring-cloud-netf
To disable the Eureka Discovery Client, you can set `eureka.client.enabled` to `false`. Eureka Discovery Client will also be disabled when `spring.cloud.discovery.enabled` is set to `false`.
-### [](#authenticating-with-the-eureka-server)[1.3. Authenticating with the Eureka Server](#authenticating-with-the-eureka-server) ###
+### [](#authenticating-with-the-eureka-server)[1.3. Authenticating with the Eureka Server](#authenticating-with-the-eureka-server)
HTTP basic authentication is automatically added to your eureka client if one of the `eureka.client.serviceUrl.defaultZone` URLs has credentials embedded in it (curl style, as follows: `[user:[email protected]:8761/eureka](https://user:password@localhost:8761/eureka)`).
For more complex needs, you can create a `@Bean` of type `DiscoveryClientOptionalArgs` and inject `ClientFilter` instances into it, all of which is applied to the calls from the client to the server.
@@ -101,7 +152,7 @@ The `eureka.client.tls.enabled` needs to be true to enable Eureka client side TL
If you want to customize the RestTemplate used by the Eureka HTTP Client you may want to create a bean of `EurekaClientHttpRequestFactorySupplier` and provide your own logic for generating a `ClientHttpRequestFactory` instance.
-### [](#status-page-and-health-indicator)[1.4. Status Page and Health Indicator](#status-page-and-health-indicator) ###
+### [](#status-page-and-health-indicator)[1.4. Status Page and Health Indicator](#status-page-and-health-indicator)
The status page and health indicators for a Eureka instance default to `/info` and `/health` respectively, which are the default locations of useful endpoints in a Spring Boot Actuator application.
You need to change these, even for an Actuator application if you use a non-default context path or servlet path (such as `server.servletPath=/custom`). The following example shows the default values for the two settings:
@@ -120,7 +171,7 @@ These links show up in the metadata that is consumed by clients and are used in
| |In Dalston it was also required to set the status and health check URLs when changing
that management context path. This requirement was removed beginning in Edgware.|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#registering-a-secure-application)[1.5. Registering a Secure Application](#registering-a-secure-application) ###
+### [](#registering-a-secure-application)[1.5. Registering a Secure Application](#registering-a-secure-application)
If your app wants to be contacted over HTTPS, you can set two flags in the `EurekaInstanceConfigBean`:
@@ -152,7 +203,7 @@ Spring placeholders as well — for example, by using `${eureka.instance.hos
| |If your application runs behind a proxy, and the SSL termination is in the proxy (for example, if you run in Cloud Foundry or other platforms as a service), then you need to ensure that the proxy “forwarded” headers are intercepted and handled by the application.
If the Tomcat container embedded in a Spring Boot application has explicit configuration for the 'X-Forwarded-\\\*` headers, this happens automatically.
The links rendered by your app to itself being wrong (the wrong host, port, or protocol) is a sign that you got this configuration wrong.|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#eurekas-health-checks)[1.6. Eureka’s Health Checks](#eurekas-health-checks) ###
+### [](#eurekas-health-checks)[1.6. Eureka’s Health Checks](#eurekas-health-checks)
By default, Eureka uses the client heartbeat to determine if a client is up.
Unless specified otherwise, the Discovery Client does not propagate the current health check status of the application, per the Spring Boot Actuator.
@@ -174,7 +225,7 @@ eureka:
If you require more control over the health checks, consider implementing your own `com.netflix.appinfo.HealthCheckHandler`.
-### [](#eureka-metadata-for-instances-and-clients)[1.7. Eureka Metadata for Instances and Clients](#eureka-metadata-for-instances-and-clients) ###
+### [](#eureka-metadata-for-instances-and-clients)[1.7. Eureka Metadata for Instances and Clients](#eureka-metadata-for-instances-and-clients)
It is worth spending a bit of time understanding how the Eureka metadata works, so you can use it in a way that makes sense in your platform.
There is standard metadata for information such as hostname, IP address, port numbers, the status page, and health check.
@@ -183,7 +234,7 @@ Additional metadata can be added to the instance registration in the `eureka.ins
In general, additional metadata does not change the behavior of the client, unless the client is made aware of the meaning of the metadata.
There are a couple of special cases, described later in this document, where Spring Cloud already assigns meaning to the metadata map.
-#### [](#using-eureka-on-cloud-foundry)[1.7.1. Using Eureka on Cloud Foundry](#using-eureka-on-cloud-foundry) ####
+#### [](#using-eureka-on-cloud-foundry)[1.7.1. Using Eureka on Cloud Foundry](#using-eureka-on-cloud-foundry)
Cloud Foundry has a global router so that all instances of the same app have the same hostname (other PaaS solutions with a similar architecture have the same arrangement).
This is not necessarily a barrier to using Eureka.
@@ -203,7 +254,7 @@ eureka:
Depending on the way the security rules are set up in your Cloud Foundry instance, you might be able to register and use the IP address of the host VM for direct service-to-service calls.
This feature is not yet available on Pivotal Web Services ([PWS](https://run.pivotal.io)).
-#### [](#using-eureka-on-aws)[1.7.2. Using Eureka on AWS](#using-eureka-on-aws) ####
+#### [](#using-eureka-on-aws)[1.7.2. Using Eureka on AWS](#using-eureka-on-aws)
If the application is planned to be deployed to an AWS cloud, the Eureka instance must be configured to be AWS-aware. You can do so by customizing the [EurekaInstanceConfigBean](https://github.com/spring-cloud/spring-cloud-netflix/tree/main/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaInstanceConfigBean.java) as follows:
@@ -218,7 +269,7 @@ public EurekaInstanceConfigBean eurekaInstanceConfig(InetUtils inetUtils) {
}
```
-#### [](#changing-the-eureka-instance-id)[1.7.3. Changing the Eureka Instance ID](#changing-the-eureka-instance-id) ####
+#### [](#changing-the-eureka-instance-id)[1.7.3. Changing the Eureka Instance ID](#changing-the-eureka-instance-id)
A vanilla Netflix Eureka instance is registered with an ID that is equal to its host name (that is, there is only one service per host).
Spring Cloud Eureka provides a sensible default, which is defined as follows:
@@ -240,7 +291,7 @@ eureka:
With the metadata shown in the preceding example and multiple service instances deployed on localhost, the random value is inserted there to make the instance unique.
In Cloud Foundry, the `vcap.application.instance_id` is populated automatically in a Spring Boot application, so the random value is not needed.
-### [](#using-the-eurekaclient)[1.8. Using the EurekaClient](#using-the-eurekaclient) ###
+### [](#using-the-eurekaclient)[1.8. Using the EurekaClient](#using-the-eurekaclient)
Once you have an application that is a discovery client, you can use it to discover service instances from the [Eureka Server](#spring-cloud-eureka-server).
One way to do so is to use the native `com.netflix.discovery.EurekaClient` (as opposed to the Spring Cloud `DiscoveryClient`), as shown in the following example:
@@ -258,7 +309,7 @@ public String serviceUrl() {
| |Do not use the `EurekaClient` in a `@PostConstruct` method or in a `@Scheduled` method (or anywhere where the `ApplicationContext` might not be started yet).
It is initialized in a `SmartLifecycle` (with `phase=0`), so the earliest you can rely on it being available is in another `SmartLifecycle` with a higher phase.|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [](#eurekaclient-with-jersey)[1.8.1. EurekaClient with Jersey](#eurekaclient-with-jersey) ####
+#### [](#eurekaclient-with-jersey)[1.8.1. EurekaClient with Jersey](#eurekaclient-with-jersey)
By default, EurekaClient uses Spring’s `RestTemplate` for HTTP communication.
If you wish to use Jersey instead, you need to add the Jersey dependencies to your classpath.
@@ -279,7 +330,7 @@ The following example shows the dependencies you need to add:
```
-### [](#alternatives-to-the-native-netflix-eurekaclient)[1.9. Alternatives to the Native Netflix EurekaClient](#alternatives-to-the-native-netflix-eurekaclient) ###
+### [](#alternatives-to-the-native-netflix-eurekaclient)[1.9. Alternatives to the Native Netflix EurekaClient](#alternatives-to-the-native-netflix-eurekaclient)
You need not use the raw Netflix `EurekaClient`.
Also, it is usually more convenient to use it behind a wrapper of some sort.
@@ -300,7 +351,7 @@ public String serviceUrl() {
}
```
-### [](#why-is-it-so-slow-to-register-a-service)[1.10. Why Is It so Slow to Register a Service?](#why-is-it-so-slow-to-register-a-service) ###
+### [](#why-is-it-so-slow-to-register-a-service)[1.10. Why Is It so Slow to Register a Service?](#why-is-it-so-slow-to-register-a-service)
Being an instance also involves a periodic heartbeat to the registry
(through the client’s `serviceUrl`) with a default duration of 30 seconds.
@@ -310,7 +361,7 @@ You can change the period by setting `eureka.instance.leaseRenewalIntervalInSeco
Setting it to a value of less than 30 speeds up the process of getting clients connected to other services.
In production, it is probably better to stick with the default, because of internal computations in the server that make assumptions about the lease renewal period.
-### [](#zones)[1.11. Zones](#zones) ###
+### [](#zones)[1.11. Zones](#zones)
If you have deployed Eureka clients to multiple zones, you may prefer that those clients use services within the same zone before trying services in another zone.
To set that up, you need to configure your Eureka clients correctly.
@@ -337,14 +388,14 @@ eureka.instance.metadataMap.zone = zone2
eureka.client.preferSameZoneEureka = true
```
-### [](#refreshing-eureka-clients)[1.12. Refreshing Eureka Clients](#refreshing-eureka-clients) ###
+### [](#refreshing-eureka-clients)[1.12. Refreshing Eureka Clients](#refreshing-eureka-clients)
By default, the `EurekaClient` bean is refreshable, meaning the Eureka client properties can be changed and refreshed.
When a refresh occurs clients will be unregistered from the Eureka server and there might be a brief moment of time
where all instance of a given service are not available. One way to eliminate this from happening is to disable
the ability to refresh Eureka clients. To do this set `eureka.client.refresh.enable=false`.
-### [](#using-eureka-with-spring-cloud-loadbalancer)[1.13. Using Eureka with Spring Cloud LoadBalancer](#using-eureka-with-spring-cloud-loadbalancer) ###
+### [](#using-eureka-with-spring-cloud-loadbalancer)[1.13. Using Eureka with Spring Cloud LoadBalancer](#using-eureka-with-spring-cloud-loadbalancer)
We offer support for the Spring Cloud LoadBalancer `ZonePreferenceServiceInstanceListSupplier`.
The `zone` value from the Eureka instance metadata (`eureka.instance.metadataMap.zone`) is used for setting the
@@ -356,12 +407,11 @@ it can use the domain name from the server hostname as a proxy for the zone.
If there is no other source of zone data, then a guess is made, based on the client configuration (as opposed to the instance configuration).
We take `eureka.client.availabilityZones`, which is a map from region name to a list of zones, and pull out the first zone for the instance’s own region (that is, the `eureka.client.region`, which defaults to "us-east-1", for compatibility with native Netflix).
-[](#spring-cloud-eureka-server)[2. Service Discovery: Eureka Server](#spring-cloud-eureka-server)
-----------
+## [](#spring-cloud-eureka-server)[2. Service Discovery: Eureka Server](#spring-cloud-eureka-server)
This section describes how to set up a Eureka server.
-### [](#netflix-eureka-server-starter)[2.1. How to Include Eureka Server](#netflix-eureka-server-starter) ###
+### [](#netflix-eureka-server-starter)[2.1. How to Include Eureka Server](#netflix-eureka-server-starter)
To include Eureka Server in your project, use the starter with a group ID of `org.springframework.cloud` and an artifact ID of `spring-cloud-starter-netflix-eureka-server`.
See the [Spring Cloud Project page](https://projects.spring.io/spring-cloud/) for details on setting up your build system with the current Spring Cloud Release Train.
@@ -378,7 +428,7 @@ spring:
prefer-file-system-access: false
```
-### [](#spring-cloud-running-eureka-server)[2.2. How to Run a Eureka Server](#spring-cloud-running-eureka-server) ###
+### [](#spring-cloud-running-eureka-server)[2.2. How to Run a Eureka Server](#spring-cloud-running-eureka-server)
The following example shows a minimal Eureka server:
@@ -401,7 +451,7 @@ The following links have some Eureka background reading: [flux capacitor](https:
| |Due to Gradle’s dependency resolution rules and the lack of a parent bom feature, depending on `spring-cloud-starter-netflix-eureka-server` can cause failures on application startup.
To remedy this issue, add the Spring Boot Gradle plugin and import the Spring cloud starter parent bom as follows:
build.gradle
```
buildscript {
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-docs-version}")
}
}
apply plugin: "spring-boot"
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:{spring-cloud-version}"
}
}
```|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#spring-cloud-eureka-server-zones-and-regions)[2.3. High Availability, Zones and Regions](#spring-cloud-eureka-server-zones-and-regions) ###
+### [](#spring-cloud-eureka-server-zones-and-regions)[2.3. High Availability, Zones and Regions](#spring-cloud-eureka-server-zones-and-regions)
The Eureka server does not have a back end store, but the service instances in the registry all have to send heartbeats to keep their registrations up to date (so this can be done in memory).
Clients also have an in-memory cache of Eureka registrations (so they do not have to go to the registry for every request to a service).
@@ -409,7 +459,7 @@ Clients also have an in-memory cache of Eureka registrations (so they do not hav
By default, every Eureka server is also a Eureka client and requires (at least one) service URL to locate a peer.
If you do not provide it, the service runs and works, but it fills your logs with a lot of noise about not being able to register with the peer.
-### [](#spring-cloud-eureka-server-standalone-mode)[2.4. Standalone Mode](#spring-cloud-eureka-server-standalone-mode) ###
+### [](#spring-cloud-eureka-server-standalone-mode)[2.4. Standalone Mode](#spring-cloud-eureka-server-standalone-mode)
The combination of the two caches (client and server) and the heartbeats make a standalone Eureka server fairly resilient to failure, as long as there is some sort of monitor or elastic runtime (such as Cloud Foundry) keeping it alive.
In standalone mode, you might prefer to switch off the client side behavior so that it does not keep trying and failing to reach its peers.
@@ -433,7 +483,7 @@ eureka:
Notice that the `serviceUrl` is pointing to the same host as the local instance.
-### [](#spring-cloud-eureka-server-peer-awareness)[2.5. Peer Awareness](#spring-cloud-eureka-server-peer-awareness) ###
+### [](#spring-cloud-eureka-server-peer-awareness)[2.5. Peer Awareness](#spring-cloud-eureka-server-peer-awareness)
Eureka can be made even more resilient and available by running multiple instances and asking them to register with each other.
In fact, this is the default behavior, so all you need to do to make it work is add a valid `serviceUrl` to a peer, as shown in the following example:
@@ -503,7 +553,7 @@ eureka:
hostname: peer3
```
-### [](#spring-cloud-eureka-server-prefer-ip-address)[2.6. When to Prefer IP Address](#spring-cloud-eureka-server-prefer-ip-address) ###
+### [](#spring-cloud-eureka-server-prefer-ip-address)[2.6. When to Prefer IP Address](#spring-cloud-eureka-server-prefer-ip-address)
In some cases, it is preferable for Eureka to advertise the IP addresses of services rather than the hostname.
Set `eureka.instance.preferIpAddress` to `true` and, when the application registers with eureka, it uses its IP address rather than its hostname.
@@ -511,7 +561,7 @@ Set `eureka.instance.preferIpAddress` to `true` and, when the application regist
| |If the hostname cannot be determined by Java, then the IP address is sent to Eureka.
Only explict way of setting the hostname is by setting `eureka.instance.hostname` property.
You can set your hostname at the run-time by using an environment variable — for example, `eureka.instance.hostname=${HOST_NAME}`.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#securing-the-eureka-server)[2.7. Securing The Eureka Server](#securing-the-eureka-server) ###
+### [](#securing-the-eureka-server)[2.7. Securing The Eureka Server](#securing-the-eureka-server)
You can secure your Eureka server simply by adding Spring Security to your
server’s classpath via `spring-boot-starter-security`. By default when Spring Security is on the classpath it will require that
@@ -535,7 +585,7 @@ For more information on CSRF see the [Spring Security documentation](https://doc
A demo Eureka Server can be found in the Spring Cloud Samples [repo](https://github.com/spring-cloud-samples/eureka/tree/Eureka-With-Security).
-### [](#jdk-11-support)[2.8. JDK 11 Support](#jdk-11-support) ###
+### [](#jdk-11-support)[2.8. JDK 11 Support](#jdk-11-support)
The JAXB modules which the Eureka server depends upon were removed in JDK 11. If you intend to use JDK 11
when running a Eureka server you must include these dependencies in your POM or Gradle file.
@@ -547,7 +597,8 @@ when running a Eureka server you must include these dependencies in your POM or
```
-[](#configuration-properties)[3. Configuration properties](#configuration-properties)
-----------
+## [](#configuration-properties)[3. Configuration properties](#configuration-properties)
To see the list of all Spring Cloud Netflix related configuration properties please check [the Appendix page](appendix.html).
+
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-openfeign.md b/docs/en/spring-cloud/spring-cloud-openfeign.md
index e7877e3db3501d731dd90a463468c08c614d6c0a..2c40ce25dbeee983fd38c61239c429dd37c80386 100644
--- a/docs/en/spring-cloud/spring-cloud-openfeign.md
+++ b/docs/en/spring-cloud/spring-cloud-openfeign.md
@@ -1,11 +1,58 @@
-Spring Cloud OpenFeign
-==========
+Spring Cloud OpenFeign.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud OpenFeign
+
+Table of Contents
+
+* [1. Declarative REST Client: Feign](#spring-cloud-feign)
+ * [1.1. How to Include Feign](#netflix-feign-starter)
+ * [1.2. Overriding Feign Defaults](#spring-cloud-feign-overriding-defaults)
+ * [1.2.1. `SpringEncoder` configuration](#springencoder-configuration)
+
+ * [1.3. Timeout Handling](#timeout-handling)
+ * [1.4. Creating Feign Clients Manually](#creating-feign-clients-manually)
+ * [1.5. Feign Spring Cloud CircuitBreaker Support](#spring-cloud-feign-circuitbreaker)
+ * [1.6. Feign Spring Cloud CircuitBreaker Fallbacks](#spring-cloud-feign-circuitbreaker-fallback)
+ * [1.7. Feign and `@Primary`](#feign-and-primary)
+ * [1.8. Feign Inheritance Support](#spring-cloud-feign-inheritance)
+ * [1.9. Feign request/response compression](#feign-requestresponse-compression)
+ * [1.10. Feign logging](#feign-logging)
+ * [1.11. Feign Capability support](#feign-capability-support)
+ * [1.12. Feign metrics](#feign-metrics)
+ * [1.13. Feign Caching](#feign-caching)
+ * [1.14. Feign @QueryMap support](#feign-querymap-support)
+ * [1.15. HATEOAS support](#hateoas-support)
+ * [1.16. Spring @MatrixVariable Support](#spring-matrixvariable-support)
+ * [1.17. Feign `CollectionFormat` support](#feign-collectionformat-support)
+ * [1.18. Reactive Support](#reactive-support)
+ * [1.18.1. Early Initialization Errors](#early-initialization-errors)
+
+ * [1.19. Spring Data Support](#spring-data-support)
+ * [1.20. Spring `@RefreshScope` Support](#spring-refreshscope-support)
+ * [1.21. OAuth2 Support](#oauth2-support)
+
+* [2. Configuration properties](#configuration-properties)
+
+**3.1.1**
This project provides OpenFeign integrations for Spring Boot apps through autoconfiguration
and binding to the Spring Environment and other Spring programming model idioms.
-[](#spring-cloud-feign)[1. Declarative REST Client: Feign](#spring-cloud-feign)
-----------
+## [](#spring-cloud-feign)[1. Declarative REST Client: Feign](#spring-cloud-feign)
[Feign](https://github.com/OpenFeign/feign) is a declarative web service client.
It makes writing web service clients easier.
@@ -15,7 +62,7 @@ Feign also supports pluggable encoders and decoders.
Spring Cloud adds support for Spring MVC annotations and for using the same `HttpMessageConverters` used by default in Spring Web.
Spring Cloud integrates Eureka, Spring Cloud CircuitBreaker, as well as Spring Cloud LoadBalancer to provide a load-balanced http client when using Feign.
-### [](#netflix-feign-starter)[1.1. How to Include Feign](#netflix-feign-starter) ###
+### [](#netflix-feign-starter)[1.1. How to Include Feign](#netflix-feign-starter)
To include Feign in your project use the starter with group `org.springframework.cloud`and artifact id `spring-cloud-starter-openfeign`. See the [Spring Cloud Project page](https://projects.spring.io/spring-cloud/)for details on setting up your build system with the current Spring Cloud Release Train.
@@ -70,7 +117,7 @@ Spring Cloud OpenFeign supports all the features available for the blocking mode
| |To use `@EnableFeignClients` annotation on `@Configuration`-annotated-classes, make sure to specify where the clients are located, for example:`@EnableFeignClients(basePackages = "com.example.clients")`or list them explicitly:`@EnableFeignClients(clients = InventoryServiceFeignClient.class)`|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#spring-cloud-feign-overriding-defaults)[1.2. Overriding Feign Defaults](#spring-cloud-feign-overriding-defaults) ###
+### [](#spring-cloud-feign-overriding-defaults)[1.2. Overriding Feign Defaults](#spring-cloud-feign-overriding-defaults)
A central concept in Spring Cloud’s Feign support is that of the named client. Each feign client is part of an ensemble of components that work together to contact a remote server on demand, and the ensemble has a name that you give it as an application developer using the `@FeignClient` annotation. Spring Cloud creates a new ensemble as an`ApplicationContext` on demand for each named client using `FeignClientsConfiguration`. This contains (amongst other things) an `feign.Decoder`, a `feign.Encoder`, and a `feign.Contract`.
It is possible to override the name of that ensemble by using the `contextId`attribute of the `@FeignClient` annotation.
@@ -267,13 +314,13 @@ public FeignClientConfigurer feignClientConfigurer() {
| |By default, Feign clients do not encode slash `/` characters. You can change this behaviour, by setting the value of `feign.client.decodeSlash` to `false`.|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [](#springencoder-configuration)[1.2.1. `SpringEncoder` configuration](#springencoder-configuration) ####
+#### [](#springencoder-configuration)[1.2.1. `SpringEncoder` configuration](#springencoder-configuration)
In the `SpringEncoder` that we provide, we set `null` charset for binary content types and `UTF-8` for all the other ones.
You can modify this behaviour to derive the charset from the `Content-Type` header charset instead by setting the value of `feign.encoder.charset-from-content-type` to `true`.
-### [](#timeout-handling)[1.3. Timeout Handling](#timeout-handling) ###
+### [](#timeout-handling)[1.3. Timeout Handling](#timeout-handling)
We can configure timeouts on both the default and the named client. OpenFeign works with two timeout parameters:
@@ -284,7 +331,7 @@ We can configure timeouts on both the default and the named client. OpenFeign wo
| |In case the server is not running or available a packet results in *connection refused*. The communication ends either with an error message or in a fallback. This can happen *before* the `connectTimeout` if it is set very low. The time taken to perform a lookup and to receive such a packet causes a significant part of this delay. It is subject to change based on the remote host that involves a DNS lookup.|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#creating-feign-clients-manually)[1.4. Creating Feign Clients Manually](#creating-feign-clients-manually) ###
+### [](#creating-feign-clients-manually)[1.4. Creating Feign Clients Manually](#creating-feign-clients-manually)
In some cases it might be necessary to customize your Feign Clients in a way that is not
possible using the methods above. In this case you can create Clients using the[Feign Builder API](https://github.com/OpenFeign/feign/#basics). Below is an example
@@ -332,7 +379,7 @@ class FooController {
You can also use the `Builder`to configure FeignClient not to inherit beans from the parent context.
You can do this by overriding calling `inheritParentContext(false)` on the `Builder`.
-### [](#spring-cloud-feign-circuitbreaker)[1.5. Feign Spring Cloud CircuitBreaker Support](#spring-cloud-feign-circuitbreaker) ###
+### [](#spring-cloud-feign-circuitbreaker)[1.5. Feign Spring Cloud CircuitBreaker Support](#spring-cloud-feign-circuitbreaker)
If Spring Cloud CircuitBreaker is on the classpath and `feign.circuitbreaker.enabled=true`, Feign will wrap all methods with a circuit breaker.
@@ -368,7 +415,7 @@ public class FooConfiguration {
To enable Spring Cloud CircuitBreaker group set the `feign.circuitbreaker.group.enabled` property to `true` (by default `false`).
-### [](#spring-cloud-feign-circuitbreaker-fallback)[1.6. Feign Spring Cloud CircuitBreaker Fallbacks](#spring-cloud-feign-circuitbreaker-fallback) ###
+### [](#spring-cloud-feign-circuitbreaker-fallback)[1.6. Feign Spring Cloud CircuitBreaker Fallbacks](#spring-cloud-feign-circuitbreaker-fallback)
Spring Cloud CircuitBreaker supports the notion of a fallback: a default code path that is executed when the circuit is open or there is an error. To enable fallbacks for a given `@FeignClient` set the `fallback` attribute to the class name that implements the fallback. You also need to declare your implementation as a Spring bean.
@@ -440,7 +487,7 @@ If one needs access to the cause that made the fallback trigger, one can use the
}
```
-### [](#feign-and-primary)[1.7. Feign and `@Primary`](#feign-and-primary) ###
+### [](#feign-and-primary)[1.7. Feign and `@Primary`](#feign-and-primary)
When using Feign with Spring Cloud CircuitBreaker fallbacks, there are multiple beans in the `ApplicationContext` of the same type. This will cause `@Autowired` to not work because there isn’t exactly one bean, or one marked as primary. To work around this, Spring Cloud OpenFeign marks all Feign instances as `@Primary`, so Spring Framework will know which bean to inject. In some cases, this may not be desirable. To turn off this behavior set the `primary` attribute of `@FeignClient` to false.
@@ -451,7 +498,7 @@ public interface HelloClient {
}
```
-### [](#spring-cloud-feign-inheritance)[1.8. Feign Inheritance Support](#spring-cloud-feign-inheritance) ###
+### [](#spring-cloud-feign-inheritance)[1.8. Feign Inheritance Support](#spring-cloud-feign-inheritance)
Feign supports boilerplate apis via single-inheritance interfaces.
This allows grouping common operations into convenient base interfaces.
@@ -489,7 +536,7 @@ public interface UserClient extends UserService {
| |`@FeignClient` interfaces should not be shared between server and client and annotating `@FeignClient` interfaces with `@RequestMapping` on class level is no longer supported.|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#feign-requestresponse-compression)[1.9. Feign request/response compression](#feign-requestresponse-compression) ###
+### [](#feign-requestresponse-compression)[1.9. Feign request/response compression](#feign-requestresponse-compression)
You may consider enabling the request or response GZIP compression for your
Feign requests. You can do this by enabling one of the properties:
@@ -509,7 +556,7 @@ feign.compression.request.min-request-size=2048
These properties allow you to be selective about the compressed media types and minimum request threshold length.
-### [](#feign-logging)[1.10. Feign logging](#feign-logging) ###
+### [](#feign-logging)[1.10. Feign logging](#feign-logging)
A logger is created for each Feign client created. By default the name of the logger is the full class name of the interface used to create the Feign client. Feign logging only responds to the `DEBUG` level.
@@ -541,7 +588,7 @@ public class FooConfiguration {
}
```
-### [](#feign-capability-support)[1.11. Feign Capability support](#feign-capability-support) ###
+### [](#feign-capability-support)[1.11. Feign Capability support](#feign-capability-support)
The Feign capabilities expose core Feign components so that these components can be modified. For example, the capabilities can take the `Client`, *decorate* it, and give the decorated instance back to Feign.
The support for metrics libraries is a good real-life example for this. See [Feign metrics](#feign-metrics).
@@ -558,7 +605,7 @@ public class FooConfiguration {
}
```
-### [](#feign-metrics)[1.12. Feign metrics](#feign-metrics) ###
+### [](#feign-metrics)[1.12. Feign metrics](#feign-metrics)
If all of the following conditions are true, a `MicrometerCapability` bean is created and registered so that your Feign client publishes metrics to Micrometer:
@@ -600,7 +647,7 @@ public class FooConfiguration {
}
```
-### [](#feign-caching)[1.13. Feign Caching](#feign-caching) ###
+### [](#feign-caching)[1.13. Feign Caching](#feign-caching)
If `@EnableCaching` annotation is used, a `CachingCapability` bean is created and registered so that your Feign client recognizes `@Cache*` annotations on its interface:
@@ -615,7 +662,7 @@ public interface DemoClient {
You can also disable the feature via property `feign.cache.enabled=false`.
-### [](#feign-querymap-support)[1.14. Feign @QueryMap support](#feign-querymap-support) ###
+### [](#feign-querymap-support)[1.14. Feign @QueryMap support](#feign-querymap-support)
The OpenFeign `@QueryMap` annotation provides support for POJOs to be used as
GET parameter maps. Unfortunately, the default OpenFeign QueryMap annotation is
@@ -649,7 +696,7 @@ public interface DemoTemplate {
If you need more control over the generated query parameter map, you can implement a custom `QueryMapEncoder` bean.
-### [](#hateoas-support)[1.15. HATEOAS support](#hateoas-support) ###
+### [](#hateoas-support)[1.15. HATEOAS support](#hateoas-support)
Spring provides some APIs to create REST representations that follow the [HATEOAS](https://en.wikipedia.org/wiki/HATEOAS) principle, [Spring Hateoas](https://spring.io/projects/spring-hateoas) and [Spring Data REST](https://spring.io/projects/spring-data-rest).
@@ -668,7 +715,7 @@ public interface DemoTemplate {
}
```
-### [](#spring-matrixvariable-support)[1.16. Spring @MatrixVariable Support](#spring-matrixvariable-support) ###
+### [](#spring-matrixvariable-support)[1.16. Spring @MatrixVariable Support](#spring-matrixvariable-support)
Spring Cloud OpenFeign provides support for the Spring `@MatrixVariable` annotation.
@@ -699,7 +746,7 @@ public interface DemoTemplate {
}
```
-### [](#feign-collectionformat-support)[1.17. Feign `CollectionFormat` support](#feign-collectionformat-support) ###
+### [](#feign-collectionformat-support)[1.17. Feign `CollectionFormat` support](#feign-collectionformat-support)
We support `feign.CollectionFormat` by providing the `@CollectionFormat` annotation.
You can annotate a Feign client method (or the whole class to affect all methods) with it by passing the desired `feign.CollectionFormat` as annotation value.
@@ -720,13 +767,13 @@ protected interface PageableFeignClient {
| |Set the `CSV` format while sending `Pageable` as a query parameter in order for it to be encoded correctly.|
|---|-----------------------------------------------------------------------------------------------------------|
-### [](#reactive-support)[1.18. Reactive Support](#reactive-support) ###
+### [](#reactive-support)[1.18. Reactive Support](#reactive-support)
As the [OpenFeign project](https://github.com/OpenFeign/feign) does not currently support reactive clients, such as [Spring WebClient](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/function/client/WebClient.html), neither does Spring Cloud OpenFeign.We will add support for it here as soon as it becomes available in the core project.
Until that is done, we recommend using [feign-reactive](https://github.com/Playtika/feign-reactive) for Spring WebClient support.
-#### [](#early-initialization-errors)[1.18.1. Early Initialization Errors](#early-initialization-errors) ####
+#### [](#early-initialization-errors)[1.18.1. Early Initialization Errors](#early-initialization-errors)
Depending on how you are using your Feign clients you may see initialization errors when starting your application.
To work around this problem you can use an `ObjectProvider` when autowiring your client.
@@ -736,7 +783,7 @@ To work around this problem you can use an `ObjectProvider` when autowiring your
ObjectProvider testFeignClient;
```
-### [](#spring-data-support)[1.19. Spring Data Support](#spring-data-support) ###
+### [](#spring-data-support)[1.19. Spring Data Support](#spring-data-support)
You may consider enabling Jackson Modules for the support `org.springframework.data.domain.Page` and `org.springframework.data.domain.Sort` decoding.
@@ -744,7 +791,7 @@ You may consider enabling Jackson Modules for the support `org.springframework.d
feign.autoconfiguration.jackson.enabled=true
```
-### [](#spring-refreshscope-support)[1.20. Spring `@RefreshScope` Support](#spring-refreshscope-support) ###
+### [](#spring-refreshscope-support)[1.20. Spring `@RefreshScope` Support](#spring-refreshscope-support)
If Feign client refresh is enabled, each feign client is created with `feign.Request.Options` as a refresh-scoped bean. This means properties such as `connectTimeout` and `readTimeout` can be refreshed against any Feign client instance through `POST /actuator/refresh`.
@@ -757,7 +804,7 @@ feign.client.refresh-enabled=true
| |DO NOT annotate the `@FeignClient` interface with the `@RefreshScope` annotation.|
|---|---------------------------------------------------------------------------------|
-### [](#oauth2-support)[1.21. OAuth2 Support](#oauth2-support) ###
+### [](#oauth2-support)[1.21. OAuth2 Support](#oauth2-support)
OAuth2 support can be enabled by setting following flag:
@@ -772,7 +819,8 @@ Sometimes, when load balancing is enabled for Feign clients, you may want to use
feign.oauth2.load-balanced=true
```
-[](#configuration-properties)[2. Configuration properties](#configuration-properties)
-----------
+## [](#configuration-properties)[2. Configuration properties](#configuration-properties)
To see the list of all Spring Cloud OpenFeign related configuration properties please check [the Appendix page](appendix.html).
+
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-sleuth.md b/docs/en/spring-cloud/spring-cloud-sleuth.md
index 295ecac149ae4c341348d2156c5a94b8626c5c6f..6b7d93e1b4c5a554e1034c030c6c8efc5d3780fb 100644
--- a/docs/en/spring-cloud/spring-cloud-sleuth.md
+++ b/docs/en/spring-cloud/spring-cloud-sleuth.md
@@ -1,5 +1,20 @@
-Spring Cloud Sleuth Reference Documentation
-==========
+Spring Cloud Sleuth Reference Documentation.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Sleuth Reference Documentation
Adrian Cole, Spencer Gibb, Marcin Grzejszczak, Dave Syer, Jay Bryant
@@ -14,3 +29,5 @@ The reference documentation consists of the following sections:
| [“How-to” Guides](howto.html#howto) | Add sampling, propagate remote tags, and more. |
| [Spring Cloud Sleuth Integrations](integrations.html#sleuth-integration) | Instrumentation configuration, context propagation, and more. |
| [Appendices](appendix.html#appendix) | Span definitions and configuration properties. |
+
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-stream.md b/docs/en/spring-cloud/spring-cloud-stream.md
index b692e6079ca528d9283bb3ea77a8d4cd9e29937f..51bb355b053d3a954125cefa2d0206d47883612a 100644
--- a/docs/en/spring-cloud/spring-cloud-stream.md
+++ b/docs/en/spring-cloud/spring-cloud-stream.md
@@ -1,5 +1,42 @@
-Spring Cloud Stream Reference Documentation
-==========
+Spring Cloud Stream Reference Documentation.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Stream Reference Documentation
+
+Sabby Anandan
+Marius Bogoevici
+Eric Bottard
+Mark Fisher
+Ilayaperumal Gopinathan
+Mark Heckler
+Gunnar Hillert
+Mark Pollack
+Patrick Peralta
+Glenn Renfro
+Thomas Risberg
+Dave Syer
+David Turanski
+Janne Valkealahti
+Benjamin Klein
+Vinicius Carvalho
+Gary Russell
+Oleg Zhurakousky
+Jay Bryant
+Soby Chacko
+Domenico Sibilio
**3.2.2**
@@ -19,3 +56,5 @@ Relevant Links:
|--------------------------------------------------------------------------------|------------------------------------------------------|
|[Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/)|Patterns and Best Practices for Enterprise Integration|
| [Spring Integration](https://spring.io/projects/spring-integration) | Spring Integration framework |
+
+if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1\*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}
\ No newline at end of file
diff --git a/docs/en/spring-cloud/spring-cloud-task.md b/docs/en/spring-cloud/spring-cloud-task.md
index 5c0bdc36227bccf1ce89b6c24e78c03d43f1c552..6a4b51bc8bd990ef27042260c2e2b5336ef4d9e4 100644
--- a/docs/en/spring-cloud/spring-cloud-task.md
+++ b/docs/en/spring-cloud/spring-cloud-task.md
@@ -1,16 +1,123 @@
-Spring Cloud Task Reference Guide
-==========
-
-
-[](#preface)[Preface](#preface)
-==========
+Spring Cloud Task Reference Guide.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:not(:first-child) { border-width: 0 0 0 1px; border-style: solid; border-color: #7a2518;
+} .switch--item.selected { background-color: #7a2519; color: #ffffff;
+} function addBlockSwitches() { for (var primary of document.querySelectorAll('.primary')) { var switchItem = createSwitchItem(primary, createBlockSwitch(primary)); switchItem.item.classList.add("selected"); var title = primary.querySelector('.title') title.remove(); } for (var secondary of document.querySelectorAll('.secondary')) { var primary = findPrimary(secondary); if (primary === null) { console.error("Found secondary block with no primary sibling"); } else { var switchItem = createSwitchItem(secondary, primary.querySelector('.switch')); switchItem.content.classList.add("hidden"); primary.append(switchItem.content); secondary.remove(); } }
+} function createElementFromHtml(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content.firstChild;
+} function createBlockSwitch(primary) { var blockSwitch = createElementFromHtml('\\
'); primary.prepend(blockSwitch) return blockSwitch;
+} function findPrimary(secondary) { var candidate = secondary.previousElementSibling; while (candidate != null && !candidate.classList.contains('primary')) { candidate = candidate.previousElementSibling; } return candidate;
+} function createSwitchItem(block, blockSwitch) { var blockName = block.querySelector('.title').textContent; var content = block.querySelectorAll('.content').item(0); var colist = nextSibling(block, '.colist'); if (colist != null) { content.append(colist); } var item = createElementFromHtml('\' + blockName + '\
'); item.dataset.blockName = blockName; content.dataset.blockName = blockName; blockSwitch.append(item); return {'item': item, 'content': content};
+} function nextSibling(element, selector) { var sibling = element.nextElementSibling; while (sibling) { if (sibling.matches(selector)) { return sibling; } sibling = sibling.nextElementSibling; }
+} function globalSwitch() { document.querySelectorAll(".switch--item").forEach(function(item) { var blockId = blockIdForSwitchItem(item); var handler = function(event) { selectedText = event.target.textContent; window.localStorage.setItem(blockId, selectedText); for (var switchItem of document.querySelectorAll(".switch--item")) { if (blockIdForSwitchItem(switchItem) === blockId && switchItem.textContent === selectedText) { select(switchItem); } } } item.addEventListener("click", handler); if (item.textContent === window.localStorage.getItem(blockId)) { select(item); } });
+} function select(selected) { for (var child of selected.parentNode.children) { child.classList.remove("selected"); } selected.classList.add("selected"); for (var child of selected.parentNode.parentNode.children) { if (child.classList.contains("content")) { if (selected.dataset.blockName === child.dataset.blockName) { child.classList.remove("hidden"); } else { child.classList.add("hidden"); } } } } function blockIdForSwitchItem(item) { idComponents = [] for (var switchItem of item.parentNode.querySelectorAll(".switch--item")) { idComponents.push(switchItem.textContent.toLowerCase()); } return idComponents.sort().join("-")
+} window.onload = function() { addBlockSwitches(); globalSwitch();
+};
+
+# Spring Cloud Task Reference Guide
+
+Michael Minella, Glenn Renfro, Jay Bryant
+
+Table of Contents
+
+* [Preface](#preface)
+ * [1. About the documentation](#about-the-documentation)
+ * [2. Getting help](#task-documentation-getting-help)
+ * [3. First Steps](#task-documentation-first-steps)
+
+* [Getting started](#getting-started)
+ * [4. Introducing Spring Cloud Task](#getting-started-introducing-spring-cloud-task)
+ * [5. System Requirements](#getting-started-system-requirements)
+ * [5.1. Database Requirements](#database-requirements)
+
+ * [6. Developing Your First Spring Cloud Task Application](#getting-started-developing-first-task)
+ * [6.1. Creating the Spring Task Project using Spring Initializr](#getting-started-creating-project)
+ * [6.2. Writing the Code](#getting-started-writing-the-code)
+ * [6.3. Running the Example](#getting-started-running-the-example)
+
+* [Features](#features)
+ * [7. The lifecycle of a Spring Cloud Task](#features-lifecycle)
+ * [7.1. The TaskExecution](#features-task-execution-details)
+ * [7.2. Mapping Exit Codes](#features-lifecycle-exit-codes)
+
+ * [8. Configuration](#features-configuration)
+ * [8.1. DataSource](#features-data-source)
+ * [8.2. Table Prefix](#features-table-prefix)
+ * [8.3. Enable/Disable table initialization](#features-table-initialization)
+ * [8.4. Externally Generated Task ID](#features-generated_task_id)
+ * [8.5. External Task Id](#features-external_task_id)
+ * [8.6. Parent Task Id](#features-parent_task_id)
+ * [8.7. TaskConfigurer](#features-task-configurer)
+ * [8.8. Task Name](#features-task-name)
+ * [8.9. Task Execution Listener](#features-task-execution-listener)
+ * [8.10. Restricting Spring Cloud Task Instances](#features-single-instance-enabled)
+ * [8.11. Disabling Spring Cloud Task Auto Configuration](#disabling-spring-cloud-task-auto-configuration)
+ * [8.12. Closing the Context](#closing-the-context)
+
+* [Batch](#batch)
+ * [9. Associating a Job Execution to the Task in which It Was Executed](#batch-association)
+ * [9.1. Overriding the TaskBatchExecutionListener](#batch-association-override)
+
+ * [10. Remote Partitioning](#batch-partitioning)
+ * [10.1. Notes on Developing a Batch-partitioned application for the Kubernetes Platform](#notes-on-developing-a-batch-partitioned-application-for-the-kubernetes-platform)
+ * [10.2. Notes on Developing a Batch-partitioned Application for the Cloud Foundry Platform](#notes-on-developing-a-batch-partitioned-application-for-the-cloud-foundry-platform)
+
+ * [11. Batch Informational Messages](#batch-informational-messages)
+ * [12. Batch Job Exit Codes](#batch-failures-and-tasks)
+
+* [Single Step Batch Job Starter](#batch-job-starter)
+ * [13. Defining a Job](#job-definition)
+ * [13.1. Properties](#job-definition-properties)
+
+ * [14. Autoconfiguration for ItemReader Implementations](#item-readers)
+ * [14.1. AmqpItemReader](#amqpitemreader)
+ * [14.2. FlatFileItemReader](#flatfileitemreader)
+ * [14.3. JdbcCursorItemReader](#jdbcCursorItemReader)
+ * [14.4. KafkaItemReader](#kafkaItemReader)
+
+ * [15. ItemProcessor Configuration](#item-processors)
+ * [16. Autoconfiguration for ItemWriter implementations](#item-writers)
+ * [16.1. AmqpItemWriter](#amqpitemwriter)
+ * [16.2. FlatFileItemWriter](#flatfileitemwriter)
+ * [16.3. JdbcBatchItemWriter](#jdbcitemwriter)
+ * [16.4. KafkaItemWriter](#kafkaitemwriter)
+
+* [Spring Cloud Stream Integration](#stream-integration)
+ * [17. Launching a Task from a Spring Cloud Stream](#stream-integration-launching-sink)
+ * [17.1. Spring Cloud Data Flow](#stream-integration-launching-sink-dataflow)
+
+ * [18. Spring Cloud Task Events](#stream-integration-events)
+ * [18.1. Disabling Specific Task Events](#stream-integration-disable-task-events)
+
+ * [19. Spring Batch Events](#stream-integration-batch-events)
+ * [19.1. Sending Batch Events to Different Channels](#sending-batch-events-to-different-channels)
+ * [19.2. Disabling Batch Events](#disabling-batch-events)
+ * [19.3. Emit Order for Batch Events](#emit-order-for-batch-events)
+
+* [Appendices](#appendix)
+ * [20. Task Repository Schema](#appendix-task-repository-schema)
+ * [20.1. Table Information](#table-information)
+ * [20.2. SQL Server](#sql-server)
+
+ * [21. Building This Documentation](#appendix-building-the-documentation)
+ * [22. Running a Task App on Cloud Foundry](#appendix-cloud-foundry)
+
+Version 2.4.1
+
+© 2009-2021 VMware, Inc. All rights reserved.
+
+Copies of this document may be made for your own use and for distribution to
+others, provided that you do not charge any fee for such copies and further
+provided that each copy contains this Copyright Notice, whether distributed in
+print or electronically.
+
+# [](#preface)[Preface](#preface)
This section provides a brief overview of the Spring Cloud Task reference documentation.
Think of it as a map for the rest of the document. You can read this reference guide in a
linear fashion or you can skip sections if something does not interest you.
-[](#about-the-documentation)[1. About the documentation](#about-the-documentation)
-----------
+## [](#about-the-documentation)[1. About the documentation](#about-the-documentation)
The Spring Cloud Task reference guide is available in [html](https://docs.spring.io/spring-cloud-task/docs/current/reference)and [pdf](https://docs.spring.io/spring-cloud-task/docs/current/reference/index.pdf),[epub](https://docs.spring.io/spring-cloud-task/docs/current/reference/index.epub) . The
latest copy is available at [docs.spring.io/spring-cloud-task/docs/current-SNAPSHOT/reference/html/](https://docs.spring.io/spring-cloud-task/docs/current-SNAPSHOT/reference/html/).
@@ -19,8 +126,7 @@ Copies of this document may be made for your own use and for distribution to oth
provided that you do not charge any fee for such copies and further provided that each
copy contains this Copyright Notice, whether distributed in print or electronically.
-[](#task-documentation-getting-help)[2. Getting help](#task-documentation-getting-help)
-----------
+## [](#task-documentation-getting-help)[2. Getting help](#task-documentation-getting-help)
Having trouble with Spring Cloud Task? We would like to help!
@@ -32,8 +138,7 @@ Having trouble with Spring Cloud Task? We would like to help!
| |All of Spring Cloud Task is open source, including the documentation. If you find
a problem with the docs or if you just want to improve them, please [get
involved](https://github.com/spring-cloud/spring-cloud-task/tree/master).|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#task-documentation-first-steps)[3. First Steps](#task-documentation-first-steps)
-----------
+## [](#task-documentation-first-steps)[3. First Steps](#task-documentation-first-steps)
If you are just getting started with Spring Cloud Task or with 'Spring' in general, we
suggesting reading the [Getting started](#getting-started) chapter.
@@ -47,28 +152,25 @@ To get started from scratch, read the following sections:
To follow the tutorial, read[Developing Your First Spring Cloud Task Application](#getting-started-developing-first-task)
To run your example, read[Running the Example](#getting-started-running-the-example)
-[](#getting-started)[Getting started](#getting-started)
-==========
+# [](#getting-started)[Getting started](#getting-started)
If you are just getting started with Spring Cloud Task, you should read this section.
Here, we answer the basic “what?”, “how?”, and “why?” questions. We start with a
gentle introduction to Spring Cloud Task. We then build a Spring Cloud Task application,
discussing some core principles as we go.
-[](#getting-started-introducing-spring-cloud-task)[4. Introducing Spring Cloud Task](#getting-started-introducing-spring-cloud-task)
-----------
+## [](#getting-started-introducing-spring-cloud-task)[4. Introducing Spring Cloud Task](#getting-started-introducing-spring-cloud-task)
Spring Cloud Task makes it easy to create short-lived microservices. It provides
capabilities that let short lived JVM processes be executed on demand in a production
environment.
-[](#getting-started-system-requirements)[5. System Requirements](#getting-started-system-requirements)
-----------
+## [](#getting-started-system-requirements)[5. System Requirements](#getting-started-system-requirements)
You need to have Java installed (Java 8 or better). To build, you need to have Maven
installed as well.
-### [](#database-requirements)[5.1. Database Requirements](#database-requirements) ###
+### [](#database-requirements)[5.1. Database Requirements](#database-requirements)
Spring Cloud Task uses a relational database to store the results of an executed task.
While you can begin developing a task without a database (the status of the task is logged
@@ -89,8 +191,7 @@ use a supported database. Spring Cloud Task currently supports the following dat
* SqlServer
-[](#getting-started-developing-first-task)[6. Developing Your First Spring Cloud Task Application](#getting-started-developing-first-task)
-----------
+## [](#getting-started-developing-first-task)[6. Developing Your First Spring Cloud Task Application](#getting-started-developing-first-task)
A good place to start is with a simple “Hello, World!” application, so we create the
Spring Cloud Task equivalent to highlight the features of the framework. Most IDEs have
@@ -99,7 +200,7 @@ good support for Apache Maven, so we use it as the build tool for this project.
| |The spring.io web site contains many [“`Getting Started`”
guides](https://spring.io/guides) that use Spring Boot. If you need to solve a specific problem, check there first.
You can shortcut the following steps by going to the[Spring Initializr](https://start.spring.io/) and creating a new project. Doing so
automatically generates a new project structure so that you can start coding right away.
We recommend experimenting with the Spring Initializr to become familiar with it.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#getting-started-creating-project)[6.1. Creating the Spring Task Project using Spring Initializr](#getting-started-creating-project) ###
+### [](#getting-started-creating-project)[6.1. Creating the Spring Task Project using Spring Initializr](#getting-started-creating-project)
Now we can create and test an application that prints `Hello, World!` to the console.
@@ -119,7 +220,7 @@ To do so:
2. Unzip the helloworld.zip file and import the project into your favorite IDE.
-### [](#getting-started-writing-the-code)[6.2. Writing the Code](#getting-started-writing-the-code) ###
+### [](#getting-started-writing-the-code)[6.2. Writing the Code](#getting-started-writing-the-code)
To finish our application, we need to update the generated `HelloworldApplication` with the following contents so that it launches a Task.
@@ -172,7 +273,7 @@ logging.level.org.springframework.cloud.task=DEBUG
spring.application.name=helloWorld
```
-#### [](#getting-started-at-task)[6.2.1. Task Auto Configuration](#getting-started-at-task) ####
+#### [](#getting-started-at-task)[6.2.1. Task Auto Configuration](#getting-started-at-task)
When including Spring Cloud Task Starter dependency, Task auto configures all beans to bootstrap it’s functionality.
Part of this configuration registers the `TaskRepository` and the infrastructure for its use.
@@ -187,12 +288,12 @@ Spring Cloud Task.
When our sample application runs, Spring Boot launches our `HelloWorldCommandLineRunner`and outputs our “Hello, World!” message to standard out. The `TaskLifecycleListener`records the start of the task and the end of the task in the repository.
-#### [](#getting-started-main-method)[6.2.2. The main method](#getting-started-main-method) ####
+#### [](#getting-started-main-method)[6.2.2. The main method](#getting-started-main-method)
The main method serves as the entry point to any java application. Our main method
delegates to Spring Boot’s [SpringApplication](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html) class.
-#### [](#getting-started-clr)[6.2.3. The CommandLineRunner](#getting-started-clr) ####
+#### [](#getting-started-clr)[6.2.3. The CommandLineRunner](#getting-started-clr)
Spring includes many ways to bootstrap an application’s logic. Spring Boot provides
a convenient method of doing so in an organized manner through its `*Runner` interfaces
@@ -205,7 +306,7 @@ to once they are all complete. Spring Boot lets an application use multiple`*Run
| |Any processing bootstrapped from mechanisms other than a `CommandLineRunner` or`ApplicationRunner` (by using `InitializingBean#afterPropertiesSet` for example) is not
recorded by Spring Cloud Task.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#getting-started-running-the-example)[6.3. Running the Example](#getting-started-running-the-example) ###
+### [](#getting-started-running-the-example)[6.3. Running the Example](#getting-started-running-the-example)
At this point, our application should work. Since this application is Spring Boot-based,
we can run it from the command line by using `$ mvn spring-boot:run` from the root
@@ -256,14 +357,12 @@ The preceding output has three lines that of interest to us here:
| |A simple task application can be found in the samples module of the Spring Cloud
Task Project[here](https://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-samples/timestamp).|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#features)[Features](#features)
-==========
+# [](#features)[Features](#features)
This section goes into more detail about Spring Cloud Task, including how to use it, how
to configure it, and the appropriate extension points.
-[](#features-lifecycle)[7. The lifecycle of a Spring Cloud Task](#features-lifecycle)
-----------
+## [](#features-lifecycle)[7. The lifecycle of a Spring Cloud Task](#features-lifecycle)
In most cases, the modern cloud environment is designed around the execution of processes
that are not expected to end. If they do end, they are typically restarted. While most
@@ -304,7 +403,7 @@ updated in the repository with the results.
| |If the application requires the `ApplicationContext` to be closed at the
completion of a task (all `*Runner#run` methods have been called and the task
repository has been updated), set the property `spring.cloud.task.closecontextEnabled`to true.|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#features-task-execution-details)[7.1. The TaskExecution](#features-task-execution-details) ###
+### [](#features-task-execution-details)[7.1. The TaskExecution](#features-task-execution-details)
The information stored in the `TaskRepository` is modeled in the `TaskExecution` class and
consists of the following information:
@@ -320,7 +419,7 @@ consists of the following information:
|`errorMessage`| If an exception is the cause of the end of the task (as indicated by an`ApplicationFailedEvent`), the stack trace for that exception is stored here. |
| `arguments` | A `List` of the string command line arguments as they were passed into the executable
boot application. |
-### [](#features-lifecycle-exit-codes)[7.2. Mapping Exit Codes](#features-lifecycle-exit-codes) ###
+### [](#features-lifecycle-exit-codes)[7.2. Mapping Exit Codes](#features-lifecycle-exit-codes)
When a task completes, it tries to return an exit code to the OS. If we take a look
at our [original example](#getting-started-developing-first-task), we can see that we are
@@ -338,13 +437,12 @@ otherwise specified within the code.
| |While the task is running, the exit code is stored as a null in the repository.
Once the task completes, the appropriate exit code is stored based on the guidelines described
earlier in this section.|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#features-configuration)[8. Configuration](#features-configuration)
-----------
+## [](#features-configuration)[8. Configuration](#features-configuration)
Spring Cloud Task provides a ready-to-use configuration, as defined in the`DefaultTaskConfigurer` and `SimpleTaskConfiguration` classes. This section walks through
the defaults and how to customize Spring Cloud Task for your needs.
-### [](#features-data-source)[8.1. DataSource](#features-data-source) ###
+### [](#features-data-source)[8.1. DataSource](#features-data-source)
Spring Cloud Task uses a datasource for storing the results of task executions. By
default, we provide an in-memory instance of H2 to provide a simple method of
@@ -359,7 +457,7 @@ If your application uses more than one `DataSource`, you need to configure the t
repository with the appropriate `DataSource`. This customization can be done through an
implementation of `TaskConfigurer`.
-### [](#features-table-prefix)[8.2. Table Prefix](#features-table-prefix) ###
+### [](#features-table-prefix)[8.2. Table Prefix](#features-table-prefix)
One modifiable property of `TaskRepository` is the table prefix for the task tables. By
default, they are all prefaced with `TASK_`. `TASK_EXECUTION` and `TASK_EXECUTION_PARAMS`are two examples. However, there are potential reasons to modify this prefix. If the
@@ -374,7 +472,7 @@ create the task tables that meet both the criteria for the task table schema but
with modifications that are required for a user’s business needs.
You can utilize the Spring Cloud Task Schema DDL as a guide when creating your own Task DDL as seen[here](https://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-core/src/main/resources/org/springframework/cloud/task).
-### [](#features-table-initialization)[8.3. Enable/Disable table initialization](#features-table-initialization) ###
+### [](#features-table-initialization)[8.3. Enable/Disable table initialization](#features-table-initialization)
In cases where you are creating the task tables and do not wish for Spring Cloud Task to
create them at task startup, set the `spring.cloud.task.initialize-enabled` property to`false`, as follows:
@@ -386,7 +484,7 @@ It defaults to `true`.
| |The property `spring.cloud.task.initialize.enable` has been deprecated.|
|---|-----------------------------------------------------------------------|
-### [](#features-generated_task_id)[8.4. Externally Generated Task ID](#features-generated_task_id) ###
+### [](#features-generated_task_id)[8.4. Externally Generated Task ID](#features-generated_task_id)
In some cases, you may want to allow for the time difference between when a task is
requested and when the infrastructure actually launches it. Spring Cloud Task lets you
@@ -403,7 +501,7 @@ following property:
`spring.cloud.task.executionid=yourtaskId`
-### [](#features-external_task_id)[8.5. External Task Id](#features-external_task_id) ###
+### [](#features-external_task_id)[8.5. External Task Id](#features-external_task_id)
Spring Cloud Task lets you store an external task ID for each`TaskExecution`. An example of this would be a task ID provided by
Cloud Foundry when a task is launched on the platform.
@@ -412,7 +510,7 @@ following property:
`spring.cloud.task.external-execution-id=`
-### [](#features-parent_task_id)[8.6. Parent Task Id](#features-parent_task_id) ###
+### [](#features-parent_task_id)[8.6. Parent Task Id](#features-parent_task_id)
Spring Cloud Task lets you store a parent task ID for each `TaskExecution`. An example of
this would be a task that executes another task or tasks and you want to record which task
@@ -420,7 +518,7 @@ launched each of the child tasks. In order to configure your Task to set a paren
`spring.cloud.task.parent-execution-id=`
-### [](#features-task-configurer)[8.7. TaskConfigurer](#features-task-configurer) ###
+### [](#features-task-configurer)[8.7. TaskConfigurer](#features-task-configurer)
The `TaskConfigurer` is a strategy interface that lets you customize the way components of
Spring Cloud Task are configured. By default, we provide the `DefaultTaskConfigurer` that
@@ -442,7 +540,7 @@ may be required.
| |Users should not directly use getter methods from a `TaskConfigurer` directly
unless they are using it to supply implementations to be exposed as Spring Beans.|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#features-task-name)[8.8. Task Name](#features-task-name) ###
+### [](#features-task-name)[8.8. Task Name](#features-task-name)
In most cases, the name of the task is the application name as configured in Spring
Boot. However, there are some cases where you may want to map the run of a task to a
@@ -457,7 +555,7 @@ following options (in order of precedence):
2. The application name as resolved using Spring Boot’s rules (obtained through`ApplicationContext#getId`).
-### [](#features-task-execution-listener)[8.9. Task Execution Listener](#features-task-execution-listener) ###
+### [](#features-task-execution-listener)[8.9. Task Execution Listener](#features-task-execution-listener)
`TaskExecutionListener` lets you register listeners for specific events that occur during
the task lifecycle. To do so, create a class that implements the`TaskExecutionListener` interface. The class that implements the `TaskExecutionListener`interface is notified of the following events:
@@ -502,7 +600,7 @@ The following example shows the three annotations in use:
| |Inserting an `ApplicationListener` earlier in the chain than `TaskLifecycleListener` exists may cause unexpected effects.|
|---|-------------------------------------------------------------------------------------------------------------------------|
-#### [](#features-task-execution-listener-Exceptions)[8.9.1. Exceptions Thrown by Task Execution Listener](#features-task-execution-listener-Exceptions) ####
+#### [](#features-task-execution-listener-Exceptions)[8.9.1. Exceptions Thrown by Task Execution Listener](#features-task-execution-listener-Exceptions)
If an exception is thrown by a `TaskExecutionListener` event handler, all listener
processing for that event handler stops. For example, if three `onTaskStartup` listeners
@@ -520,7 +618,7 @@ If an exception is thrown in either a `onTaskEnd` or `onTaskFailed`method, the e
| |In the case of an exception being thrown in a `onTaskStartup`, `onTaskEnd`, or `onTaskFailed`you can not override the exit code for the application using `ExitCodeExceptionMapper`.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-#### [](#features-task-execution-listener-exit-messages)[8.9.2. Exit Messages](#features-task-execution-listener-exit-messages) ####
+#### [](#features-task-execution-listener-exit-messages)[8.9.2. Exit Messages](#features-task-execution-listener-exit-messages)
You can set the exit message for a task programmatically by using a`TaskExecutionListener`. This is done by setting the `TaskExecution’s` `exitMessage`,
which then gets passed into the `TaskExecutionListener`. The following example shows
@@ -545,7 +643,7 @@ For example, if you set an `exitMessage` for the `onTaskStartup` and `onTaskFail
the `onTaskFailed` is stored. Also if you set the `exitMessage` with an`onTaskEnd` listener, the `exitMessage` from the `onTaskEnd` supersedes
the exit messages from both the `onTaskStartup` and `onTaskFailed`.
-### [](#features-single-instance-enabled)[8.10. Restricting Spring Cloud Task Instances](#features-single-instance-enabled) ###
+### [](#features-single-instance-enabled)[8.10. Restricting Spring Cloud Task Instances](#features-single-instance-enabled)
Spring Cloud Task lets you establish that only one task with a given task name can be run
at a time. To do so, you need to establish the [task name](#features-task-name) and set`spring.cloud.task.single-instance-enabled=true` for each task execution. While the first
@@ -573,7 +671,7 @@ application:
| |The exit code for the application will be 1 if the task fails because this feature
is enabled and another task is running with the same task name.|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#disabling-spring-cloud-task-auto-configuration)[8.11. Disabling Spring Cloud Task Auto Configuration](#disabling-spring-cloud-task-auto-configuration) ###
+### [](#disabling-spring-cloud-task-auto-configuration)[8.11. Disabling Spring Cloud Task Auto Configuration](#disabling-spring-cloud-task-auto-configuration)
In cases where Spring Cloud Task should not be auto configured for an implementation, you can disable Task’s auto configuration.
This can be done either by adding the following annotation to your Task application:
@@ -584,7 +682,7 @@ This can be done either by adding the following annotation to your Task applicat
You may also disable Task auto configuration by setting the `spring.cloud.task.autoconfiguration.enabled` property to `false`.
-### [](#closing-the-context)[8.12. Closing the Context](#closing-the-context) ###
+### [](#closing-the-context)[8.12. Closing the Context](#closing-the-context)
If the application requires the `ApplicationContext` to be closed at the
completion of a task (all `*Runner#run` methods have been called and the task
@@ -597,16 +695,14 @@ set the `spring.cloud.task.closecontextEnabled` property to `true` when launchin
This will close the application’s context once the task is complete.
Thus allowing the application to terminate.
-[](#batch)[Batch](#batch)
-==========
+# [](#batch)[Batch](#batch)
This section goes into more detail about Spring Cloud Task’s integration with Spring
Batch. Tracking the association between a job execution and the task in which it was
executed as well as remote partitioning through Spring Cloud Deployer are covered in
this section.
-[](#batch-association)[9. Associating a Job Execution to the Task in which It Was Executed](#batch-association)
-----------
+## [](#batch-association)[9. Associating a Job Execution to the Task in which It Was Executed](#batch-association)
Spring Boot provides facilities for the execution of batch jobs within an über-jar.
Spring Boot’s support of this functionality lets a developer execute multiple batch jobs
@@ -620,7 +716,7 @@ this listener is auto configured in any context that has both a Spring Batch Job
configured (by having a bean of type `Job` defined in the context) and the`spring-cloud-task-batch` jar on the classpath. The listener is injected into all jobs
that meet those conditions.
-### [](#batch-association-override)[9.1. Overriding the TaskBatchExecutionListener](#batch-association-override) ###
+### [](#batch-association-override)[9.1. Overriding the TaskBatchExecutionListener](#batch-association-override)
To prevent the listener from being injected into any batch jobs within the current
context, you can disable the autoconfiguration by using standard Spring Boot mechanisms.
@@ -642,8 +738,7 @@ public TaskBatchExecutionListenerBeanPostProcessor batchTaskExecutionListenerBea
| |You can find a sample batch application in the samples module of the Spring Cloud
Task Project,[here](https://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-samples/batch-job).|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#batch-partitioning)[10. Remote Partitioning](#batch-partitioning)
-----------
+## [](#batch-partitioning)[10. Remote Partitioning](#batch-partitioning)
Spring Cloud Deployer provides facilities for launching Spring Boot-based applications on
most cloud infrastructures. The `DeployerPartitionHandler` and`DeployerStepExecutionHandler` delegate the launching of worker step executions to Spring
@@ -714,7 +809,7 @@ public DeployerStepExecutionHandler stepExecutionHandler(JobExplorer jobExplorer
| |You can find a sample remote partition application in the samples module of the
Spring Cloud Task project,[here](https://github.com/spring-cloud/spring-cloud-task/tree/master/spring-cloud-task-samples/partitioned-batch-job).|
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-### [](#notes-on-developing-a-batch-partitioned-application-for-the-kubernetes-platform)[10.1. Notes on Developing a Batch-partitioned application for the Kubernetes Platform](#notes-on-developing-a-batch-partitioned-application-for-the-kubernetes-platform) ###
+### [](#notes-on-developing-a-batch-partitioned-application-for-the-kubernetes-platform)[10.1. Notes on Developing a Batch-partitioned application for the Kubernetes Platform](#notes-on-developing-a-batch-partitioned-application-for-the-kubernetes-platform)
* When deploying partitioned apps on the Kubernetes platform, you must use the following
dependency for the Spring Cloud Kubernetes Deployer:
@@ -730,7 +825,7 @@ public DeployerStepExecutionHandler stepExecutionHandler(JobExplorer jobExplorer
the following regex pattern: `[a-z0-9]([-a-z0-9]*[a-z0-9])`.
Otherwise, an exception is thrown.
-### [](#notes-on-developing-a-batch-partitioned-application-for-the-cloud-foundry-platform)[10.2. Notes on Developing a Batch-partitioned Application for the Cloud Foundry Platform](#notes-on-developing-a-batch-partitioned-application-for-the-cloud-foundry-platform) ###
+### [](#notes-on-developing-a-batch-partitioned-application-for-the-cloud-foundry-platform)[10.2. Notes on Developing a Batch-partitioned Application for the Cloud Foundry Platform](#notes-on-developing-a-batch-partitioned-application-for-the-cloud-foundry-platform)
* When deploying partitioned apps on the Cloud Foundry platform, you must use the
following dependencies for the Spring Cloud Foundry Deployer:
@@ -790,14 +885,12 @@ spring_cloud_deployer_cloudfoundry_taskTimeout=300
| |When using PCF-Dev, the following environment variable is also required:`spring_cloud_deployer_cloudfoundry_skipSslValidation=true`|
|---|-----------------------------------------------------------------------------------------------------------------------------------|
-[](#batch-informational-messages)[11. Batch Informational Messages](#batch-informational-messages)
-----------
+## [](#batch-informational-messages)[11. Batch Informational Messages](#batch-informational-messages)
Spring Cloud Task provides the ability for batch jobs to emit informational messages. The
“[Spring Batch Events](#stream-integration-batch-events)” section covers this feature in detail.
-[](#batch-failures-and-tasks)[12. Batch Job Exit Codes](#batch-failures-and-tasks)
-----------
+## [](#batch-failures-and-tasks)[12. Batch Job Exit Codes](#batch-failures-and-tasks)
As discussed [earlier](#features-lifecycle-exit-codes), Spring Cloud Task
applications support the ability to record the exit code of a task execution. However, in
@@ -814,8 +907,7 @@ Boot. By default, it is configured with the same order. However, if you want to
the order in which the `CommandLineRunner` is run, you can set its order by setting the`spring.cloud.task.batch.commandLineRunnerOrder` property. To have your task return the
exit code based on the result of the batch job execution, you need to write your own`CommandLineRunner`.
-[](#batch-job-starter)[Single Step Batch Job Starter](#batch-job-starter)
-==========
+# [](#batch-job-starter)[Single Step Batch Job Starter](#batch-job-starter)
This section goes into how to develop a Spring Batch `Job` with a single `Step` by using the
starter included in Spring Cloud Task. This starter lets you use configuration
@@ -838,13 +930,12 @@ To obtain the starter for Gradle, add the following to your build:
compile "org.springframework.cloud:spring-cloud-starter-single-step-batch-job:2.3.0"
```
-[](#job-definition)[13. Defining a Job](#job-definition)
-----------
+## [](#job-definition)[13. Defining a Job](#job-definition)
You can use the starter to define as little as an `ItemReader` or an `ItemWriter` or as much as a full `Job`.
In this section, we define which properties are required to be defined to configure a`Job`.
-### [](#job-definition-properties)[13.1. Properties](#job-definition-properties) ###
+### [](#job-definition-properties)[13.1. Properties](#job-definition-properties)
To begin, the starter provides a set of properties that let you configure the basics of a Job with one Step:
@@ -865,14 +956,13 @@ mechanisms.
| |If you configure your own, the input and output types must match the others in the step.
The `ItemReader` implementations and `ItemWriter` implementations in this starter all use
a `Map` as the input and the output item.|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-[](#item-readers)[14. Autoconfiguration for ItemReader Implementations](#item-readers)
-----------
+## [](#item-readers)[14. Autoconfiguration for ItemReader Implementations](#item-readers)
This starter provides autoconfiguration for four different `ItemReader` implementations:`AmqpItemReader`, `FlatFileItemReader`, `JdbcCursorItemReader`, and `KafkaItemReader`.
In this section, we outline how to configure each of these by using the provided
autoconfiguration.
-### [](#amqpitemreader)[14.1. AmqpItemReader](#amqpitemreader) ###
+### [](#amqpitemreader)[14.1. AmqpItemReader](#amqpitemreader)
You can read from a queue or topic with AMQP by using the `AmqpItemReader`. The
autoconfiguration for this `ItemReader` implementation is dependent upon two sets of
@@ -888,7 +978,7 @@ by setting the following properties:
For more information, see the [`AmqpItemReader` documentation](https://docs.spring.io/spring-batch/docs/4.3.x/api/org/springframework/batch/item/amqp/AmqpItemReader.html).
-### [](#flatfileitemreader)[14.2. FlatFileItemReader](#flatfileitemreader) ###
+### [](#flatfileitemreader)[14.2. FlatFileItemReader](#flatfileitemreader)
`FlatFileItemReader` lets you read from flat files (such as CSVs
and other file formats). To read from a file, you can provide some components
@@ -917,7 +1007,7 @@ following properties to configure the reader:
See the [`FlatFileItemReader` documentation](https://docs.spring.io/spring-batch/docs/4.3.x/api/org/springframework/batch/item/file/FlatFileItemReader.html).
-### [](#jdbcCursorItemReader)[14.3. JdbcCursorItemReader](#jdbcCursorItemReader) ###
+### [](#jdbcCursorItemReader)[14.3. JdbcCursorItemReader](#jdbcCursorItemReader)
The `JdbcCursorItemReader` runs a query against a relational database and iterates over
the resulting cursor (`ResultSet`) to provide the resulting items. This autoconfiguration
@@ -941,7 +1031,7 @@ can also use the following properties to configure a `JdbcCursorItemReader`:
See the [`JdbcCursorItemReader` documentation](https://docs.spring.io/spring-batch/docs/4.3.x/api/org/springframework/batch/item/database/JdbcCursorItemReader.html).
-### [](#kafkaItemReader)[14.4. KafkaItemReader](#kafkaItemReader) ###
+### [](#kafkaItemReader)[14.4. KafkaItemReader](#kafkaItemReader)
Ingesting a partition of data from a Kafka topic is useful and exactly what the`KafkaItemReader` can do. To configure a `KafkaItemReader`, two pieces
of configuration are required. First, configuring Kafka with Spring Boot’s Kafka
@@ -958,22 +1048,20 @@ Once you have configured the Kafka properties from Spring Boot, you can configur
See the [`KafkaItemReader` documentation](https://docs.spring.io/spring-batch/docs/4.3.x/api/org/springframework/batch/item/kafka/KafkaItemReader.html).
-[](#item-processors)[15. ItemProcessor Configuration](#item-processors)
-----------
+## [](#item-processors)[15. ItemProcessor Configuration](#item-processors)
The single-step batch job autoconfiguration accepts an `ItemProcessor` if one
is available within the `ApplicationContext`. If one is found of the correct type
(`ItemProcessor