Sync docs from vGreenwich.RC2 to gh-pages
35
Greenwich.RC2/multi/css/highlight.css
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
code highlight CSS resemblign the Eclipse IDE default color schema
|
||||
@author Costin Leau
|
||||
*/
|
||||
|
||||
.hl-keyword {
|
||||
color: #7F0055;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hl-comment {
|
||||
color: #3F5F5F;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hl-multiline-comment {
|
||||
color: #3F5FBF;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hl-tag {
|
||||
color: #3F7F7F;
|
||||
}
|
||||
|
||||
.hl-attribute {
|
||||
color: #7F007F;
|
||||
}
|
||||
|
||||
.hl-value {
|
||||
color: #2A00FF;
|
||||
}
|
||||
|
||||
.hl-string {
|
||||
color: #2A00FF;
|
||||
}
|
||||
9
Greenwich.RC2/multi/css/manual-multipage.css
Normal file
@@ -0,0 +1,9 @@
|
||||
@IMPORT url("manual.css");
|
||||
|
||||
body.firstpage {
|
||||
background: url("../images/background.png") no-repeat center top;
|
||||
}
|
||||
|
||||
div.part h1 {
|
||||
border-top: none;
|
||||
}
|
||||
6
Greenwich.RC2/multi/css/manual-singlepage.css
Normal file
@@ -0,0 +1,6 @@
|
||||
@IMPORT url("manual.css");
|
||||
|
||||
body {
|
||||
background: url("../images/background.png") no-repeat center top;
|
||||
}
|
||||
|
||||
344
Greenwich.RC2/multi/css/manual.css
Normal file
@@ -0,0 +1,344 @@
|
||||
@IMPORT url("highlight.css");
|
||||
|
||||
html {
|
||||
padding: 0pt;
|
||||
margin: 0pt;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #333333;
|
||||
margin: 15px 30px;
|
||||
font-family: Helvetica, Arial, Freesans, Clean, Sans-serif;
|
||||
line-height: 1.6;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 16px;
|
||||
font-family: Consolas, "Liberation Mono", Courier, monospace;
|
||||
}
|
||||
|
||||
:not(a)>code {
|
||||
color: #6D180B;
|
||||
}
|
||||
|
||||
:not(pre)>code {
|
||||
background-color: #F2F2F2;
|
||||
border: 1px solid #CCCCCC;
|
||||
border-radius: 4px;
|
||||
padding: 1px 3px 0;
|
||||
text-shadow: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
body>*:first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
div {
|
||||
margin: 0pt;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid #CCCCCC;
|
||||
background: #CCCCCC;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
color: #000000;
|
||||
cursor: text;
|
||||
font-weight: bold;
|
||||
margin: 30px 0 10px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1,h2,h3 {
|
||||
margin: 40px 0 10px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 70px 0 30px;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
div.part h1 {
|
||||
border-top: 1px dotted #CCCCCC;
|
||||
}
|
||||
|
||||
h1,h1 code {
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
h2,h2 code {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
h3,h3 code {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
h4,h1 code,h5,h5 code,h6,h6 code {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
div.book,div.chapter,div.appendix,div.part,div.preface {
|
||||
min-width: 300px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
p.releaseinfo {
|
||||
font-weight: bold;
|
||||
margin-bottom: 40px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
div.authorgroup {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
p.copyright {
|
||||
line-height: 1;
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
.legalnotice p {
|
||||
font-style: italic;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
div.titlepage+p,div.titlepage+p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
line-height: 1.0;
|
||||
color: black;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #4183C4;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 15px 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
ul,ol {
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
li p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.table {
|
||||
margin: 1em;
|
||||
padding: 0.5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.table table,div.informaltable table {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.table td {
|
||||
padding-left: 7px;
|
||||
padding-right: 7px;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
line-height: 1.4;
|
||||
padding: 0 20px;
|
||||
background-color: #F8F8F8;
|
||||
border: 1px solid #CCCCCC;
|
||||
border-radius: 3px 3px 3px 3px;
|
||||
}
|
||||
|
||||
.sidebar p.title {
|
||||
color: #6D180B;
|
||||
}
|
||||
|
||||
pre.programlisting,pre.screen {
|
||||
font-size: 15px;
|
||||
padding: 6px 10px;
|
||||
background-color: #F8F8F8;
|
||||
border: 1px solid #CCCCCC;
|
||||
border-radius: 3px 3px 3px 3px;
|
||||
clear: both;
|
||||
overflow: auto;
|
||||
line-height: 1.4;
|
||||
font-family: Consolas, "Liberation Mono", Courier, monospace;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
border: 1px solid #DDDDDD !important;
|
||||
border-radius: 4px !important;
|
||||
border-collapse: separate !important;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
table thead {
|
||||
background: #F5F5F5;
|
||||
}
|
||||
|
||||
table tr {
|
||||
border: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
table th {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table th,table td {
|
||||
border: none !important;
|
||||
padding: 6px 13px;
|
||||
}
|
||||
|
||||
table tr:nth-child(2n) {
|
||||
background-color: #F8F8F8;
|
||||
}
|
||||
|
||||
td p {
|
||||
margin: 0 0 15px 0;
|
||||
}
|
||||
|
||||
div.table-contents td p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.important *,div.note *,div.tip *,div.warning *,div.navheader *,div.navfooter *,div.calloutlist *
|
||||
{
|
||||
border: none !important;
|
||||
background: none !important;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.important p,div.note p,div.tip p,div.warning p {
|
||||
color: #6F6F6F;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
div.important code,div.note code,div.tip code,div.warning code {
|
||||
background-color: #F2F2F2 !important;
|
||||
border: 1px solid #CCCCCC !important;
|
||||
border-radius: 4px !important;
|
||||
padding: 1px 3px 0 !important;
|
||||
text-shadow: none !important;
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
.note th,.tip th,.warning th {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.note tr:first-child td,.tip tr:first-child td,.warning tr:first-child td
|
||||
{
|
||||
border-right: 1px solid #CCCCCC !important;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
div.calloutlist p,div.calloutlist td {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.calloutlist>table>tbody>tr>td:first-child {
|
||||
padding-left: 10px;
|
||||
width: 30px !important;
|
||||
}
|
||||
|
||||
div.important,div.note,div.tip,div.warning {
|
||||
margin-left: 0px !important;
|
||||
margin-right: 20px !important;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
div.toc {
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
dl,dt {
|
||||
margin-top: 1px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.toc>dl>dt {
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
margin: 30px 0 10px 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
div.toc>dl>dd>dl>dt {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin: 20px 0 10px 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
div.toc>dl>dd>dl>dd>dl>dt {
|
||||
font-weight: bold;
|
||||
font-size: 20px;
|
||||
margin: 10px 0 0 0;
|
||||
}
|
||||
|
||||
tbody.footnotes * {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
div.footnote p {
|
||||
margin: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
div.footnote p sup {
|
||||
margin-right: 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.navheader {
|
||||
border-bottom: 1px solid #CCCCCC;
|
||||
}
|
||||
|
||||
div.navfooter {
|
||||
border-top: 1px solid #CCCCCC;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-left: -1em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.title>a {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
font-size: 0.85em;
|
||||
margin-top: 0.05em;
|
||||
margin-left: -1em;
|
||||
vertical-align: text-top;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.title>a:before {
|
||||
content: "\00A7";
|
||||
}
|
||||
|
||||
.title:hover>a,.title>a:hover,.title:hover>a:hover {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.title:focus>a,.title>a:focus,.title:focus>a:focus {
|
||||
outline: 0;
|
||||
}
|
||||
BIN
Greenwich.RC2/multi/images/background.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
Greenwich.RC2/multi/images/callouts/1.png
Normal file
|
After Width: | Height: | Size: 329 B |
BIN
Greenwich.RC2/multi/images/callouts/2.png
Normal file
|
After Width: | Height: | Size: 353 B |
BIN
Greenwich.RC2/multi/images/callouts/3.png
Normal file
|
After Width: | Height: | Size: 350 B |
BIN
Greenwich.RC2/multi/images/caution.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
Greenwich.RC2/multi/images/important.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
Greenwich.RC2/multi/images/logo.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
Greenwich.RC2/multi/images/note.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
Greenwich.RC2/multi/images/tip.png
Normal file
|
After Width: | Height: | Size: 931 B |
BIN
Greenwich.RC2/multi/images/warning.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,9 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>24. A Brief History of Spring’s Data Integration Journey</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="prev" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="next" href="multi__quick_start_2.html" title="25. Quick Start"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">24. A Brief History of Spring’s Data Integration Journey</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_stream.html">Prev</a> </td><th width="60%" align="center">Part V. Spring Cloud Stream</th><td width="20%" align="right"> <a accesskey="n" href="multi__quick_start_2.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_a_brief_history_of_spring_s_data_integration_journey" href="#_a_brief_history_of_spring_s_data_integration_journey"></a>24. A Brief History of Spring’s Data Integration Journey</h2></div></div></div><p>Spring’s journey on Data Integration started with <a class="link" href="https://projects.spring.io/spring-integration/" target="_top">Spring Integration</a>. With its programming model, it provided a consistent developer experience to build applications that can embrace <a class="link" href="http://www.enterpriseintegrationpatterns.com/" target="_top">Enterprise Integration Patterns</a> to connect with external systems such as, databases, message brokers, and among others.</p><p>Fast forward to the cloud-era, where microservices have become prominent in the enterprise setting. <a class="link" href="https://projects.spring.io/spring-boot/" target="_top">Spring Boot</a> transformed the way how developers built Applications. With Spring’s programming model and the runtime responsibilities handled by Spring Boot, it became seamless to develop stand-alone, production-grade Spring-based microservices.</p><p>To extend this to Data Integration workloads, Spring Integration and Spring Boot were put together into a new project. Spring Cloud Stream was born.</p><p>With Spring Cloud Stream, developers can:
|
||||
* Build, test, iterate, and deploy data-centric applications in isolation.
|
||||
* Apply modern microservices architecture patterns, including composition through messaging.
|
||||
* Decouple application responsibilities with event-centric thinking. An event can represent something that has happened in time, to which the downstream consumer applications can react without knowing where it originated or the producer’s identity.
|
||||
* Port the business logic onto message brokers (such as RabbitMQ, Apache Kafka, Amazon Kinesis).
|
||||
* Interoperate between channel-based and non-channel-based application binding scenarios to support stateless and stateful computations by using Project Reactor’s Flux and Kafka Streams APIs.
|
||||
* Rely on the framework’s automatic content-type support for common use-cases. Extending to different data conversion types is possible.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_stream.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_stream.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__quick_start_2.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part V. Spring Cloud Stream </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 25. Quick Start</td></tr></table></div></body></html>
|
||||
45
Greenwich.RC2/multi/multi__actuator_api.html
Normal file
4
Greenwich.RC2/multi/multi__additional_resources.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>51. Additional Resources</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__introduction.html" title="50. Introduction"><link rel="next" href="multi__features_2.html" title="52. Features"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">51. Additional Resources</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__introduction.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__features_2.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_additional_resources" href="#_additional_resources"></a>51. Additional Resources</h2></div></div></div><p>You can watch a video of <a class="link" href="https://twitter.com/reshmi9k" target="_top">Reshmi Krishna</a> and <a class="link" href="https://twitter.com/mgrzejszczak" target="_top">Marcin Grzejszczak</a> talking about Spring Cloud
|
||||
Sleuth and Zipkin <a class="link" href="https://content.pivotal.io/springone-platform-2017/distributed-tracing-latency-analysis-for-your-microservices-grzejszczak-krishna" target="_top">by clicking here</a>.</p><p>You can check different setups of Sleuth and Brave <a class="link" href="https://github.com/openzipkin/sleuth-webmvc-example" target="_top">in the openzipkin/sleuth-webmvc-example repository</a>.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__introduction.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__features_2.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">50. Introduction </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 52. Features</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,6 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>45. Addressing All Instances of a Service</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_bus.html" title="Part VII. Spring Cloud Bus"><link rel="prev" href="multi__addressing_an_instance.html" title="44. Addressing an Instance"><link rel="next" href="multi__service_id_must_be_unique.html" title="46. Service ID Must Be Unique"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">45. Addressing All Instances of a Service</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__addressing_an_instance.html">Prev</a> </td><th width="60%" align="center">Part VII. Spring Cloud Bus</th><td width="20%" align="right"> <a accesskey="n" href="multi__service_id_must_be_unique.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_addressing_all_instances_of_a_service" href="#_addressing_all_instances_of_a_service"></a>45. Addressing All Instances of a Service</h2></div></div></div><p>The “destination” parameter is used in a Spring <code class="literal">PathMatcher</code> (with the path separator
|
||||
as a colon — <code class="literal">:</code>) to determine if an instance processes the message. Using the example
|
||||
from earlier, <code class="literal">/bus-env/customers:**</code> targets all instances of the
|
||||
“customers” service regardless of the rest of the service ID.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__addressing_an_instance.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_bus.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__service_id_must_be_unique.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">44. Addressing an Instance </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 46. Service ID Must Be Unique</td></tr></table></div></body></html>
|
||||
12
Greenwich.RC2/multi/multi__addressing_an_instance.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>44. Addressing an Instance</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_bus.html" title="Part VII. Spring Cloud Bus"><link rel="prev" href="multi__bus_endpoints.html" title="43. Bus Endpoints"><link rel="next" href="multi__addressing_all_instances_of_a_service.html" title="45. Addressing All Instances of a Service"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">44. Addressing an Instance</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__bus_endpoints.html">Prev</a> </td><th width="60%" align="center">Part VII. Spring Cloud Bus</th><td width="20%" align="right"> <a accesskey="n" href="multi__addressing_all_instances_of_a_service.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_addressing_an_instance" href="#_addressing_an_instance"></a>44. Addressing an Instance</h2></div></div></div><p>Each instance of the application has a service ID, whose value can be set with
|
||||
<code class="literal">spring.cloud.bus.id</code> 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
|
||||
constructed from the environment as a combination of the <code class="literal">spring.application.name</code> and
|
||||
<code class="literal">server.port</code> (or <code class="literal">spring.application.index</code>, if set). The default value of the ID is
|
||||
constructed in the form of <code class="literal">app:index:id</code>, where:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">app</code> is the <code class="literal">vcap.application.name</code>, if it exists, or <code class="literal">spring.application.name</code></li><li class="listitem"><code class="literal">index</code> is the <code class="literal">vcap.application.instance_index</code>, if it exists,
|
||||
<code class="literal">spring.application.index</code>, <code class="literal">local.server.port</code>, <code class="literal">server.port</code>, or <code class="literal">0</code> (in that order).</li><li class="listitem"><code class="literal">id</code> is the <code class="literal">vcap.application.instance_id</code>, if it exists, or a random value.</li></ul></div><p>The HTTP endpoints accept a “destination” path parameter, such as
|
||||
<code class="literal">/bus-refresh/customers:9000</code>, where <code class="literal">destination</code> is a service ID. If the ID
|
||||
is owned by an instance on the bus, it processes the message, and all other instances
|
||||
ignore it.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__bus_endpoints.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_bus.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__addressing_all_instances_of_a_service.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">43. Bus Endpoints </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 45. Addressing All Instances of a Service</td></tr></table></div></body></html>
|
||||
311
Greenwich.RC2/multi/multi__apache_kafka_binder.html
Normal file
@@ -0,0 +1,311 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>39. Apache Kafka Binder</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__binder_implementations.html" title="Part VI. Binder Implementations"><link rel="prev" href="multi__binder_implementations.html" title="Part VI. Binder Implementations"><link rel="next" href="multi__apache_kafka_streams_binder.html" title="40. Apache Kafka Streams Binder"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">39. Apache Kafka Binder</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__binder_implementations.html">Prev</a> </td><th width="60%" align="center">Part VI. Binder Implementations</th><td width="20%" align="right"> <a accesskey="n" href="multi__apache_kafka_streams_binder.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_apache_kafka_binder" href="#_apache_kafka_binder"></a>39. Apache Kafka Binder</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_usage" href="#_usage"></a>39.1 Usage</h2></div></div></div><p>To use Apache Kafka binder, you need to add <code class="literal">spring-cloud-stream-binder-kafka</code> as a dependency to your Spring Cloud Stream application, as shown in the following example for Maven:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-stream-binder-kafka<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p>Alternatively, you can also use the Spring Cloud Stream Kafka Starter, as shown inn the following example for Maven:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-stream-kafka<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_apache_kafka_binder_overview" href="#_apache_kafka_binder_overview"></a>39.2 Apache Kafka Binder Overview</h2></div></div></div><p>The following image shows a simplified diagram of how the Apache Kafka binder operates:</p><div class="figure"><a name="d0e11855" href="#d0e11855"></a><p class="title"><b>Figure 39.1. Kafka Binder</b></p><div class="figure-contents"><div class="mediaobject"><img src="images/images/kafka-binder.png" alt="kafka binder"></div></div></div><br class="figure-break"><p>The Apache Kafka Binder implementation maps each destination to an Apache Kafka topic.
|
||||
The consumer group maps directly to the same Apache Kafka concept.
|
||||
Partitioning also maps directly to Apache Kafka partitions as well.</p><p>The binder currently uses the Apache Kafka <code class="literal">kafka-clients</code> 1.0.0 jar and is designed to be used with a broker of at least that version.
|
||||
This client can communicate with older brokers (see the Kafka documentation), but certain features may not be available.
|
||||
For example, with versions earlier than 0.11.x.x, native headers are not supported.
|
||||
Also, 0.11.x.x does not support the <code class="literal">autoAddPartitions</code> property.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_configuration_options_2" href="#_configuration_options_2"></a>39.3 Configuration Options</h2></div></div></div><p>This section contains the configuration options used by the Apache Kafka binder.</p><p>For common configuration options and properties pertaining to binder, see the <a class="link" href="multi__configuration_options.html#binding-properties" title="31.2 Binding Properties">core documentation</a>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_kafka_binder_properties" href="#_kafka_binder_properties"></a>39.3.1 Kafka Binder Properties</h3></div></div></div><div class="variablelist"><dl class="variablelist"><dt><span class="term">spring.cloud.stream.kafka.binder.brokers</span></dt><dd><p class="simpara">A list of brokers to which the Kafka binder connects.</p><p class="simpara">Default: <code class="literal">localhost</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.defaultBrokerPort</span></dt><dd><p class="simpara"><code class="literal">brokers</code> allows hosts specified with or without port information (for example, <code class="literal">host1,host2:port2</code>).
|
||||
This sets the default port when no port is configured in the broker list.</p><p class="simpara">Default: <code class="literal">9092</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.configuration</span></dt><dd><p class="simpara">Key/Value map of client properties (both producers and consumer) passed to all clients created by the binder.
|
||||
Due to the fact that these properties are used by both producers and consumers, usage should be restricted to common properties — for example, security settings.
|
||||
Properties here supersede any properties set in boot.</p><p class="simpara">Default: Empty map.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.consumerProperties</span></dt><dd><p class="simpara">Key/Value map of arbitrary Kafka client consumer properties.
|
||||
Properties here supersede any properties set in boot and in the <code class="literal">configuration</code> property above.</p><p class="simpara">Default: Empty map.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.headers</span></dt><dd><p class="simpara">The list of custom headers that are transported by the binder.
|
||||
Only required when communicating with older applications (⇐ 1.3.x) with a <code class="literal">kafka-clients</code> version < 0.11.0.0. Newer versions support headers natively.</p><p class="simpara">Default: empty.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.healthTimeout</span></dt><dd><p class="simpara">The time to wait to get partition information, in seconds.
|
||||
Health reports as down if this timer expires.</p><p class="simpara">Default: 10.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.requiredAcks</span></dt><dd><p class="simpara">The number of required acks on the broker.
|
||||
See the Kafka documentation for the producer <code class="literal">acks</code> property.</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.minPartitionCount</span></dt><dd><p class="simpara">Effective only if <code class="literal">autoCreateTopics</code> or <code class="literal">autoAddPartitions</code> is set.
|
||||
The global minimum number of partitions that the binder configures on topics on which it produces or consumes data.
|
||||
It can be superseded by the <code class="literal">partitionCount</code> setting of the producer or by the value of <code class="literal">instanceCount * concurrency</code> settings of the producer (if either is larger).</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.producerProperties</span></dt><dd><p class="simpara">Key/Value map of arbitrary Kafka client producer properties.
|
||||
Properties here supersede any properties set in boot and in the <code class="literal">configuration</code> property above.</p><p class="simpara">Default: Empty map.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.replicationFactor</span></dt><dd><p class="simpara">The replication factor of auto-created topics if <code class="literal">autoCreateTopics</code> is active.
|
||||
Can be overridden on each binding.</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.autoCreateTopics</span></dt><dd><p class="simpara">If set to <code class="literal">true</code>, the binder creates new topics automatically.
|
||||
If set to <code class="literal">false</code>, the binder relies on the topics being already configured.
|
||||
In the latter case, if the topics do not exist, the binder fails to start.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>This setting is independent of the <code class="literal">auto.topic.create.enable</code> setting of the broker and does not influence it.
|
||||
If the server is set to auto-create topics, they may be created as part of the metadata retrieval request, with default broker settings.</p></td></tr></table></div><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.autoAddPartitions</span></dt><dd><p class="simpara">If set to <code class="literal">true</code>, the binder creates new partitions if required.
|
||||
If set to <code class="literal">false</code>, the binder relies on the partition size of the topic being already configured.
|
||||
If the partition count of the target topic is smaller than the expected value, the binder fails to start.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.transaction.transactionIdPrefix</span></dt><dd><p class="simpara">Enables transactions in the binder. See <code class="literal">transaction.id</code> in the Kafka documentation and <a class="link" href="https://docs.spring.io/spring-kafka/reference/html/_reference.html#transactions" target="_top">Transactions</a> in the <code class="literal">spring-kafka</code> documentation.
|
||||
When transactions are enabled, individual <code class="literal">producer</code> properties are ignored and all producers use the <code class="literal">spring.cloud.stream.kafka.binder.transaction.producer.*</code> properties.</p><p class="simpara">Default <code class="literal">null</code> (no transactions)</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.transaction.producer.*</span></dt><dd><p class="simpara">Global producer properties for producers in a transactional binder.
|
||||
See <code class="literal">spring.cloud.stream.kafka.binder.transaction.transactionIdPrefix</code> and <a class="xref" href="multi__apache_kafka_binder.html#kafka-producer-properties" title="39.3.3 Kafka Producer Properties">Section 39.3.3, “Kafka Producer Properties”</a> and the general producer properties supported by all binders.</p><p class="simpara">Default: See individual producer properties.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.headerMapperBeanName</span></dt><dd><p class="simpara">The bean name of a <code class="literal">KafkaHeaderMapper</code> used for mapping <code class="literal">spring-messaging</code> headers to and from Kafka headers.
|
||||
Use this, for example, if you wish to customize the trusted packages in a <code class="literal">DefaultKafkaHeaderMapper</code> that uses JSON deserialization for the headers.</p><p class="simpara">Default: none.</p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="kafka-consumer-properties" href="#kafka-consumer-properties"></a>39.3.2 Kafka Consumer Properties</h3></div></div></div><p>The following properties are available for Kafka consumers only and
|
||||
must be prefixed with <code class="literal">spring.cloud.stream.kafka.bindings.<channelName>.consumer.</code>.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">admin.configuration</span></dt><dd><p class="simpara">A <code class="literal">Map</code> of Kafka topic properties used when provisioning topics — for example, <code class="literal">spring.cloud.stream.kafka.bindings.input.consumer.admin.configuration.message.format.version=0.9.0.0</code></p><p class="simpara">Default: none.</p></dd><dt><span class="term">admin.replicas-assignment</span></dt><dd><p class="simpara">A Map<Integer, List<Integer>> of replica assignments, with the key being the partition and the value being the assignments.
|
||||
Used when provisioning new topics.
|
||||
See the <code class="literal">NewTopic</code> Javadocs in the <code class="literal">kafka-clients</code> jar.</p><p class="simpara">Default: none.</p></dd><dt><span class="term">admin.replication-factor</span></dt><dd><p class="simpara">The replication factor to use when provisioning topics. Overrides the binder-wide setting.
|
||||
Ignored if <code class="literal">replicas-assignments</code> is present.</p><p class="simpara">Default: none (the binder-wide default of 1 is used).</p></dd><dt><span class="term">autoRebalanceEnabled</span></dt><dd><p class="simpara">When <code class="literal">true</code>, topic partitions is automatically rebalanced between the members of a consumer group.
|
||||
When <code class="literal">false</code>, each consumer is assigned a fixed set of partitions based on <code class="literal">spring.cloud.stream.instanceCount</code> and <code class="literal">spring.cloud.stream.instanceIndex</code>.
|
||||
This requires both the <code class="literal">spring.cloud.stream.instanceCount</code> and <code class="literal">spring.cloud.stream.instanceIndex</code> properties to be set appropriately on each launched instance.
|
||||
The value of the <code class="literal">spring.cloud.stream.instanceCount</code> property must typically be greater than 1 in this case.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">ackEachRecord</span></dt><dd><p class="simpara">When <code class="literal">autoCommitOffset</code> is <code class="literal">true</code>, this setting dictates whether to commit the offset after each record is processed.
|
||||
By default, offsets are committed after all records in the batch of records returned by <code class="literal">consumer.poll()</code> have been processed.
|
||||
The number of records returned by a poll can be controlled with the <code class="literal">max.poll.records</code> Kafka property, which is set through the consumer <code class="literal">configuration</code> property.
|
||||
Setting this to <code class="literal">true</code> may cause a degradation in performance, but doing so reduces the likelihood of redelivered records when a failure occurs.
|
||||
Also, see the binder <code class="literal">requiredAcks</code> property, which also affects the performance of committing offsets.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">autoCommitOffset</span></dt><dd><p class="simpara">Whether to autocommit offsets when a message has been processed.
|
||||
If set to <code class="literal">false</code>, a header with the key <code class="literal">kafka_acknowledgment</code> of the type <code class="literal">org.springframework.kafka.support.Acknowledgment</code> header is present in the inbound message.
|
||||
Applications may use this header for acknowledging messages.
|
||||
See the examples section for details.
|
||||
When this property is set to <code class="literal">false</code>, Kafka binder sets the ack mode to <code class="literal">org.springframework.kafka.listener.AbstractMessageListenerContainer.AckMode.MANUAL</code> and the application is responsible for acknowledging records.
|
||||
Also see <code class="literal">ackEachRecord</code>.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">autoCommitOnError</span></dt><dd><p class="simpara">Effective only if <code class="literal">autoCommitOffset</code> is set to <code class="literal">true</code>.
|
||||
If set to <code class="literal">false</code>, it suppresses auto-commits for messages that result in errors and commits only for successful messages. It allows a stream to automatically replay from the last successfully processed message, in case of persistent failures.
|
||||
If set to <code class="literal">true</code>, it always auto-commits (if auto-commit is enabled).
|
||||
If not set (the default), it effectively has the same value as <code class="literal">enableDlq</code>, auto-committing erroneous messages if they are sent to a DLQ and not committing them otherwise.</p><p class="simpara">Default: not set.</p></dd><dt><span class="term">resetOffsets</span></dt><dd><p class="simpara">Whether to reset offsets on the consumer to the value provided by startOffset.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">startOffset</span></dt><dd><p class="simpara">The starting offset for new groups.
|
||||
Allowed values: <code class="literal">earliest</code> and <code class="literal">latest</code>.
|
||||
If the consumer group is set explicitly for the consumer 'binding' (through <code class="literal">spring.cloud.stream.bindings.<channelName>.group</code>), 'startOffset' is set to <code class="literal">earliest</code>. Otherwise, it is set to <code class="literal">latest</code> for the <code class="literal">anonymous</code> consumer group.
|
||||
Also see <code class="literal">resetOffsets</code> (earlier in this list).</p><p class="simpara">Default: null (equivalent to <code class="literal">earliest</code>).</p></dd><dt><span class="term">enableDlq</span></dt><dd><p class="simpara">When set to true, it enables DLQ behavior for the consumer.
|
||||
By default, messages that result in errors are forwarded to a topic named <code class="literal">error.<destination>.<group></code>.
|
||||
The DLQ topic name can be configurable by setting the <code class="literal">dlqName</code> property.
|
||||
This provides an alternative option to the more common Kafka replay scenario for the case when the number of errors is relatively small and replaying the entire original topic may be too cumbersome.
|
||||
See <a class="xref" href="multi__apache_kafka_binder.html#kafka-dlq-processing" title="39.6 Dead-Letter Topic Processing">Section 39.6, “Dead-Letter Topic Processing”</a> processing for more information.
|
||||
Starting with version 2.0, messages sent to the DLQ topic are enhanced with the following headers: <code class="literal">x-original-topic</code>, <code class="literal">x-exception-message</code>, and <code class="literal">x-exception-stacktrace</code> as <code class="literal">byte[]</code>.
|
||||
<span class="strong"><strong>Not allowed when <code class="literal">destinationIsPattern</code> is <code class="literal">true</code>.</strong></span></p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">configuration</span></dt><dd><p class="simpara">Map with a key/value pair containing generic Kafka consumer properties.</p><p class="simpara">Default: Empty map.</p></dd><dt><span class="term">dlqName</span></dt><dd><p class="simpara">The name of the DLQ topic to receive the error messages.</p><p class="simpara">Default: null (If not specified, messages that result in errors are forwarded to a topic named <code class="literal">error.<destination>.<group></code>).</p></dd><dt><span class="term">dlqProducerProperties</span></dt><dd><p class="simpara">Using this, DLQ-specific producer properties can be set.
|
||||
All the properties available through kafka producer properties can be set through this property.</p><p class="simpara">Default: Default Kafka producer properties.</p></dd><dt><span class="term">standardHeaders</span></dt><dd><p class="simpara">Indicates which standard headers are populated by the inbound channel adapter.
|
||||
Allowed values: <code class="literal">none</code>, <code class="literal">id</code>, <code class="literal">timestamp</code>, or <code class="literal">both</code>.
|
||||
Useful if using native deserialization and the first component to receive a message needs an <code class="literal">id</code> (such as an aggregator that is configured to use a JDBC message store).</p><p class="simpara">Default: <code class="literal">none</code></p></dd><dt><span class="term">converterBeanName</span></dt><dd><p class="simpara">The name of a bean that implements <code class="literal">RecordMessageConverter</code>. Used in the inbound channel adapter to replace the default <code class="literal">MessagingMessageConverter</code>.</p><p class="simpara">Default: <code class="literal">null</code></p></dd><dt><span class="term">idleEventInterval</span></dt><dd><p class="simpara">The interval, in milliseconds, between events indicating that no messages have recently been received.
|
||||
Use an <code class="literal">ApplicationListener<ListenerContainerIdleEvent></code> to receive these events.
|
||||
See <a class="xref" href="multi__apache_kafka_binder.html#pause-resume" title="Example: Pausing and Resuming the Consumer">the section called “Example: Pausing and Resuming the Consumer”</a> for a usage example.</p><p class="simpara">Default: <code class="literal">30000</code></p></dd><dt><span class="term">destinationIsPattern</span></dt><dd><p class="simpara">When true, the destination is treated as a regular expression <code class="literal">Pattern</code> used to match topic names by the broker.
|
||||
When true, topics are not provisioned, and <code class="literal">enableDlq</code> is not allowed, because the binder does not know the topic names during the provisioning phase.
|
||||
Note, the time taken to detect new topics that match the pattern is controlled by the consumer property <code class="literal">metadata.max.age.ms</code>, which (at the time of writing) defaults to 300,000ms (5 minutes).
|
||||
This can be configured using the <code class="literal">configuration</code> property above.</p><p class="simpara">Default: <code class="literal">false</code></p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="kafka-producer-properties" href="#kafka-producer-properties"></a>39.3.3 Kafka Producer Properties</h3></div></div></div><p>The following properties are available for Kafka producers only and
|
||||
must be prefixed with <code class="literal">spring.cloud.stream.kafka.bindings.<channelName>.producer.</code>.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">admin.configuration</span></dt><dd><p class="simpara">A <code class="literal">Map</code> of Kafka topic properties used when provisioning new topics — for example, <code class="literal">spring.cloud.stream.kafka.bindings.input.consumer.admin.configuration.message.format.version=0.9.0.0</code></p><p class="simpara">Default: none.</p></dd><dt><span class="term">admin.replicas-assignment</span></dt><dd><p class="simpara">A Map<Integer, List<Integer>> of replica assignments, with the key being the partition and the value being the assignments.
|
||||
Used when provisioning new topics.
|
||||
See <code class="literal">NewTopic</code> javadocs in the <code class="literal">kafka-clients</code> jar.</p><p class="simpara">Default: none.</p></dd><dt><span class="term">admin.replication-factor</span></dt><dd><p class="simpara">The replication factor to use when provisioning new topics. Overrides the binder-wide setting.
|
||||
Ignored if <code class="literal">replicas-assignments</code> is present.</p><p class="simpara">Default: none (the binder-wide default of 1 is used).</p></dd><dt><span class="term">bufferSize</span></dt><dd><p class="simpara">Upper limit, in bytes, of how much data the Kafka producer attempts to batch before sending.</p><p class="simpara">Default: <code class="literal">16384</code>.</p></dd><dt><span class="term">sync</span></dt><dd><p class="simpara">Whether the producer is synchronous.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">batchTimeout</span></dt><dd><p class="simpara">How long the producer waits to allow more messages to accumulate in the same batch before sending the messages.
|
||||
(Normally, the producer does not wait at all and simply sends all the messages that accumulated while the previous send was in progress.) A non-zero value may increase throughput at the expense of latency.</p><p class="simpara">Default: <code class="literal">0</code>.</p></dd><dt><span class="term">messageKeyExpression</span></dt><dd><p class="simpara">A SpEL expression evaluated against the outgoing message used to populate the key of the produced Kafka message — for example, <code class="literal">headers['myKey']</code>.
|
||||
The payload cannot be used because, by the time this expression is evaluated, the payload is already in the form of a <code class="literal">byte[]</code>.</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">headerPatterns</span></dt><dd><p class="simpara">A comma-delimited list of simple patterns to match Spring messaging headers to be mapped to the Kafka <code class="literal">Headers</code> in the <code class="literal">ProducerRecord</code>.
|
||||
Patterns can begin or end with the wildcard character (asterisk).
|
||||
Patterns can be negated by prefixing with <code class="literal">!</code>.
|
||||
Matching stops after the first match (positive or negative).
|
||||
For example <code class="literal">!ask,as*</code> will pass <code class="literal">ash</code> but not <code class="literal">ask</code>.
|
||||
<code class="literal">id</code> and <code class="literal">timestamp</code> are never mapped.</p><p class="simpara">Default: <code class="literal">*</code> (all headers - except the <code class="literal">id</code> and <code class="literal">timestamp</code>)</p></dd><dt><span class="term">configuration</span></dt><dd><p class="simpara">Map with a key/value pair containing generic Kafka producer properties.</p><p class="simpara">Default: Empty map.</p></dd></dl></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The Kafka binder uses the <code class="literal">partitionCount</code> setting of the producer as a hint to create a topic with the given partition count (in conjunction with the <code class="literal">minPartitionCount</code>, the maximum of the two being the value being used).
|
||||
Exercise caution when configuring both <code class="literal">minPartitionCount</code> for a binder and <code class="literal">partitionCount</code> for an application, as the larger value is used.
|
||||
If a topic already exists with a smaller partition count and <code class="literal">autoAddPartitions</code> is disabled (the default), the binder fails to start.
|
||||
If a topic already exists with a smaller partition count and <code class="literal">autoAddPartitions</code> is enabled, new partitions are added.
|
||||
If a topic already exists with a larger number of partitions than the maximum of (<code class="literal">minPartitionCount</code> or <code class="literal">partitionCount</code>), the existing partition count is used.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_usage_examples" href="#_usage_examples"></a>39.3.4 Usage examples</h3></div></div></div><p>In this section, we show the use of the preceding properties for specific scenarios.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_example_setting_literal_autocommitoffset_literal_to_literal_false_literal_and_relying_on_manual_acking" href="#_example_setting_literal_autocommitoffset_literal_to_literal_false_literal_and_relying_on_manual_acking"></a>Example: Setting <code class="literal">autoCommitOffset</code> to <code class="literal">false</code> and Relying on Manual Acking</h4></div></div></div><p>This example illustrates how one may manually acknowledge offsets in a consumer application.</p><p>This example requires that <code class="literal">spring.cloud.stream.kafka.bindings.input.consumer.autoCommitOffset</code> be set to <code class="literal">false</code>.
|
||||
Use the corresponding input channel name for your example.</p><pre class="screen">@SpringBootApplication
|
||||
@EnableBinding(Sink.class)
|
||||
public class ManuallyAcknowdledgingConsumer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ManuallyAcknowdledgingConsumer.class, args);
|
||||
}
|
||||
|
||||
@StreamListener(Sink.INPUT)
|
||||
public void process(Message<?> message) {
|
||||
Acknowledgment acknowledgment = message.getHeaders().get(KafkaHeaders.ACKNOWLEDGMENT, Acknowledgment.class);
|
||||
if (acknowledgment != null) {
|
||||
System.out.println("Acknowledgment provided");
|
||||
acknowledgment.acknowledge();
|
||||
}
|
||||
}
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_example_security_configuration" href="#_example_security_configuration"></a>Example: Security Configuration</h4></div></div></div><p>Apache Kafka 0.9 supports secure connections between client and brokers.
|
||||
To take advantage of this feature, follow the guidelines in the <a class="link" href="http://kafka.apache.org/090/documentation.html#security_configclients" target="_top">Apache Kafka Documentation</a> as well as the Kafka 0.9 <a class="link" href="http://docs.confluent.io/2.0.0/kafka/security.html" target="_top">security guidelines from the Confluent documentation</a>.
|
||||
Use the <code class="literal">spring.cloud.stream.kafka.binder.configuration</code> option to set security properties for all clients created by the binder.</p><p>For example, to set <code class="literal">security.protocol</code> to <code class="literal">SASL_SSL</code>, set the following property:</p><pre class="screen">spring.cloud.stream.kafka.binder.configuration.security.protocol=SASL_SSL</pre><p>All the other security properties can be set in a similar manner.</p><p>When using Kerberos, follow the instructions in the <a class="link" href="http://kafka.apache.org/090/documentation.html#security_sasl_clientconfig" target="_top">reference documentation</a> for creating and referencing the JAAS configuration.</p><p>Spring Cloud Stream supports passing JAAS configuration information to the application by using a JAAS configuration file and using Spring Boot properties.</p><div class="section"><div class="titlepage"><div><div><h5 class="title"><a name="_using_jaas_configuration_files" href="#_using_jaas_configuration_files"></a>Using JAAS Configuration Files</h5></div></div></div><p>The JAAS and (optionally) krb5 file locations can be set for Spring Cloud Stream applications by using system properties.
|
||||
The following example shows how to launch a Spring Cloud Stream application with SASL and Kerberos by using a JAAS configuration file:</p><pre class="programlisting"> java -Djava.security.auth.login.config=/path.to/kafka_client_jaas.conf -jar log.jar \
|
||||
--spring.cloud.stream.kafka.binder.brokers=secure.server:<span class="hl-number">9092</span> \
|
||||
--spring.cloud.stream.bindings.input.destination=stream.ticktock \
|
||||
--spring.cloud.stream.kafka.binder.configuration.security.protocol=SASL_PLAINTEXT</pre></div><div class="section"><div class="titlepage"><div><div><h5 class="title"><a name="_using_spring_boot_properties" href="#_using_spring_boot_properties"></a>Using Spring Boot Properties</h5></div></div></div><p>As an alternative to having a JAAS configuration file, Spring Cloud Stream provides a mechanism for setting up the JAAS configuration for Spring Cloud Stream applications by using Spring Boot properties.</p><p>The following properties can be used to configure the login context of the Kafka client:</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">spring.cloud.stream.kafka.binder.jaas.loginModule</span></dt><dd><p class="simpara">The login module name. Not necessary to be set in normal cases.</p><p class="simpara">Default: <code class="literal">com.sun.security.auth.module.Krb5LoginModule</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.jaas.controlFlag</span></dt><dd><p class="simpara">The control flag of the login module.</p><p class="simpara">Default: <code class="literal">required</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.binder.jaas.options</span></dt><dd><p class="simpara">Map with a key/value pair containing the login module options.</p><p class="simpara">Default: Empty map.</p></dd></dl></div><p>The following example shows how to launch a Spring Cloud Stream application with SASL and Kerberos by using Spring Boot configuration properties:</p><pre class="programlisting"> java --spring.cloud.stream.kafka.binder.brokers=secure.server:<span class="hl-number">9092</span> \
|
||||
--spring.cloud.stream.bindings.input.destination=stream.ticktock \
|
||||
--spring.cloud.stream.kafka.binder.autoCreateTopics=false \
|
||||
--spring.cloud.stream.kafka.binder.configuration.security.protocol=SASL_PLAINTEXT \
|
||||
--spring.cloud.stream.kafka.binder.jaas.options.useKeyTab=true \
|
||||
--spring.cloud.stream.kafka.binder.jaas.options.storeKey=true \
|
||||
--spring.cloud.stream.kafka.binder.jaas.options.keyTab=/etc/security/keytabs/kafka_client.keytab \
|
||||
--spring.cloud.stream.kafka.binder.jaas.options.principal=kafka-client-<span class="hl-number">1</span>@EXAMPLE.COM</pre><p>The preceding example represents the equivalent of the following JAAS file:</p><pre class="screen">KafkaClient {
|
||||
com.sun.security.auth.module.Krb5LoginModule required
|
||||
useKeyTab=true
|
||||
storeKey=true
|
||||
keyTab="/etc/security/keytabs/kafka_client.keytab"
|
||||
principal="kafka-client-1@EXAMPLE.COM";
|
||||
};</pre><p>If the topics required already exist on the broker or will be created by an administrator, autocreation can be turned off and only client JAAS properties need to be sent.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Do not mix JAAS configuration files and Spring Boot properties in the same application.
|
||||
If the <code class="literal">-Djava.security.auth.login.config</code> system property is already present, Spring Cloud Stream ignores the Spring Boot properties.</p></td></tr></table></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Be careful when using the <code class="literal">autoCreateTopics</code> and <code class="literal">autoAddPartitions</code> with Kerberos.
|
||||
Usually, applications may use principals that do not have administrative rights in Kafka and Zookeeper.
|
||||
Consequently, relying on Spring Cloud Stream to create/modify topics may fail.
|
||||
In secure environments, we strongly recommend creating topics and managing ACLs administratively by using Kafka tooling.</p></td></tr></table></div></div></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="pause-resume" href="#pause-resume"></a>Example: Pausing and Resuming the Consumer</h4></div></div></div><p>If you wish to suspend consumption but not cause a partition rebalance, you can pause and resume the consumer.
|
||||
This is facilitated by adding the <code class="literal">Consumer</code> as a parameter to your <code class="literal">@StreamListener</code>.
|
||||
To resume, you need an <code class="literal">ApplicationListener</code> for <code class="literal">ListenerContainerIdleEvent</code> instances.
|
||||
The frequency at which events are published is controlled by the <code class="literal">idleEventInterval</code> property.
|
||||
Since the consumer is not thread-safe, you must call these methods on the calling thread.</p><p>The following simple application shows how to pause and resume:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Sink.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(Application.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Sink.INPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> in(String in, <em><span class="hl-annotation" style="color: gray">@Header(KafkaHeaders.CONSUMER)</span></em> Consumer<?, ?> consumer) {
|
||||
System.out.println(in);
|
||||
consumer.pause(Collections.singleton(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TopicPartition(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"myTopic"</span>, <span class="hl-number">0</span>)));
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> ApplicationListener<ListenerContainerIdleEvent> idleListener() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> event -> {
|
||||
System.out.println(event);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (event.getConsumer().paused().size() > <span class="hl-number">0</span>) {
|
||||
event.getConsumer().resume(event.getConsumer().paused());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}</pre></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="kafka-error-channels" href="#kafka-error-channels"></a>39.4 Error Channels</h2></div></div></div><p>Starting with version 1.3, the binder unconditionally sends exceptions to an error channel for each consumer destination and can also be configured to send async producer send failures to an error channel.
|
||||
See <a class="xref" href="multi__programming_model.html#spring-cloud-stream-overview-error-handling" title="29.4 Error Handling">Section 29.4, “Error Handling”</a> for more information.</p><p>The payload of the <code class="literal">ErrorMessage</code> for a send failure is a <code class="literal">KafkaSendFailureException</code> with properties:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">failedMessage</code>: The Spring Messaging <code class="literal">Message<?></code> that failed to be sent.</li><li class="listitem"><code class="literal">record</code>: The raw <code class="literal">ProducerRecord</code> that was created from the <code class="literal">failedMessage</code></li></ul></div><p>There is no automatic handling of producer exceptions (such as sending to a <a class="link" href="multi__apache_kafka_binder.html#kafka-dlq-processing" title="39.6 Dead-Letter Topic Processing">Dead-Letter queue</a>).
|
||||
You can consume these exceptions with your own Spring Integration flow.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="kafka-metrics" href="#kafka-metrics"></a>39.5 Kafka Metrics</h2></div></div></div><p>Kafka binder module exposes the following metrics:</p><p><code class="literal">spring.cloud.stream.binder.kafka.offset</code>: This metric indicates how many messages have not been yet consumed from a given binder’s topic by a given consumer group.
|
||||
The metrics provided are based on the Mircometer metrics library. The metric contains the consumer group information, topic and the actual lag in committed offset from the latest offset on the topic.
|
||||
This metric is particularly useful for providing auto-scaling feedback to a PaaS platform.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="kafka-dlq-processing" href="#kafka-dlq-processing"></a>39.6 Dead-Letter Topic Processing</h2></div></div></div><p>Because you cannot anticipate how users would want to dispose of dead-lettered messages, the framework does not provide any standard mechanism to handle them.
|
||||
If the reason for the dead-lettering is transient, you may wish to route the messages back to the original topic.
|
||||
However, if the problem is a permanent issue, that could cause an infinite loop.
|
||||
The sample Spring Boot application within this topic is an example of how to route those messages back to the original topic, but it moves them to a “parking lot” topic after three attempts.
|
||||
The application is another spring-cloud-stream application that reads from the dead-letter topic.
|
||||
It terminates when no messages are received for 5 seconds.</p><p>The examples assume the original destination is <code class="literal">so8400out</code> and the consumer group is <code class="literal">so8400</code>.</p><p>There are a couple of strategies to consider:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Consider running the rerouting only when the main application is not running.
|
||||
Otherwise, the retries for transient errors are used up very quickly.</li><li class="listitem">Alternatively, use a two-stage approach: Use this application to route to a third topic and another to route from there back to the main topic.</li></ul></div><p>The following code listings show the sample application:</p><p><b>application.properties. </b>
|
||||
</p><pre class="screen">spring.cloud.stream.bindings.input.group=so8400replay
|
||||
spring.cloud.stream.bindings.input.destination=error.so8400out.so8400
|
||||
|
||||
spring.cloud.stream.bindings.output.destination=so8400out
|
||||
spring.cloud.stream.bindings.output.producer.partitioned=true
|
||||
|
||||
spring.cloud.stream.bindings.parkingLot.destination=so8400in.parkingLot
|
||||
spring.cloud.stream.bindings.parkingLot.producer.partitioned=true
|
||||
|
||||
spring.cloud.stream.kafka.binder.configuration.auto.offset.reset=earliest
|
||||
|
||||
spring.cloud.stream.kafka.binder.headers=x-retries</pre><p>
|
||||
</p><p><b>Application. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(TwoOutputProcessor.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> ReRouteDlqKApplication <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">implements</span> CommandLineRunner {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String X_RETRIES_HEADER = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-retries"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(ReRouteDlqKApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args).close();
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> AtomicInteger processed = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> AtomicInteger();
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> MessageChannel parkingLot;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Processor.INPUT)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@SendTo(Processor.OUTPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Message<?> reRoute(Message<?> failed) {
|
||||
processed.incrementAndGet();
|
||||
Integer retries = failed.getHeaders().get(X_RETRIES_HEADER, Integer.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (retries == null) {
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"First retry for "</span> + failed);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> MessageBuilder.fromMessage(failed)
|
||||
.setHeader(X_RETRIES_HEADER, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Integer(<span class="hl-number">1</span>))
|
||||
.setHeader(BinderHeaders.PARTITION_OVERRIDE,
|
||||
failed.getHeaders().get(KafkaHeaders.RECEIVED_PARTITION_ID))
|
||||
.build();
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">else</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (retries.intValue() < <span class="hl-number">3</span>) {
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Another retry for "</span> + failed);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> MessageBuilder.fromMessage(failed)
|
||||
.setHeader(X_RETRIES_HEADER, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Integer(retries.intValue() + <span class="hl-number">1</span>))
|
||||
.setHeader(BinderHeaders.PARTITION_OVERRIDE,
|
||||
failed.getHeaders().get(KafkaHeaders.RECEIVED_PARTITION_ID))
|
||||
.build();
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">else</span> {
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Retries exhausted for "</span> + failed);
|
||||
parkingLot.send(MessageBuilder.fromMessage(failed)
|
||||
.setHeader(BinderHeaders.PARTITION_OVERRIDE,
|
||||
failed.getHeaders().get(KafkaHeaders.RECEIVED_PARTITION_ID))
|
||||
.build());
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> null;
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> run(String... args) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">while</span> (true) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">int</span> count = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.processed.get();
|
||||
Thread.sleep(<span class="hl-number">5000</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (count == <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.processed.get()) {
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Idle, terminating"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> TwoOutputProcessor <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> Processor {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Output("parkingLot")</span></em>
|
||||
MessageChannel parkingLot();
|
||||
|
||||
}
|
||||
|
||||
}</pre><p>
|
||||
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_partitioning_with_the_kafka_binder" href="#_partitioning_with_the_kafka_binder"></a>39.7 Partitioning with the Kafka Binder</h2></div></div></div><p>Apache Kafka supports topic partitioning natively.</p><p>Sometimes it is advantageous to send data to specific partitions — for example, when you want to strictly order message processing (all messages for a particular customer should go to the same partition).</p><p>The following example shows how to configure the producer and consumer side:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Source.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> KafkaPartitionProducerApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> Random RANDOM = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Random(System.currentTimeMillis());
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String[] data = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> String[] {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo1"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"bar1"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"qux1"</span>,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo2"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"bar2"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"qux2"</span>,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo3"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"bar3"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"qux3"</span>,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo4"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"bar4"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"qux4"</span>,
|
||||
};
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> SpringApplicationBuilder(KafkaPartitionProducerApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>)
|
||||
.web(false)
|
||||
.run(args);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@InboundChannelAdapter(channel = Source.OUTPUT, poller = @Poller(fixedRate = "5000"))</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Message<?> generate() {
|
||||
String value = data[RANDOM.nextInt(data.length)];
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Sending: "</span> + value);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> MessageBuilder.withPayload(value)
|
||||
.setHeader(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"partitionKey"</span>, value)
|
||||
.build();
|
||||
}
|
||||
|
||||
}</pre><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> stream</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> bindings</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> output</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> destination</span>: partitioned.topic
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> producer</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> partitioned</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">true</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> partition-key-expression</span>: headers[<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'partitionKey'</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> partition-count</span>: <span class="hl-number">12</span></pre><p>
|
||||
</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>The topic must be provisioned to have enough partitions to achieve the desired concurrency for all consumer groups.
|
||||
The above configuration supports up to 12 consumer instances (6 if their <code class="literal">concurrency</code> is 2, 4 if their concurrency is 3, and so on).
|
||||
It is generally best to “over-provision” the partitions to allow for future increases in consumers or concurrency.</p></td></tr></table></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The preceding configuration uses the default partitioning (<code class="literal">key.hashCode() % partitionCount</code>).
|
||||
This may or may not provide a suitably balanced algorithm, depending on the key values.
|
||||
You can override this default by using the <code class="literal">partitionSelectorExpression</code> or <code class="literal">partitionSelectorClass</code> properties.</p></td></tr></table></div><p>Since partitions are natively handled by Kafka, no special configuration is needed on the consumer side.
|
||||
Kafka allocates partitions across the instances.</p><p>The following Spring Boot application listens to a Kafka stream and prints (to the console) the partition ID to which each message goes:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Sink.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> KafkaPartitionConsumerApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> SpringApplicationBuilder(KafkaPartitionConsumerApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>)
|
||||
.web(false)
|
||||
.run(args);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Sink.INPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> listen(<em><span class="hl-annotation" style="color: gray">@Payload</span></em> String in, <em><span class="hl-annotation" style="color: gray">@Header(KafkaHeaders.RECEIVED_PARTITION_ID)</span></em> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">int</span> partition) {
|
||||
System.out.println(in + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">" received from partition "</span> + partition);
|
||||
}
|
||||
|
||||
}</pre><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> stream</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> bindings</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> input</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> destination</span>: partitioned.topic
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> group</span>: myGroup</pre><p>
|
||||
</p><p>You can add instances as needed.
|
||||
Kafka rebalances the partition allocations.
|
||||
If the instance count (or <code class="literal">instance count * concurrency</code>) exceeds the number of partitions, some consumers are idle.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__binder_implementations.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__binder_implementations.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__apache_kafka_streams_binder.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part VI. Binder Implementations </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 40. Apache Kafka Streams Binder</td></tr></table></div></body></html>
|
||||
276
Greenwich.RC2/multi/multi__apache_kafka_streams_binder.html
Normal file
@@ -0,0 +1,276 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>40. Apache Kafka Streams Binder</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__binder_implementations.html" title="Part VI. Binder Implementations"><link rel="prev" href="multi__apache_kafka_binder.html" title="39. Apache Kafka Binder"><link rel="next" href="multi__rabbitmq_binder.html" title="41. RabbitMQ Binder"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">40. Apache Kafka Streams Binder</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__apache_kafka_binder.html">Prev</a> </td><th width="60%" align="center">Part VI. Binder Implementations</th><td width="20%" align="right"> <a accesskey="n" href="multi__rabbitmq_binder.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_apache_kafka_streams_binder" href="#_apache_kafka_streams_binder"></a>40. Apache Kafka Streams Binder</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_usage_2" href="#_usage_2"></a>40.1 Usage</h2></div></div></div><p>For using the Kafka Streams binder, you just need to add it to your Spring Cloud Stream application, using the following
|
||||
Maven coordinates:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-stream-binder-kafka-streams<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_kafka_streams_binder_overview" href="#_kafka_streams_binder_overview"></a>40.2 Kafka Streams Binder Overview</h2></div></div></div><p>Spring Cloud Stream’s Apache Kafka support also includes a binder implementation designed explicitly for Apache Kafka
|
||||
Streams binding. With this native integration, a Spring Cloud Stream "processor" application can directly use the
|
||||
<a class="link" href="https://kafka.apache.org/documentation/streams/developer-guide" target="_top">Apache Kafka Streams</a> APIs in the core business logic.</p><p>Kafka Streams binder implementation builds on the foundation provided by the <a class="link" href="http://docs.spring.io/spring-kafka/reference/html/_reference.html#kafka-streams" target="_top">Kafka Streams in Spring Kafka</a>
|
||||
project.</p><p>Kafka Streams binder provides binding capabilities for the three major types in Kafka Streams - KStream, KTable and GlobalKTable.</p><p>As part of this native integration, the high-level <a class="link" href="https://docs.confluent.io/current/streams/developer-guide/dsl-api.html" target="_top">Streams DSL</a>
|
||||
provided by the Kafka Streams API is available for use in the business logic.</p><p>An early version of the <a class="link" href="https://docs.confluent.io/current/streams/developer-guide/processor-api.html" target="_top">Processor API</a>
|
||||
support is available as well.</p><p>As noted early-on, Kafka Streams support in Spring Cloud Stream is strictly only available for use in the Processor model.
|
||||
A model in which the messages read from an inbound topic, business processing can be applied, and the transformed messages
|
||||
can be written to an outbound topic. It can also be used in Processor applications with a no-outbound destination.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_streams_dsl" href="#_streams_dsl"></a>40.2.1 Streams DSL</h3></div></div></div><p>This application consumes data from a Kafka topic (e.g., <code class="literal">words</code>), computes word count for each unique word in a 5 seconds
|
||||
time window, and the computed results are sent to a downstream topic (e.g., <code class="literal">counts</code>) for further processing.</p><pre class="screen">@SpringBootApplication
|
||||
@EnableBinding(KStreamProcessor.class)
|
||||
public class WordCountProcessorApplication {
|
||||
|
||||
@StreamListener("input")
|
||||
@SendTo("output")
|
||||
public KStream<?, WordCount> process(KStream<?, String> input) {
|
||||
return input
|
||||
.flatMapValues(value -> Arrays.asList(value.toLowerCase().split("\\W+")))
|
||||
.groupBy((key, value) -> value)
|
||||
.windowedBy(TimeWindows.of(5000))
|
||||
.count(Materialized.as("WordCounts-multi"))
|
||||
.toStream()
|
||||
.map((key, value) -> new KeyValue<>(null, new WordCount(key.key(), value, new Date(key.window().start()), new Date(key.window().end()))));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(WordCountProcessorApplication.class, args);
|
||||
}</pre><p>Once built as a uber-jar (e.g., <code class="literal">wordcount-processor.jar</code>), you can run the above example like the following.</p><pre class="screen">java -jar wordcount-processor.jar --spring.cloud.stream.bindings.input.destination=words --spring.cloud.stream.bindings.output.destination=counts</pre><p>This application will consume messages from the Kafka topic <code class="literal">words</code> and the computed results are published to an output
|
||||
topic <code class="literal">counts</code>.</p><p>Spring Cloud Stream will ensure that the messages from both the incoming and outgoing topics are automatically bound as
|
||||
KStream objects. As a developer, you can exclusively focus on the business aspects of the code, i.e. writing the logic
|
||||
required in the processor. Setting up the Streams DSL specific configuration required by the Kafka Streams infrastructure
|
||||
is automatically handled by the framework.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_configuration_options_3" href="#_configuration_options_3"></a>40.3 Configuration Options</h2></div></div></div><p>This section contains the configuration options used by the Kafka Streams binder.</p><p>For common configuration options and properties pertaining to binder, refer to the <a class="link" href="multi__configuration_options.html#binding-properties" title="31.2 Binding Properties">core documentation</a>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_kafka_streams_properties" href="#_kafka_streams_properties"></a>40.3.1 Kafka Streams Properties</h3></div></div></div><p>The following properties are available at the binder level and must be prefixed with <code class="literal">spring.cloud.stream.kafka.streams.binder.</code>
|
||||
literal.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">configuration</span></dt><dd> Map with a key/value pair containing properties pertaining to Apache Kafka Streams API.
|
||||
This property must be prefixed with <code class="literal">spring.cloud.stream.kafka.streams.binder.</code>.
|
||||
Following are some examples of using this property.</dd></dl></div><pre class="screen">spring.cloud.stream.kafka.streams.binder.configuration.default.key.serde=org.apache.kafka.common.serialization.Serdes$StringSerde
|
||||
spring.cloud.stream.kafka.streams.binder.configuration.default.value.serde=org.apache.kafka.common.serialization.Serdes$StringSerde
|
||||
spring.cloud.stream.kafka.streams.binder.configuration.commit.interval.ms=1000</pre><p>For more information about all the properties that may go into streams configuration, see StreamsConfig JavaDocs in
|
||||
Apache Kafka Streams docs.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">brokers</span></dt><dd><p class="simpara">Broker URL</p><p class="simpara">Default: <code class="literal">localhost</code></p></dd><dt><span class="term">zkNodes</span></dt><dd><p class="simpara">Zookeeper URL</p><p class="simpara">Default: <code class="literal">localhost</code></p></dd><dt><span class="term">serdeError</span></dt><dd><p class="simpara">Deserialization error handler type.
|
||||
Possible values are - <code class="literal">logAndContinue</code>, <code class="literal">logAndFail</code> or <code class="literal">sendToDlq</code></p><p class="simpara">Default: <code class="literal">logAndFail</code></p></dd><dt><span class="term">applicationId</span></dt><dd><p class="simpara">Convenient way to set the application.id for the Kafka Streams application globally at the binder level.
|
||||
If the application contains multiple <code class="literal">StreamListener</code> methods, then application.id should be set at the binding level per input binding.</p><p class="simpara">Default: <code class="literal">none</code></p></dd></dl></div><p>The following properties are <span class="emphasis"><em>only</em></span> available for Kafka Streams producers and must be prefixed with <code class="literal">spring.cloud.stream.kafka.streams.bindings.<binding name>.producer.</code> literal.
|
||||
For convenience, if there multiple output bindings and they all require a common value, that can be configured by using the prefix <code class="literal">spring.cloud.stream.kafka.streams.default.producer.</code>.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">keySerde</span></dt><dd><p class="simpara">key serde to use</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">valueSerde</span></dt><dd><p class="simpara">value serde to use</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">useNativeEncoding</span></dt><dd><p class="simpara">flag to enable native encoding</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd></dl></div><p>The following properties are <span class="emphasis"><em>only</em></span> available for Kafka Streams consumers and must be prefixed with <code class="literal">spring.cloud.stream.kafka.streams.bindings.<binding name>.consumer.`literal.
|
||||
For convenience, if there multiple input bindings and they all require a common value, that can be configured by using the prefix `spring.cloud.stream.kafka.streams.default.consumer.</code>.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">applicationId</span></dt><dd><p class="simpara">Setting application.id per input binding.</p><p class="simpara">Default: <code class="literal">none</code></p></dd><dt><span class="term">keySerde</span></dt><dd><p class="simpara">key serde to use</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">valueSerde</span></dt><dd><p class="simpara">value serde to use</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">materializedAs</span></dt><dd><p class="simpara">state store to materialize when using incoming KTable types</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">useNativeDecoding</span></dt><dd><p class="simpara">flag to enable native decoding</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">dlqName</span></dt><dd><p class="simpara">DLQ topic name.</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_timewindow_properties" href="#_timewindow_properties"></a>40.3.2 TimeWindow properties:</h3></div></div></div><p>Windowing is an important concept in stream processing applications. Following properties are available to configure
|
||||
time-window computations.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">spring.cloud.stream.kafka.streams.timeWindow.length</span></dt><dd><p class="simpara">When this property is given, you can autowire a <code class="literal">TimeWindows</code> bean into the application.
|
||||
The value is expressed in milliseconds.</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd><dt><span class="term">spring.cloud.stream.kafka.streams.timeWindow.advanceBy</span></dt><dd><p class="simpara">Value is given in milliseconds.</p><p class="simpara">Default: <code class="literal">none</code>.</p></dd></dl></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_multiple_input_bindings" href="#_multiple_input_bindings"></a>40.4 Multiple Input Bindings</h2></div></div></div><p>For use cases that requires multiple incoming KStream objects or a combination of KStream and KTable objects, the Kafka
|
||||
Streams binder provides multiple bindings support.</p><p>Let’s see it in action.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_multiple_input_bindings_as_a_sink" href="#_multiple_input_bindings_as_a_sink"></a>40.4.1 Multiple Input Bindings as a Sink</h3></div></div></div><pre class="screen">@EnableBinding(KStreamKTableBinding.class)
|
||||
.....
|
||||
.....
|
||||
@StreamListener
|
||||
public void process(@Input("inputStream") KStream<String, PlayEvent> playEvents,
|
||||
@Input("inputTable") KTable<Long, Song> songTable) {
|
||||
....
|
||||
....
|
||||
}
|
||||
|
||||
interface KStreamKTableBinding {
|
||||
|
||||
@Input("inputStream")
|
||||
KStream<?, ?> inputStream();
|
||||
|
||||
@Input("inputTable")
|
||||
KTable<?, ?> inputTable();
|
||||
}</pre><p>In the above example, the application is written as a sink, i.e. there are no output bindings and the application has to
|
||||
decide concerning downstream processing. When you write applications in this style, you might want to send the information
|
||||
downstream or store them in a state store (See below for Queryable State Stores).</p><p>In the case of incoming KTable, if you want to materialize the computations to a state store, you have to express it
|
||||
through the following property.</p><pre class="screen">spring.cloud.stream.kafka.streams.bindings.inputTable.consumer.materializedAs: all-songs</pre><p>The above example shows the use of KTable as an input binding.
|
||||
The binder also supports input bindings for GlobalKTable.
|
||||
GlobalKTable binding is useful when you have to ensure that all instances of your application has access to the data updates from the topic.
|
||||
KTable and GlobalKTable bindings are only available on the input.
|
||||
Binder supports both input and output bindings for KStream.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_multiple_input_bindings_as_a_processor" href="#_multiple_input_bindings_as_a_processor"></a>40.4.2 Multiple Input Bindings as a Processor</h3></div></div></div><pre class="screen">@EnableBinding(KStreamKTableBinding.class)
|
||||
....
|
||||
....
|
||||
|
||||
@StreamListener
|
||||
@SendTo("output")
|
||||
public KStream<String, Long> process(@Input("input") KStream<String, Long> userClicksStream,
|
||||
@Input("inputTable") KTable<String, String> userRegionsTable) {
|
||||
....
|
||||
....
|
||||
}
|
||||
|
||||
interface KStreamKTableBinding extends KafkaStreamsProcessor {
|
||||
|
||||
@Input("inputX")
|
||||
KTable<?, ?> inputTable();
|
||||
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_multiple_output_bindings_aka_branching" href="#_multiple_output_bindings_aka_branching"></a>40.5 Multiple Output Bindings (aka Branching)</h2></div></div></div><p>Kafka Streams allow outbound data to be split into multiple topics based on some predicates. The Kafka Streams binder provides
|
||||
support for this feature without compromising the programming model exposed through <code class="literal">StreamListener</code> in the end user application.</p><p>You can write the application in the usual way as demonstrated above in the word count example. However, when using the
|
||||
branching feature, you are required to do a few things. First, you need to make sure that your return type is <code class="literal">KStream[]</code>
|
||||
instead of a regular <code class="literal">KStream</code>. Second, you need to use the <code class="literal">SendTo</code> annotation containing the output bindings in the order
|
||||
(see example below). For each of these output bindings, you need to configure destination, content-type etc., complying with
|
||||
the standard Spring Cloud Stream expectations.</p><p>Here is an example:</p><pre class="screen">@EnableBinding(KStreamProcessorWithBranches.class)
|
||||
@EnableAutoConfiguration
|
||||
public static class WordCountProcessorApplication {
|
||||
|
||||
@Autowired
|
||||
private TimeWindows timeWindows;
|
||||
|
||||
@StreamListener("input")
|
||||
@SendTo({"output1","output2","output3})
|
||||
public KStream<?, WordCount>[] process(KStream<Object, String> input) {
|
||||
|
||||
Predicate<Object, WordCount> isEnglish = (k, v) -> v.word.equals("english");
|
||||
Predicate<Object, WordCount> isFrench = (k, v) -> v.word.equals("french");
|
||||
Predicate<Object, WordCount> isSpanish = (k, v) -> v.word.equals("spanish");
|
||||
|
||||
return input
|
||||
.flatMapValues(value -> Arrays.asList(value.toLowerCase().split("\\W+")))
|
||||
.groupBy((key, value) -> value)
|
||||
.windowedBy(timeWindows)
|
||||
.count(Materialized.as("WordCounts-1"))
|
||||
.toStream()
|
||||
.map((key, value) -> new KeyValue<>(null, new WordCount(key.key(), value, new Date(key.window().start()), new Date(key.window().end()))))
|
||||
.branch(isEnglish, isFrench, isSpanish);
|
||||
}
|
||||
|
||||
interface KStreamProcessorWithBranches {
|
||||
|
||||
@Input("input")
|
||||
KStream<?, ?> input();
|
||||
|
||||
@Output("output1")
|
||||
KStream<?, ?> output1();
|
||||
|
||||
@Output("output2")
|
||||
KStream<?, ?> output2();
|
||||
|
||||
@Output("output3")
|
||||
KStream<?, ?> output3();
|
||||
}
|
||||
}</pre><p>Properties:</p><pre class="screen">spring.cloud.stream.bindings.output1.contentType: application/json
|
||||
spring.cloud.stream.bindings.output2.contentType: application/json
|
||||
spring.cloud.stream.bindings.output3.contentType: application/json
|
||||
spring.cloud.stream.kafka.streams.binder.configuration.commit.interval.ms: 1000
|
||||
spring.cloud.stream.kafka.streams.binder.configuration:
|
||||
default.key.serde: org.apache.kafka.common.serialization.Serdes$StringSerde
|
||||
default.value.serde: org.apache.kafka.common.serialization.Serdes$StringSerde
|
||||
spring.cloud.stream.bindings.output1:
|
||||
destination: foo
|
||||
producer:
|
||||
headerMode: raw
|
||||
spring.cloud.stream.bindings.output2:
|
||||
destination: bar
|
||||
producer:
|
||||
headerMode: raw
|
||||
spring.cloud.stream.bindings.output3:
|
||||
destination: fox
|
||||
producer:
|
||||
headerMode: raw
|
||||
spring.cloud.stream.bindings.input:
|
||||
destination: words
|
||||
consumer:
|
||||
headerMode: raw</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_message_conversion" href="#_message_conversion"></a>40.6 Message Conversion</h2></div></div></div><p>Similar to message-channel based binder applications, the Kafka Streams binder adapts to the out-of-the-box content-type
|
||||
conversions without any compromise.</p><p>It is typical for Kafka Streams operations to know the type of SerDe’s used to transform the key and value correctly.
|
||||
Therefore, it may be more natural to rely on the SerDe facilities provided by the Apache Kafka Streams library itself at
|
||||
the inbound and outbound conversions rather than using the content-type conversions offered by the framework.
|
||||
On the other hand, you might be already familiar with the content-type conversion patterns provided by the framework, and
|
||||
that, you’d like to continue using for inbound and outbound conversions.</p><p>Both the options are supported in the Kafka Streams binder implementation.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_outbound_serialization" href="#_outbound_serialization"></a>40.6.1 Outbound serialization</h3></div></div></div><p>If native encoding is disabled (which is the default), then the framework will convert the message using the contentType
|
||||
set by the user (otherwise, the default <code class="literal">application/json</code> will be applied). It will ignore any SerDe set on the outbound
|
||||
in this case for outbound serialization.</p><p>Here is the property to set the contentType on the outbound.</p><pre class="screen">spring.cloud.stream.bindings.output.contentType: application/json</pre><p>Here is the property to enable native encoding.</p><pre class="screen">spring.cloud.stream.bindings.output.nativeEncoding: true</pre><p>If native encoding is enabled on the output binding (user has to enable it as above explicitly), then the framework will
|
||||
skip any form of automatic message conversion on the outbound. In that case, it will switch to the Serde set by the user.
|
||||
The <code class="literal">valueSerde</code> property set on the actual output binding will be used. Here is an example.</p><pre class="screen">spring.cloud.stream.kafka.streams.bindings.output.producer.valueSerde: org.apache.kafka.common.serialization.Serdes$StringSerde</pre><p>If this property is not set, then it will use the "default" SerDe: <code class="literal">spring.cloud.stream.kafka.streams.binder.configuration.default.value.serde</code>.</p><p>It is worth to mention that Kafka Streams binder does not serialize the keys on outbound - it simply relies on Kafka itself.
|
||||
Therefore, you either have to specify the <code class="literal">keySerde</code> property on the binding or it will default to the application-wide common
|
||||
<code class="literal">keySerde</code>.</p><p>Binding level key serde:</p><pre class="screen">spring.cloud.stream.kafka.streams.bindings.output.producer.keySerde</pre><p>Common Key serde:</p><pre class="screen">spring.cloud.stream.kafka.streams.binder.configuration.default.key.serde</pre><p>If branching is used, then you need to use multiple output bindings. For example,</p><pre class="screen">interface KStreamProcessorWithBranches {
|
||||
|
||||
@Input("input")
|
||||
KStream<?, ?> input();
|
||||
|
||||
@Output("output1")
|
||||
KStream<?, ?> output1();
|
||||
|
||||
@Output("output2")
|
||||
KStream<?, ?> output2();
|
||||
|
||||
@Output("output3")
|
||||
KStream<?, ?> output3();
|
||||
}</pre><p>If <code class="literal">nativeEncoding</code> is set, then you can set different SerDe’s on individual output bindings as below.</p><pre class="screen">spring.cloud.stream.kafka.streams.bindings.output1.producer.valueSerde=IntegerSerde
|
||||
spring.cloud.stream.kafka.streams.bindings.output2.producer.valueSerde=StringSerde
|
||||
spring.cloud.stream.kafka.streams.bindings.output3.producer.valueSerde=JsonSerde</pre><p>Then if you have <code class="literal">SendTo</code> like this, @SendTo({"output1", "output2", "output3"}), the <code class="literal">KStream[]</code> from the branches are
|
||||
applied with proper SerDe objects as defined above. If you are not enabling <code class="literal">nativeEncoding</code>, you can then set different
|
||||
contentType values on the output bindings as below. In that case, the framework will use the appropriate message converter
|
||||
to convert the messages before sending to Kafka.</p><pre class="screen">spring.cloud.stream.bindings.output1.contentType: application/json
|
||||
spring.cloud.stream.bindings.output2.contentType: application/java-serialzied-object
|
||||
spring.cloud.stream.bindings.output3.contentType: application/octet-stream</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_inbound_deserialization" href="#_inbound_deserialization"></a>40.6.2 Inbound Deserialization</h3></div></div></div><p>Similar rules apply to data deserialization on the inbound.</p><p>If native decoding is disabled (which is the default), then the framework will convert the message using the contentType
|
||||
set by the user (otherwise, the default <code class="literal">application/json</code> will be applied). It will ignore any SerDe set on the inbound
|
||||
in this case for inbound deserialization.</p><p>Here is the property to set the contentType on the inbound.</p><pre class="screen">spring.cloud.stream.bindings.input.contentType: application/json</pre><p>Here is the property to enable native decoding.</p><pre class="screen">spring.cloud.stream.bindings.input.nativeDecoding: true</pre><p>If native decoding is enabled on the input binding (user has to enable it as above explicitly), then the framework will
|
||||
skip doing any message conversion on the inbound. In that case, it will switch to the SerDe set by the user. The <code class="literal">valueSerde</code>
|
||||
property set on the actual output binding will be used. Here is an example.</p><pre class="screen">spring.cloud.stream.kafka.streams.bindings.input.consumer.valueSerde: org.apache.kafka.common.serialization.Serdes$StringSerde</pre><p>If this property is not set, it will use the default SerDe: <code class="literal">spring.cloud.stream.kafka.streams.binder.configuration.default.value.serde</code>.</p><p>It is worth to mention that Kafka Streams binder does not deserialize the keys on inbound - it simply relies on Kafka itself.
|
||||
Therefore, you either have to specify the <code class="literal">keySerde</code> property on the binding or it will default to the application-wide common
|
||||
<code class="literal">keySerde</code>.</p><p>Binding level key serde:</p><pre class="screen">spring.cloud.stream.kafka.streams.bindings.input.consumer.keySerde</pre><p>Common Key serde:</p><pre class="screen">spring.cloud.stream.kafka.streams.binder.configuration.default.key.serde</pre><p>As in the case of KStream branching on the outbound, the benefit of setting value SerDe per binding is that if you have
|
||||
multiple input bindings (multiple KStreams object) and they all require separate value SerDe’s, then you can configure
|
||||
them individually. If you use the common configuration approach, then this feature won’t be applicable.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_error_handling" href="#_error_handling"></a>40.7 Error Handling</h2></div></div></div><p>Apache Kafka Streams provide the capability for natively handling exceptions from deserialization errors.
|
||||
For details on this support, please see <a class="link" href="https://cwiki.apache.org/confluence/display/KAFKA/KIP-161%3A+streams+deserialization+exception+handlers" target="_top">this</a>
|
||||
Out of the box, Apache Kafka Streams provide two kinds of deserialization exception handlers - <code class="literal">logAndContinue</code> and <code class="literal">logAndFail</code>.
|
||||
As the name indicates, the former will log the error and continue processing the next records and the latter will log the
|
||||
error and fail. <code class="literal">LogAndFail</code> is the default deserialization exception handler.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_handling_deserialization_exceptions" href="#_handling_deserialization_exceptions"></a>40.7.1 Handling Deserialization Exceptions</h3></div></div></div><p>Kafka Streams binder supports a selection of exception handlers through the following properties.</p><pre class="screen">spring.cloud.stream.kafka.streams.binder.serdeError: logAndContinue</pre><p>In addition to the above two deserialization exception handlers, the binder also provides a third one for sending the erroneous
|
||||
records (poison pills) to a DLQ topic. Here is how you enable this DLQ exception handler.</p><pre class="screen">spring.cloud.stream.kafka.streams.binder.serdeError: sendToDlq</pre><p>When the above property is set, all the deserialization error records are automatically sent to the DLQ topic.</p><pre class="screen">spring.cloud.stream.kafka.streams.bindings.input.consumer.dlqName: foo-dlq</pre><p>If this is set, then the error records are sent to the topic <code class="literal">foo-dlq</code>. If this is not set, then it will create a DLQ
|
||||
topic with the name <code class="literal">error.<input-topic-name>.<group-name></code>.</p><p>A couple of things to keep in mind when using the exception handling feature in Kafka Streams binder.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">The property <code class="literal">spring.cloud.stream.kafka.streams.binder.serdeError</code> is applicable for the entire application. This implies
|
||||
that if there are multiple <code class="literal">StreamListener</code> methods in the same application, this property is applied to all of them.</li><li class="listitem">The exception handling for deserialization works consistently with native deserialization and framework provided message
|
||||
conversion.</li></ul></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_handling_non_deserialization_exceptions" href="#_handling_non_deserialization_exceptions"></a>40.7.2 Handling Non-Deserialization Exceptions</h3></div></div></div><p>For general error handling in Kafka Streams binder, it is up to the end user applications to handle application level errors.
|
||||
As a side effect of providing a DLQ for deserialization exception handlers, Kafka Streams binder provides a way to get
|
||||
access to the DLQ sending bean directly from your application.
|
||||
Once you get access to that bean, you can programmatically send any exception records from your application to the DLQ.</p><p>It continues to remain hard to robust error handling using the high-level DSL; Kafka Streams doesn’t natively support error
|
||||
handling yet.</p><p>However, when you use the low-level Processor API in your application, there are options to control this behavior. See
|
||||
below.</p><pre class="screen">@Autowired
|
||||
private SendToDlqAndContinue dlqHandler;
|
||||
|
||||
@StreamListener("input")
|
||||
@SendTo("output")
|
||||
public KStream<?, WordCount> process(KStream<Object, String> input) {
|
||||
|
||||
input.process(() -> new Processor() {
|
||||
ProcessorContext context;
|
||||
|
||||
@Override
|
||||
public void init(ProcessorContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Object o, Object o2) {
|
||||
|
||||
try {
|
||||
.....
|
||||
.....
|
||||
}
|
||||
catch(Exception e) {
|
||||
//explicitly provide the kafka topic corresponding to the input binding as the first argument.
|
||||
//DLQ handler will correctly map to the dlq topic from the actual incoming destination.
|
||||
dlqHandler.sendToDlq("topic-name", (byte[]) o1, (byte[]) o2, context.partition());
|
||||
}
|
||||
}
|
||||
|
||||
.....
|
||||
.....
|
||||
});
|
||||
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_state_store" href="#_state_store"></a>40.8 State Store</h2></div></div></div><p>State store is created automatically by Kafka Streams when the DSL is used.
|
||||
When processor API is used, you need to register a state store manually. In order to do so, you can use <code class="literal">KafkaStreamsStateStore</code> annotation.
|
||||
You can specify the name and type of the store, flags to control log and disabling cache, etc.
|
||||
Once the store is created by the binder during the bootstrapping phase, you can access this state store through the processor API.
|
||||
Below are some primitives for doing this.</p><p>Creating a state store:</p><pre class="screen">@KafkaStreamsStateStore(name="mystate", type= KafkaStreamsStateStoreProperties.StoreType.WINDOW, lengthMs=300000)
|
||||
public void process(KStream<Object, Product> input) {
|
||||
...
|
||||
}</pre><p>Accessing the state store:</p><pre class="screen">Processor<Object, Product>() {
|
||||
|
||||
WindowStore<Object, String> state;
|
||||
|
||||
@Override
|
||||
public void init(ProcessorContext processorContext) {
|
||||
state = (WindowStore)processorContext.getStateStore("mystate");
|
||||
}
|
||||
...
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_interactive_queries" href="#_interactive_queries"></a>40.9 Interactive Queries</h2></div></div></div><p>As part of the public Kafka Streams binder API, we expose a class called <code class="literal">InteractiveQueryService</code>.
|
||||
You can access this as a Spring bean in your application. An easy way to get access to this bean from your application is to "autowire" the bean.</p><pre class="screen">@Autowired
|
||||
private InteractiveQueryService interactiveQueryService;</pre><p>Once you gain access to this bean, then you can query for the particular state-store that you are interested. See below.</p><pre class="screen">ReadOnlyKeyValueStore<Object, Object> keyValueStore =
|
||||
interactiveQueryService.getQueryableStoreType("my-store", QueryableStoreTypes.keyValueStore());</pre><p>If there are multiple instances of the kafka streams application running, then before you can query them interactively, you need to identify which application instance hosts the key.
|
||||
<code class="literal">InteractiveQueryService</code> API provides methods for identifying the host information.</p><p>In order for this to work, you must configure the property <code class="literal">application.server</code> as below:</p><pre class="screen">spring.cloud.stream.kafka.streams.binder.configuration.application.server: <server>:<port></pre><p>Here are some code snippets:</p><pre class="screen">org.apache.kafka.streams.state.HostInfo hostInfo = interactiveQueryService.getHostInfo("store-name",
|
||||
key, keySerializer);
|
||||
|
||||
if (interactiveQueryService.getCurrentHostInfo().equals(hostInfo)) {
|
||||
|
||||
//query from the store that is locally available
|
||||
}
|
||||
else {
|
||||
//query from the remote host
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_accessing_the_underlying_kafkastreams_object" href="#_accessing_the_underlying_kafkastreams_object"></a>40.10 Accessing the underlying KafkaStreams object</h2></div></div></div><p><code class="literal">StreamBuilderFactoryBean</code> from spring-kafka that is responsible for constructing the <code class="literal">KafkaStreams</code> object can be accessed programmatically.
|
||||
Each <code class="literal">StreamBuilderFactoryBean</code> is registered as <code class="literal">stream-builder</code> and appended with the <code class="literal">StreamListener</code> method name.
|
||||
If your <code class="literal">StreamListener</code> method is named as <code class="literal">process</code> for example, the stream builder bean is named as <code class="literal">stream-builder-process</code>.
|
||||
Since this is a factory bean, it should be accessed by prepending an ampersand (<code class="literal">&</code>) when accessing it programmatically.
|
||||
Following is an example and it assumes the <code class="literal">StreamListener</code> method is named as <code class="literal">process</code></p><pre class="screen">StreamsBuilderFactoryBean streamsBuilderFactoryBean = context.getBean("&stream-builder-process", StreamsBuilderFactoryBean.class);
|
||||
KafkaStreams kafkaStreams = streamsBuilderFactoryBean.getKafkaStreams();</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_state_cleanup" href="#_state_cleanup"></a>40.11 State Cleanup</h2></div></div></div><p>By default, the <code class="literal">Kafkastreams.cleanup()</code> method is called when the binding is stopped.
|
||||
See <a class="link" href="https://docs.spring.io/spring-kafka/reference/html/_reference.html#_configuration" target="_top">the Spring Kafka documentation</a>.
|
||||
To modify this behavior simply add a single <code class="literal">CleanupConfig</code> <code class="literal">@Bean</code> (configured to clean up on start, stop, or neither) to the application context; the bean will be detected and wired into the factory bean.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__apache_kafka_binder.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__binder_implementations.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__rabbitmq_binder.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">39. Apache Kafka Binder </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 41. RabbitMQ Binder</td></tr></table></div></body></html>
|
||||
3
Greenwich.RC2/multi/multi__binder_implementations.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>Part VI. Binder Implementations</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="prev" href="multi__samples.html" title="38. Samples"><link rel="next" href="multi__apache_kafka_binder.html" title="39. Apache Kafka Binder"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Part VI. Binder Implementations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__samples.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__apache_kafka_binder.html">Next</a></td></tr></table><hr></div><div class="part"><div class="titlepage"><div><div><h1 class="title"><a name="_binder_implementations" href="#_binder_implementations"></a>Part VI. Binder Implementations</h1></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__samples.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__apache_kafka_binder.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">38. Samples </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 39. Apache Kafka Binder</td></tr></table></div></body></html>
|
||||
34
Greenwich.RC2/multi/multi__broadcasting_your_own_events.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>49. Broadcasting Your Own Events</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_bus.html" title="Part VII. Spring Cloud Bus"><link rel="prev" href="multi__tracing_bus_events.html" title="48. Tracing Bus Events"><link rel="next" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">49. Broadcasting Your Own Events</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__tracing_bus_events.html">Prev</a> </td><th width="60%" align="center">Part VII. Spring Cloud Bus</th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_sleuth.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_broadcasting_your_own_events" href="#_broadcasting_your_own_events"></a>49. Broadcasting Your Own Events</h2></div></div></div><p>The Bus can carry any event of type <code class="literal">RemoteApplicationEvent</code>. The default transport is
|
||||
JSON, and the deserializer needs to know which types are going to be used ahead of time.
|
||||
To register a new type, you must put it in a subpackage of
|
||||
<code class="literal">org.springframework.cloud.bus.event</code>.</p><p>To customise the event name, you can use <code class="literal">@JsonTypeName</code> on your custom class or rely on
|
||||
the default strategy, which is to use the simple name of the class.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Both the producer and the consumer need access to the class definition.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_registering_events_in_custom_packages" href="#_registering_events_in_custom_packages"></a>49.1 Registering events in custom packages</h2></div></div></div><p>If you cannot or do not want to use a subpackage of <code class="literal">org.springframework.cloud.bus.event</code>
|
||||
for your custom events, you must specify which packages to scan for events of type
|
||||
<code class="literal">RemoteApplicationEvent</code> by using the <code class="literal">@RemoteApplicationEventScan</code> annotation. Packages
|
||||
specified with <code class="literal">@RemoteApplicationEventScan</code> include subpackages.</p><p>For example, consider the following custom event, called <code class="literal">MyEvent</code>:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.acme;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyEvent <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> RemoteApplicationEvent {
|
||||
...
|
||||
}</pre><p>You can register that event with the deserializer in the following way:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.acme;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@RemoteApplicationEventScan</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> BusConfiguration {
|
||||
...
|
||||
}</pre><p>Without specifying a value, the package of the class where <code class="literal">@RemoteApplicationEventScan</code>
|
||||
is used is registered. In this example, <code class="literal">com.acme</code> is registered by using the package of
|
||||
<code class="literal">BusConfiguration</code>.</p><p>You can also explicitly specify the packages to scan by using the <code class="literal">value</code>, <code class="literal">basePackages</code>
|
||||
or <code class="literal">basePackageClasses</code> properties on <code class="literal">@RemoteApplicationEventScan</code>, as shown in the
|
||||
following example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.acme;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//@RemoteApplicationEventScan({"com.acme", "foo.bar"})</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//@RemoteApplicationEventScan(basePackages = {"com.acme", "foo.bar", "fizz.buzz"})</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@RemoteApplicationEventScan(basePackageClasses = BusConfiguration.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> BusConfiguration {
|
||||
...
|
||||
}</pre><p>All of the preceding examples of <code class="literal">@RemoteApplicationEventScan</code> are equivalent, in that the
|
||||
<code class="literal">com.acme</code> package is registered by explicitly specifying the packages on
|
||||
<code class="literal">@RemoteApplicationEventScan</code>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>You can specify multiple base packages to scan.</p></td></tr></table></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__tracing_bus_events.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_bus.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_sleuth.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">48. Tracing Bus Events </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part VIII. Spring Cloud Sleuth</td></tr></table></div></body></html>
|
||||
47
Greenwich.RC2/multi/multi__building.html
Normal file
@@ -0,0 +1,47 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>145. Building</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_kubernetes.html" title="Part XVII. Spring Cloud Kubernetes"><link rel="prev" href="multi__other_resources.html" title="144. Other Resources"><link rel="next" href="multi__contributing.html" title="146. Contributing"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">145. Building</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__other_resources.html">Prev</a> </td><th width="60%" align="center">Part XVII. Spring Cloud Kubernetes</th><td width="20%" align="right"> <a accesskey="n" href="multi__contributing.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_building" href="#_building"></a>145. Building</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_basic_compile_and_test" href="#_basic_compile_and_test"></a>145.1 Basic Compile and Test</h2></div></div></div><p>To build the source you will need to install JDK 1.7.</p><p>Spring Cloud uses Maven for most build-related activities, and you
|
||||
should be able to get off the ground quite quickly by cloning the
|
||||
project you are interested in and typing</p><pre class="screen">$ ./mvnw install</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>You can also install Maven (>=3.3.3) yourself and run the <code class="literal">mvn</code> command
|
||||
in place of <code class="literal">./mvnw</code> in the examples below. If you do that you also
|
||||
might need to add <code class="literal">-P spring</code> if your local Maven settings do not
|
||||
contain repository declarations for spring pre-release artifacts.</p></td></tr></table></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Be aware that you might need to increase the amount of memory
|
||||
available to Maven by setting a <code class="literal">MAVEN_OPTS</code> environment variable with
|
||||
a value like <code class="literal">-Xmx512m -XX:MaxPermSize=128m</code>. We try to cover this in
|
||||
the <code class="literal">.mvn</code> configuration, so if you find you have to do it to make a
|
||||
build succeed, please raise a ticket to get the settings added to
|
||||
source control.</p></td></tr></table></div><p>For hints on how to build the project look in <code class="literal">.travis.yml</code> if there
|
||||
is one. There should be a "script" and maybe "install" command. Also
|
||||
look at the "services" section to see if any services need to be
|
||||
running locally (e.g. mongo or rabbit). Ignore the git-related bits
|
||||
that you might find in "before_install" since they’re related to setting git
|
||||
credentials and you already have those.</p><p>The projects that require middleware generally include a
|
||||
<code class="literal">docker-compose.yml</code>, so consider using
|
||||
<a class="link" href="http://compose.docker.io/" target="_top">Docker Compose</a> to run the middeware servers
|
||||
in Docker containers. See the README in the
|
||||
<a class="link" href="https://github.com/spring-cloud-samples/scripts" target="_top">scripts demo
|
||||
repository</a> for specific instructions about the common cases of mongo,
|
||||
rabbit and redis.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>If all else fails, build with the command from <code class="literal">.travis.yml</code> (usually
|
||||
<code class="literal">./mvnw install</code>).</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_documentation" href="#_documentation"></a>145.2 Documentation</h2></div></div></div><p>The spring-cloud-build module has a "docs" profile, and if you switch
|
||||
that on it will try to build asciidoc sources from
|
||||
<code class="literal">src/main/asciidoc</code>. As part of that process it will look for a
|
||||
<code class="literal">README.adoc</code> and process it by loading all the includes, but not
|
||||
parsing or rendering it, just copying it to <code class="literal">${main.basedir}</code>
|
||||
(defaults to <code class="literal">$../../../..</code>, i.e. the root of the project). If there are
|
||||
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.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_working_with_the_code" href="#_working_with_the_code"></a>145.3 Working with the code</h2></div></div></div><p>If you don’t have an IDE preference we would recommend that you use
|
||||
<a class="link" href="http://www.springsource.com/developer/sts" target="_top">Spring Tools Suite</a> or
|
||||
<a class="link" href="http://eclipse.org" target="_top">Eclipse</a> when working with the code. We use the
|
||||
<a class="link" href="http://eclipse.org/m2e/" target="_top">m2eclipse</a> 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.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_importing_into_eclipse_with_m2eclipse" href="#_importing_into_eclipse_with_m2eclipse"></a>145.3.1 Importing into eclipse with m2eclipse</h3></div></div></div><p>We recommend the <a class="link" href="http://eclipse.org/m2e/" target="_top">m2eclipse</a> eclipse plugin when working with
|
||||
eclipse. If you don’t already have m2eclipse installed it is available from the "eclipse
|
||||
marketplace".</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>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 <code class="literal">settings.xml</code>. Alternatively you can
|
||||
copy the repository settings from the "spring" profile of the parent
|
||||
pom into your <code class="literal">settings.xml</code>.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_importing_into_eclipse_without_m2eclipse" href="#_importing_into_eclipse_without_m2eclipse"></a>145.3.2 Importing into eclipse without m2eclipse</h3></div></div></div><p>If you prefer not to use m2eclipse you can generate eclipse project metadata using the
|
||||
following command:</p><pre class="screen">$ ./mvnw eclipse:eclipse</pre><p>The generated eclipse projects can be imported by selecting <code class="literal">import existing projects</code>
|
||||
from the <code class="literal">file</code> menu.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__other_resources.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_kubernetes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__contributing.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">144. Other Resources </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 146. Contributing</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,31 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>123. Building a Simple Gateway Using Spring MVC or Webflux</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_gateway.html" title="Part XV. Spring Cloud Gateway"><link rel="prev" href="multi__developer_guide.html" title="122. Developer Guide"><link rel="next" href="multi__spring_cloud_function_2.html" title="Part XVI. Spring Cloud Function"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">123. Building a Simple Gateway Using Spring MVC or Webflux</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__developer_guide.html">Prev</a> </td><th width="60%" align="center">Part XV. Spring Cloud Gateway</th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_function_2.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_building_a_simple_gateway_using_spring_mvc_or_webflux" href="#_building_a_simple_gateway_using_spring_mvc_or_webflux"></a>123. Building a Simple Gateway Using Spring MVC or Webflux</h2></div></div></div><p>Spring Cloud Gateway provides a utility object called <code class="literal">ProxyExchange</code> which you can use inside a regular Spring web handler as a method parameter. It supports basic downstream HTTP exchanges via methods that mirror the HTTP verbs. With MVC it also supports forwarding to a local handler via the <code class="literal">forward()</code> method. To use the <code class="literal">ProxyExchange</code> just include the right module in your classpath (either <code class="literal">spring-cloud-gateway-mvc</code> or <code class="literal">spring-cloud-gateway-webflux</code>).</p><p>MVC example (proxying a request to "/test" downstream to a remote server):</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@RestController</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> GatewaySampleApplication {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Value("${remote.home}")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> URI home;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@GetMapping("/test")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> ResponseEntity<?> proxy(ProxyExchange<<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">byte</span>[]> proxy) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> proxy.uri(home.toString() + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/image/png"</span>).get();
|
||||
}
|
||||
|
||||
}</pre><p>The same thing with Webflux:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@RestController</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> GatewaySampleApplication {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Value("${remote.home}")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> URI home;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@GetMapping("/test")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Mono<ResponseEntity<?>> proxy(ProxyExchange<<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">byte</span>[]> proxy) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> proxy.uri(home.toString() + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/image/png"</span>).get();
|
||||
}
|
||||
|
||||
}</pre><p>There are convenience methods on the <code class="literal">ProxyExchange</code> to enable the handler method to discover and enhance the URI path of the incoming request. For example you might want to extract the trailing elements of a path to pass them downstream:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@GetMapping("/proxy/path/**")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> ResponseEntity<?> proxyPath(ProxyExchange<<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">byte</span>[]> proxy) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
String path = proxy.path(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/proxy/path/"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> proxy.uri(home.toString() + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/foos/"</span> + path).get();
|
||||
}</pre><p>All the features of Spring MVC or Webflux are available to Gateway handler methods. So you can inject request headers and query parameters, for instance, and you can constrain the incoming requests with declarations in the mapping annotation. See the documentation for <code class="literal">@RequestMapping</code> in Spring MVC for more details of those features.</p><p>Headers can be added to the downstream response using the <code class="literal">header()</code> methods on <code class="literal">ProxyExchange</code>.</p><p>You can also manipulate response headers (and anything else you like in the response) by adding a mapper to the <code class="literal">get()</code> etc. method. The mapper is a <code class="literal">Function</code> that takes the incoming <code class="literal">ResponseEntity</code> and converts it to an outgoing one.</p><p>First class support is provided for "sensitive" headers ("cookie" and "authorization" by default) which are not passed downstream, and for "proxy" headers (<code class="literal">x-forwarded-*</code>).</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__developer_guide.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_gateway.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_function_2.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">122. Developer Guide </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part XVI. Spring Cloud Function</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,18 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>126. Building and Running a Function</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_function_2.html" title="Part XVI. Spring Cloud Function"><link rel="prev" href="multi__getting_started.html" title="125. Getting Started"><link rel="next" href="multi__function_catalog_and_flexible_function_signatures.html" title="127. Function Catalog and Flexible Function Signatures"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">126. Building and Running a Function</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__getting_started.html">Prev</a> </td><th width="60%" align="center">Part XVI. Spring Cloud Function</th><td width="20%" align="right"> <a accesskey="n" href="multi__function_catalog_and_flexible_function_signatures.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_building_and_running_a_function" href="#_building_and_running_a_function"></a>126. Building and Running a Function</h2></div></div></div><p>The sample <code class="literal">@SpringBootApplication</code> above has a function that can be
|
||||
decorated at runtime by Spring Cloud Function to be an HTTP endpoint,
|
||||
or a Stream processor, for instance with RabbitMQ, Apache Kafka or
|
||||
JMS.</p><p>The <code class="literal">@Beans</code> can be <code class="literal">Function</code>, <code class="literal">Consumer</code> or <code class="literal">Supplier</code> (all from
|
||||
<code class="literal">java.util</code>), and their parametric types can be String or POJO.</p><p>Functions can also be of <code class="literal">Flux<String></code> or <code class="literal">Flux<Pojo></code> and Spring
|
||||
Cloud Function takes care of converting the data to and from the
|
||||
desired types, as long as it comes in as plain text or (in the case of
|
||||
the POJO) JSON. There is also support for <code class="literal">Message<Pojo></code> where the
|
||||
message headers are copied from the incoming event, depending on the
|
||||
adapter. The web adapter also supports conversion from form-encoded
|
||||
data to a <code class="literal">Map</code>, and if you are using the function with Spring Cloud
|
||||
Stream then all the conversion and coercion features for message
|
||||
payloads will be applicable as well.</p><p>Functions can be grouped together in a single application, or deployed
|
||||
one-per-jar. It’s up to the developer to choose. An app with multiple
|
||||
functions can be deployed multiple times in different "personalities",
|
||||
exposing different functions over different physical transports.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__getting_started.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_function_2.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__function_catalog_and_flexible_function_signatures.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">125. Getting Started </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 127. Function Catalog and Flexible Function Signatures</td></tr></table></div></body></html>
|
||||
13
Greenwich.RC2/multi/multi__bus_endpoints.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>43. Bus Endpoints</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_bus.html" title="Part VII. Spring Cloud Bus"><link rel="prev" href="multi__quick_start_3.html" title="42. Quick Start"><link rel="next" href="multi__addressing_an_instance.html" title="44. Addressing an Instance"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">43. Bus Endpoints</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__quick_start_3.html">Prev</a> </td><th width="60%" align="center">Part VII. Spring Cloud Bus</th><td width="20%" align="right"> <a accesskey="n" href="multi__addressing_an_instance.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_bus_endpoints" href="#_bus_endpoints"></a>43. Bus Endpoints</h2></div></div></div><p>Spring Cloud Bus provides two endpoints, <code class="literal">/actuator/bus-refresh</code> and <code class="literal">/actuator/bus-env</code>
|
||||
that correspond to individual actuator endpoints in Spring Cloud Commons,
|
||||
<code class="literal">/actuator/refresh</code> and <code class="literal">/actuator/env</code> respectively.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_bus_refresh_endpoint" href="#_bus_refresh_endpoint"></a>43.1 Bus Refresh Endpoint</h2></div></div></div><p>The <code class="literal">/actuator/bus-refresh</code> endpoint clears the <code class="literal">RefreshScope</code> cache and rebinds
|
||||
<code class="literal">@ConfigurationProperties</code>. See the <a class="link" href="multi__spring_cloud_context_application_context_services.html#refresh-scope" title="2.9 Refresh Scope">Refresh Scope</a> documentation for
|
||||
more information.</p><p>To expose the <code class="literal">/actuator/bus-refresh</code> endpoint, you need to add following configuration to your
|
||||
application:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">management.endpoints.web.exposure.include</span>=bus-refresh</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_bus_env_endpoint" href="#_bus_env_endpoint"></a>43.2 Bus Env Endpoint</h2></div></div></div><p>The <code class="literal">/actuator/bus-env</code> endpoint updates each instances environment with the specified
|
||||
key/value pair across multiple instances.</p><p>To expose the <code class="literal">/actuator/bus-env</code> endpoint, you need to add following configuration to your
|
||||
application:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">management.endpoints.web.exposure.include</span>=bus-env</pre><p>The <code class="literal">/actuator/bus-env</code> endpoint accepts <code class="literal">POST</code> requests with the following shape:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">{</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"name"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"key1"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"value"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"value1"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">}</span></pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__quick_start_3.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_bus.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__addressing_an_instance.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">42. Quick Start </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 44. Addressing an Instance</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,61 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>13. Circuit Breaker: Hystrix Clients</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_netflix.html" title="Part III. Spring Cloud Netflix"><link rel="prev" href="multi_spring-cloud-eureka-server.html" title="12. Service Discovery: Eureka Server"><link rel="next" href="multi__circuit_breaker_hystrix_dashboard.html" title="14. Circuit Breaker: Hystrix Dashboard"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">13. Circuit Breaker: Hystrix Clients</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_spring-cloud-eureka-server.html">Prev</a> </td><th width="60%" align="center">Part III. Spring Cloud Netflix</th><td width="20%" align="right"> <a accesskey="n" href="multi__circuit_breaker_hystrix_dashboard.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_circuit_breaker_hystrix_clients" href="#_circuit_breaker_hystrix_clients"></a>13. Circuit Breaker: Hystrix Clients</h2></div></div></div><p>Netflix has created a library called <a class="link" href="https://github.com/Netflix/Hystrix" target="_top">Hystrix</a> that implements the <a class="link" href="http://martinfowler.com/bliki/CircuitBreaker.html" target="_top">circuit breaker pattern</a>.
|
||||
In a microservice architecture, it is common to have multiple layers of service calls, as shown in the following example:</p><div class="figure"><a name="d0e4278" href="#d0e4278"></a><p class="title"><b>Figure 13.1. Microservice Graph</b></p><div class="figure-contents"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-netflix/master/docs/src/main/asciidoc/images/Hystrix.png" alt="Hystrix"></div></div></div><br class="figure-break"><p>A service failure in the lower level of services can cause cascading failure all the way up to the user.
|
||||
When calls to a particular service exceed <code class="literal">circuitBreaker.requestVolumeThreshold</code> (default: 20 requests) and the failure percentage is greater than <code class="literal">circuitBreaker.errorThresholdPercentage</code> (default: >50%) in a rolling window defined by <code class="literal">metrics.rollingStats.timeInMilliseconds</code> (default: 10 seconds), the circuit opens and the call is not made.
|
||||
In cases of error and an open circuit, a fallback can be provided by the developer.</p><div class="figure"><a name="d0e4298" href="#d0e4298"></a><p class="title"><b>Figure 13.2. Hystrix fallback prevents cascading failures</b></p><div class="figure-contents"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-netflix/master/docs/src/main/asciidoc/images/HystrixFallback.png" alt="HystrixFallback"></div></div></div><br class="figure-break"><p>Having an open circuit stops cascading failures and allows overwhelmed or failing services time to recover.
|
||||
The fallback can be another Hystrix protected call, static data, or a sensible empty value.
|
||||
Fallbacks may be chained so that the first fallback makes some other business call, which in turn falls back to static data.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_how_to_include_hystrix" href="#_how_to_include_hystrix"></a>13.1 How to Include Hystrix</h2></div></div></div><p>To include Hystrix in your project, use the starter with a group ID of <code class="literal">org.springframework.cloud</code>
|
||||
and a artifact ID of <code class="literal">spring-cloud-starter-netflix-hystrix</code>.
|
||||
See the <a class="link" href="http://projects.spring.io/spring-cloud/" target="_top">Spring Cloud Project page</a> for details on setting up your build system with the current Spring Cloud Release Train.</p><p>The following example shows a minimal Eureka server with a Hystrix circuit breaker:</p><pre class="screen">@SpringBootApplication
|
||||
@EnableCircuitBreaker
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpringApplicationBuilder(Application.class).web(true).run(args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Component
|
||||
public class StoreIntegration {
|
||||
|
||||
@HystrixCommand(fallbackMethod = "defaultStores")
|
||||
public Object getStores(Map<String, Object> parameters) {
|
||||
//do stuff that might fail
|
||||
}
|
||||
|
||||
public Object defaultStores(Map<String, Object> parameters) {
|
||||
return /* something useful */;
|
||||
}
|
||||
}</pre><p>The <code class="literal">@HystrixCommand</code> is provided by a Netflix contrib library called <a class="link" href="https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica" target="_top">“javanica”</a>.
|
||||
Spring Cloud automatically wraps Spring beans with that annotation in a proxy that is connected to the Hystrix circuit breaker.
|
||||
The circuit breaker calculates when to open and close the circuit and what to do in case of a failure.</p><p>To configure the <code class="literal">@HystrixCommand</code> you can use the <code class="literal">commandProperties</code>
|
||||
attribute with a list of <code class="literal">@HystrixProperty</code> annotations. See
|
||||
<a class="link" href="https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica#configuration" target="_top">here</a>
|
||||
for more details. See the <a class="link" href="https://github.com/Netflix/Hystrix/wiki/Configuration" target="_top">Hystrix wiki</a>
|
||||
for details on the properties available.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="netflix-hystrix-starter" href="#netflix-hystrix-starter"></a>13.2 Propagating the Security Context or Using Spring Scopes</h2></div></div></div><p>If you want some thread local context to propagate into a <code class="literal">@HystrixCommand</code>, the default declaration does not work, because it executes the command in a thread pool (in case of timeouts).
|
||||
You can switch Hystrix to use the same thread as the caller through configuration or directly in the annotation, by asking it to use a different “Isolation Strategy”.
|
||||
The following example demonstrates setting the thread in the annotation:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@HystrixCommand(fallbackMethod = "stubMyService",
|
||||
commandProperties = {
|
||||
@HystrixProperty(name="execution.isolation.strategy", value="SEMAPHORE")
|
||||
}
|
||||
)</span></em>
|
||||
...</pre><p>The same thing applies if you are using <code class="literal">@SessionScope</code> or <code class="literal">@RequestScope</code>.
|
||||
If you encounter a runtime exception that says it cannot find the scoped context, you need to use the same thread.</p><p>You also have the option to set the <code class="literal">hystrix.shareSecurityContext</code> property to <code class="literal">true</code>.
|
||||
Doing so auto-configures a Hystrix concurrency strategy plugin hook to transfer the <code class="literal">SecurityContext</code> from your main thread to the one used by the Hystrix command.
|
||||
Hystrix does not let multiple Hystrix concurrency strategy be registered so an extension mechanism is available by declaring your own <code class="literal">HystrixConcurrencyStrategy</code> as a Spring bean.
|
||||
Spring Cloud looks for your implementation within the Spring context and wrap it inside its own plugin.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_health_indicator_4" href="#_health_indicator_4"></a>13.3 Health Indicator</h2></div></div></div><p>The state of the connected circuit breakers are also exposed in the <code class="literal">/health</code> endpoint of the calling application, as shown in the following example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">{</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"hystrix"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">{</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"openCircuitBreakers"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">[</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"StoreIntegration::getStoresByLocationLink"</span>
|
||||
]<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"status"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"CIRCUIT_OPEN"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">},</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"status"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"UP"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">}</span></pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_hystrix_metrics_stream" href="#_hystrix_metrics_stream"></a>13.4 Hystrix Metrics Stream</h2></div></div></div><p>To enable the Hystrix metrics stream, include a dependency on <code class="literal">spring-boot-starter-actuator</code> and set
|
||||
<code class="literal">management.endpoints.web.exposure.include: hystrix.stream</code>.
|
||||
Doing so exposes the <code class="literal">/actuator/hystrix.stream</code> as a management endpoint, as shown in the following example:</p><pre class="programlisting"> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-starter-actuator<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_spring-cloud-eureka-server.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_netflix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__circuit_breaker_hystrix_dashboard.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">12. Service Discovery: Eureka Server </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 14. Circuit Breaker: Hystrix Dashboard</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,4 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>14. Circuit Breaker: Hystrix Dashboard</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_netflix.html" title="Part III. Spring Cloud Netflix"><link rel="prev" href="multi__circuit_breaker_hystrix_clients.html" title="13. Circuit Breaker: Hystrix Clients"><link rel="next" href="multi__hystrix_timeouts_and_ribbon_clients.html" title="15. Hystrix Timeouts And Ribbon Clients"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">14. Circuit Breaker: Hystrix Dashboard</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__circuit_breaker_hystrix_clients.html">Prev</a> </td><th width="60%" align="center">Part III. Spring Cloud Netflix</th><td width="20%" align="right"> <a accesskey="n" href="multi__hystrix_timeouts_and_ribbon_clients.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_circuit_breaker_hystrix_dashboard" href="#_circuit_breaker_hystrix_dashboard"></a>14. Circuit Breaker: Hystrix Dashboard</h2></div></div></div><p>One of the main benefits of Hystrix is the set of metrics it gathers about each HystrixCommand.
|
||||
The Hystrix Dashboard displays the health of each circuit breaker in an efficient manner.</p><div class="figure"><a name="d0e4415" href="#d0e4415"></a><p class="title"><b>Figure 14.1. Hystrix Dashboard</b></p><div class="figure-contents"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-netflix/master/docs/src/main/asciidoc/images/Hystrix.png" alt="Hystrix"></div></div></div><br class="figure-break"></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__circuit_breaker_hystrix_clients.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_netflix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__hystrix_timeouts_and_ribbon_clients.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">13. Circuit Breaker: Hystrix Clients </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 15. Hystrix Timeouts And Ribbon Clients</td></tr></table></div></body></html>
|
||||
66
Greenwich.RC2/multi/multi__client_side_usage_2.html
Normal file
@@ -0,0 +1,66 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>100. Client Side Usage</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_vault.html" title="Part XIV. Spring Cloud Vault"><link rel="prev" href="multi__quick_start_4.html" title="99. Quick Start"><link rel="next" href="multi_vault.config.authentication.html" title="101. Authentication methods"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">100. Client Side Usage</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__quick_start_4.html">Prev</a> </td><th width="60%" align="center">Part XIV. Spring Cloud Vault</th><td width="20%" align="right"> <a accesskey="n" href="multi_vault.config.authentication.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_client_side_usage_2" href="#_client_side_usage_2"></a>100. Client Side Usage</h2></div></div></div><p>To use these features in an application, just build it as a Spring
|
||||
Boot application that depends on <code class="literal">spring-cloud-vault-config</code> (e.g. see
|
||||
the test cases). Example Maven configuration:</p><div class="example"><a name="d0e29365" href="#d0e29365"></a><p class="title"><b>Example 100.1. pom.xml</b></p><div class="example-contents"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><parent></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-starter-parent<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>2.0.0.RELEASE<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><relativePath /></span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- lookup parent from repository --></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></parent></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-vault-config<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>1.0.0.BUILD-SNAPSHOT<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-starter-test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><scope></span>test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></scope></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencies></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><build></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><plugins></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><plugin></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-maven-plugin<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></plugin></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></plugins></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></build></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- repositories also needed for snapshots and milestones --></span></pre></div></div><br class="example-break"><p>Then you can create a standard Spring Boot application, like this simple HTTP server:</p><div class="informalexample"><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@RestController</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestMapping("/")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String home() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Hello World!"</span>;
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(Application.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
}
|
||||
}</pre></div><p>When it runs it will pick up the external configuration from the
|
||||
default local Vault server on port <code class="literal">8200</code> if it is running. To modify
|
||||
the startup behavior you can change the location of the Vault server
|
||||
using <code class="literal">bootstrap.properties</code> (like <code class="literal">application.properties</code> but for
|
||||
the bootstrap phase of an application context), e.g.</p><div class="example"><a name="d0e29386" href="#d0e29386"></a><p class="title"><b>Example 100.2. bootstrap.yml</b></p><div class="example-contents"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.cloud.vault</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> host</span>: localhost
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> port</span>: <span class="hl-number">8200</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> scheme</span>: https
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: https://localhost:<span class="hl-number">8200</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> connection-timeout</span>: <span class="hl-number">5000</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> read-timeout</span>: <span class="hl-number">15000</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> config</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> order</span>: -<span class="hl-number">10</span></pre></div></div><br class="example-break"><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">host</code> sets the hostname of the Vault host. The host name will be used
|
||||
for SSL certificate validation</li><li class="listitem"><code class="literal">port</code> sets the Vault port</li><li class="listitem"><code class="literal">scheme</code> setting the scheme to <code class="literal">http</code> will use plain HTTP.
|
||||
Supported schemes are <code class="literal">http</code> and <code class="literal">https</code>.</li><li class="listitem"><code class="literal">uri</code> configure the Vault endpoint with an URI. Takes precedence over host/port/scheme configuration</li><li class="listitem"><code class="literal">connection-timeout</code> sets the connection timeout in milliseconds</li><li class="listitem"><code class="literal">read-timeout</code> sets the read timeout in milliseconds</li><li class="listitem"><code class="literal">config.order</code> sets the order for the property source</li></ul></div><p>Enabling further integrations requires additional dependencies and
|
||||
configuration. Depending on how you have set up Vault you might need
|
||||
additional configuration like
|
||||
<a class="link" href="http://cloud.spring.io/spring-cloud-vault/spring-cloud-vault.html#vault.config.ssl" target="_top">SSL</a> and
|
||||
<a class="link" href="http://cloud.spring.io/spring-cloud-vault/spring-cloud-vault.html#vault.config.authentication" target="_top">authentication</a>.</p><p>If the application imports the <code class="literal">spring-boot-starter-actuator</code> project, the
|
||||
status of the vault server will be available via the <code class="literal">/health</code> endpoint.</p><p>The vault health indicator can be enabled or disabled through the property <code class="literal">management.health.vault.enabled</code> (default to <code class="literal">true</code>).</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_authentication_2" href="#_authentication_2"></a>100.1 Authentication</h2></div></div></div><p>Vault requires an <a class="link" href="https://www.vaultproject.io/docs/concepts/auth.html" target="_top">authentication mechanism</a> to <a class="link" href="https://www.vaultproject.io/docs/concepts/tokens.html" target="_top">authorize client requests</a>.</p><p>Spring Cloud Vault supports multiple <a class="link" href="http://cloud.spring.io/spring-cloud-vault/spring-cloud-vault.html#vault.config.authentication" target="_top">authentication mechanisms</a> to authenticate applications with Vault.</p><p>For a quickstart, use the root token printed by the <a class="link" href="multi__quick_start_4.html#quickstart.vault.start">Vault initialization</a>.</p><div class="example"><a name="d0e29481" href="#d0e29481"></a><p class="title"><b>Example 100.3. bootstrap.yml</b></p><div class="example-contents"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.cloud.vault</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> token</span>: <span class="hl-number">19</span>aefa97-cccc-bbbb-aaaa-<span class="hl-number">225940e63d</span>76</pre></div></div><br class="example-break"><div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Warning"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="images/warning.png"></td><th align="left">Warning</th></tr><tr><td align="left" valign="top"><p>Consider carefully your security requirements. Static token authentication is fine if you want quickly get started with Vault, but a static token is not protected any further. Any disclosure to unintended parties allows Vault use with the associated token roles.</p></td></tr></table></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__quick_start_4.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_vault.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_vault.config.authentication.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">99. Quick Start </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 101. Authentication methods</td></tr></table></div></body></html>
|
||||
8
Greenwich.RC2/multi/multi__cloud_foundry.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>164. Cloud Foundry</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi_spring-cloud-gcp-reference.html" title="Part XVIII. Spring Cloud GCP"><link rel="prev" href="multi__google_cloud_vision.html" title="163. Google Cloud Vision"><link rel="next" href="multi__appendix_compendium_of_configuration_properties.html" title="Part XIX. Appendix: Compendium of Configuration Properties"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">164. Cloud Foundry</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__google_cloud_vision.html">Prev</a> </td><th width="60%" align="center">Part XVIII. Spring Cloud GCP</th><td width="20%" align="right"> <a accesskey="n" href="multi__appendix_compendium_of_configuration_properties.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_cloud_foundry" href="#_cloud_foundry"></a>164. Cloud Foundry</h2></div></div></div><p>Spring Cloud GCP provides support for Cloud Foundry’s <a class="link" href="https://docs.pivotal.io/partners/gcp-sb/index.html" target="_top">GCP Service Broker</a>.
|
||||
Our Pub/Sub, Cloud Spanner, Storage, Stackdriver Trace and Cloud SQL MySQL and PostgreSQL starters are Cloud Foundry aware and retrieve properties like project ID, credentials, etc., that are used in auto configuration from the Cloud Foundry environment.</p><p>In cases like Pub/Sub’s topic and subscription, or Storage’s bucket name, where those parameters are not used in auto configuration, you can fetch them using the VCAP mapping provided by Spring Boot.
|
||||
For example, to retrieve the provisioned Pub/Sub topic, you can use the <code class="literal">vcap.services.mypubsub.credentials.topic_name</code> property from the application environment.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>If the same service is bound to the same application more than once, the auto configuration will not be able to choose among bindings and will not be activated for that service.
|
||||
This includes both MySQL and PostgreSQL bindings to the same app.</p></td></tr></table></div><div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Warning"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="images/warning.png"></td><th align="left">Warning</th></tr><tr><td align="left" valign="top"><p>In order for the Cloud SQL integration to work in Cloud Foundry, auto-reconfiguration must be disabled.
|
||||
You can do so using the <code class="literal">cf set-env <APP> JBP_CONFIG_SPRING_AUTO_RECONFIGURATION '{enabled: false}'</code> command.
|
||||
Otherwise, Cloud Foundry will produce a <code class="literal">DataSource</code> with an invalid JDBC URL (i.e., <code class="literal">jdbc:mysql://null/null</code>).</p></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__google_cloud_vision.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi_spring-cloud-gcp-reference.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__appendix_compendium_of_configuration_properties.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">163. Google Cloud Vision </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part XIX. Appendix: Compendium of Configuration Properties</td></tr></table></div></body></html>
|
||||
14
Greenwich.RC2/multi/multi__cloud_memorystore_for_redis.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>161. Cloud Memorystore for Redis</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi_spring-cloud-gcp-reference.html" title="Part XVIII. Spring Cloud GCP"><link rel="prev" href="multi__spring_data_cloud_datastore.html" title="160. Spring Data Cloud Datastore"><link rel="next" href="multi__cloud_identity_aware_proxy_iap_authentication.html" title="162. Cloud Identity-Aware Proxy (IAP) Authentication"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">161. Cloud Memorystore for Redis</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_data_cloud_datastore.html">Prev</a> </td><th width="60%" align="center">Part XVIII. Spring Cloud GCP</th><td width="20%" align="right"> <a accesskey="n" href="multi__cloud_identity_aware_proxy_iap_authentication.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_cloud_memorystore_for_redis" href="#_cloud_memorystore_for_redis"></a>161. Cloud Memorystore for Redis</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spring_caching" href="#_spring_caching"></a>161.1 Spring Caching</h2></div></div></div><p><a class="link" href="https://cloud.google.com/memorystore/" target="_top">Cloud Memorystore for Redis</a> provides a fully managed in-memory data store service.
|
||||
Cloud Memorystore is compatible with the Redis protocol, allowing easy integration with <a class="link" href="https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-caching.html" target="_top">Spring Caching</a>.</p><p>All you have to do is create a Cloud Memorystore instance and use its IP address in <code class="literal">application.properties</code> file as <code class="literal">spring.redis.host</code> property value. Everything else is exactly the same as setting up redis-backed Spring caching.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Memorystore instances and your application instances have to be located in the same region.</p></td></tr></table></div><p>In short, the following dependencies are needed:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-starter-cache<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-starter-data-redis<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p>And then you can use <code class="literal">org.springframework.cache.annotation.Cacheable</code> annotation for methods you’d like to be cached.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Cacheable("cache1")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String hello(<em><span class="hl-annotation" style="color: gray">@PathVariable</span></em> String name) {
|
||||
....
|
||||
}</pre><p>If you are interested in a detailed how-to guide, please check <a class="link" href="https://codelabs.developers.google.com/codelabs/cloud-spring-cache-memorystore/" target="_top">Spring Boot Caching using Cloud Memorystore codelab</a>.</p><p>Cloud Memorystore documentation can be found <a class="link" href="https://cloud.google.com/memorystore/docs/redis/" target="_top">here</a>.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_data_cloud_datastore.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi_spring-cloud-gcp-reference.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__cloud_identity_aware_proxy_iap_authentication.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">160. Spring Data Cloud Datastore </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 162. Cloud Identity-Aware Proxy (IAP) Authentication</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,9 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>Part I. Cloud Native Applications</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="prev" href="multi__features.html" title="1. Features"><link rel="next" href="multi__spring_cloud_context_application_context_services.html" title="2. Spring Cloud Context: Application Context Services"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Part I. Cloud Native Applications</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__features.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_context_application_context_services.html">Next</a></td></tr></table><hr></div><div class="part"><div class="titlepage"><div><div><h1 class="title"><a name="_cloud_native_applications" href="#_cloud_native_applications"></a>Part I. Cloud Native Applications</h1></div></div></div><div class="partintro"><div></div><p><a class="link" href="http://pivotal.io/platform-as-a-service/migrating-to-cloud-native-application-architectures-ebook" target="_top">Cloud Native</a> is a style of application development that encourages easy adoption of best practices in the areas of continuous delivery and value-driven development.
|
||||
A related discipline is that of building <a class="link" href="http://12factor.net/" target="_top">12-factor Applications</a>, in which development practices are aligned with delivery and operations goals — for instance, by using declarative programming and management and monitoring.
|
||||
Spring Cloud facilitates these styles of development in a number of specific ways.
|
||||
The starting point is a set of features to which all components in a distributed system need easy access.</p><p>Many of those features are covered by <a class="link" href="http://projects.spring.io/spring-boot" target="_top">Spring Boot</a>, on which Spring Cloud builds. Some more features are delivered by Spring Cloud as two libraries: Spring Cloud Context and Spring Cloud Commons.
|
||||
Spring Cloud Context provides utilities and special services for the <code class="literal">ApplicationContext</code> of a Spring Cloud application (bootstrap context, encryption, refresh scope, and environment endpoints). Spring Cloud Commons is a set of abstractions and common classes used in different Spring Cloud implementations (such as Spring Cloud Netflix and Spring Cloud Consul).</p><p>If you get an exception due to "Illegal key size" and you use Sun’s JDK, you need to install the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files.
|
||||
See the following links for more information:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="link" href="http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html" target="_top">Java 6 JCE</a></li><li class="listitem"><a class="link" href="http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html" target="_top">Java 7 JCE</a></li><li class="listitem"><a class="link" href="http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html" target="_top">Java 8 JCE</a></li></ul></div><p>Extract the files into the JDK/jre/lib/security folder for whichever version of JRE/JDK x64/x86 you use.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Spring Cloud is released under the non-restrictive Apache 2.0 license.
|
||||
If you would like to contribute to this section of the documentation or if you find an error, you can find the source code and issue trackers for the project at <a class="link" href="https://github.com/spring-cloud/spring-cloud-commons/tree/master/docs/src/main/asciidoc" target="_top">github</a>.</p></td></tr></table></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__features.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_context_application_context_services.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">1. Features </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 2. Spring Cloud Context: Application Context Services</td></tr></table></div></body></html>
|
||||
63
Greenwich.RC2/multi/multi__configuration_2.html
Normal file
@@ -0,0 +1,63 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>118. Configuration</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_gateway.html" title="Part XV. Spring Cloud Gateway"><link rel="prev" href="multi__tls_ssl.html" title="117. TLS / SSL"><link rel="next" href="multi__reactor_netty_access_logs.html" title="119. Reactor Netty Access Logs"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">118. Configuration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__tls_ssl.html">Prev</a> </td><th width="60%" align="center">Part XV. Spring Cloud Gateway</th><td width="20%" align="right"> <a accesskey="n" href="multi__reactor_netty_access_logs.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_configuration_2" href="#_configuration_2"></a>118. Configuration</h2></div></div></div><p>Configuration for Spring Cloud Gateway is driven by a collection of `RouteDefinitionLocator`s.</p><p><b>RouteDefinitionLocator.java. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> RouteDefinitionLocator {
|
||||
Flux<RouteDefinition> getRouteDefinitions();
|
||||
}</pre><p>
|
||||
</p><p>By default, a <code class="literal">PropertiesRouteDefinitionLocator</code> loads properties using Spring Boot’s <code class="literal">@ConfigurationProperties</code> mechanism.</p><p>The configuration examples above all use a shortcut notation that uses positional arguments rather than named ones. The two examples below are equivalent:</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: setstatus_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: SetStatus
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> args</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> status</span>: <span class="hl-number">401</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: setstatusshortcut_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - SetStatus</span>=<span class="hl-number">401</span></pre><p>
|
||||
</p><p>For some usages of the gateway, properties will be adequate, but some production use cases will benefit from loading configuration from an external source, such as a database. Future milestone versions will have <code class="literal">RouteDefinitionLocator</code> implementations based off of Spring Data Repositories such as: Redis, MongoDB and Cassandra.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_fluent_java_routes_api" href="#_fluent_java_routes_api"></a>118.1 Fluent Java Routes API</h2></div></div></div><p>To allow for simple configuration in Java, there is a fluent API defined in the <code class="literal">RouteLocatorBuilder</code> bean.</p><p><b>GatewaySampleApplication.java. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// static imports from GatewayFilters and RoutePredicates</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> RouteLocator customRouteLocator(RouteLocatorBuilder builder, ThrottleGatewayFilterFactory throttle) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> builder.routes()
|
||||
.route(r -> r.host(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"**.abc.org"</span>).and().path(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/image/png"</span>)
|
||||
.filters(f ->
|
||||
f.addResponseHeader(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"X-TestHeader"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foobar"</span>))
|
||||
.uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://httpbin.org:80"</span>)
|
||||
)
|
||||
.route(r -> r.path(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/image/webp"</span>)
|
||||
.filters(f ->
|
||||
f.addResponseHeader(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"X-AnotherHeader"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"baz"</span>))
|
||||
.uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://httpbin.org:80"</span>)
|
||||
)
|
||||
.route(r -> r.order(-<span class="hl-number">1</span>)
|
||||
.host(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"**.throttle.org"</span>).and().path(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/get"</span>)
|
||||
.filters(f -> f.filter(throttle.apply(<span class="hl-number">1</span>,
|
||||
<span class="hl-number">1</span>,
|
||||
<span class="hl-number">10</span>,
|
||||
TimeUnit.SECONDS)))
|
||||
.uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://httpbin.org:80"</span>)
|
||||
)
|
||||
.build();
|
||||
}</pre><p>
|
||||
</p><p>This style also allows for more custom predicate assertions. The predicates defined by <code class="literal">RouteDefinitionLocator</code> beans are combined using logical <code class="literal">and</code>. By using the fluent Java API, you can use the <code class="literal">and()</code>, <code class="literal">or()</code> and <code class="literal">negate()</code> operators on the <code class="literal">Predicate</code> class.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_discoveryclient_route_definition_locator" href="#_discoveryclient_route_definition_locator"></a>118.2 DiscoveryClient Route Definition Locator</h2></div></div></div><p>The Gateway can be configured to create routes based on services registered with a <code class="literal">DiscoveryClient</code> compatible service registry.</p><p>To enable this, set <code class="literal">spring.cloud.gateway.discovery.locator.enabled=true</code> and make sure a <code class="literal">DiscoveryClient</code> implementation is on the classpath and enabled (such as Netflix Eureka, Consul or Zookeeper).</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_configuring_predicates_and_filters_for_discoveryclient_routes" href="#_configuring_predicates_and_filters_for_discoveryclient_routes"></a>118.2.1 Configuring Predicates and Filters For DiscoveryClient Routes</h3></div></div></div><p>By default the Gateway defines a single predicate and filter for routes created via a <code class="literal">DiscoveryClient</code>.</p><p>The default predicate is a path predicate defined with the pattern <code class="literal">/serviceId/**</code>, where <code class="literal">serviceId</code> is
|
||||
the id of the service from the <code class="literal">DiscoveryClient</code>.</p><p>The default filter is rewrite path filter with the regex <code class="literal">/serviceId/(?<remaining>.*)</code> and the replacement
|
||||
<code class="literal">/${remaining}</code>. This just strips the service id from the path before the request is sent
|
||||
downstream.</p><p>If you would like to customize the predicates and/or filters used by the <code class="literal">DiscoveryClient</code> routes you can do so
|
||||
by setting <code class="literal">spring.cloud.gateway.discovery.locator.predicates[x]</code> and <code class="literal">spring.cloud.gateway.discovery.locator.filters[y]</code>.
|
||||
When doing so you need to make sure to include the default predicate and filter above, if you want to retain
|
||||
that functionality. Below is an example of what this looks like.</p><p><b>application.properties. </b>
|
||||
</p><pre class="screen">spring.cloud.gateway.discovery.locator.predicates[0].name: Path
|
||||
spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "'/'+serviceId+'/**'"
|
||||
spring.cloud.gateway.discovery.locator.predicates[1].name: Host
|
||||
spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "'**.foo.com'"
|
||||
spring.cloud.gateway.discovery.locator.filters[0].name: Hystrix
|
||||
spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
|
||||
spring.cloud.gateway.discovery.locator.filters[1].name: RewritePath
|
||||
spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId + '/(?<remaining>.*)'"
|
||||
spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"</pre><p>
|
||||
</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__tls_ssl.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_gateway.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__reactor_netty_access_logs.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">117. TLS / SSL </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 119. Reactor Netty Access Logs</td></tr></table></div></body></html>
|
||||
127
Greenwich.RC2/multi/multi__configuration_options.html
Normal file
@@ -0,0 +1,127 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>31. Configuration Options</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="prev" href="multi_spring-cloud-stream-overview-binders.html" title="30. Binders"><link rel="next" href="multi_content-type-management.html" title="32. Content Type Negotiation"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">31. Configuration Options</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_spring-cloud-stream-overview-binders.html">Prev</a> </td><th width="60%" align="center">Part V. Spring Cloud Stream</th><td width="20%" align="right"> <a accesskey="n" href="multi_content-type-management.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_configuration_options" href="#_configuration_options"></a>31. Configuration Options</h2></div></div></div><p>Spring Cloud Stream supports general configuration options as well as configuration for bindings and binders.
|
||||
Some binders let additional binding properties support middleware-specific features.</p><p>Configuration options can be provided to Spring Cloud Stream applications through any mechanism supported by Spring Boot.
|
||||
This includes application arguments, environment variables, and YAML or .properties files.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_binding_service_properties" href="#_binding_service_properties"></a>31.1 Binding Service Properties</h2></div></div></div><p>These properties are exposed via <code class="literal">org.springframework.cloud.stream.config.BindingServiceProperties</code></p><div class="variablelist"><dl class="variablelist"><dt><span class="term">spring.cloud.stream.instanceCount</span></dt><dd><p class="simpara">The number of deployed instances of an application.
|
||||
Must be set for partitioning on the producer side. Must be set on the consumer side when using RabbitMQ and with Kafka if <code class="literal">autoRebalanceEnabled=false</code>.</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">spring.cloud.stream.instanceIndex</span></dt><dd>The instance index of the application: A number from <code class="literal">0</code> to <code class="literal">instanceCount - 1</code>.
|
||||
Used for partitioning with RabbitMQ and with Kafka if <code class="literal">autoRebalanceEnabled=false</code>.
|
||||
Automatically set in Cloud Foundry to match the application’s instance index.</dd><dt><span class="term">spring.cloud.stream.dynamicDestinations</span></dt><dd><p class="simpara">A list of destinations that can be bound dynamically (for example, in a dynamic routing scenario).
|
||||
If set, only listed destinations can be bound.</p><p class="simpara">Default: empty (letting any destination be bound).</p></dd><dt><span class="term">spring.cloud.stream.defaultBinder</span></dt><dd><p class="simpara">The default binder to use, if multiple binders are configured.
|
||||
See <a class="link" href="multi_spring-cloud-stream-overview-binders.html#multiple-binders" title="30.4 Multiple Binders on the Classpath">Multiple Binders on the Classpath</a>.</p><p class="simpara">Default: empty.</p></dd><dt><span class="term">spring.cloud.stream.overrideCloudConnectors</span></dt><dd><p class="simpara">This property is only applicable when the <code class="literal">cloud</code> profile is active and Spring Cloud Connectors are provided with the application.
|
||||
If the property is <code class="literal">false</code> (the default), the binder detects a suitable bound service (for example, a RabbitMQ service bound in Cloud Foundry for the RabbitMQ binder) and uses it for creating connections (usually through Spring Cloud Connectors).
|
||||
When set to <code class="literal">true</code>, this property instructs binders to completely ignore the bound services and rely on Spring Boot properties (for example, relying on the <code class="literal">spring.rabbitmq.*</code> properties provided in the environment for the RabbitMQ binder).
|
||||
The typical usage of this property is to be nested in a customized environment <a class="link" href="multi_spring-cloud-stream-overview-binders.html#multiple-systems" title="30.5 Connecting to Multiple Systems">when connecting to multiple systems</a>.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">spring.cloud.stream.bindingRetryInterval</span></dt><dd><p class="simpara">The interval (in seconds) between retrying binding creation when, for example, the binder does not support late binding and the broker (for example, Apache Kafka) is down.
|
||||
Set it to zero to treat such conditions as fatal, preventing the application from starting.</p><p class="simpara">Default: <code class="literal">30</code></p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="binding-properties" href="#binding-properties"></a>31.2 Binding Properties</h2></div></div></div><p>Binding properties are supplied by using the format of <code class="literal">spring.cloud.stream.bindings.<channelName>.<property>=<value></code>.
|
||||
The <code class="literal"><channelName></code> represents the name of the channel being configured (for example, <code class="literal">output</code> for a <code class="literal">Source</code>).</p><p>To avoid repetition, Spring Cloud Stream supports setting values for all channels, in the format of <code class="literal">spring.cloud.stream.default.<property>=<value></code>.</p><p>When it comes to avoiding repetitions for extended binding properties, this format should be used - <code class="literal">spring.cloud.stream.<binder-type>.default.<producer|consumer>.<property>=<value></code>.</p><p>In what follows, we indicate where we have omitted the <code class="literal">spring.cloud.stream.bindings.<channelName>.</code> prefix and focus just on the property name, with the understanding that the prefix ise included at runtime.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_common_binding_properties" href="#_common_binding_properties"></a>31.2.1 Common Binding Properties</h3></div></div></div><p>These properties are exposed via <code class="literal">org.springframework.cloud.stream.config.BindingProperties</code></p><p>The following binding properties are available for both input and output bindings and must be prefixed with <code class="literal">spring.cloud.stream.bindings.<channelName>.</code> (for example, <code class="literal">spring.cloud.stream.bindings.input.destination=ticktock</code>).</p><p>Default values can be set by using the <code class="literal">spring.cloud.stream.default</code> prefix (for example`spring.cloud.stream.default.contentType=application/json`).</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">destination</span></dt><dd>The target destination of a channel on the bound middleware (for example, the RabbitMQ exchange or Kafka topic).
|
||||
If the channel is bound as a consumer, it could be bound to multiple destinations, and the destination names can be specified as comma-separated <code class="literal">String</code> values.
|
||||
If not set, the channel name is used instead.
|
||||
The default value of this property cannot be overridden.</dd><dt><span class="term">group</span></dt><dd><p class="simpara">The consumer group of the channel.
|
||||
Applies only to inbound bindings.
|
||||
See <a class="link" href="multi__main_concepts.html#consumer-groups" title="28.4 Consumer Groups">Consumer Groups</a>.</p><p class="simpara">Default: <code class="literal">null</code> (indicating an anonymous consumer).</p></dd><dt><span class="term">contentType</span></dt><dd><p class="simpara">The content type of the channel.
|
||||
See “<a class="xref" href="multi_content-type-management.html" title="32. Content Type Negotiation">Chapter 32, <i>Content Type Negotiation</i></a>”.</p><p class="simpara">Default: <code class="literal">application/json</code>.</p></dd><dt><span class="term">binder</span></dt><dd><p class="simpara">The binder used by this binding.
|
||||
See “<a class="xref" href="multi_spring-cloud-stream-overview-binders.html#multiple-binders" title="30.4 Multiple Binders on the Classpath">Section 30.4, “Multiple Binders on the Classpath”</a>” for details.</p><p class="simpara">Default: <code class="literal">null</code> (the default binder is used, if it exists).</p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_consumer_properties" href="#_consumer_properties"></a>31.2.2 Consumer Properties</h3></div></div></div><p>These properties are exposed via <code class="literal">org.springframework.cloud.stream.binder.ConsumerProperties</code></p><p>The following binding properties are available for input bindings only and must be prefixed with <code class="literal">spring.cloud.stream.bindings.<channelName>.consumer.</code> (for example, <code class="literal">spring.cloud.stream.bindings.input.consumer.concurrency=3</code>).</p><p>Default values can be set by using the <code class="literal">spring.cloud.stream.default.consumer</code> prefix (for example, <code class="literal">spring.cloud.stream.default.consumer.headerMode=none</code>).</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">concurrency</span></dt><dd><p class="simpara">The concurrency of the inbound consumer.</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">partitioned</span></dt><dd><p class="simpara">Whether the consumer receives data from a partitioned producer.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">headerMode</span></dt><dd><p class="simpara">When set to <code class="literal">none</code>, disables header parsing on input.
|
||||
Effective only for messaging middleware that does not support message headers natively and requires header embedding.
|
||||
This option is useful when consuming data from non-Spring Cloud Stream applications when native headers are not supported.
|
||||
When set to <code class="literal">headers</code>, it uses the middleware’s native header mechanism.
|
||||
When set to <code class="literal">embeddedHeaders</code>, it embeds headers into the message payload.</p><p class="simpara">Default: depends on the binder implementation.</p></dd><dt><span class="term">maxAttempts</span></dt><dd><p class="simpara">If processing fails, the number of attempts to process the message (including the first).
|
||||
Set to <code class="literal">1</code> to disable retry.</p><p class="simpara">Default: <code class="literal">3</code>.</p></dd><dt><span class="term">backOffInitialInterval</span></dt><dd><p class="simpara">The backoff initial interval on retry.</p><p class="simpara">Default: <code class="literal">1000</code>.</p></dd><dt><span class="term">backOffMaxInterval</span></dt><dd><p class="simpara">The maximum backoff interval.</p><p class="simpara">Default: <code class="literal">10000</code>.</p></dd><dt><span class="term">backOffMultiplier</span></dt><dd><p class="simpara">The backoff multiplier.</p><p class="simpara">Default: <code class="literal">2.0</code>.</p></dd><dt><span class="term">defaultRetryable</span></dt><dd><p class="simpara">Whether exceptions thrown by the listener that are not listed in the <code class="literal">retryableExceptions</code> are retryable.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">instanceIndex</span></dt><dd><p class="simpara">When set to a value greater than equal to zero, it allows customizing the instance index of this consumer (if different from <code class="literal">spring.cloud.stream.instanceIndex</code>).
|
||||
When set to a negative value, it defaults to <code class="literal">spring.cloud.stream.instanceIndex</code>.
|
||||
See “<a class="xref" href="multi__inter_application_communication.html#spring-cloud-stream-overview-instance-index-instance-count" title="34.2 Instance Index and Instance Count">Section 34.2, “Instance Index and Instance Count”</a>” for more information.</p><p class="simpara">Default: <code class="literal">-1</code>.</p></dd><dt><span class="term">instanceCount</span></dt><dd><p class="simpara">When set to a value greater than equal to zero, it allows customizing the instance count of this consumer (if different from <code class="literal">spring.cloud.stream.instanceCount</code>).
|
||||
When set to a negative value, it defaults to <code class="literal">spring.cloud.stream.instanceCount</code>.
|
||||
See “<a class="xref" href="multi__inter_application_communication.html#spring-cloud-stream-overview-instance-index-instance-count" title="34.2 Instance Index and Instance Count">Section 34.2, “Instance Index and Instance Count”</a>” for more information.</p><p class="simpara">Default: <code class="literal">-1</code>.</p></dd><dt><span class="term">retryableExceptions</span></dt><dd><p class="simpara">A map of Throwable class names in the key and a boolean in the value.
|
||||
Specify those exceptions (and subclasses) that will or won’t be retried.
|
||||
Also see <code class="literal">defaultRetriable</code>.
|
||||
Example: <code class="literal">spring.cloud.stream.bindings.input.consumer.retryable-exceptions.java.lang.IllegalStateException=false</code>.</p><p class="simpara">Default: empty.</p></dd><dt><span class="term">useNativeDecoding</span></dt><dd><p class="simpara">When set to <code class="literal">true</code>, the inbound message is deserialized directly by the client library, which must be configured correspondingly (for example, setting an appropriate Kafka producer value deserializer).
|
||||
When this configuration is being used, the inbound message unmarshalling is not based on the <code class="literal">contentType</code> of the binding.
|
||||
When native decoding is used, it is the responsibility of the producer to use an appropriate encoder (for example, the Kafka producer value serializer) to serialize the outbound message.
|
||||
Also, when native encoding and decoding is used, the <code class="literal">headerMode=embeddedHeaders</code> property is ignored and headers are not embedded in the message.
|
||||
See the producer property <code class="literal">useNativeEncoding</code>.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_producer_properties" href="#_producer_properties"></a>31.2.3 Producer Properties</h3></div></div></div><p>These properties are exposed via <code class="literal">org.springframework.cloud.stream.binder.ProducerProperties</code></p><p>The following binding properties are available for output bindings only and must be prefixed with <code class="literal">spring.cloud.stream.bindings.<channelName>.producer.</code> (for example, <code class="literal">spring.cloud.stream.bindings.input.producer.partitionKeyExpression=payload.id</code>).</p><p>Default values can be set by using the prefix <code class="literal">spring.cloud.stream.default.producer</code> (for example, <code class="literal">spring.cloud.stream.default.producer.partitionKeyExpression=payload.id</code>).</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">partitionKeyExpression</span></dt><dd><p class="simpara">A SpEL expression that determines how to partition outbound data.
|
||||
If set, or if <code class="literal">partitionKeyExtractorClass</code> is set, outbound data on this channel is partitioned. <code class="literal">partitionCount</code> must be set to a value greater than 1 to be effective.
|
||||
Mutually exclusive with <code class="literal">partitionKeyExtractorClass</code>.
|
||||
See “<a class="xref" href="multi__main_concepts.html#partitioning" title="28.6 Partitioning Support">Section 28.6, “Partitioning Support”</a>”.</p><p class="simpara">Default: null.</p></dd><dt><span class="term">partitionKeyExtractorClass</span></dt><dd><p class="simpara">A <code class="literal">PartitionKeyExtractorStrategy</code> implementation.
|
||||
If set, or if <code class="literal">partitionKeyExpression</code> is set, outbound data on this channel is partitioned. <code class="literal">partitionCount</code> must be set to a value greater than 1 to be effective.
|
||||
Mutually exclusive with <code class="literal">partitionKeyExpression</code>.
|
||||
See “<a class="xref" href="multi__main_concepts.html#partitioning" title="28.6 Partitioning Support">Section 28.6, “Partitioning Support”</a>”.</p><p class="simpara">Default: <code class="literal">null</code>.</p></dd><dt><span class="term">partitionSelectorClass</span></dt><dd><p class="simpara"> A <code class="literal">PartitionSelectorStrategy</code> implementation.
|
||||
Mutually exclusive with <code class="literal">partitionSelectorExpression</code>.
|
||||
If neither is set, the partition is selected as the <code class="literal">hashCode(key) % partitionCount</code>, where <code class="literal">key</code> is computed through either <code class="literal">partitionKeyExpression</code> or <code class="literal">partitionKeyExtractorClass</code>.</p><p class="simpara">Default: <code class="literal">null</code>.</p></dd><dt><span class="term">partitionSelectorExpression</span></dt><dd><p class="simpara">A SpEL expression for customizing partition selection.
|
||||
Mutually exclusive with <code class="literal">partitionSelectorClass</code>.
|
||||
If neither is set, the partition is selected as the <code class="literal">hashCode(key) % partitionCount</code>, where <code class="literal">key</code> is computed through either <code class="literal">partitionKeyExpression</code> or <code class="literal">partitionKeyExtractorClass</code>.</p><p class="simpara">Default: <code class="literal">null</code>.</p></dd><dt><span class="term">partitionCount</span></dt><dd><p class="simpara">The number of target partitions for the data, if partitioning is enabled.
|
||||
Must be set to a value greater than 1 if the producer is partitioned.
|
||||
On Kafka, it is interpreted as a hint. The larger of this and the partition count of the target topic is used instead.</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">requiredGroups</span></dt><dd>A comma-separated list of groups to which the producer must ensure message delivery even if they start after it has been created (for example, by pre-creating durable queues in RabbitMQ).</dd><dt><span class="term">headerMode</span></dt><dd><p class="simpara">When set to <code class="literal">none</code>, it disables header embedding on output.
|
||||
It is effective only for messaging middleware that does not support message headers natively and requires header embedding.
|
||||
This option is useful when producing data for non-Spring Cloud Stream applications when native headers are not supported.
|
||||
When set to <code class="literal">headers</code>, it uses the middleware’s native header mechanism.
|
||||
When set to <code class="literal">embeddedHeaders</code>, it embeds headers into the message payload.</p><p class="simpara">Default: Depends on the binder implementation.</p></dd><dt><span class="term">useNativeEncoding</span></dt><dd><p class="simpara">When set to <code class="literal">true</code>, the outbound message is serialized directly by the client library, which must be configured correspondingly (for example, setting an appropriate Kafka producer value serializer).
|
||||
When this configuration is being used, the outbound message marshalling is not based on the <code class="literal">contentType</code> of the binding.
|
||||
When native encoding is used, it is the responsibility of the consumer to use an appropriate decoder (for example, the Kafka consumer value de-serializer) to deserialize the inbound message.
|
||||
Also, when native encoding and decoding is used, the <code class="literal">headerMode=embeddedHeaders</code> property is ignored and headers are not embedded in the message.
|
||||
See the consumer property <code class="literal">useNativeDecoding</code>.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">errorChannelEnabled</span></dt><dd><p class="simpara">When set to <code class="literal">true</code>, if the binder supports asynchroous send results, send failures are sent to an error channel for the destination.
|
||||
See “<a class="xref" href="">???</a>” for more information.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd></dl></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="dynamicdestination" href="#dynamicdestination"></a>31.3 Using Dynamically Bound Destinations</h2></div></div></div><p>Besides the channels defined by using <code class="literal">@EnableBinding</code>, Spring Cloud Stream lets applications send messages to dynamically bound destinations.
|
||||
This is useful, for example, when the target destination needs to be determined at runtime.
|
||||
Applications can do so by using the <code class="literal">BinderAwareChannelResolver</code> bean, registered automatically by the <code class="literal">@EnableBinding</code> annotation.</p><p>The 'spring.cloud.stream.dynamicDestinations' property can be used for restricting the dynamic destination names to a known set (whitelisting).
|
||||
If this property is not set, any destination can be bound dynamically.</p><p>The <code class="literal">BinderAwareChannelResolver</code> can be used directly, as shown in the following example of a REST controller using a path variable to decide the target channel:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Controller</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> SourceWithDynamicDestination {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> BinderAwareChannelResolver resolver;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestMapping(path = "/{target}", method = POST, consumes = "*/*")</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@ResponseStatus(HttpStatus.ACCEPTED)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> handleRequest(<em><span class="hl-annotation" style="color: gray">@RequestBody</span></em> String body, <em><span class="hl-annotation" style="color: gray">@PathVariable("target")</span></em> target,
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestHeader(HttpHeaders.CONTENT_TYPE)</span></em> Object contentType) {
|
||||
sendMessage(body, target, contentType);
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> sendMessage(String body, String target, Object contentType) {
|
||||
resolver.resolveDestination(target).send(MessageBuilder.createMessage(body,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, contentType))));
|
||||
}
|
||||
}</pre><p>Now consider what happens when we start the application on the default port (8080) and make the following requests with CURL:</p><pre class="screen">curl -H "Content-Type: application/json" -X POST -d "customer-1" http://localhost:8080/customers
|
||||
|
||||
curl -H "Content-Type: application/json" -X POST -d "order-1" http://localhost:8080/orders</pre><p>The destinations, 'customers' and 'orders', are created in the broker (in the exchange for Rabbit or in the topic for Kafka) with names of 'customers' and 'orders', and the data is published to the appropriate destinations.</p><p>The <code class="literal">BinderAwareChannelResolver</code> is a general-purpose Spring Integration <code class="literal">DestinationResolver</code> and can be injected in other components — for example, in a router using a SpEL expression based on the <code class="literal">target</code> field of an incoming JSON message. The following example includes a router that reads SpEL expressions:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Controller</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> SourceWithDynamicDestination {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> BinderAwareChannelResolver resolver;
|
||||
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestMapping(path = "/", method = POST, consumes = "application/json")</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@ResponseStatus(HttpStatus.ACCEPTED)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> handleRequest(<em><span class="hl-annotation" style="color: gray">@RequestBody</span></em> String body, <em><span class="hl-annotation" style="color: gray">@RequestHeader(HttpHeaders.CONTENT_TYPE)</span></em> Object contentType) {
|
||||
sendMessage(body, contentType);
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> sendMessage(Object body, Object contentType) {
|
||||
routerChannel().send(MessageBuilder.createMessage(body,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> MessageHeaders(Collections.singletonMap(MessageHeaders.CONTENT_TYPE, contentType))));
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean(name = "routerChannel")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> MessageChannel routerChannel() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> DirectChannel();
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@ServiceActivator(inputChannel = "routerChannel")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> ExpressionEvaluatingRouter router() {
|
||||
ExpressionEvaluatingRouter router =
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ExpressionEvaluatingRouter(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> SpelExpressionParser().parseExpression(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"payload.target"</span>));
|
||||
router.setDefaultOutputChannelName(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"default-output"</span>);
|
||||
router.setChannelResolver(resolver);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> router;
|
||||
}
|
||||
}</pre><p>The <a class="link" href="https://github.com/spring-cloud-stream-app-starters/router" target="_top">Router Sink Application</a> uses this technique to create the destinations on-demand.</p><p>If the channel names are known in advance, you can configure the producer properties as with any other destination.
|
||||
Alternatively, if you register a <code class="literal">NewBindingCallback<></code> bean, it is invoked just before the binding is created.
|
||||
The callback takes the generic type of the extended producer properties used by the binder.
|
||||
It has one method:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> configure(String channelName, MessageChannel channel, ProducerProperties producerProperties,
|
||||
T extendedProducerProperties);</pre><p>The following example shows how to use the RabbitMQ binder:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> NewBindingCallback<RabbitProducerProperties> dynamicConfigurer() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> (name, channel, props, extended) -> {
|
||||
props.setRequiredGroups(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"bindThisQueue"</span>);
|
||||
extended.setQueueNameGroupOnly(true);
|
||||
extended.setAutoBindDlq(true);
|
||||
extended.setDeadLetterQueueName(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"myDLQ"</span>);
|
||||
};
|
||||
}</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>If you need to support dynamic destinations with multiple binder types, use <code class="literal">Object</code> for the generic type and cast the <code class="literal">extended</code> argument as needed.</p></td></tr></table></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_spring-cloud-stream-overview-binders.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_stream.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_content-type-management.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">30. Binders </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 32. Content Type Negotiation</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,17 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>83. Configuring Authentication Downstream of a Zuul Proxy</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_security.html" title="Part XI. Spring Cloud Security"><link rel="prev" href="multi__more_detail.html" title="82. More Detail"><link rel="next" href="multi__spring_cloud_for_cloud_foundry.html" title="Part XII. Spring Cloud for Cloud Foundry"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">83. Configuring Authentication Downstream of a Zuul Proxy</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__more_detail.html">Prev</a> </td><th width="60%" align="center">Part XI. Spring Cloud Security</th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_for_cloud_foundry.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_configuring_authentication_downstream_of_a_zuul_proxy" href="#_configuring_authentication_downstream_of_a_zuul_proxy"></a>83. Configuring Authentication Downstream of a Zuul Proxy</h2></div></div></div><p>You can control the authorization behaviour downstream of an
|
||||
<code class="literal">@EnableZuulProxy</code> through the <code class="literal">proxy.auth.*</code> settings. Example:</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">proxy</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> auth</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> customers</span>: oauth2
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> stores</span>: passthru
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> recommendations</span>: none</pre><p>
|
||||
</p><p>In this example the "customers" service gets an OAuth2 token relay,
|
||||
the "stores" service gets a passthrough (the authorization header is
|
||||
just passed downstream), and the "recommendations" service has its
|
||||
authorization header removed. The default behaviour is to do a token
|
||||
relay if there is a token available, and passthru otherwise.</p><p>See
|
||||
<a class="link" href="https://github.com/spring-cloud/spring-cloud-security/tree/master/src/main/java/org/springframework/cloud/security/oauth2/proxy/ProxyAuthenticationProperties" target="_top">
|
||||
ProxyAuthenticationProperties</a> for full details.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__more_detail.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_security.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_for_cloud_foundry.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">82. More Detail </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part XII. Spring Cloud for Cloud Foundry</td></tr></table></div></body></html>
|
||||
28
Greenwich.RC2/multi/multi__contributing.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>146. Contributing</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_kubernetes.html" title="Part XVII. Spring Cloud Kubernetes"><link rel="prev" href="multi__building.html" title="145. Building"><link rel="next" href="multi_spring-cloud-gcp-reference.html" title="Part XVIII. Spring Cloud GCP"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">146. Contributing</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__building.html">Prev</a> </td><th width="60%" align="center">Part XVII. Spring Cloud Kubernetes</th><td width="20%" align="right"> <a accesskey="n" href="multi_spring-cloud-gcp-reference.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_contributing" href="#_contributing"></a>146. Contributing</h2></div></div></div><p>Spring Cloud is released under the non-restrictive Apache 2.0 license,
|
||||
and follows a very standard Github development process, using Github
|
||||
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.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_sign_the_contributor_license_agreement" href="#_sign_the_contributor_license_agreement"></a>146.1 Sign the Contributor License Agreement</h2></div></div></div><p>Before we accept a non-trivial patch or pull request we will need you to sign the
|
||||
<a class="link" href="https://cla.pivotal.io/sign/spring" target="_top">Contributor License Agreement</a>.
|
||||
Signing the contributor’s agreement does not grant anyone commit rights to the main
|
||||
repository, but it does mean that we can accept your contributions, and you will get an
|
||||
author credit if we do. Active contributors might be asked to join the core team, and
|
||||
given the ability to merge pull requests.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_code_of_conduct" href="#_code_of_conduct"></a>146.2 Code of Conduct</h2></div></div></div><p>This project adheres to the Contributor Covenant <a class="link" href="https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc" target="_top">code of
|
||||
conduct</a>. By participating, you are expected to uphold this code. Please report
|
||||
unacceptable behavior to <a class="link" href="mailto:spring-code-of-conduct@pivotal.io" target="_top">spring-code-of-conduct@pivotal.io</a>.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_code_conventions_and_housekeeping" href="#_code_conventions_and_housekeeping"></a>146.3 Code Conventions and Housekeeping</h2></div></div></div><p>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.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Use the Spring Framework code format conventions. If you use Eclipse
|
||||
you can import formatter settings using the
|
||||
<code class="literal">eclipse-code-formatter.xml</code> file from the
|
||||
<a class="link" href="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-dependencies-parent/eclipse-code-formatter.xml" target="_top">Spring
|
||||
Cloud Build</a> project. If using IntelliJ, you can use the
|
||||
<a class="link" href="http://plugins.jetbrains.com/plugin/6546" target="_top">Eclipse Code Formatter
|
||||
Plugin</a> to import the same file.</li><li class="listitem">Make sure all new <code class="literal">.java</code> files to have a simple Javadoc class comment with at least an
|
||||
<code class="literal">@author</code> tag identifying you, and preferably at least a paragraph on what the class is
|
||||
for.</li><li class="listitem">Add the ASF license header comment to all new <code class="literal">.java</code> files (copy from existing files
|
||||
in the project)</li><li class="listitem">Add yourself as an <code class="literal">@author</code> to the .java files that you modify substantially (more
|
||||
than cosmetic changes).</li><li class="listitem">Add some Javadocs and, if you change the namespace, some XSD doc elements.</li><li class="listitem">A few unit tests would help a lot as well — someone has to do it.</li><li class="listitem">If no-one else is using your branch, please rebase it against the current master (or
|
||||
other target branch in the main project).</li><li class="listitem">When writing a commit message please follow <a class="link" href="http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html" target="_top">these conventions</a>,
|
||||
if you are fixing an existing issue please add <code class="literal">Fixes gh-XXXX</code> at the end of the commit
|
||||
message (where XXXX is the issue number).</li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__building.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_kubernetes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_spring-cloud-gcp-reference.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">145. Building </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part XVIII. Spring Cloud GCP</td></tr></table></div></body></html>
|
||||
13
Greenwich.RC2/multi/multi__cors_configuration.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>120. CORS Configuration</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_gateway.html" title="Part XV. Spring Cloud Gateway"><link rel="prev" href="multi__reactor_netty_access_logs.html" title="119. Reactor Netty Access Logs"><link rel="next" href="multi__actuator_api.html" title="121. Actuator API"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">120. CORS Configuration</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__reactor_netty_access_logs.html">Prev</a> </td><th width="60%" align="center">Part XV. Spring Cloud Gateway</th><td width="20%" align="right"> <a accesskey="n" href="multi__actuator_api.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_cors_configuration" href="#_cors_configuration"></a>120. CORS Configuration</h2></div></div></div><p>The gateway can be configured to control CORS behavior. The "global" CORS configuration is a map of URL patterns to <a class="link" href="https://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/cors/CorsConfiguration.html" target="_top">Spring Framework <code class="literal">CorsConfiguration</code></a>.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> globalcors</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> corsConfigurations</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> '[/**]'</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> allowedOrigins</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://docs.spring.io"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> allowedMethods</span>:
|
||||
- GET</pre><p>
|
||||
</p><p>In the example above, CORS requests will be allowed from requests that originate from docs.spring.io for all GET requested paths.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__reactor_netty_access_logs.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_gateway.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__actuator_api.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">119. Reactor Netty Access Logs </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 121. Actuator API</td></tr></table></div></body></html>
|
||||
19
Greenwich.RC2/multi/multi__current_span.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>56. Current Span</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__current_tracing_component.html" title="55. Current Tracing Component"><link rel="next" href="multi__instrumentation.html" title="57. Instrumentation"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">56. Current Span</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__current_tracing_component.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__instrumentation.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_current_span" href="#_current_span"></a>56. Current Span</h2></div></div></div><p>Brave supports a “current span” concept which represents the in-flight operation.
|
||||
You can use <code class="literal">Tracer.currentSpan()</code> to add custom tags to a span and <code class="literal">Tracer.nextSpan()</code> to create a child of whatever is in-flight.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>In Sleuth, you can autowire the <code class="literal">Tracer</code> bean to retrieve the current span via
|
||||
<code class="literal">tracer.currentSpan()</code> method. To retrieve the current context just call
|
||||
<code class="literal">tracer.currentSpan().context()</code>. To get the current trace id as String
|
||||
you can use the <code class="literal">traceIdString()</code> method like this: <code class="literal">tracer.currentSpan().context().traceIdString()</code>.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_setting_a_span_in_scope_manually" href="#_setting_a_span_in_scope_manually"></a>56.1 Setting a span in scope manually</h2></div></div></div><p>When writing new instrumentation, it is important to place a span you created in scope as the current span.
|
||||
Not only does doing so let users access it with <code class="literal">Tracer.currentSpan()</code>, but it also allows customizations such as SLF4J MDC to see the current trace IDs.</p><p><code class="literal">Tracer.withSpanInScope(Span)</code> facilitates this and is most conveniently employed by using the try-with-resources idiom.
|
||||
Whenever external code might be invoked (such as proceeding an interceptor or otherwise), place the span in scope, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> (SpanInScope ws = tracer.withSpanInScope(span)) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> inboundRequest.invoke();
|
||||
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">finally</span> { <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// note the scope is independent of the span</span>
|
||||
span.finish();
|
||||
}</pre><p>In edge cases, you may need to clear the current span temporarily (for example, launching a task that should not be associated with the current request). To do tso, pass null to <code class="literal">withSpanInScope</code>, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> (SpanInScope cleared = tracer.withSpanInScope(null)) {
|
||||
startBackgroundThread();
|
||||
}</pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__current_tracing_component.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__instrumentation.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">55. Current Tracing Component </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 57. Instrumentation</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,7 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>55. Current Tracing Component</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__propagation.html" title="54. Propagation"><link rel="next" href="multi__current_span.html" title="56. Current Span"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">55. Current Tracing Component</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__propagation.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__current_span.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_current_tracing_component" href="#_current_tracing_component"></a>55. Current Tracing Component</h2></div></div></div><p>Brave supports a “current tracing component” concept, which should only be used when you have no other way to get a reference.
|
||||
This was made for JDBC connections, as they often initialize prior to the tracing component.</p><p>The most recent tracing component instantiated is available through <code class="literal">Tracing.current()</code>.
|
||||
You can also use <code class="literal">Tracing.currentTracer()</code> to get only the tracer.
|
||||
If you use either of these methods, do not cache the result.
|
||||
Instead, look them up each time you need them.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__propagation.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__current_span.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">54. Propagation </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 56. Current Span</td></tr></table></div></body></html>
|
||||
217
Greenwich.RC2/multi/multi__customization.html
Normal file
@@ -0,0 +1,217 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>94. Customization</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_contract.html" title="Part XIII. Spring Cloud Contract"><link rel="prev" href="multi_contract-dsl.html" title="93. Contract DSL"><link rel="next" href="multi__using_the_pluggable_architecture.html" title="95. Using the Pluggable Architecture"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">94. Customization</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_contract-dsl.html">Prev</a> </td><th width="60%" align="center">Part XIII. Spring Cloud Contract</th><td width="20%" align="right"> <a accesskey="n" href="multi__using_the_pluggable_architecture.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_customization" href="#_customization"></a>94. Customization</h2></div></div></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>This section is valid only for Groovy DSL</p></td></tr></table></div><p>You can customize the Spring Cloud Contract Verifier by extending the DSL, as shown in
|
||||
the remainder of this section.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_extending_the_dsl" href="#_extending_the_dsl"></a>94.1 Extending the DSL</h2></div></div></div><p>You can provide your own functions to the DSL. The key requirement for this feature is to
|
||||
maintain the static compatibility. Later in this document, you can see examples of:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Creating a JAR with reusable classes.</li><li class="listitem">Referencing of these classes in the DSLs.</li></ul></div><p>You can find the full example
|
||||
<a class="link" href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples" target="_top">here</a>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_common_jar" href="#_common_jar"></a>94.1.1 Common JAR</h3></div></div></div><p>The following examples show three classes that can be reused in the DSLs.</p><p><span class="strong"><strong>PatternUtils</strong></span> contains functions used by both the <span class="strong"><strong>consumer</strong></span> and the <span class="strong"><strong>producer</strong></span>.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.example;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> java.util.regex.Pattern;
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* If you want to use {@link Pattern} directly in your tests
|
||||
* then you can create a class resembling this one. It can
|
||||
* contain all the {@link Pattern} you want to use in the DSL.
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* request {
|
||||
* body(
|
||||
* [ age: $(c(PatternUtils.oldEnough()))]
|
||||
* )
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Notice that we're using both {@code $()} for dynamic values
|
||||
* and {@code c()} for the consumer side.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//tag::impl[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> PatternUtils {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> String tooYoung() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::start[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"[0-1][0-9]"</span>;
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::end[return]</span>
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> Pattern oldEnough() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::start[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> Pattern.compile(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"[2-9][0-9]"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::end[return]</span>
|
||||
}
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* Makes little sense but it's just an example ;)
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> Pattern ok() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::start[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> Pattern.compile(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"OK"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::end[return]</span>
|
||||
}
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//end::impl[]</span></pre><p><span class="strong"><strong>ConsumerUtils</strong></span> contains functions used by the <span class="strong"><strong>consumer</strong></span>.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.example;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.contract.spec.internal.ClientDslProperty;
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* DSL Properties passed to the DSL from the consumer's perspective.
|
||||
* That means that on the input side {@code Request} for HTTP
|
||||
* or {@code Input} for messaging you can have a regular expression.
|
||||
* On the {@code Response} for HTTP or {@code Output} for messaging
|
||||
* you have to have a concrete value.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//tag::impl[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> ConsumerUtils {
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* Consumer side property. By using the {@link ClientDslProperty}
|
||||
* you can omit most of boilerplate code from the perspective
|
||||
* of dynamic values. Example
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* request {
|
||||
* body(
|
||||
* [ age: $(ConsumerUtils.oldEnough())]
|
||||
* )
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* That way it's in the implementation that we decide what value we will pass to the consumer
|
||||
* and which one to the producer.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> ClientDslProperty oldEnough() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::start[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// this example is not the best one and</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// theoretically you could just pass the regex instead of `ServerDslProperty` but</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// it's just to show some new tricks :)</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ClientDslProperty(PatternUtils.oldEnough(), <span class="hl-number">40</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//remove::end[return]</span>
|
||||
}
|
||||
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//end::impl[]</span></pre><p><span class="strong"><strong>ProducerUtils</strong></span> contains functions used by the <span class="strong"><strong>producer</strong></span>.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> com.example;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.contract.spec.internal.ServerDslProperty;
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* DSL Properties passed to the DSL from the producer's perspective.
|
||||
* That means that on the input side {@code Request} for HTTP
|
||||
* or {@code Input} for messaging you have to have a concrete value.
|
||||
* On the {@code Response} for HTTP or {@code Output} for messaging
|
||||
* you can have a regular expression.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//tag::impl[]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> ProducerUtils {
|
||||
|
||||
<strong class="hl-tag" style="color: blue">/**
|
||||
* Producer side property. By using the {@link ProducerUtils}
|
||||
* you can omit most of boilerplate code from the perspective
|
||||
* of dynamic values. Example
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* response {
|
||||
* body(
|
||||
* [ status: $(ProducerUtils.ok())]
|
||||
* )
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* That way it's in the implementation that we decide what value we will pass to the consumer
|
||||
* and which one to the producer.
|
||||
*/</strong>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> ServerDslProperty ok() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// this example is not the best one and</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// theoretically you could just pass the regex instead of `ServerDslProperty` but</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// it's just to show some new tricks :)</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ServerDslProperty( PatternUtils.ok(), <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"OK"</span>);
|
||||
}
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//end::impl[]</span></pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_adding_the_dependency_to_the_project" href="#_adding_the_dependency_to_the_project"></a>94.1.2 Adding the Dependency to the Project</h3></div></div></div><p>In order for the plugins and IDE to be able to reference the common JAR classes, you need
|
||||
to pass the dependency to your project.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_test_the_dependency_in_the_project_s_dependencies" href="#_test_the_dependency_in_the_project_s_dependencies"></a>94.1.3 Test the Dependency in the Project’s Dependencies</h3></div></div></div><p>First, add the common jar dependency as a test dependency. Because your contracts files
|
||||
are available on the test resources path, the common jar classes automatically become
|
||||
visible in your Groovy files. The following examples show how to test the dependency:</p><p class="primary"><b>Maven. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>com.example<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>beer-common<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>${project.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><scope></span>test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></scope></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p class="primary">
|
||||
</p><p class="secondary"><b>Gradle. </b>
|
||||
</p><pre class="programlisting">testCompile(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"com.example:beer-common:0.0.1-SNAPSHOT"</span>)</pre><p class="secondary">
|
||||
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_test_a_dependency_in_the_plugin_s_dependencies" href="#_test_a_dependency_in_the_plugin_s_dependencies"></a>94.1.4 Test a Dependency in the Plugin’s Dependencies</h3></div></div></div><p>Now, you must add the dependency for the plugin to reuse at runtime, as shown in the
|
||||
following example:</p><p class="primary"><b>Maven. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><plugin></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-contract-maven-plugin<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>${spring-cloud-contract.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><extensions></span>true<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></extensions></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><configuration></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><packageWithBaseClasses></span>com.example<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></packageWithBaseClasses></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><baseClassMappings></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><baseClassMapping></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><contractPackageRegex></span>.*intoxication.*<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></contractPackageRegex></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><baseClassFQN></span>com.example.intoxication.BeerIntoxicationBase<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></baseClassFQN></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></baseClassMapping></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></baseClassMappings></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></configuration></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>com.example<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>beer-common<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>${project.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><scope></span>compile<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></scope></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></plugin></span></pre><p class="primary">
|
||||
</p><p class="secondary"><b>Gradle. </b>
|
||||
</p><pre class="programlisting">classpath <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"com.example:beer-common:0.0.1-SNAPSHOT"</span></pre><p class="secondary">
|
||||
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_referencing_classes_in_dsls" href="#_referencing_classes_in_dsls"></a>94.1.5 Referencing classes in DSLs</h3></div></div></div><p>You can now reference your classes in your DSL, as shown in the following example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">package</span> contracts.beer.rest
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> com.example.ConsumerUtils
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> com.example.ProducerUtils
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">import</span> org.springframework.cloud.contract.spec.Contract
|
||||
|
||||
Contract.make {
|
||||
description(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">""</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"
|
||||
</span>Represents a successful scenario of getting a beer
|
||||
|
||||
```
|
||||
given:
|
||||
client is old enough
|
||||
when:
|
||||
he applies <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">for</span> a beer
|
||||
then:
|
||||
we<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'ll grant him the beer
|
||||
</span>```
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">""</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">")
|
||||
</span> request {
|
||||
method <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'POST'</span>
|
||||
url <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'/check'</span>
|
||||
body(
|
||||
age: $(ConsumerUtils.oldEnough())
|
||||
)
|
||||
headers {
|
||||
contentType(applicationJson())
|
||||
}
|
||||
}
|
||||
response {
|
||||
status <span class="hl-number">200</span>
|
||||
body(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">""</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"
|
||||
</span> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"status"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"${value(ProducerUtils.ok())}"</span>
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">""</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">")
|
||||
</span> headers {
|
||||
contentType(applicationJson())
|
||||
}
|
||||
}
|
||||
}</pre></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_contract-dsl.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_contract.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__using_the_pluggable_architecture.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">93. Contract DSL </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 95. Using the Pluggable Architecture</td></tr></table></div></body></html>
|
||||
87
Greenwich.RC2/multi/multi__customizations.html
Normal file
@@ -0,0 +1,87 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>61. Customizations</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__managing_spans_with_annotations.html" title="60. Managing Spans with Annotations"><link rel="next" href="multi__sending_spans_to_zipkin.html" title="62. Sending Spans to Zipkin"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">61. Customizations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__managing_spans_with_annotations.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__sending_spans_to_zipkin.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_customizations" href="#_customizations"></a>61. Customizations</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_http" href="#_http"></a>61.1 HTTP</h2></div></div></div><p>If a customization of client / server parsing of the HTTP related spans is required,
|
||||
just register a bean of type <code class="literal">brave.http.HttpClientParser</code> or
|
||||
<code class="literal">brave.http.HttpServerParser</code>. If client /server sampling is required, just
|
||||
register a bean of type <code class="literal">brave.http.HttpSampler</code> and name the bean
|
||||
<code class="literal">sleuthClientSampler</code> for client sampler and <code class="literal">sleuthServerSampler</code> for server sampler.
|
||||
For your convenience the <code class="literal">@ClientSampler</code> and <code class="literal">@ServerSampler</code>
|
||||
annotations can be used to inject the proper beans or to
|
||||
reference the bean names via their static String <code class="literal">NAME</code> fields.</p><p>Check out Brave’s code to see an example of how to make a path-based sampler
|
||||
<a class="link" href="https://github.com/openzipkin/brave/tree/master/instrumentation/http#sampling-policy" target="_top">https://github.com/openzipkin/brave/tree/master/instrumentation/http#sampling-policy</a></p><p>If you want to completely rewrite the <code class="literal">HttpTracing</code> bean you can use the <code class="literal">SkipPatternProvider</code>
|
||||
interface to retrieve the URL <code class="literal">Pattern</code> for spans that should be not sampled. Below you can see
|
||||
an example of usage of <code class="literal">SkipPatternProvider</code> inside a server side, <code class="literal">HttpSampler</code>.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Config {
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean(name = ServerSampler.NAME)</span></em>
|
||||
HttpSampler myHttpSampler(SkipPatternProvider provider) {
|
||||
Pattern pattern = provider.skipPattern();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> HttpSampler() {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <Req> Boolean trySample(HttpAdapter<Req, ?> adapter, Req request) {
|
||||
String url = adapter.path(request);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> shouldSkip = pattern.matcher(url).matches();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (shouldSkip) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> false;
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="__literal_tracingfilter_literal" href="#__literal_tracingfilter_literal"></a>61.2 <code class="literal">TracingFilter</code></h2></div></div></div><p>You can also modify the behavior of the <code class="literal">TracingFilter</code>, which is the component that is responsible for processing the input HTTP request and adding tags basing on the HTTP response.
|
||||
You can customize the tags or modify the response headers by registering your own instance of the <code class="literal">TracingFilter</code> bean.</p><p>In the following example, we register the <code class="literal">TracingFilter</code> bean, add the <code class="literal">ZIPKIN-TRACE-ID</code> response header containing the current Span’s trace id, and add a tag with key <code class="literal">custom</code> and a value <code class="literal">tag</code> to the span.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Component</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Order(TraceWebServletAutoConfiguration.TRACING_FILTER_ORDER + 1)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyFilter <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> GenericFilterBean {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> Tracer tracer;
|
||||
|
||||
MyFilter(Tracer tracer) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracer = tracer;
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> IOException, ServletException {
|
||||
Span currentSpan = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracer.currentSpan();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (currentSpan == null) {
|
||||
chain.doFilter(request, response);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span>;
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// for readability we're returning trace id in a hex form</span>
|
||||
((HttpServletResponse) response).addHeader(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"ZIPKIN-TRACE-ID"</span>,
|
||||
currentSpan.context().traceIdString());
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// we can also add some custom tags</span>
|
||||
currentSpan.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"custom"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tag"</span>);
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_custom_service_name" href="#_custom_service_name"></a>61.3 Custom service name</h2></div></div></div><p>By default, Sleuth assumes that, when you send a span to Zipkin, you want the span’s service name to be equal to the value of the <code class="literal">spring.application.name</code> property.
|
||||
That is not always the case, though.
|
||||
There are situations in which you want to explicitly provide a different service name for all spans coming from your application.
|
||||
To achieve that, you can pass the following property to your application to override that value (the example is for a service named <code class="literal">myService</code>):</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.zipkin.service.name</span>: myService</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_customization_of_reported_spans" href="#_customization_of_reported_spans"></a>61.4 Customization of Reported Spans</h2></div></div></div><p>Before reporting spans (for example, to Zipkin) you may want to modify that span in some way.
|
||||
You can do so by using the <code class="literal">FinishedSpanHandler</code> interface.</p><p>In Sleuth, we generate spans with a fixed name.
|
||||
Some users want to modify the name depending on values of tags.
|
||||
You can implement the <code class="literal">FinishedSpanHandler</code> interface to alter that name.</p><p>The following example shows how to register two beans that implement <code class="literal">FinishedSpanHandler</code>:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
FinishedSpanHandler handlerOne() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> FinishedSpanHandler() {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> handle(TraceContext traceContext, MutableSpan span) {
|
||||
span.name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> true; <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// keep this span</span>
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
FinishedSpanHandler handlerTwo() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> FinishedSpanHandler() {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> handle(TraceContext traceContext, MutableSpan span) {
|
||||
span.name(span.name() + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">" bar"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> true; <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// keep this span</span>
|
||||
}
|
||||
};
|
||||
}</pre><p>The preceding example results in changing the name of the reported span to <code class="literal">foo bar</code>, just before it gets reported (for example, to Zipkin).</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_host_locator" href="#_host_locator"></a>61.5 Host Locator</h2></div></div></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>This section is about defining <span class="strong"><strong>host</strong></span> from service discovery.
|
||||
It is <span class="strong"><strong>NOT</strong></span> about finding Zipkin through service discovery.</p></td></tr></table></div><p>To define the host that corresponds to a particular span, we need to resolve the host name and port.
|
||||
The default approach is to take these values from server properties.
|
||||
If those are not set, we try to retrieve the host name from the network interfaces.</p><p>If you have the discovery client enabled and prefer to retrieve the host address from the registered instance in a service registry, you have to set the <code class="literal">spring.zipkin.locator.discovery.enabled</code> property (it is applicable for both HTTP-based and Stream-based span reporting), as follows:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.zipkin.locator.discovery.enabled</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">true</span></pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__managing_spans_with_annotations.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__sending_spans_to_zipkin.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">60. Managing Spans with Annotations </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 62. Sending Spans to Zipkin</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>47. Customizing the Message Broker</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_bus.html" title="Part VII. Spring Cloud Bus"><link rel="prev" href="multi__service_id_must_be_unique.html" title="46. Service ID Must Be Unique"><link rel="next" href="multi__tracing_bus_events.html" title="48. Tracing Bus Events"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">47. Customizing the Message Broker</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__service_id_must_be_unique.html">Prev</a> </td><th width="60%" align="center">Part VII. Spring Cloud Bus</th><td width="20%" align="right"> <a accesskey="n" href="multi__tracing_bus_events.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_customizing_the_message_broker" href="#_customizing_the_message_broker"></a>47. Customizing the Message Broker</h2></div></div></div><p>Spring Cloud Bus uses <a class="link" href="https://cloud.spring.io/spring-cloud-stream" target="_top">Spring Cloud Stream</a> to
|
||||
broadcast the messages. So, to get messages to flow, you need only include the binder
|
||||
implementation of your choice in the classpath. There are convenient starters for the bus
|
||||
with AMQP (RabbitMQ) and Kafka (<code class="literal">spring-cloud-starter-bus-[amqp|kafka]</code>). Generally
|
||||
speaking, Spring Cloud Stream relies on Spring Boot autoconfiguration conventions for
|
||||
configuring middleware. For instance, the AMQP broker address can be changed with
|
||||
<code class="literal">spring.rabbitmq.*</code> configuration properties. Spring Cloud Bus has a handful of
|
||||
native configuration properties in <code class="literal">spring.cloud.bus.*</code> (for example,
|
||||
<code class="literal">spring.cloud.bus.destination</code> is the name of the topic to use as the external
|
||||
middleware). Normally, the defaults suffice.</p><p>To learn more about how to customize the message broker settings, consult the Spring Cloud
|
||||
Stream documentation.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__service_id_must_be_unique.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_bus.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__tracing_bus_events.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">46. Service ID Must Be Unique </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 48. Tracing Bus Events</td></tr></table></div></body></html>
|
||||
15
Greenwich.RC2/multi/multi__dependency_management.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>148. Dependency Management</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi_spring-cloud-gcp-reference.html" title="Part XVIII. Spring Cloud GCP"><link rel="prev" href="multi__introduction_4.html" title="147. Introduction"><link rel="next" href="multi__getting_started_2.html" title="149. Getting started"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">148. Dependency Management</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__introduction_4.html">Prev</a> </td><th width="60%" align="center">Part XVIII. Spring Cloud GCP</th><td width="20%" align="right"> <a accesskey="n" href="multi__getting_started_2.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_dependency_management" href="#_dependency_management"></a>148. Dependency Management</h2></div></div></div><p>The Spring Cloud GCP Bill of Materials (BOM) contains the versions of all the dependencies it uses.</p><p>If you’re a Maven user, adding the following to your pom.xml file will allow you to not specify any Spring Cloud GCP dependency versions.
|
||||
Instead, the version of the BOM you’re using determines the versions of the used dependencies.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencyManagement></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-gcp-dependencies<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>{project-version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><type></span>pom<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></type></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><scope></span>import<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></scope></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencyManagement></span></pre><p>In the following sections, it will be assumed you are using the Spring Cloud GCP BOM and the dependency snippets will not contain versions.</p><p>Gradle users can achieve the same kind of BOM experience using Spring’s <a class="link" href="https://github.com/spring-gradle-plugins/dependency-management-plugin" target="_top">dependency-management-plugin</a> Gradle plugin.
|
||||
For simplicity, the Gradle dependency snippets in the remainder of this document will also omit their versions.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__introduction_4.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi_spring-cloud-gcp-reference.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__getting_started_2.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">147. Introduction </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 149. Getting started</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>130. Deploying a Packaged Function</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_function_2.html" title="Part XVI. Spring Cloud Function"><link rel="prev" href="multi__standalone_streaming_applications.html" title="129. Standalone Streaming Applications"><link rel="next" href="multi__functional_bean_definitions.html" title="131. Functional Bean Definitions"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">130. Deploying a Packaged Function</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__standalone_streaming_applications.html">Prev</a> </td><th width="60%" align="center">Part XVI. Spring Cloud Function</th><td width="20%" align="right"> <a accesskey="n" href="multi__functional_bean_definitions.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_deploying_a_packaged_function" href="#_deploying_a_packaged_function"></a>130. Deploying a Packaged Function</h2></div></div></div><p>Spring Cloud Function provides a "deployer" library that allows you to launch a jar file (or exploded archive, or set of jar files) with an isolated class loader and expose the functions defined in it. This is quite a powerful tool that would allow you to, for instance, adapt a function to a range of different input-output adapters without changing the target jar file. Serverless platforms often have this kind of feature built in, so you could see it as a building block for a function invoker in such a platform (indeed the <a class="link" href="https://projectriff.io" target="_top">Riff</a> Java function invoker uses this library).</p><p>The standard entry point of the API is the Spring configuration annotation <code class="literal">@EnableFunctionDeployer</code>. If that is used in a Spring Boot application the deployer kicks in and looks for some configuration to tell it where to find the function jar. At a minimum the user has to provide a <code class="literal">function.location</code> which is a URL or resource location for the archive containing the functions. It can optionally use a <code class="literal">maven:</code> prefix to locate the artifact via a dependency lookup (see <code class="literal">FunctionProperties</code> for complete details). A Spring Boot application is bootstrapped from the jar file, using the <code class="literal">MANIFEST.MF</code> to locate a start class, so that a standard Spring Boot fat jar works well, for example. If the target jar can be launched successfully then the result is a function registered in the main application’s <code class="literal">FunctionCatalog</code>. The registered function can be applied by code in the main application, even though it was created in an isolated class loader (by deault).</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__standalone_streaming_applications.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_function_2.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__functional_bean_definitions.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">129. Standalone Streaming Applications </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 131. Functional Bean Definitions</td></tr></table></div></body></html>
|
||||
50
Greenwich.RC2/multi/multi__developer_guide.html
Normal file
@@ -0,0 +1,50 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>122. Developer Guide</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_gateway.html" title="Part XV. Spring Cloud Gateway"><link rel="prev" href="multi__actuator_api.html" title="121. Actuator API"><link rel="next" href="multi__building_a_simple_gateway_using_spring_mvc_or_webflux.html" title="123. Building a Simple Gateway Using Spring MVC or Webflux"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">122. Developer Guide</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__actuator_api.html">Prev</a> </td><th width="60%" align="center">Part XV. Spring Cloud Gateway</th><td width="20%" align="right"> <a accesskey="n" href="multi__building_a_simple_gateway_using_spring_mvc_or_webflux.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_developer_guide" href="#_developer_guide"></a>122. Developer Guide</h2></div></div></div><p>TODO: overview of writing custom integrations</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_writing_custom_route_predicate_factories" href="#_writing_custom_route_predicate_factories"></a>122.1 Writing Custom Route Predicate Factories</h2></div></div></div><p>TODO: document writing Custom Route Predicate Factories</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_writing_custom_gatewayfilter_factories" href="#_writing_custom_gatewayfilter_factories"></a>122.2 Writing Custom GatewayFilter Factories</h2></div></div></div><p>In order to write a GatewayFilter you will need to implement <code class="literal">GatewayFilterFactory</code>. There is an abstract class called <code class="literal">AbstractGatewayFilterFactory</code> which you can extend.</p><p><b>PreGatewayFilterFactory.java. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> PreGatewayFilterFactory <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> PreGatewayFilterFactory() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">super</span>(Config.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> GatewayFilter apply(Config config) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// grab configuration from Config object</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> (exchange, chain) -> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//If you want to build a "pre" filter you need to manipulate the</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//request before calling change.filter</span>
|
||||
ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//use builder to manipulate the request</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> chain.filter(exchange.mutate().request(request).build());
|
||||
};
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Config {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//Put the configuration properties for your filter here</span>
|
||||
}
|
||||
|
||||
}</pre><p>
|
||||
</p><p><b>PostGatewayFilterFactory.java. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> PostGatewayFilterFactory <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> PostGatewayFilterFactory() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">super</span>(Config.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> GatewayFilter apply(Config config) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// grab configuration from Config object</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> (exchange, chain) -> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> chain.filter(exchange).then(Mono.fromRunnable(() -> {
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//Manipulate the response in some way</span>
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Config {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//Put the configuration properties for your filter here</span>
|
||||
}
|
||||
|
||||
}</pre><p>
|
||||
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_writing_custom_global_filters" href="#_writing_custom_global_filters"></a>122.3 Writing Custom Global Filters</h2></div></div></div><p>TODO: document writing Custom Global Filters</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_writing_custom_route_locators_and_writers" href="#_writing_custom_route_locators_and_writers"></a>122.4 Writing Custom Route Locators and Writers</h2></div></div></div><p>TODO: document writing Custom Route Locators and Writers</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__actuator_api.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_gateway.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__building_a_simple_gateway_using_spring_mvc_or_webflux.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">121. Actuator API </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 123. Building a Simple Gateway Using Spring MVC or Webflux</td></tr></table></div></body></html>
|
||||
22
Greenwich.RC2/multi/multi__discovery.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>84. Discovery</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_for_cloud_foundry.html" title="Part XII. Spring Cloud for Cloud Foundry"><link rel="prev" href="multi__spring_cloud_for_cloud_foundry.html" title="Part XII. Spring Cloud for Cloud Foundry"><link rel="next" href="multi__single_sign_on_2.html" title="85. Single Sign On"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">84. Discovery</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_for_cloud_foundry.html">Prev</a> </td><th width="60%" align="center">Part XII. Spring Cloud for Cloud Foundry</th><td width="20%" align="right"> <a accesskey="n" href="multi__single_sign_on_2.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_discovery" href="#_discovery"></a>84. Discovery</h2></div></div></div><p>Here’s a Spring Cloud app with Cloud Foundry discovery:</p><p><b>app.groovy. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Grab('org.springframework.cloud:spring-cloud-cloudfoundry')</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@RestController</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableDiscoveryClient</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
DiscoveryClient client
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestMapping('/')</span></em>
|
||||
String home() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'Hello from '</span> + client.getLocalServiceInstance()
|
||||
}
|
||||
|
||||
}</pre><p>
|
||||
</p><p>If you run it without any service bindings:</p><pre class="screen">$ spring jar app.jar app.groovy
|
||||
$ cf push -p app.jar</pre><p>It will show its app name in the home page.</p><p>The <code class="literal">DiscoveryClient</code> can lists all the apps in a space, according to
|
||||
the credentials it is authenticated with, where the space defaults to
|
||||
the one the client is running in (if any). If neither org nor space
|
||||
are configured, they default per the user’s profile in Cloud Foundry.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_for_cloud_foundry.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_for_cloud_foundry.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__single_sign_on_2.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part XII. Spring Cloud for Cloud Foundry </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 85. Single Sign On</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,20 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>135. DiscoveryClient for Kubernetes</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_kubernetes.html" title="Part XVII. Spring Cloud Kubernetes"><link rel="prev" href="multi__why_do_you_need_spring_cloud_kubernetes.html" title="134. Why do you need Spring Cloud Kubernetes?"><link rel="next" href="multi__kubernetes_native_service_discovery.html" title="136. Kubernetes native service discovery"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">135. DiscoveryClient for Kubernetes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__why_do_you_need_spring_cloud_kubernetes.html">Prev</a> </td><th width="60%" align="center">Part XVII. Spring Cloud Kubernetes</th><td width="20%" align="right"> <a accesskey="n" href="multi__kubernetes_native_service_discovery.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_discoveryclient_for_kubernetes" href="#_discoveryclient_for_kubernetes"></a>135. DiscoveryClient for Kubernetes</h2></div></div></div><p>This project provides an implementation of <a class="link" href="https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/DiscoveryClient.java" target="_top">Discovery Client</a>
|
||||
for <a class="link" href="http://kubernetes.io" target="_top">Kubernetes</a>.
|
||||
This allows you to query Kubernetes endpoints <span class="strong"><strong>(see <a class="link" href="http://kubernetes.io/docs/user-guide/services/" target="_top">services</a>)</strong></span> by name.
|
||||
A service is typically exposed by the Kubernetes API server as a collection of endpoints which represent <code class="literal">http</code>, <code class="literal">https</code> addresses that a client can
|
||||
access from a Spring Boot application running as a pod. This discovery feature is also used by the Spring Cloud Kubernetes Ribbon project
|
||||
to fetch the list of the endpoints defined for an application to be load balanced.</p><p>This is something that you get for free just by adding the following dependency inside your project:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-kubernetes<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>${latest.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p>To enable loading of the <code class="literal">DiscoveryClient</code>, add <code class="literal">@EnableDiscoveryClient</code> to the according configuration or application class like this:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableDiscoveryClient</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(Application.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
}
|
||||
}</pre><p>Then you can inject the client in your code simply by:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> DiscoveryClient discoveryClient;</pre><p>If for any reason you need to disable the <code class="literal">DiscoveryClient</code> you can simply set the following property in <code class="literal">application.properties</code>:</p><pre class="screen">spring.cloud.kubernetes.discovery.enabled=false</pre><p>Some Spring Cloud components use the <code class="literal">DiscoveryClient</code> in order to obtain info about the local service instance. For
|
||||
this to work you need to align the Kubernetes service name with the <code class="literal">spring.application.name</code> property.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__why_do_you_need_spring_cloud_kubernetes.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_kubernetes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__kubernetes_native_service_discovery.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">134. Why do you need Spring Cloud Kubernetes? </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 136. Kubernetes native service discovery</td></tr></table></div></body></html>
|
||||
23
Greenwich.RC2/multi/multi__dynamic_compilation.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>132. Dynamic Compilation</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_function_2.html" title="Part XVI. Spring Cloud Function"><link rel="prev" href="multi__functional_bean_definitions.html" title="131. Functional Bean Definitions"><link rel="next" href="multi__serverless_platform_adapters.html" title="133. Serverless Platform Adapters"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">132. Dynamic Compilation</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__functional_bean_definitions.html">Prev</a> </td><th width="60%" align="center">Part XVI. Spring Cloud Function</th><td width="20%" align="right"> <a accesskey="n" href="multi__serverless_platform_adapters.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_dynamic_compilation" href="#_dynamic_compilation"></a>132. Dynamic Compilation</h2></div></div></div><p>There is a sample app that uses the function compiler to create a
|
||||
function from a configuration property. The vanilla "function-sample"
|
||||
also has that feature. And there are some scripts that you can run to
|
||||
see the compilation happening at run time. To run these examples,
|
||||
change into the <code class="literal">scripts</code> directory:</p><pre class="screen">cd scripts</pre><p>Also, start a RabbitMQ server locally (e.g. execute <code class="literal">rabbitmq-server</code>).</p><p>Start the Function Registry Service:</p><pre class="screen">./function-registry.sh</pre><p>Register a Function:</p><pre class="screen">./registerFunction.sh -n uppercase -f "f->f.map(s->s.toString().toUpperCase())"</pre><p>Run a REST Microservice using that Function:</p><pre class="screen">./web.sh -f uppercase -p 9000
|
||||
curl -H "Content-Type: text/plain" -H "Accept: text/plain" localhost:9000/uppercase -d foo</pre><p>Register a Supplier:</p><pre class="screen">./registerSupplier.sh -n words -f "()->Flux.just(\"foo\",\"bar\")"</pre><p>Run a REST Microservice using that Supplier:</p><pre class="screen">./web.sh -s words -p 9001
|
||||
curl -H "Accept: application/json" localhost:9001/words</pre><p>Register a Consumer:</p><pre class="screen">./registerConsumer.sh -n print -t String -f "System.out::println"</pre><p>Run a REST Microservice using that Consumer:</p><pre class="screen">./web.sh -c print -p 9002
|
||||
curl -X POST -H "Content-Type: text/plain" -d foo localhost:9002/print</pre><p>Run Stream Processing Microservices:</p><p>First register a streaming words supplier:</p><pre class="screen">./registerSupplier.sh -n wordstream -f "()->Flux.interval(Duration.ofMillis(1000)).map(i->\"message-\"+i)"</pre><p>Then start the source (supplier), processor (function), and sink (consumer) apps
|
||||
(in reverse order):</p><pre class="screen">./stream.sh -p 9103 -i uppercaseWords -c print
|
||||
./stream.sh -p 9102 -i words -f uppercase -o uppercaseWords
|
||||
./stream.sh -p 9101 -s wordstream -o words</pre><p>The output will appear in the console of the sink app (one message per second, converted to uppercase):</p><pre class="screen">MESSAGE-0
|
||||
MESSAGE-1
|
||||
MESSAGE-2
|
||||
MESSAGE-3
|
||||
MESSAGE-4
|
||||
MESSAGE-5
|
||||
MESSAGE-6
|
||||
MESSAGE-7
|
||||
MESSAGE-8
|
||||
MESSAGE-9
|
||||
...</pre></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__functional_bean_definitions.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_function_2.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__serverless_platform_adapters.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">131. Functional Bean Definitions </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 133. Serverless Platform Adapters</td></tr></table></div></body></html>
|
||||
26
Greenwich.RC2/multi/multi__embedding_the_config_server.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>8. Embedding the Config Server</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_config.html" title="Part II. Spring Cloud Config"><link rel="prev" href="multi__serving_plain_text.html" title="7. Serving Plain Text"><link rel="next" href="multi__push_notifications_and_spring_cloud_bus.html" title="9. Push Notifications and Spring Cloud Bus"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">8. Embedding the Config Server</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__serving_plain_text.html">Prev</a> </td><th width="60%" align="center">Part II. Spring Cloud Config</th><td width="20%" align="right"> <a accesskey="n" href="multi__push_notifications_and_spring_cloud_bus.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_embedding_the_config_server" href="#_embedding_the_config_server"></a>8. Embedding the Config Server</h2></div></div></div><p>The Config Server runs best as a standalone application.
|
||||
However, if need be, you can embed it in another application.
|
||||
To do so, use the <code class="literal">@EnableConfigServer</code> annotation.
|
||||
An optional property named <code class="literal">spring.cloud.config.server.bootstrap</code> can be useful in this case.
|
||||
It is a flag to indicate whether the server should configure itself from its own remote repository.
|
||||
By default, the flag is off, because it can delay startup.
|
||||
However, when embedded in another application, it makes sense to initialize the same way as any other application.
|
||||
When setting <code class="literal">spring.cloud.config.server.bootstrap</code> to <code class="literal">true</code> you must also use a <a class="link" href="multi__spring_cloud_config_server.html#composite-environment-repositories" title="5.1.9 Composite Environment Repositories">composite environment repository configuration</a>.
|
||||
For example</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> application</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: configserver
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> profiles</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> active</span>: composite
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> config</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> server</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> composite</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - type</span>: native
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> search-locations</span>: ${HOME}/Desktop/config
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> bootstrap</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">true</span></pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>If you use the bootstrap flag, the config server needs to have its name and repository URI configured in <code class="literal">bootstrap.yml</code>.</p></td></tr></table></div><p>To change the location of the server endpoints, you can (optionally) set <code class="literal">spring.cloud.config.server.prefix</code> (for example, <code class="literal">/config</code>), to serve the resources under a prefix.
|
||||
The prefix should start but not end with a <code class="literal">/</code>.
|
||||
It is applied to the <code class="literal">@RequestMappings</code> in the Config Server (that is, underneath the Spring Boot <code class="literal">server.servletPath</code> and <code class="literal">server.contextPath</code> prefixes).</p><p>If you want to read the configuration for an application directly from the backend repository (instead of from the config server), you
|
||||
basically want an embedded config server with no endpoints.
|
||||
You can switch off the endpoints entirely by not using the <code class="literal">@EnableConfigServer</code> annotation (set <code class="literal">spring.cloud.config.server.bootstrap=true</code>).</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__serving_plain_text.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_config.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__push_notifications_and_spring_cloud_bus.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">7. Serving Plain Text </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 9. Push Notifications and Spring Cloud Bus</td></tr></table></div></body></html>
|
||||
5
Greenwich.RC2/multi/multi__examples_2.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>143. Examples</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_kubernetes.html" title="Part XVII. Spring Cloud Kubernetes"><link rel="prev" href="multi__security_configurations_inside_kubernetes.html" title="142. Security Configurations inside Kubernetes"><link rel="next" href="multi__other_resources.html" title="144. Other Resources"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">143. Examples</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__security_configurations_inside_kubernetes.html">Prev</a> </td><th width="60%" align="center">Part XVII. Spring Cloud Kubernetes</th><td width="20%" align="right"> <a accesskey="n" href="multi__other_resources.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_examples_2" href="#_examples_2"></a>143. Examples</h2></div></div></div><p>Spring Cloud Kubernetes tries to make it transparent for your applications to consume Kubernetes Native Services
|
||||
following the Spring Cloud interfaces.</p><p>In your applications, you need to add the <span class="strong"><strong>spring-cloud-kubernetes-discovery</strong></span> dependency to your classpath and remove any other dependency that contains a <span class="strong"><strong>DiscoveryClient</strong></span> implementation (ie. Eureka Discovery Client).
|
||||
The same applies for PropertySourceLocator, where you need to add to the classpath the <span class="strong"><strong>spring-cloud-kubernetes-config</strong></span> and remove any other dependency that contains a <span class="strong"><strong>PropertySourceLocator</strong></span> implementation (ie. Config Server Client).</p><p>The following projects highlight the usage of these dependencies and demonstrate how these libraries can be used from any Spring Boot application.</p><p>List of examples using these projects:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="link" href="https://github.com/spring-cloud/spring-cloud-kubernetes/tree/master/spring-cloud-kubernetes-examples" target="_top">Spring Cloud Kubernetes Examples</a>: the ones located inside this repository.</li><li class="listitem">Spring Cloud Kubernetes Full Example: Minions and Boss</li><li class="listitem"><a class="link" href="https://github.com/salaboy/spring-cloud-k8s-minion" target="_top">Minion</a></li><li class="listitem"><a class="link" href="https://github.com/salaboy/spring-cloud-k8s-boss" target="_top">Boss</a></li><li class="listitem">Spring Cloud Kubernetes Full Example: <a class="link" href="https://github.com/salaboy/s1p_docs" target="_top">SpringOne Platform Tickets Service</a></li><li class="listitem"><a class="link" href="https://github.com/salaboy/s1p_gateway" target="_top">Spring Cloud Gateway with Spring Cloud Kubernetes Discovery and Config</a></li><li class="listitem"><a class="link" href="https://github.com/salaboy/showcase-admin-tool" target="_top">Spring Boot Admin with Spring Cloud Kubernetes Discovery and Config</a></li></ul></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__security_configurations_inside_kubernetes.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_kubernetes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__other_resources.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">142. Security Configurations inside Kubernetes </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 144. Other Resources</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,20 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>17. External Configuration: Archaius</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_netflix.html" title="Part III. Spring Cloud Netflix"><link rel="prev" href="multi_spring-cloud-ribbon.html" title="16. Client Side Load Balancer: Ribbon"><link rel="next" href="multi__router_and_filter_zuul.html" title="18. Router and Filter: Zuul"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">17. External Configuration: Archaius</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_spring-cloud-ribbon.html">Prev</a> </td><th width="60%" align="center">Part III. Spring Cloud Netflix</th><td width="20%" align="right"> <a accesskey="n" href="multi__router_and_filter_zuul.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_external_configuration_archaius" href="#_external_configuration_archaius"></a>17. External Configuration: Archaius</h2></div></div></div><p><a class="link" href="https://github.com/Netflix/archaius" target="_top">Archaius</a> is the Netflix client-side configuration library.
|
||||
It is the library used by all of the Netflix OSS components for configuration.
|
||||
Archaius is an extension of the <a class="link" href="http://commons.apache.org/proper/commons-configuration" target="_top">Apache Commons Configuration</a> project.
|
||||
It allows updates to configuration by either polling a source for changes or by letting a source push changes to the client.
|
||||
Archaius uses Dynamic<Type>Property classes as handles to properties, as shown in the following example:</p><p><b>Archaius Example. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> ArchaiusTest {
|
||||
DynamicStringProperty myprop = DynamicPropertyFactory
|
||||
.getInstance()
|
||||
.getStringProperty(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"my.prop"</span>);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> doSomething() {
|
||||
OtherClass.someMethod(myprop.get());
|
||||
}
|
||||
}</pre><p>
|
||||
</p><p>Archaius has its own set of configuration files and loading priorities.
|
||||
Spring applications should generally not use Archaius directly, but the need to configure the Netflix tools natively remains.
|
||||
Spring Cloud has a Spring Environment Bridge so that Archaius can read properties from the Spring Environment.
|
||||
This bridge allows Spring Boot projects to use the normal configuration toolchain while letting them configure the Netflix tools as documented (for the most part).</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_spring-cloud-ribbon.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_netflix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__router_and_filter_zuul.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">16. Client Side Load Balancer: Ribbon </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 18. Router and Filter: Zuul</td></tr></table></div></body></html>
|
||||
4
Greenwich.RC2/multi/multi__features.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>1. Features</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="prev" href="multi_pr01.html" title=""><link rel="next" href="multi__cloud_native_applications.html" title="Part I. Cloud Native Applications"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">1. Features</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_pr01.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__cloud_native_applications.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_features" href="#_features"></a>1. Features</h1></div></div></div><p>Spring Cloud focuses on providing good out of box experience for typical use cases
|
||||
and extensibility mechanism to cover others.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Distributed/versioned configuration</li><li class="listitem">Service registration and discovery</li><li class="listitem">Routing</li><li class="listitem">Service-to-service calls</li><li class="listitem">Load balancing</li><li class="listitem">Circuit Breakers</li><li class="listitem">Distributed messaging</li></ul></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_pr01.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__cloud_native_applications.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top"> </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part I. Cloud Native Applications</td></tr></table></div></body></html>
|
||||
139
Greenwich.RC2/multi/multi__features_2.html
Normal file
@@ -0,0 +1,139 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>52. Features</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__additional_resources.html" title="51. Additional Resources"><link rel="next" href="multi__sampling.html" title="53. Sampling"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">52. Features</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__additional_resources.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__sampling.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_features_2" href="#_features_2"></a>52. Features</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p class="simpara">Adds trace and span IDs to the Slf4J MDC, so you can extract all the logs from a given trace or span in a log aggregator, as shown in the following example logs:</p><pre class="screen">2016-02-02 15:30:57.902 INFO [bar,6bfd228dc00d216b,6bfd228dc00d216b,false] 23030 --- [nio-8081-exec-3] ...
|
||||
2016-02-02 15:30:58.372 ERROR [bar,6bfd228dc00d216b,6bfd228dc00d216b,false] 23030 --- [nio-8081-exec-3] ...
|
||||
2016-02-02 15:31:01.936 INFO [bar,46ab0d418373cbc9,46ab0d418373cbc9,false] 23030 --- [nio-8081-exec-4] ...</pre><p class="simpara">Notice the <code class="literal">[appname,traceId,spanId,exportable]</code> entries from the MDC:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem"><span class="strong"><strong><code class="literal">spanId</code></strong></span>: The ID of a specific operation that took place.</li><li class="listitem"><span class="strong"><strong><code class="literal">appname</code></strong></span>: The name of the application that logged the span.</li><li class="listitem"><span class="strong"><strong><code class="literal">traceId</code></strong></span>: The ID of the latency graph that contains the span.</li><li class="listitem"><span class="strong"><strong><code class="literal">exportable</code></strong></span>: Whether the log should be exported to Zipkin.
|
||||
When would you like the span not to be exportable?
|
||||
When you want to wrap some operation in a Span and have it written to the logs only.</li></ul></div></li><li class="listitem">Provides an abstraction over common distributed tracing data models: traces, spans (forming a DAG), annotations, and key-value annotations.
|
||||
Spring Cloud Sleuth is loosely based on HTrace but is compatible with Zipkin (Dapper).</li><li class="listitem">Sleuth records timing information to aid in latency analysis.
|
||||
By using sleuth, you can pinpoint causes of latency in your applications.</li><li class="listitem"><p class="simpara">Sleuth is written to not log too much and to not cause your production application to crash.
|
||||
To that end, Sleuth:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem">Propagates structural data about your call graph in-band and the rest out-of-band.</li><li class="listitem">Includes opinionated instrumentation of layers such as HTTP.</li><li class="listitem">Includes a sampling policy to manage volume.</li><li class="listitem">Can report to a Zipkin system for query and visualization.</li></ul></div></li><li class="listitem">Instruments common ingress and egress points from Spring applications (servlet filter, async endpoints, rest template, scheduled actions, message channels, Zuul filters, and Feign client).</li><li class="listitem">Sleuth includes default logic to join a trace across HTTP or messaging boundaries.
|
||||
For example, HTTP propagation works over Zipkin-compatible request headers.</li><li class="listitem">Sleuth can propagate context (also known as baggage) between processes.
|
||||
Consequently, if you set a baggage element on a Span, it is sent downstream to other processes over either HTTP or messaging.</li><li class="listitem">Provides a way to create or continue spans and add tags and logs through annotations.</li><li class="listitem"><p class="simpara">If <code class="literal">spring-cloud-sleuth-zipkin</code> is on the classpath, the app generates and collects Zipkin-compatible traces.
|
||||
By default, it sends them over HTTP to a Zipkin server on localhost (port 9411).
|
||||
You can configure the location of the service by setting <code class="literal">spring.zipkin.baseUrl</code>.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem">If you depend on <code class="literal">spring-rabbit</code>, your app sends traces to a RabbitMQ broker instead of HTTP.</li><li class="listitem">If you depend on <code class="literal">spring-kafka</code>, and set <code class="literal">spring.zipkin.sender.type: kafka</code>, your app sends traces to a Kafka broker instead of HTTP.</li></ul></div></li></ul></div><div class="caution" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Caution"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="images/caution.png"></td><th align="left">Caution</th></tr><tr><td align="left" valign="top"><p><code class="literal">spring-cloud-sleuth-stream</code> is deprecated and should no longer be used.</p></td></tr></table></div><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Spring Cloud Sleuth is <a class="link" href="http://opentracing.io/" target="_top">OpenTracing</a> compatible.</li></ul></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>If you use Zipkin, configure the probability of spans exported by setting <code class="literal">spring.sleuth.sampler.probability</code>
|
||||
(default: 0.1, which is 10 percent). Otherwise, you might think that Sleuth is not working be cause it omits some spans.</p></td></tr></table></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The SLF4J MDC is always set and logback users immediately see the trace and span IDs in logs per the example
|
||||
shown earlier.
|
||||
Other logging systems have to configure their own formatter to get the same result.
|
||||
The default is as follows:
|
||||
<code class="literal">logging.pattern.level</code> set to <code class="literal">%5p [${spring.zipkin.service.name:${spring.application.name:-}},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]</code>
|
||||
(this is a Spring Boot feature for logback users).
|
||||
If you do not use SLF4J, this pattern is NOT automatically applied.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_introduction_to_brave" href="#_introduction_to_brave"></a>52.1 Introduction to Brave</h2></div></div></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Starting with version <code class="literal">2.0.0</code>, Spring Cloud Sleuth uses
|
||||
<a class="link" href="https://github.com/openzipkin/brave" target="_top">Brave</a> as the tracing library.
|
||||
For your convenience, we embed part of the Brave’s docs here.</p></td></tr></table></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>In the vast majority of cases you need to just use the <code class="literal">Tracer</code>
|
||||
or <code class="literal">SpanCustomizer</code> beans from Brave that Sleuth provides. The documentation below contains
|
||||
a high overview of what Brave is and how it works.</p></td></tr></table></div><p>Brave is a library used to capture and report latency information about distributed operations to Zipkin.
|
||||
Most users do not use Brave directly. They use libraries or frameworks rather than employ Brave on their behalf.</p><p>This module includes a tracer that creates and joins spans that model the latency of potentially distributed work.
|
||||
It also includes libraries to propagate the trace context over network boundaries (for example, with HTTP headers).</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_tracing" href="#_tracing"></a>52.1.1 Tracing</h3></div></div></div><p>Most importantly, you need a <code class="literal">brave.Tracer</code>, configured to <a class="link" href="https://github.com/openzipkin/zipkin-reporter-java" target="_top">report to Zipkin</a>.</p><p>The following example setup sends trace data (spans) to Zipkin over HTTP (as opposed to Kafka):</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyClass {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> Tracer tracer;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Tracer will be autowired</span>
|
||||
MyClass(Tracer tracer) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracer = tracer;
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> doSth() {
|
||||
Span span = tracer.newTrace().name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>).start();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// ...</span>
|
||||
}
|
||||
}</pre><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>If your span contains a name longer than 50 chars, then that name is truncated to 50 chars.
|
||||
Your names have to be explicit and concrete.
|
||||
Big names lead to latency issues and sometimes even thrown exceptions.</p></td></tr></table></div><p>The tracer creates and joins spans that model the latency of potentially distributed work.
|
||||
It can employ sampling to reduce overhead during the process, to reduce the amount of data sent to Zipkin, or both.</p><p>Spans returned by a tracer report data to Zipkin when finished or do nothing if unsampled.
|
||||
After starting a span, you can annotate events of interest or add tags containing details or lookup keys.</p><p>Spans have a context that includes trace identifiers that place the span at the correct spot in the tree representing the distributed operation.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_local_tracing" href="#_local_tracing"></a>52.1.2 Local Tracing</h3></div></div></div><p>When tracing code that never leaves your process, run it inside a scoped span.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Start a new trace or a span within an existing trace representing an operation</span>
|
||||
ScopedSpan span = tracer.startScopedSpan(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// The span is in "scope" meaning downstream code such as loggers can see trace IDs</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> encoder.encode();
|
||||
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">catch</span> (RuntimeException | Error e) {
|
||||
span.error(e); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Unless you handle exceptions, you might not know the operation failed!</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throw</span> e;
|
||||
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">finally</span> {
|
||||
span.finish(); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// always finish the span</span>
|
||||
}</pre><p>When you need more features, or finer control, use the <code class="literal">Span</code> type:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Start a new trace or a span within an existing trace representing an operation</span>
|
||||
Span span = tracer.nextSpan().name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>).start();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Put the span in "scope" so that downstream code such as loggers can see trace IDs</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> (SpanInScope ws = tracer.withSpanInScope(span)) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> encoder.encode();
|
||||
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">catch</span> (RuntimeException | Error e) {
|
||||
span.error(e); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Unless you handle exceptions, you might not know the operation failed!</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throw</span> e;
|
||||
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">finally</span> {
|
||||
span.finish(); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// note the scope is independent of the span. Always finish a span.</span>
|
||||
}</pre><p>Both of the above examples report the exact same span on finish!</p><p>In the above example, the span will be either a new root span or the
|
||||
next child in an existing trace.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_customizing_spans" href="#_customizing_spans"></a>52.1.3 Customizing Spans</h3></div></div></div><p>Once you have a span, you can add tags to it.
|
||||
The tags can be used as lookup keys or details.
|
||||
For example, you might add a tag with your runtime version, as shown in the following example:</p><pre class="programlisting">span.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"clnt/finagle.version"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"6.36.0"</span>);</pre><p>When exposing the ability to customize spans to third parties, prefer <code class="literal">brave.SpanCustomizer</code> as opposed to <code class="literal">brave.Span</code>.
|
||||
The former is simpler to understand and test and does not tempt users with span lifecycle hooks.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> MyTraceCallback {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> request(Request request, SpanCustomizer customizer);
|
||||
}</pre><p>Since <code class="literal">brave.Span</code> implements <code class="literal">brave.SpanCustomizer</code>, you can pass it to users, as shown in the following example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">for</span> (MyTraceCallback callback : userCallbacks) {
|
||||
callback.request(request, span);
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_implicitly_looking_up_the_current_span" href="#_implicitly_looking_up_the_current_span"></a>52.1.4 Implicitly Looking up the Current Span</h3></div></div></div><p>Sometimes, you do not know if a trace is in progress or not, and you do not want users to do null checks.
|
||||
<code class="literal">brave.CurrentSpanCustomizer</code> handles this problem by adding data to any span that’s in progress or drops, as shown in the following example:</p><p>Ex.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// The user code can then inject this without a chance of it being null.</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> SpanCustomizer span;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> userCode() {
|
||||
span.annotate(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tx.started"</span>);
|
||||
...
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_rpc_tracing" href="#_rpc_tracing"></a>52.1.5 RPC tracing</h3></div></div></div><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>Check for <a class="link" href="https://github.com/openzipkin/brave/tree/master/instrumentation" target="_top">instrumentation written here</a> and <a class="link" href="http://zipkin.io/pages/existing_instrumentations.html" target="_top">Zipkin’s list</a> before rolling your own RPC instrumentation.</p></td></tr></table></div><p>RPC tracing is often done automatically by interceptors. Behind the scenes, they add tags and events that relate to their role in an RPC operation.</p><p>The following example shows how to add a client span:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracing tracing;
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// before you send a request, add metadata that describes the operation</span>
|
||||
span = tracer.nextSpan().name(service + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/"</span> + method).kind(CLIENT);
|
||||
span.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"myrpc.version"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"1.0.0"</span>);
|
||||
span.remoteServiceName(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"backend"</span>);
|
||||
span.remoteIpAndPort(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"172.3.4.1"</span>, <span class="hl-number">8108</span>);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Add the trace context to the request, so it can be propagated in-band</span>
|
||||
tracing.propagation().injector(Request::addHeader)
|
||||
.inject(span.context(), request);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when the request is scheduled, start the span</span>
|
||||
span.start();
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// if there is an error, tag the span</span>
|
||||
span.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"error"</span>, error.getCode());
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// or if there is an exception</span>
|
||||
span.error(exception);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when the response is complete, finish the span</span>
|
||||
span.finish();</pre><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_one_way_tracing" href="#_one_way_tracing"></a>One-Way tracing</h4></div></div></div><p>Sometimes, you need to model an asynchronous operation where there is a
|
||||
request but no response. In normal RPC tracing, you use <code class="literal">span.finish()</code>
|
||||
to indicate that the response was received. In one-way tracing, you use
|
||||
<code class="literal">span.flush()</code> instead, as you do not expect a response.</p><p>The following example shows how a client might model a one-way operation:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracing tracing;
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// start a new span representing a client request</span>
|
||||
oneWaySend = tracer.nextSpan().name(service + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/"</span> + method).kind(CLIENT);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Add the trace context to the request, so it can be propagated in-band</span>
|
||||
tracing.propagation().injector(Request::addHeader)
|
||||
.inject(oneWaySend.context(), request);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// fire off the request asynchronously, totally dropping any response</span>
|
||||
request.execute();
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// start the client side and flush instead of finish</span>
|
||||
oneWaySend.start().flush();</pre><p>The following example shows how a server might handle a one-way operation:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracing tracing;
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// pull the context out of the incoming request</span>
|
||||
extractor = tracing.propagation().extractor(Request::getHeader);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// convert that context to a span which you can name and add tags to</span>
|
||||
oneWayReceive = nextSpan(tracer, extractor.extract(request))
|
||||
.name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"process-request"</span>)
|
||||
.kind(SERVER)
|
||||
... add tags etc.
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// start the server side and flush instead of finish</span>
|
||||
oneWayReceive.start().flush();
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// you should not modify this span anymore as it is complete. However,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// you can create children to represent follow-up work.</span>
|
||||
next = tracer.newSpan(oneWayReceive.context()).name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"step2"</span>).start();</pre></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__additional_resources.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__sampling.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">51. Additional Resources </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 53. Sampling</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,39 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>127. Function Catalog and Flexible Function Signatures</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_function_2.html" title="Part XVI. Spring Cloud Function"><link rel="prev" href="multi__building_and_running_a_function.html" title="126. Building and Running a Function"><link rel="next" href="multi__standalone_web_applications.html" title="128. Standalone Web Applications"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">127. Function Catalog and Flexible Function Signatures</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__building_and_running_a_function.html">Prev</a> </td><th width="60%" align="center">Part XVI. Spring Cloud Function</th><td width="20%" align="right"> <a accesskey="n" href="multi__standalone_web_applications.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_function_catalog_and_flexible_function_signatures" href="#_function_catalog_and_flexible_function_signatures"></a>127. Function Catalog and Flexible Function Signatures</h2></div></div></div><p>One of the main features of Spring Cloud Function is to adapt and support a range of type signatures for user-defined functions,
|
||||
while providing a consistent execution model.
|
||||
That’s why all user defined functions are transformed into a canonical representation by <code class="literal">FunctionCatalog</code>, using primitives
|
||||
defined by the <a class="link" href="https://projectreactor.io/" target="_top">Project Reactor</a> (i.e., <code class="literal">Flux<T></code> and <code class="literal">Mono<T></code>).
|
||||
Users can supply a bean of type <code class="literal">Function<String,String></code>, for instance, and the <code class="literal">FunctionCatalog</code> will wrap it into a
|
||||
<code class="literal">Function<Flux<String>,Flux<String>></code>.</p><p>Using Reactor based primitives not only helps with the canonical representation of user defined functions, but it also
|
||||
facilitates a more robust and flexible(reactive) execution model.</p><p>While users don’t normally have to care about the <code class="literal">FunctionCatalog</code> at all, it is useful to know what
|
||||
kind of functions are supported in user code.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_java_8_function_support" href="#_java_8_function_support"></a>127.1 Java 8 function support</h2></div></div></div><p>Generally speaking users can expect that if they write a function for
|
||||
a plain old Java type (or primitive wrapper), then the function
|
||||
catalog will wrap it to a <code class="literal">Flux</code> of the same type. If the user writes
|
||||
a function using <code class="literal">Message</code> (from spring-messaging) it will receive and
|
||||
transmit headers from any adapter that supports key-value metadata
|
||||
(e.g. HTTP headers). Here are the details.</p><div class="informaltable"><table style="border-collapse: collapse;border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; "><colgroup><col class="col_1"><col class="col_2"><col class="col_3"></colgroup><thead><tr><th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top">User Function</th><th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top">Catalog Registration</th><th style="border-bottom: 0.5pt solid ; " align="left" valign="top"> </th></tr></thead><tbody><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Function<S,T></code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Function<Flux<S>, Flux<T>></code></p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"> </td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Function<Message<S>,Message<T>></code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Function<Flux<Message<S>>, Flux<Message<T>>></code></p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"> </td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Function<Flux<S>, Flux<T>></code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Function<Flux<S>, Flux<T>></code> (pass through)</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"> </td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Supplier<T></code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Supplier<Flux<T>></code></p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"> </td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Supplier<Flux<T>></code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Supplier<Flux<T>></code></p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"> </td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Consumer<T></code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Function<Flux<T>, Mono<Void>></code></p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"> </td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Consumer<Message<T>></code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Function<Flux<Message<T>>, Mono<Void>></code></p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"> </td></tr><tr><td style="border-right: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Consumer<Flux<T>></code></p></td><td style="border-right: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">Consumer<Flux<T>></code></p></td><td style="" align="left" valign="top"> </td></tr></tbody></table></div><p>Consumer is a little bit special because it has a <code class="literal">void</code> return type,
|
||||
which implies blocking, at least potentially. Most likely you will not
|
||||
need to write <code class="literal">Consumer<Flux<?>></code>, but if you do need to do that,
|
||||
remember to subscribe to the input flux. If you declare a <code class="literal">Consumer</code>
|
||||
of a non publisher type (which is normal), it will be converted to a
|
||||
function that returns a publisher, so that it can be subscribed to in
|
||||
a controlled way.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_kotlin_lambda_support" href="#_kotlin_lambda_support"></a>127.2 Kotlin Lambda support</h2></div></div></div><p>We also provide support for Kotlin lambdas (since v2.0).
|
||||
Consider the following:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
open fun kotlinSupplier(): () -> String {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> { <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Hello from Kotlin"</span> }
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
open fun kotlinFunction(): (String) -> String {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> { it.toUpperCase() }
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
open fun kotlinConsumer(): (String) -> Unit {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> { println(it) }
|
||||
}</pre><p>The above represents Kotlin lambdas configured as Spring beans. The signature of each maps to a Java equivalent of
|
||||
<code class="literal">Supplier</code>, <code class="literal">Function</code> and <code class="literal">Consumer</code>, and thus supported/recognized signatures by the framework.
|
||||
While mechanics of Kotlin-to-Java mapping are outside of the scope of this documentation, it is important to understand that the
|
||||
same rules for signature transformation outlined in "Java 8 function support" section are applied here as well.</p><p>To enable Kotlin support all you need is to add <code class="literal">spring-cloud-function-kotlin</code> module to your classpath which contains the appropriate
|
||||
autoconfiguration and supporting classes.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__building_and_running_a_function.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_function_2.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__standalone_web_applications.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">126. Building and Running a Function </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 128. Standalone Web Applications</td></tr></table></div></body></html>
|
||||
81
Greenwich.RC2/multi/multi__functional_bean_definitions.html
Normal file
@@ -0,0 +1,81 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>131. Functional Bean Definitions</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_function_2.html" title="Part XVI. Spring Cloud Function"><link rel="prev" href="multi__deploying_a_packaged_function.html" title="130. Deploying a Packaged Function"><link rel="next" href="multi__dynamic_compilation.html" title="132. Dynamic Compilation"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">131. Functional Bean Definitions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__deploying_a_packaged_function.html">Prev</a> </td><th width="60%" align="center">Part XVI. Spring Cloud Function</th><td width="20%" align="right"> <a accesskey="n" href="multi__dynamic_compilation.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_functional_bean_definitions" href="#_functional_bean_definitions"></a>131. Functional Bean Definitions</h2></div></div></div><p>Spring Cloud Function supports a "functional" style of bean declarations for small apps where you need fast startup. The functional style of bean declaration was a feature of Spring Framework 5.0 with significant enhancements in 5.1.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_comparing_functional_with_traditional_bean_definitions" href="#_comparing_functional_with_traditional_bean_definitions"></a>131.1 Comparing Functional with Traditional Bean Definitions</h2></div></div></div><p>Here’s a vanilla Spring Cloud Function application from with the
|
||||
familiar <code class="literal">@Configuration</code> and <code class="literal">@Bean</code> declaration style:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> DemoApplication {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Function<String, String> uppercase() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> value -> value.toUpperCase();
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(DemoApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
}
|
||||
|
||||
}</pre><p>You can run the above in a serverless platform, like AWS Lambda or Azure Functions, or you can run it in its own HTTP server just by including <code class="literal">spring-cloud-function-starter-web</code> on the classpath. Running the main method would expose an endpoint that you can use to ping that <code class="literal">uppercase</code> function:</p><pre class="screen">$ curl localhost:8080 -d foo
|
||||
FOO</pre><p>The web adapter in <code class="literal">spring-cloud-function-starter-web</code> uses Spring MVC, so you needed a Servlet container. You can also use Webflux where the default server is netty (even though you can still use Servlet containers if you want to) - just include the <code class="literal">spring-cloud-starter-function-webflux</code> dependency instead. The functionality is the same, and the user application code can be used in both.</p><p>Now for the functional beans: the user application code can be recast into "functional"
|
||||
form, like this:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootConfiguration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> DemoApplication <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">implements</span> ApplicationContextInitializer<GenericApplicationContext> {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
FunctionalSpringApplication.run(DemoApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Function<String, String> uppercase() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> value -> value.toUpperCase();
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> initialize(GenericApplicationContext context) {
|
||||
context.registerBean(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"demo"</span>, FunctionRegistration.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>,
|
||||
() -> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> FunctionRegistration<>(uppercase())
|
||||
.type(FunctionType.from(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>).to(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>)));
|
||||
}
|
||||
|
||||
}</pre><p>The main differences are:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">The main class is an <code class="literal">ApplicationContextInitializer</code>.</li><li class="listitem">The <code class="literal">@Bean</code> methods have been converted to calls to <code class="literal">context.registerBean()</code></li><li class="listitem">The <code class="literal">@SpringBootApplication</code> has been replaced with
|
||||
<code class="literal">@SpringBootConfiguration</code> to signify that we are not enabling Spring
|
||||
Boot autoconfiguration, and yet still marking the class as an "entry
|
||||
point".</li><li class="listitem">The <code class="literal">SpringApplication</code> from Spring Boot has been replaced with a
|
||||
<code class="literal">FunctionalSpringApplication</code> from Spring Cloud Function (it’s a
|
||||
subclass).</li></ul></div><p>The business logic beans that you register in a Spring Cloud Function app are of type <code class="literal">FunctionRegistration</code>. This is a wrapper that contains both the function and information about the input and output types. In the <code class="literal">@Bean</code> form of the application that information can be derived reflectively, but in a functional bean registration some of it is lost unless we use a <code class="literal">FunctionRegistration</code>.</p><p>An alternative to using an <code class="literal">ApplicationContextInitializer</code> and <code class="literal">FunctionRegistration</code> is to make the application itself implement <code class="literal">Function</code> (or <code class="literal">Consumer</code> or <code class="literal">Supplier</code>). Example (equivalent to the above):</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootConfiguration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> DemoApplication <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">implements</span> Function<String, String> {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
FunctionalSpringApplication.run(DemoApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String uppercase(String value) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> value.toUpperCase();
|
||||
}
|
||||
|
||||
}</pre><p>It would also work if you add a separate, standalone class of type <code class="literal">Function</code> and register it with the <code class="literal">SpringApplication</code> using an alternative form of the <code class="literal">run()</code> method. The main thing is that the generic type information is available at runtime through the class declaration.</p><p>The app runs in its own HTTP server if you add <code class="literal">spring-cloud-starter-function-webflux</code> (it won’t work with the MVC starter at the moment because the functional form of the embedded Servlet container hasn’t been implemented). The app also runs just fine in AWS Lambda or Azure Functions, and the improvements in startup time are dramatic.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The "lite" web server has some limitations for the range of <code class="literal">Function</code> signatures - in particular it doesn’t (yet) support <code class="literal">Message</code> input and output, but POJOs and any kind of <code class="literal">Publisher</code> should be fine.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_testing_functional_applications" href="#_testing_functional_applications"></a>131.2 Testing Functional Applications</h2></div></div></div><p>Spring Cloud Function also has some utilities for integration testing that will be very familiar to Spring Boot users. For example, here is an integration test for the HTTP server wrapping the app above:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@RunWith(SpringRunner.class)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@FunctionalSpringBootTest</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@AutoConfigureWebTestClient</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> FunctionalTests {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> WebTestClient client;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Test</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> words() <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
client.post().uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/"</span>).body(Mono.just(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo"</span>), String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>).exchange()
|
||||
.expectStatus().isOk().expectBody(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>).isEqualTo(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"FOO"</span>);
|
||||
}
|
||||
|
||||
}</pre><p>This test is almost identical to the one you would write for the <code class="literal">@Bean</code> version of the same app - the only difference is the <code class="literal">@FunctionalSpringBootTest</code> annotation, instead of the regular <code class="literal">@SpringBootTest</code>. All the other pieces, like the <code class="literal">@Autowired</code> <code class="literal">WebTestClient</code>, are standard Spring Boot features.</p><p>Or you could write a test for a non-HTTP app using just the <code class="literal">FunctionCatalog</code>. For example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@RunWith(SpringRunner.class)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@FunctionalSpringBootTest</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> FunctionalTests {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> FunctionCatalog catalog;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Test</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> words() <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
Function<Flux<String>, Flux<String>> function = catalog.lookup(Function.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"function"</span>);
|
||||
assertThat(function.apply(Flux.just(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo"</span>)).blockFirst()).isEqualTo(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"FOO"</span>);
|
||||
}
|
||||
|
||||
}</pre><p>(The <code class="literal">FunctionCatalog</code> always returns functions from <code class="literal">Flux</code> to <code class="literal">Flux</code>, even if the user declares them with a simpler signature.)</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_limitations_of_functional_bean_declaration" href="#_limitations_of_functional_bean_declaration"></a>131.3 Limitations of Functional Bean Declaration</h2></div></div></div><p>Most Spring Cloud Function apps have a relatively small scope compared to the whole of Spring Boot, so we are able to adapt it to these functional bean definitions easily. If you step outside that limited scope, you can extend your Spring Cloud Function app by switching back to <code class="literal">@Bean</code> style configuration, or by using a hybrid approach. If you want to take advantage of Spring Boot autoconfiguration for integrations with external datastores, for example, you will need to use <code class="literal">@EnableAutoConfiguration</code>. Your functions can still be defined using the functional declarations if you want (i.e. the "hybrid" style), but in that case you will need to explicitly switch off the "full functional mode" using <code class="literal">spring.functional.enabled=false</code> so that Spring Boot can take back control.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__deploying_a_packaged_function.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_function_2.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__dynamic_compilation.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">130. Deploying a Packaged Function </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 132. Dynamic Compilation</td></tr></table></div></body></html>
|
||||
325
Greenwich.RC2/multi/multi__gatewayfilter_factories.html
Normal file
@@ -0,0 +1,325 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>115. GatewayFilter Factories</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_gateway.html" title="Part XV. Spring Cloud Gateway"><link rel="prev" href="multi_gateway-request-predicates-factories.html" title="114. Route Predicate Factories"><link rel="next" href="multi__global_filters.html" title="116. Global Filters"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">115. GatewayFilter Factories</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_gateway-request-predicates-factories.html">Prev</a> </td><th width="60%" align="center">Part XV. Spring Cloud Gateway</th><td width="20%" align="right"> <a accesskey="n" href="multi__global_filters.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_gatewayfilter_factories" href="#_gatewayfilter_factories"></a>115. GatewayFilter Factories</h2></div></div></div><p>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. Spring Cloud Gateway includes many built-in GatewayFilter Factories.</p><p>NOTE For more detailed examples on how to use any of the following filters, take a look at the <a class="link" href="https://github.com/spring-cloud/spring-cloud-gateway/tree/master/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/factory" target="_top">unit tests</a>.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_addrequestheader_gatewayfilter_factory" href="#_addrequestheader_gatewayfilter_factory"></a>115.1 AddRequestHeader GatewayFilter Factory</h2></div></div></div><p>The AddRequestHeader GatewayFilter Factory takes a name and value parameter.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: add_request_header_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - AddRequestHeader</span>=X-Request-Foo<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span> Bar</pre><p>
|
||||
</p><p>This will add <code class="literal">X-Request-Foo:Bar</code> header to the downstream request’s headers for all matching requests.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_addrequestparameter_gatewayfilter_factory" href="#_addrequestparameter_gatewayfilter_factory"></a>115.2 AddRequestParameter GatewayFilter Factory</h2></div></div></div><p>The AddRequestParameter GatewayFilter Factory takes a name and value parameter.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: add_request_parameter_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - AddRequestParameter</span>=foo<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span> bar</pre><p>
|
||||
</p><p>This will add <code class="literal">foo=bar</code> to the downstream request’s query string for all matching requests.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_addresponseheader_gatewayfilter_factory" href="#_addresponseheader_gatewayfilter_factory"></a>115.3 AddResponseHeader GatewayFilter Factory</h2></div></div></div><p>The AddResponseHeader GatewayFilter Factory takes a name and value parameter.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: add_request_header_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - AddResponseHeader</span>=X-Response-Foo<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span> Bar</pre><p>
|
||||
</p><p>This will add <code class="literal">X-Response-Foo:Bar</code> header to the downstream response’s headers for all matching requests.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="hystrix" href="#hystrix"></a>115.4 Hystrix GatewayFilter Factory</h2></div></div></div><p><a class="link" href="https://github.com/Netflix/Hystrix" target="_top">Hystrix</a> is a library from Netflix that implements the <a class="link" href="https://martinfowler.com/bliki/CircuitBreaker.html" target="_top">circuit breaker pattern</a>.
|
||||
The Hystrix GatewayFilter allows you to introduce circuit breakers to your gateway routes, protecting your services from cascading failures and allowing you to provide fallback responses in the event of downstream failures.</p><p>To enable Hystrix GatewayFilters in your project, add a dependency on <code class="literal">spring-cloud-starter-netflix-hystrix</code> from <a class="link" href="http://cloud.spring.io/spring-cloud-netflix/" target="_top">Spring Cloud Netflix</a>.</p><p>The Hystrix GatewayFilter Factory requires a single <code class="literal">name</code> parameter, which is the name of the <code class="literal">HystrixCommand</code>.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: hystrix_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Hystrix</span>=myCommandName</pre><p>
|
||||
</p><p>This wraps the remaining filters in a <code class="literal">HystrixCommand</code> with command name <code class="literal">myCommandName</code>.</p><p>The Hystrix filter can also accept an optional <code class="literal">fallbackUri</code> parameter. Currently, only <code class="literal">forward:</code> schemed URIs are supported. If the fallback is called, the request will be forwarded to the controller matched by the URI.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: hystrix_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: lb://backing-service:<span class="hl-number">8088</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=/consumingserviceendpoint
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: Hystrix
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> args</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: fallbackcmd
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> fallbackUri</span>: forward:/incaseoffailureusethis
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - RewritePath</span>=/consumingserviceendpoint<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span> /backingserviceendpoint</pre><p>
|
||||
</p><p>This will forward to the <code class="literal">/incaseoffailureusethis</code> URI when the Hystrix fallback is called. Note that this example also demonstrates (optional) Spring Cloud Netflix Ribbon load-balancing via the <code class="literal">lb</code> prefix on the destination URI.</p><p>The primary scenario is to use the <code class="literal">fallbackUri</code> to an internal controller or handler within the gateway app.
|
||||
However, it is also possible to reroute the request to a controller or handler in an external application, like so:</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: ingredients
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: lb://ingredients
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=//ingredients/**
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: Hystrix
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> args</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: fetchIngredients
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> fallbackUri</span>: forward:/fallback
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: ingredients-fallback
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://localhost:<span class="hl-number">9994</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=/fallback</pre><p>
|
||||
</p><p>In this example, there is no <code class="literal">fallback</code> endpoint or handler in the gateway application, however, there is one in another
|
||||
app, registered under <code class="literal"><a class="link" href="http://localhost:9994" target="_top">http://localhost:9994</a></code>.</p><p>In case of the request being forwarded to fallback, the Hystrix Gateway filter also provides the <code class="literal">Throwable</code> that has
|
||||
caused it. It’s added to the <code class="literal">ServerWebExchange</code> as the
|
||||
<code class="literal">ServerWebExchangeUtils.HYSTRIX_EXECUTION_EXCEPTION_ATTR</code> attribute that can be used when
|
||||
handling the fallback within the gateway app.</p><p>For the external controller/ handler scenario, headers can be added with exception details. You can find more information
|
||||
on it in the <a class="link" href="multi__gatewayfilter_factories.html#fallback-headers" title="115.5 FallbackHeaders GatewayFilter Factory">FallbackHeaders GatewayFilter Factory section</a>.</p><p>Hystrix settings (such as timeouts) can be configured with global defaults or on a route by route basis using application properties as explained on the <a class="link" href="https://github.com/Netflix/Hystrix/wiki/Configuration" target="_top">Hystrix wiki</a>.</p><p>To set a 5 second timeout for the example route above, the following configuration would be used:</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">hystrix.command.fallbackcmd.execution.isolation.thread.timeoutInMilliseconds</span>: <span class="hl-number">5000</span></pre><p>
|
||||
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="fallback-headers" href="#fallback-headers"></a>115.5 FallbackHeaders GatewayFilter Factory</h2></div></div></div><p>The <code class="literal">FallbackHeaders</code> factory allows you to add Hystrix execution exception details in headers of a request forwarded to
|
||||
a <code class="literal">fallbackUri</code> in an external application, like in the following scenario:</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: ingredients
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: lb://ingredients
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=//ingredients/**
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: Hystrix
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> args</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: fetchIngredients
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> fallbackUri</span>: forward:/fallback
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: ingredients-fallback
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://localhost:<span class="hl-number">9994</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=/fallback
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: FallbackHeaders
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> args</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> executionExceptionTypeHeaderName</span>: Test-Header</pre><p>
|
||||
</p><p>In this example, after an execution exception occurs while running the <code class="literal">HystrixCommand</code>, the request will be forwarde to
|
||||
the <code class="literal">fallback</code> endpoint or handler in an app running on <code class="literal">localhost:9994</code>. The headers with the exception type, message
|
||||
and -if available- root cause exception type and message will be added to that request by the <code class="literal">FallbackHeaders</code> filter.</p><p>The names of the headers can be overwritten in the config by setting the values of the arguments listed below, along with
|
||||
their default values:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">executionExceptionTypeHeaderName</code> (<code class="literal">"Execution-Exception-Type"</code>)</li><li class="listitem"><code class="literal">executionExceptionMessageHeaderName</code> (<code class="literal">"Execution-Exception-Message"</code>)</li><li class="listitem"><code class="literal">rootCauseExceptionTypeHeaderName</code> (<code class="literal">"Root-Cause-Exception-Type"</code>)</li><li class="listitem"><code class="literal">rootCauseExceptionMessageHeaderName</code> (<code class="literal">"Root-Cause-Exception-Message"</code>)</li></ul></div><p>You can find more information on how Hystrix works with Gateway in the <a class="link" href="multi__gatewayfilter_factories.html#hystrix" title="115.4 Hystrix GatewayFilter Factory">Hystrix GatewayFilter Factory section</a>.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_prefixpath_gatewayfilter_factory" href="#_prefixpath_gatewayfilter_factory"></a>115.6 PrefixPath GatewayFilter Factory</h2></div></div></div><p>The PrefixPath GatewayFilter Factory takes a single <code class="literal">prefix</code> parameter.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: prefixpath_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - PrefixPath</span>=/mypath</pre><p>
|
||||
</p><p>This will prefix <code class="literal">/mypath</code> to the path of all matching requests. So a request to <code class="literal">/hello</code>, would be sent to <code class="literal">/mypath/hello</code>.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_preservehostheader_gatewayfilter_factory" href="#_preservehostheader_gatewayfilter_factory"></a>115.7 PreserveHostHeader GatewayFilter Factory</h2></div></div></div><p>The PreserveHostHeader GatewayFilter Factory has not parameters. This filter, sets a request attribute that the routing filter will inspect to determine if the original host header should be sent, rather than the host header determined by the http client.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: preserve_host_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
- PreserveHostHeader</pre><p>
|
||||
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_requestratelimiter_gatewayfilter_factory" href="#_requestratelimiter_gatewayfilter_factory"></a>115.8 RequestRateLimiter GatewayFilter Factory</h2></div></div></div><p>The RequestRateLimiter GatewayFilter Factory is uses a <code class="literal">RateLimiter</code> implementation to determine if the current request is allowed to proceed. If it is not, a status of <code class="literal">HTTP 429 - Too Many Requests</code> (by default) is returned.</p><p>This filter takes an optional <code class="literal">keyResolver</code> parameter and parameters specific to the rate limiter (see below).</p><p><code class="literal">keyResolver</code> is a bean that implements the <code class="literal">KeyResolver</code> interface. In configuration, reference the bean by name using SpEL. <code class="literal">#{@myKeyResolver}</code> is a SpEL expression referencing a bean with the name <code class="literal">myKeyResolver</code>.</p><p><b>KeyResolver.java. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> KeyResolver {
|
||||
Mono<String> resolve(ServerWebExchange exchange);
|
||||
}</pre><p>
|
||||
</p><p>The <code class="literal">KeyResolver</code> interface allows pluggable strategies to derive the key for limiting requests. In future milestones, there will be some <code class="literal">KeyResolver</code> implementations.</p><p>The default implementation of <code class="literal">KeyResolver</code> is the <code class="literal">PrincipalNameKeyResolver</code> which retrieves the <code class="literal">Principal</code> from the <code class="literal">ServerWebExchange</code> and calls <code class="literal">Principal.getName()</code>.</p><p>By default, if the <code class="literal">KeyResolver</code> does not find a key, requests will be denied. This behavior can be adjust with the <code class="literal">spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key</code> (true or false) and <code class="literal">spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code</code> properties.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The RequestRateLimiter is not configurable via the "shortcut" notation. The example below is <span class="emphasis"><em>invalid</em></span></p></td></tr></table></div><p><b>application.properties. </b>
|
||||
</p><pre class="screen"># INVALID SHORTCUT CONFIGURATION
|
||||
spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}</pre><p>
|
||||
</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_redis_ratelimiter" href="#_redis_ratelimiter"></a>115.8.1 Redis RateLimiter</h3></div></div></div><p>The redis implementation is based off of work done at <a class="link" href="https://stripe.com/blog/rate-limiters" target="_top">Stripe</a>. It requires the use of the <code class="literal">spring-boot-starter-data-redis-reactive</code> Spring Boot starter.</p><p>The algorithm used is the <a class="link" href="https://en.wikipedia.org/wiki/Token_bucket" target="_top">Token Bucket Algorithm</a>.</p><p>The <code class="literal">redis-rate-limiter.replenishRate</code> is how many requests per second do you want a user to be allowed to do, without any dropped requests. This is the rate that the token bucket is filled.</p><p>The <code class="literal">redis-rate-limiter.burstCapacity</code> is the maximum number of requests a user is allowed to do in a single second. This is the number of tokens the token bucket can hold. Setting this value to zero will block all requests.</p><p>A steady rate is accomplished by setting the same value in <code class="literal">replenishRate</code> and <code class="literal">burstCapacity</code>. Temporary bursts can be allowed by setting <code class="literal">burstCapacity</code> higher than <code class="literal">replenishRate</code>. In this case, the rate limiter needs to be allowed some time between bursts (according to <code class="literal">replenishRate</code>), as 2 consecutive bursts will result in dropped requests (<code class="literal">HTTP 429 - Too Many Requests</code>).</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: requestratelimiter_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: RequestRateLimiter
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> args</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> redis-rate-limiter.replenishRate</span>: <span class="hl-number">10</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> redis-rate-limiter.burstCapacity</span>: <span class="hl-number">20</span></pre><p>
|
||||
</p><p><b>Config.java. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
KeyResolver userKeyResolver() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"user"</span>));
|
||||
}</pre><p>
|
||||
</p><p>This defines a request rate limit of 10 per user. A burst of 20 is allowed, but the next second only 10 requests will be available. The <code class="literal">KeyResolver</code> is a simple one that gets the <code class="literal">user</code> request parameter (note: this is not recommended for production).</p><p>A rate limiter can also be defined as a bean implementing the <code class="literal">RateLimiter</code> interface. In configuration, reference the bean by name using SpEL. <code class="literal">#{@myRateLimiter}</code> is a SpEL expression referencing a bean with the name <code class="literal">myRateLimiter</code>.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: requestratelimiter_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: RequestRateLimiter
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> args</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> rate-limiter</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"#{@myRateLimiter}"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> key-resolver</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"#{@userKeyResolver}"</span></pre><p>
|
||||
</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_redirectto_gatewayfilter_factory" href="#_redirectto_gatewayfilter_factory"></a>115.9 RedirectTo GatewayFilter Factory</h2></div></div></div><p>The RedirectTo GatewayFilter Factory takes a <code class="literal">status</code> and a <code class="literal">url</code> parameter. The status should be a 300 series redirect http code, such as 301. The url should be a valid url. This will be the value of the <code class="literal">Location</code> header.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: prefixpath_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - RedirectTo</span>=<span class="hl-number">302</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span> http://acme.org</pre><p>
|
||||
</p><p>This will send a status 302 with a <code class="literal">Location:http://acme.org</code> header to perform a redirect.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_removenonproxyheaders_gatewayfilter_factory" href="#_removenonproxyheaders_gatewayfilter_factory"></a>115.10 RemoveNonProxyHeaders GatewayFilter Factory</h2></div></div></div><p>The RemoveNonProxyHeaders GatewayFilter Factory removes headers from forwarded requests. The default list of headers that is removed comes from the <a class="link" href="https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-7.1.3" target="_top">IETF</a>.</p><div class="itemizedlist"><p class="title"><b>The default removed headers are:</b></p><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Connection</li><li class="listitem">Keep-Alive</li><li class="listitem">Proxy-Authenticate</li><li class="listitem">Proxy-Authorization</li><li class="listitem">TE</li><li class="listitem">Trailer</li><li class="listitem">Transfer-Encoding</li><li class="listitem">Upgrade</li></ul></div><p>To change this, set the <code class="literal">spring.cloud.gateway.filter.remove-non-proxy-headers.headers</code> property to the list of header names to remove.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_removerequestheader_gatewayfilter_factory" href="#_removerequestheader_gatewayfilter_factory"></a>115.11 RemoveRequestHeader GatewayFilter Factory</h2></div></div></div><p>The RemoveRequestHeader GatewayFilter Factory takes a <code class="literal">name</code> parameter. It is the name of the header to be removed.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: removerequestheader_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - RemoveRequestHeader</span>=X-Request-Foo</pre><p>
|
||||
</p><p>This will remove the <code class="literal">X-Request-Foo</code> header before it is sent downstream.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_removeresponseheader_gatewayfilter_factory" href="#_removeresponseheader_gatewayfilter_factory"></a>115.12 RemoveResponseHeader GatewayFilter Factory</h2></div></div></div><p>The RemoveResponseHeader GatewayFilter Factory takes a <code class="literal">name</code> parameter. It is the name of the header to be removed.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: removeresponseheader_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - RemoveResponseHeader</span>=X-Response-Foo</pre><p>
|
||||
</p><p>This will remove the <code class="literal">X-Response-Foo</code> header from the response before it is returned to the gateway client.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_rewritepath_gatewayfilter_factory" href="#_rewritepath_gatewayfilter_factory"></a>115.13 RewritePath GatewayFilter Factory</h2></div></div></div><p>The RewritePath GatewayFilter Factory takes a path <code class="literal">regexp</code> parameter and a <code class="literal">replacement</code> parameter. This uses Java regular expressions for a flexible way to rewrite the request path.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: rewritepath_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=/foo/**
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - RewritePath</span>=/foo/(?<segment>.*)<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span> /$\{segment<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">}</span></pre><p>
|
||||
</p><p>For a request path of <code class="literal">/foo/bar</code>, this will set the path to <code class="literal">/bar</code> before making the downstream request. Notice the <code class="literal">$\</code> which is replaced with <code class="literal">$</code> because of the YAML spec.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_rewriteresponseheader_gatewayfilter_factory" href="#_rewriteresponseheader_gatewayfilter_factory"></a>115.14 RewriteResponseHeader GatewayFilter Factory</h2></div></div></div><p>The RewriteResponseHeader GatewayFilter Factory takes <code class="literal">name</code>, <code class="literal">regexp</code>, and <code class="literal">replacement</code> parameters. It uses Java regular expressions for a flexible way to rewrite the response header value.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: rewriteresponseheader_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - RewriteResponseHeader</span>=X-Response-Foo<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span> password=[^&]+<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span> password=***</pre><p>
|
||||
</p><p>For a header value of <code class="literal">/42?user=ford&password=omg!what&flag=true</code>, it will be set to <code class="literal">/42?user=ford&password=***&flag=true</code> after making the downstream request. Please use <code class="literal">$\</code> to mean <code class="literal">$</code> because of the YAML spec.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_savesession_gatewayfilter_factory" href="#_savesession_gatewayfilter_factory"></a>115.15 SaveSession GatewayFilter Factory</h2></div></div></div><p>The SaveSession GatewayFilter Factory forces a <code class="literal">WebSession::save</code> operation <span class="emphasis"><em>before</em></span> forwarding the call downstream. This is of particular use when
|
||||
using something like <a class="link" href="http://projects.spring.io/spring-session/" target="_top">Spring Session</a> with a lazy data store and need to ensure the session state has been saved before making the forwarded call.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: save_session
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=/foo/**
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
- SaveSession</pre><p>
|
||||
</p><p>If you are integrating <a class="link" href="http://projects.spring.io/spring-security/" target="_top">Spring Security</a> with Spring Session, and want to ensure security details have been forwarded to the remote process, this is critical.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_secureheaders_gatewayfilter_factory" href="#_secureheaders_gatewayfilter_factory"></a>115.16 SecureHeaders GatewayFilter Factory</h2></div></div></div><p>The SecureHeaders GatewayFilter Factory adds a number of headers to the response at the reccomendation from <a class="link" href="https://blog.appcanary.com/2017/http-security-headers.html" target="_top">this blog post</a>.</p><div class="itemizedlist"><p class="title"><b>The following headers are added (allong with default values):</b></p><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">X-Xss-Protection:1; mode=block</code></li><li class="listitem"><code class="literal">Strict-Transport-Security:max-age=631138519</code></li><li class="listitem"><code class="literal">X-Frame-Options:DENY</code></li><li class="listitem"><code class="literal">X-Content-Type-Options:nosniff</code></li><li class="listitem"><code class="literal">Referrer-Policy:no-referrer</code></li><li class="listitem"><code class="literal">Content-Security-Policy:default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'</code></li><li class="listitem"><code class="literal">X-Download-Options:noopen</code></li><li class="listitem"><code class="literal">X-Permitted-Cross-Domain-Policies:none</code></li></ul></div><p>To change the default values set the appropriate property in the <code class="literal">spring.cloud.gateway.filter.secure-headers</code> namespace:</p><div class="itemizedlist"><p class="title"><b>Property to change:</b></p><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">xss-protection-header</code></li><li class="listitem"><code class="literal">strict-transport-security</code></li><li class="listitem"><code class="literal">frame-options</code></li><li class="listitem"><code class="literal">content-type-options</code></li><li class="listitem"><code class="literal">referrer-policy</code></li><li class="listitem"><code class="literal">content-security-policy</code></li><li class="listitem"><code class="literal">download-options</code></li><li class="listitem"><code class="literal">permitted-cross-domain-policies</code></li></ul></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_setpath_gatewayfilter_factory" href="#_setpath_gatewayfilter_factory"></a>115.17 SetPath GatewayFilter Factory</h2></div></div></div><p>The SetPath GatewayFilter Factory takes a path <code class="literal">template</code> parameter. It offers a simple way to manipulate the request path by allowing templated segments of the path. This uses the uri templates from Spring Framework. Multiple matching segments are allowed.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: setpath_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=/foo/{segment<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">}</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - SetPath</span>=/{segment<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">}</span></pre><p>
|
||||
</p><p>For a request path of <code class="literal">/foo/bar</code>, this will set the path to <code class="literal">/bar</code> before making the downstream request.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_setresponseheader_gatewayfilter_factory" href="#_setresponseheader_gatewayfilter_factory"></a>115.18 SetResponseHeader GatewayFilter Factory</h2></div></div></div><p>The SetResponseHeader GatewayFilter Factory takes <code class="literal">name</code> and <code class="literal">value</code> parameters.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: setresponseheader_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - SetResponseHeader</span>=X-Response-Foo<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span> Bar</pre><p>
|
||||
</p><p>This GatewayFilter replaces all headers with the given name, rather than adding. So if the downstream server responded with a <code class="literal">X-Response-Foo:1234</code>, this would be replaced with <code class="literal">X-Response-Foo:Bar</code>, which is what the gateway client would receive.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_setstatus_gatewayfilter_factory" href="#_setstatus_gatewayfilter_factory"></a>115.19 SetStatus GatewayFilter Factory</h2></div></div></div><p>The SetStatus GatewayFilter Factory takes a single <code class="literal">status</code> parameter. It must be a valid Spring <code class="literal">HttpStatus</code>. It may be the integer value <code class="literal">404</code> or the string representation of the enumeration <code class="literal">NOT_FOUND</code>.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: setstatusstring_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - SetStatus</span>=BAD_REQUEST
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: setstatusint_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://example.org
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - SetStatus</span>=<span class="hl-number">401</span></pre><p>
|
||||
</p><p>In either case, the HTTP status of the response will be set to 401.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_stripprefix_gatewayfilter_factory" href="#_stripprefix_gatewayfilter_factory"></a>115.20 StripPrefix GatewayFilter Factory</h2></div></div></div><p>The StripPrefix GatewayFilter Factory takes one paramter, <code class="literal">parts</code>. The <code class="literal">parts</code> parameter indicated the number of parts in the path to strip from the request before sending it downstream.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: nameRoot
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://nameservice
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=/name/**
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - StripPrefix</span>=<span class="hl-number">2</span></pre><p>
|
||||
</p><p>When a request is made through the gateway to <code class="literal">/name/bar/foo</code> the request made to <code class="literal">nameservice</code> will look like <code class="literal"><a class="link" href="http://nameservice/foo" target="_top">http://nameservice/foo</a></code>.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_retry_gatewayfilter_factory" href="#_retry_gatewayfilter_factory"></a>115.21 Retry GatewayFilter Factory</h2></div></div></div><p>The Retry GatewayFilter Factory takes <code class="literal">retries</code>, <code class="literal">statuses</code>, <code class="literal">methods</code>, and <code class="literal">series</code> as parameters.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">retries</code>: the number of retries that should be attempted</li><li class="listitem"><code class="literal">statuses</code>: the HTTP status codes that should be retried, represented using <code class="literal">org.springframework.http.HttpStatus</code></li><li class="listitem"><code class="literal">methods</code>: the HTTP methods that should be retried, represented using <code class="literal">org.springframework.http.HttpMethod</code></li><li class="listitem"><code class="literal">series</code>: the series of status codes to be retried, represented using <code class="literal">org.springframework.http.HttpStatus.Series</code></li></ul></div><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: retry_test
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://localhost:<span class="hl-number">8080</span>/flakey
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Host</span>=*.retry.com
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: Retry
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> args</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> retries</span>: <span class="hl-number">3</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> statuses</span>: BAD_GATEWAY</pre><p>
|
||||
</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>When using the retry filter with a <code class="literal">forward:</code> prefixed URL, the target endpoint should be written carefully so that in case of an error it does not do anything that could result in a response being sent to the client and committed. For example, if the target endpoint is an annotated controller, the target controller method should not return <code class="literal">ResponseEntity</code> with an error status code. Instead it should throw an <code class="literal">Exception</code>, or signal an error, e.g. via a <code class="literal">Mono.error(ex)</code> return value, which the retry filter can be configured to handle by retrying.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_requestsize_gatewayfilter_factory" href="#_requestsize_gatewayfilter_factory"></a>115.22 RequestSize GatewayFilter Factory</h2></div></div></div><p>The RequestSize GatewayFilter Factory can restrict a request from reaching the downstream service , when the request size is greater than the permissible limit. The filter takes <code class="literal">RequestSize</code> as parameter which is the permissible size limit of the request defined in bytes.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: request_size_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://localhost:<span class="hl-number">8080</span>/upload
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=/upload
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: RequestSize
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> args</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> maxSize</span>: <span class="hl-number">5000000</span></pre><p>
|
||||
</p><p>The RequestSize GatewayFilter Factory set the response status as <code class="literal">413 Payload Too Large</code> with a additional header <code class="literal">errorMessage</code> when the Request is rejected due to size. Following is an example of such an <code class="literal">errorMessage</code> .</p><p><code class="literal">errorMessage</code> : <code class="literal">Request size is larger than permissible limit. Request size is 6.0 MB where permissible limit is 5.0 MB</code></p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The default Request size will be set to 5 MB if not provided as filter argument in route definition.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_modify_request_body_gatewayfilter_factory" href="#_modify_request_body_gatewayfilter_factory"></a>115.23 Modify Request Body GatewayFilter Factory</h2></div></div></div><p><span class="strong"><strong>This filter is considered BETA and the API may change in the future</strong></span></p><p>This filter can be used to modify the request body before it is sent downstream by the Gateway.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>This filter can only be configured using the Java DSL</p></td></tr></table></div><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> RouteLocator routes(RouteLocatorBuilder builder) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> builder.routes()
|
||||
.route(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"rewrite_request_obj"</span>, r -> r.host(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"*.rewriterequestobj.org"</span>)
|
||||
.filters(f -> f.prefixPath(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/httpbin"</span>)
|
||||
.modifyRequestBody(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, Hello.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, MediaType.APPLICATION_JSON_VALUE,
|
||||
(exchange, s) -> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> Mono.just(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Hello(s.toUpperCase())))).uri(uri))
|
||||
.build();
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Hello {
|
||||
String message;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Hello() { }
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Hello(String message) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.message = message;
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String getMessage() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> message;
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> setMessage(String message) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.message = message;
|
||||
}
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_modify_response_body_gatewayfilter_factory" href="#_modify_response_body_gatewayfilter_factory"></a>115.24 Modify Response Body GatewayFilter Factory</h2></div></div></div><p><span class="strong"><strong>This filter is considered BETA and the API may change in the future</strong></span></p><p>This filter can be used to modify the response body before it is sent back to the Client.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>This filter can only be configured using the Java DSL</p></td></tr></table></div><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> RouteLocator routes(RouteLocatorBuilder builder) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> builder.routes()
|
||||
.route(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"rewrite_response_upper"</span>, r -> r.host(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"*.rewriteresponseupper.org"</span>)
|
||||
.filters(f -> f.prefixPath(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/httpbin"</span>)
|
||||
.modifyResponseBody(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>,
|
||||
(exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri)
|
||||
.build();
|
||||
}</pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_gateway-request-predicates-factories.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_gateway.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__global_filters.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">114. Route Predicate Factories </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 116. Global Filters</td></tr></table></div></body></html>
|
||||
9
Greenwich.RC2/multi/multi__getting_started.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>125. Getting Started</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_function_2.html" title="Part XVI. Spring Cloud Function"><link rel="prev" href="multi__introduction_2.html" title="124. Introduction"><link rel="next" href="multi__building_and_running_a_function.html" title="126. Building and Running a Function"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">125. Getting Started</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__introduction_2.html">Prev</a> </td><th width="60%" align="center">Part XVI. Spring Cloud Function</th><td width="20%" align="right"> <a accesskey="n" href="multi__building_and_running_a_function.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_getting_started" href="#_getting_started"></a>125. Getting Started</h2></div></div></div><p>Build from the command line (and "install" the samples):</p><pre class="screen">$ ./mvnw clean install</pre><p>(If you like to YOLO add <code class="literal">-DskipTests</code>.)</p><p>Run one of the samples, e.g.</p><pre class="screen">$ java -jar spring-cloud-function-samples/function-sample/target/*.jar</pre><p>This runs the app and exposes its functions over HTTP, so you can
|
||||
convert a string to uppercase, like this:</p><pre class="screen">$ curl -H "Content-Type: text/plain" localhost:8080/uppercase -d Hello
|
||||
HELLO</pre><p>You can convert multiple strings (a <code class="literal">Flux<String></code>) by separating them
|
||||
with new lines</p><pre class="screen">$ curl -H "Content-Type: text/plain" localhost:8080/uppercase -d 'Hello
|
||||
> World'
|
||||
HELLOWORLD</pre><p>(You can use <code class="literal"><sup>Q</sup>J</code> in a terminal to insert a new line in a literal
|
||||
string like that.)</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__introduction_2.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_function_2.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__building_and_running_a_function.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">124. Introduction </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 126. Building and Running a Function</td></tr></table></div></body></html>
|
||||
5
Greenwich.RC2/multi/multi__getting_started_2.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>149. Getting started</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi_spring-cloud-gcp-reference.html" title="Part XVIII. Spring Cloud GCP"><link rel="prev" href="multi__dependency_management.html" title="148. Dependency Management"><link rel="next" href="multi_spring-cloud-gcp-core.html" title="150. Spring Cloud GCP Core"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">149. Getting started</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__dependency_management.html">Prev</a> </td><th width="60%" align="center">Part XVIII. Spring Cloud GCP</th><td width="20%" align="right"> <a accesskey="n" href="multi_spring-cloud-gcp-core.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_getting_started_2" href="#_getting_started_2"></a>149. Getting started</h2></div></div></div><p>There are many available resources to get you up to speed with our libraries as quickly as possible.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spring_initializr" href="#_spring_initializr"></a>149.1 Spring Initializr</h2></div></div></div><p>There are three entries in <a class="link" href="http://start.spring.io/" target="_top">Spring Initializr</a> for Spring Cloud GCP:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">GCP Support</li><li class="listitem">GCP Messaging</li><li class="listitem">GCP Storage</li></ul></div><p>The GCP Support entry contains auto-configuration support for every Spring Cloud GCP integration.
|
||||
Most of the autoconfiguration code is only enabled if other dependencies are added to the classpath.</p><div class="informaltable"><table style="border-collapse: collapse;border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; "><colgroup><col class="col_1"><col class="col_2"></colgroup><thead><tr><th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top">Spring Cloud GCP Starter</th><th style="border-bottom: 0.5pt solid ; " align="left" valign="top">Required dependencies</th></tr></thead><tbody><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Config</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>org.springframework.cloud:spring-cloud-gcp-starter-config</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Cloud Spanner</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>org.springframework.cloud:spring-cloud-gcp-starter-data-spanner</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Cloud Datastore</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>org.springframework.cloud:spring-cloud-gcp-starter-data-datastore</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Logging</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>org.springframework.cloud:spring-cloud-gcp-starter-logging</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>SQL - MySql</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>org.springframework.cloud:spring-cloud-gcp-starter-sql-mysql</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>SQL - PostgreSQL</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>org.springframework.cloud:spring-cloud-gcp-starter-sql-postgres</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Trace</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>org.springframework.cloud:spring-cloud-gcp-starter-trace</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Vision</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>org.springframework.cloud:spring-cloud-gcp-starter-vision</p></td></tr><tr><td style="border-right: 0.5pt solid ; " align="left" valign="top"><p>Security - IAP</p></td><td style="" align="left" valign="top"><p>org.springframework.cloud:spring-cloud-gcp-starter-security-iap</p></td></tr></tbody></table></div><p>The GCP Messaging entry adds the GCP Support entry and all the required dependencies so that the Google Cloud Pub/Sub integrations work out of the box.</p><p>The GCP Storage entry adds the GCP Support entry and all the required dependencies so that the Google Cloud Storage integrations work out of the box.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_code_samples" href="#_code_samples"></a>149.2 Code Samples</h2></div></div></div><p>There are <a class="link" href="https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-samples" target="_top">code samples</a> available that demonstrate the usage of all our integrations.</p><p>For example, <a class="link" href="https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-samples/spring-cloud-gcp-vision-api-sample" target="_top">the Vision API sample</a> shows how to use <code class="literal">spring-cloud-gcp-starter-vision</code> to automatically configure Vision API clients.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_code_challenges" href="#_code_challenges"></a>149.3 Code Challenges</h2></div></div></div><p>In a code challenge, you perform a task step by step, using one integration.
|
||||
There are a number of challenges available in the <a class="link" href="https://codelabs.developers.google.com/spring" target="_top">Google Developers Codelabs</a> page.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_getting_started_guides" href="#_getting_started_guides"></a>149.4 Getting Started Guides</h2></div></div></div><p>A Spring Getting Started guide on messaging with Spring Integration Channel Adapters for Google Cloud Pub/Sub is available from <a class="link" href="https://spring.io/guides/gs/messaging-gcp-pubsub/" target="_top">Spring Guides</a>.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__dependency_management.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi_spring-cloud-gcp-reference.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_spring-cloud-gcp-core.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">148. Dependency Management </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 150. Spring Cloud GCP Core</td></tr></table></div></body></html>
|
||||
64
Greenwich.RC2/multi/multi__global_filters.html
Normal file
@@ -0,0 +1,64 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>116. Global Filters</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_gateway.html" title="Part XV. Spring Cloud Gateway"><link rel="prev" href="multi__gatewayfilter_factories.html" title="115. GatewayFilter Factories"><link rel="next" href="multi__tls_ssl.html" title="117. TLS / SSL"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">116. Global Filters</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__gatewayfilter_factories.html">Prev</a> </td><th width="60%" align="center">Part XV. Spring Cloud Gateway</th><td width="20%" align="right"> <a accesskey="n" href="multi__tls_ssl.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_global_filters" href="#_global_filters"></a>116. Global Filters</h2></div></div></div><p>The <code class="literal">GlobalFilter</code> interface has the same signature as <code class="literal">GatewayFilter</code>. These are special filters that are conditionally applied to all routes. (This interface and usage are subject to change in future milestones).</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_combined_global_filter_and_gatewayfilter_ordering" href="#_combined_global_filter_and_gatewayfilter_ordering"></a>116.1 Combined Global Filter and GatewayFilter Ordering</h2></div></div></div><p>When a request comes in (and matches a Route) the Filtering Web Handler will add all instances of <code class="literal">GlobalFilter</code> and all route specific instances of <code class="literal">GatewayFilter</code> to a filter chain. This combined filter chain is sorted by the <code class="literal">org.springframework.core.Ordered</code> interface, which can be set by implementing the <code class="literal">getOrder()</code> method or by using the <code class="literal">@Order</code> annotation.</p><p>As Spring Cloud Gateway distinguishes between "pre" and "post" phases for filter logic execution (see: How It Works), the filter with the highest precedence will be the first in the "pre"-phase and the last in the "post"-phase.</p><p><b>ExampleConfiguration.java. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Order(-1)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> GlobalFilter a() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> (exchange, chain) -> {
|
||||
log.info(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"first pre filter"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> chain.filter(exchange).then(Mono.fromRunnable(() -> {
|
||||
log.info(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"third post filter"</span>);
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Order(0)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> GlobalFilter b() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> (exchange, chain) -> {
|
||||
log.info(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"second pre filter"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> chain.filter(exchange).then(Mono.fromRunnable(() -> {
|
||||
log.info(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"second post filter"</span>);
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Order(1)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> GlobalFilter c() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> (exchange, chain) -> {
|
||||
log.info(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"third pre filter"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> chain.filter(exchange).then(Mono.fromRunnable(() -> {
|
||||
log.info(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"first post filter"</span>);
|
||||
}));
|
||||
};
|
||||
}</pre><p>
|
||||
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_forward_routing_filter" href="#_forward_routing_filter"></a>116.2 Forward Routing Filter</h2></div></div></div><p>The <code class="literal">ForwardRoutingFilter</code> looks for a URI in the exchange attribute <code class="literal">ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR</code>. If the url has a <code class="literal">forward</code> scheme (ie <code class="literal">forward:///localendpoint</code>), it will use the Spring <code class="literal">DispatcherHandler</code> to handler the request. The path part of the request URL will be overridden with the path in the forward URL. The unmodified original url is appended to the list in the <code class="literal">ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR</code> attribute.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_loadbalancerclient_filter" href="#_loadbalancerclient_filter"></a>116.3 LoadBalancerClient Filter</h2></div></div></div><p>The <code class="literal">LoadBalancerClientFilter</code> looks for a URI in the exchange attribute <code class="literal">ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR</code>. If the url has a <code class="literal">lb</code> scheme (ie <code class="literal">lb://myservice</code>), it will use the Spring Cloud <code class="literal">LoadBalancerClient</code> to resolve the name (<code class="literal">myservice</code> in the previous example) to an actual host and port and replace the URI in the same attribute. The unmodified original url is appended to the list in the <code class="literal">ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR</code> attribute. The filter will also look in the <code class="literal">ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR</code> attribute to see if it equals <code class="literal">lb</code> and then the same rules apply.</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: myRoute
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: lb://service
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=/service/**</pre><p>
|
||||
</p><p>NOTE By default when a service instance cannot be found in the <code class="literal">LoadBalancer</code> a <code class="literal">503</code> will be returned.
|
||||
You can configure the Gateway to return a <code class="literal">404</code> by setting <code class="literal">spring.cloud.gateway.loadbalancer.use404=true</code>.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_netty_routing_filter" href="#_netty_routing_filter"></a>116.4 Netty Routing Filter</h2></div></div></div><p>The Netty Routing Filter runs if the url located in the <code class="literal">ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR</code> exchange attribute has a <code class="literal">http</code> or <code class="literal">https</code> scheme. It uses the Netty <code class="literal">HttpClient</code> to make the downstream proxy request. The response is put in the <code class="literal">ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR</code> exchange attribute for use in a later filter. (There is an experimental <code class="literal">WebClientHttpRoutingFilter</code> that performs the same function, but does not require netty)</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_netty_write_response_filter" href="#_netty_write_response_filter"></a>116.5 Netty Write Response Filter</h2></div></div></div><p>The <code class="literal">NettyWriteResponseFilter</code> runs if there is a Netty <code class="literal">HttpClientResponse</code> in the <code class="literal">ServerWebExchangeUtils.CLIENT_RESPONSE_ATTR</code> exchange attribute. It is run after all other filters have completed and writes the proxy response back to the gateway client response. (There is an experimental <code class="literal">WebClientWriteResponseFilter</code> that performs the same function, but does not require netty)</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_routetorequesturl_filter" href="#_routetorequesturl_filter"></a>116.6 RouteToRequestUrl Filter</h2></div></div></div><p>The <code class="literal">RouteToRequestUrlFilter</code> runs if there is a <code class="literal">Route</code> object in the <code class="literal">ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR</code> exchange attribute. It creates a new URI, based off of the request URI, but updated with the URI attribute of the <code class="literal">Route</code> object. The new URI is placed in the <code class="literal">ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR</code> exchange attribute`.</p><p>If the URI has a scheme prefix, such as <code class="literal">lb:ws://serviceid</code>, the <code class="literal">lb</code> scheme is stripped from the URI and placed in the <code class="literal">ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR</code> for use later in the filter chain.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_websocket_routing_filter" href="#_websocket_routing_filter"></a>116.7 Websocket Routing Filter</h2></div></div></div><p>The Websocket Routing Filter runs if the url located in the <code class="literal">ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR</code> exchange attribute has a <code class="literal">ws</code> or <code class="literal">wss</code> scheme. It uses the Spring Web Socket infrastructure to forward the Websocket request downstream.</p><p>Websockets may be load-balanced by prefixing the URI with <code class="literal">lb</code>, such as <code class="literal">lb:ws://serviceid</code>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>If you are using <a class="link" href="https://github.com/sockjs" target="_top">SockJS</a> as a fallback over normal http, you should configure a normal HTTP route as well as the Websocket Route.</p></td></tr></table></div><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"># SockJS route</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: websocket_sockjs_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://localhost:<span class="hl-number">3001</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=/websocket/info/**
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"># Normwal Websocket route</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: websocket_route
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: ws://localhost:<span class="hl-number">3001</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=/websocket/**</pre><p>
|
||||
</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_gateway_metrics_filter" href="#_gateway_metrics_filter"></a>116.8 Gateway Metrics Filter</h2></div></div></div><p>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 <code class="literal">spring.cloud.gateway.metrics.enabled</code> is not set to <code class="literal">false</code>. This filter adds a timer metric named "gateway.requests" with the following tags:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">routeId</code>: The route id</li><li class="listitem"><code class="literal">routeUri</code>: The URI that the API will be routed to</li><li class="listitem"><code class="literal">outcome</code>: Outcome as classified by <a class="link" href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/HttpStatus.Series.html" target="_top">HttpStatus.Series</a></li><li class="listitem"><code class="literal">status</code>: Http Status of the request returned to the client</li></ul></div><p>These metrics are then available to be scraped from <code class="literal">/actuator/metrics/gateway.requests</code> and can be easily integated with Prometheus to create a <a class="link" href="images/gateway-grafana-dashboard.jpeg" target="_top">Grafana</a> <a class="link" href="gateway-grafana-dashboard.json" target="_top">dashboard</a>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>To enable the pometheus endpoint add micrometer-registry-prometheus as a project dependency.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_making_an_exchange_as_routed" href="#_making_an_exchange_as_routed"></a>116.9 Making An Exchange As Routed</h2></div></div></div><p>After the Gateway has routed a <code class="literal">ServerWebExchange</code> it will mark that exchange as "routed" by adding <code class="literal">gatewayAlreadyRouted</code>
|
||||
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
|
||||
or check if an exchange has already been routed.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">ServerWebExchangeUtils.isAlreadyRouted</code> takes a <code class="literal">ServerWebExchange</code> object and checks if it has been "routed"</li><li class="listitem"><code class="literal">ServerWebExchangeUtils.setAlreadyRouted</code> takes a <code class="literal">ServerWebExchange</code> object and marks it as "routed"</li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__gatewayfilter_factories.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_gateway.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__tls_ssl.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">115. GatewayFilter Factories </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 117. TLS / SSL</td></tr></table></div></body></html>
|
||||
3
Greenwich.RC2/multi/multi__glossary.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>112. Glossary</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_gateway.html" title="Part XV. Spring Cloud Gateway"><link rel="prev" href="multi_gateway-starter.html" title="111. How to Include Spring Cloud Gateway"><link rel="next" href="multi_gateway-how-it-works.html" title="113. How It Works"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">112. Glossary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_gateway-starter.html">Prev</a> </td><th width="60%" align="center">Part XV. Spring Cloud Gateway</th><td width="20%" align="right"> <a accesskey="n" href="multi_gateway-how-it-works.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_glossary" href="#_glossary"></a>112. Glossary</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><span class="strong"><strong>Route</strong></span>: Route the basic building block of the gateway. It is defined by an ID, a destination URI, a collection of predicates and a collection of filters. A route is matched if aggregate predicate is true.</li><li class="listitem"><span class="strong"><strong>Predicate</strong></span>: This is a <a class="link" href="http://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html" target="_top">Java 8 Function Predicate</a>. The input type is a <a class="link" href="http://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/server/ServerWebExchange.html" target="_top">Spring Framework <code class="literal">ServerWebExchange</code></a>. This allows developers to match on anything from the HTTP request, such as headers or parameters.</li><li class="listitem"><span class="strong"><strong>Filter</strong></span>: These are instances <a class="link" href="http://docs.spring.io/spring/docs/5.0.x/javadoc-api/org/springframework/web/server/GatewayFilter.html" target="_top">Spring Framework <code class="literal">GatewayFilter</code></a> constructed in with a specific factory. Here, requests and responses can be modified before or after sending the downstream request.</li></ul></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_gateway-starter.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_gateway.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_gateway-how-it-works.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">111. How to Include Spring Cloud Gateway </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 113. How It Works</td></tr></table></div></body></html>
|
||||
79
Greenwich.RC2/multi/multi__google_cloud_pub_sub.html
Normal file
@@ -0,0 +1,79 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>151. Google Cloud Pub/Sub</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi_spring-cloud-gcp-reference.html" title="Part XVIII. Spring Cloud GCP"><link rel="prev" href="multi_spring-cloud-gcp-core.html" title="150. Spring Cloud GCP Core"><link rel="next" href="multi__spring_resources.html" title="152. Spring Resources"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">151. Google Cloud Pub/Sub</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_spring-cloud-gcp-core.html">Prev</a> </td><th width="60%" align="center">Part XVIII. Spring Cloud GCP</th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_resources.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_google_cloud_pub_sub" href="#_google_cloud_pub_sub"></a>151. Google Cloud Pub/Sub</h2></div></div></div><p>Spring Cloud GCP provides an abstraction layer to publish to and subscribe from Google Cloud Pub/Sub topics and to create, list or delete Google Cloud Pub/Sub topics and subscriptions.</p><p>A Spring Boot starter is provided to auto-configure the various required Pub/Sub components.</p><p>Maven coordinates, using Spring Cloud GCP BOM:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-gcp-starter-pubsub<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p>Gradle coordinates:</p><pre class="screen">dependencies {
|
||||
compile group: 'org.springframework.cloud', name: 'spring-cloud-gcp-starter-pubsub'
|
||||
}</pre><p>This starter is also available from <a class="link" href="https://start.spring.io" target="_top">Spring Initializr</a> through the <code class="literal">GCP Messaging</code> entry.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_pub_sub_operations_template" href="#_pub_sub_operations_template"></a>151.1 Pub/Sub Operations & Template</h2></div></div></div><p><code class="literal">PubSubOperations</code> is an abstraction that allows Spring users to use Google Cloud Pub/Sub without depending on any Google Cloud Pub/Sub API semantics.
|
||||
It provides the common set of operations needed to interact with Google Cloud Pub/Sub.
|
||||
<code class="literal">PubSubTemplate</code> is the default implementation of <code class="literal">PubSubOperations</code> and it uses the <a class="link" href="https://github.com/GoogleCloudPlatform/google-cloud-java/tree/master/google-cloud-pubsub" target="_top">Google Cloud Java Client for Pub/Sub</a> to interact with Google Cloud Pub/Sub.</p><p><code class="literal">PubSubTemplate</code> depends on a <code class="literal">PublisherFactory</code> and a <code class="literal">SubscriberFactory</code>.
|
||||
The <code class="literal">PublisherFactory</code> provides a Google Cloud Java Client for Pub/Sub <code class="literal">Publisher</code>.
|
||||
The <code class="literal">SubscriberFactory</code> provides the <code class="literal">Subscriber</code> for asynchronous message pulling, as well as a <code class="literal">SubscriberStub</code> for synchronous pulling.
|
||||
The Spring Boot starter for GCP Pub/Sub auto-configures a <code class="literal">PublisherFactory</code> and <code class="literal">SubscriberFactory</code> with default settings and uses the <code class="literal">GcpProjectIdProvider</code> and <code class="literal">CredentialsProvider</code> auto-configured by the Spring Boot GCP starter.</p><p>The <code class="literal">PublisherFactory</code> implementation provided by Spring Cloud GCP Pub/Sub, <code class="literal">DefaultPublisherFactory</code>, caches <code class="literal">Publisher</code> instances by topic name, in order to optimize resource utilization.</p><p>The <code class="literal">PubSubOperations</code> interface is actually a combination of <code class="literal">PubSubPublisherOperations</code> and <code class="literal">PubSubSubscriberOperations</code> with the corresponding <code class="literal">PubSubPublisherTemplate</code> and <code class="literal">PubSubSubscriberTemplate</code> implementations, which can be used individually or via the composite <code class="literal">PubSubTemplate</code>.
|
||||
The rest of the documentation refers to <code class="literal">PubSubTemplate</code>, but the same applies to <code class="literal">PubSubPublisherTemplate</code> and <code class="literal">PubSubSubscriberTemplate</code>, depending on whether we’re talking about publishing or subscribing.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_publishing_to_a_topic" href="#_publishing_to_a_topic"></a>151.1.1 Publishing to a topic</h3></div></div></div><p><code class="literal">PubSubTemplate</code> provides asynchronous methods to publish messages to a Google Cloud Pub/Sub topic.
|
||||
The <code class="literal">publish()</code> method takes in a topic name to post the message to, a payload of a generic type and, optionally, a map with the message headers.</p><p>Here is an example of how to publish a message to a Google Cloud Pub/Sub topic:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> publishMessage() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.pubSubTemplate.publish(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"topic"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"your message payload"</span>, ImmutableMap.of(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"key1"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"val1"</span>));
|
||||
}</pre><p>By default, the <code class="literal">SimplePubSubMessageConverter</code> is used to convert payloads of type <code class="literal">byte[]</code>, <code class="literal">ByteString</code>, <code class="literal">ByteBuffer</code>, and <code class="literal">String</code> to Pub/Sub messages.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_json_support" href="#_json_support"></a>JSON support</h4></div></div></div><p>For serialization and deserialization of POJOs using Jackson JSON, configure a <code class="literal">JacksonPubSubMessageConverter</code> bean, and the Spring Boot starter for GCP Pub/Sub will automatically wire it into the <code class="literal">PubSubTemplate</code>.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Note: The ObjectMapper is used to convert Java POJOs to and from JSON. You will have to configure</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// your own instance if you are unable to depend on the ObjectMapper provided by Spring Boot starters.</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> JacksonPubSubMessageConverter jacksonPubSubMessageConverter(ObjectMapper objectMapper) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> JacksonPubSubMessageConverter(objectMapper);
|
||||
}</pre><p>Alternatively, you can set it directly by calling the <code class="literal">setMessageConverter()</code> method on the <code class="literal">PubSubTemplate</code>.
|
||||
Other implementations of the <code class="literal">PubSubMessageConverter</code> can also be configured in the same manner.</p><p>Please refer to our <a class="link" href="../spring-cloud-gcp-samples/spring-cloud-gcp-integration-pubsub-json-sample" target="_top">Pub/Sub JSON Payload Sample App</a> as a reference for using this functionality.</p></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_subscribing_to_a_subscription" href="#_subscribing_to_a_subscription"></a>151.1.2 Subscribing to a subscription</h3></div></div></div><p>Google Cloud Pub/Sub allows many subscriptions to be associated to the same topic.
|
||||
<code class="literal">PubSubTemplate</code> allows you to listen to subscriptions via the <code class="literal">subscribe()</code> method.
|
||||
It relies on a <code class="literal">SubscriberFactory</code> object, whose only task is to generate Google Cloud Pub/Sub
|
||||
<code class="literal">Subscriber</code> objects.
|
||||
When listening to a subscription, messages will be pulled from Google Cloud Pub/Sub
|
||||
asynchronously, at a certain interval.</p><p>The Spring Boot starter for Google Cloud Pub/Sub auto-configures a <code class="literal">SubscriberFactory</code>.</p><p>If Pub/Sub message payload conversion is desired, you can use the <code class="literal">subscribeAndConvert()</code> method, which will use the converter configured in the template.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_pulling_messages_from_a_subscription" href="#_pulling_messages_from_a_subscription"></a>151.1.3 Pulling messages from a subscription</h3></div></div></div><p>Google Cloud Pub/Sub supports synchronous pulling of messages from a subscription.
|
||||
This is different from subscribing to a subscription, in the sense that subscribing is an asynchronous task which polls the subscription on a set interval.</p><p>The <code class="literal">pullNext()</code> method allows for a single message to be pulled and automatically acknowledged from a subscription.
|
||||
The <code class="literal">pull()</code> method pulls a number of messages from a subscription, allowing for the retry settings to be configured.
|
||||
Any messages received by <code class="literal">pull()</code> are not automatically acknowledged.
|
||||
Instead, since they are of the kind <code class="literal">AcknowledgeablePubsubMessage</code>, you can acknowledge them by calling the <code class="literal">ack()</code> method, or negatively acknowledge them by calling the <code class="literal">nack()</code> method.
|
||||
The <code class="literal">pullAndAck()</code> method does the same as the <code class="literal">pull()</code> method and, additionally, acknowledges all received messages.</p><p>The <code class="literal">pullAndConvert()</code> method does the same as the <code class="literal">pull()</code> method and, additionally, converts the Pub/Sub binary payload to an object of the desired type, using the converter configured in the template.</p><p>To acknowledge multiple messages received from <code class="literal">pull()</code> or <code class="literal">pullAndConvert()</code> at once, you can use the <code class="literal">PubSubTemplate.ack()</code> method.
|
||||
You can also use the <code class="literal">PubSubTemplate.nack()</code> for negatively acknowledging messages.</p><p>Using these methods for acknowledging messages in batches is more efficient than acknowledging messages individually, but they <span class="strong"><strong>require</strong></span> the collection of messages to be from the same project.</p><p>All <code class="literal">ack()</code>, <code class="literal">nack()</code>, and <code class="literal">modifyAckDeadline()</code> methods on messages as well as <code class="literal">PubSubSubscriberTemplate</code> are implemented asynchronously, returning a <code class="literal">ListenableFuture<Void></code> to be able to process the asynchronous execution.</p><p><code class="literal">PubSubTemplate</code> uses a special subscriber generated by its <code class="literal">SubscriberFactory</code> to synchronously pull messages.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_pub_sub_management" href="#_pub_sub_management"></a>151.2 Pub/Sub management</h2></div></div></div><p><code class="literal">PubSubAdmin</code> is the abstraction provided by Spring Cloud GCP to manage Google Cloud Pub/Sub resources.
|
||||
It allows for the creation, deletion and listing of topics and subscriptions.</p><p><code class="literal">PubSubAdmin</code> depends on <code class="literal">GcpProjectIdProvider</code> and either a <code class="literal">CredentialsProvider</code> or a <code class="literal">TopicAdminClient</code> and a <code class="literal">SubscriptionAdminClient</code>.
|
||||
If given a <code class="literal">CredentialsProvider</code>, it creates a <code class="literal">TopicAdminClient</code> and a <code class="literal">SubscriptionAdminClient</code> with the Google Cloud Java Library for Pub/Sub default settings.
|
||||
The Spring Boot starter for GCP Pub/Sub auto-configures a <code class="literal">PubSubAdmin</code> object using the <code class="literal">GcpProjectIdProvider</code> and the <code class="literal">CredentialsProvider</code> auto-configured by the Spring Boot GCP Core starter.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_creating_a_topic" href="#_creating_a_topic"></a>151.2.1 Creating a topic</h3></div></div></div><p><code class="literal">PubSubAdmin</code> implements a method to create topics:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Topic createTopic(String topicName)</pre><p>Here is an example of how to create a Google Cloud Pub/Sub topic:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> newTopic() {
|
||||
pubSubAdmin.createTopic(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"topicName"</span>);
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_deleting_a_topic" href="#_deleting_a_topic"></a>151.2.2 Deleting a topic</h3></div></div></div><p><code class="literal">PubSubAdmin</code> implements a method to delete topics:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> deleteTopic(String topicName)</pre><p>Here is an example of how to delete a Google Cloud Pub/Sub topic:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> deleteTopic() {
|
||||
pubSubAdmin.deleteTopic(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"topicName"</span>);
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_listing_topics" href="#_listing_topics"></a>151.2.3 Listing topics</h3></div></div></div><p><code class="literal">PubSubAdmin</code> implements a method to list topics:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> List<Topic> listTopics</pre><p>Here is an example of how to list every Google Cloud Pub/Sub topic name in a project:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> List<String> listTopics() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> pubSubAdmin
|
||||
.listTopics()
|
||||
.stream()
|
||||
.map(Topic::getNameAsTopicName)
|
||||
.map(TopicName::getTopic)
|
||||
.collect(Collectors.toList());
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_creating_a_subscription" href="#_creating_a_subscription"></a>151.2.4 Creating a subscription</h3></div></div></div><p><code class="literal">PubSubAdmin</code> implements a method to create subscriptions to existing topics:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Subscription createSubscription(String subscriptionName, String topicName, Integer ackDeadline, String pushEndpoint)</pre><p>Here is an example of how to create a Google Cloud Pub/Sub subscription:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> newSubscription() {
|
||||
pubSubAdmin.createSubscription(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"subscriptionName"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"topicName"</span>, <span class="hl-number">10</span>, “http:<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//my.endpoint/push”);</span>
|
||||
}</pre><p>Alternative methods with default settings are provided for ease of use.
|
||||
The default value for <code class="literal">ackDeadline</code> is 10 seconds.
|
||||
If <code class="literal">pushEndpoint</code> isn’t specified, the subscription uses message pulling, instead.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Subscription createSubscription(String subscriptionName, String topicName)</pre><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Subscription createSubscription(String subscriptionName, String topicName, Integer ackDeadline)</pre><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Subscription createSubscription(String subscriptionName, String topicName, String pushEndpoint)</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_deleting_a_subscription" href="#_deleting_a_subscription"></a>151.2.5 Deleting a subscription</h3></div></div></div><p><code class="literal">PubSubAdmin</code> implements a method to delete subscriptions:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> deleteSubscription(String subscriptionName)</pre><p>Here is an example of how to delete a Google Cloud Pub/Sub subscription:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> deleteSubscription() {
|
||||
pubSubAdmin.deleteSubscription(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"subscriptionName"</span>);
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_listing_subscriptions" href="#_listing_subscriptions"></a>151.2.6 Listing subscriptions</h3></div></div></div><p><code class="literal">PubSubAdmin</code> implements a method to list subscriptions:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> List<Subscription> listSubscriptions()</pre><p>Here is an example of how to list every subscription name in a project:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> List<String> listSubscriptions() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> pubSubAdmin
|
||||
.listSubscriptions()
|
||||
.stream()
|
||||
.map(Subscription::getNameAsSubscriptionName)
|
||||
.map(SubscriptionName::getSubscription)
|
||||
.collect(Collectors.toList());
|
||||
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="pubsub-configuration" href="#pubsub-configuration"></a>151.3 Configuration</h2></div></div></div><p>The Spring Boot starter for Google Cloud Pub/Sub provides the following configuration options:</p><div class="informaltable"><table style="border-collapse: collapse;border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; "><colgroup><col class="col_1"><col class="col_2"><col class="col_3"><col class="col_4"></colgroup><tbody><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Name</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Description</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Required</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Default value</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.enabled</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Enables or disables Pub/Sub auto-configuration</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">true</code></p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.subscriber.executor-threads</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Number of threads used by <code class="literal">Subscriber</code>
|
||||
instances created by <code class="literal">SubscriberFactory</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>4</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.publisher.executor-threads</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Number of threads used by <code class="literal">Publisher</code>
|
||||
instances created by <code class="literal">PublisherFactory</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>4</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.project-id</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>GCP project ID where the Google Cloud Pub/Sub API
|
||||
is hosted, if different from the one in the <a class="link" href="multi_spring-cloud-gcp-core.html" title="150. Spring Cloud GCP Core">Spring Cloud GCP Core Module</a></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"> </td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.credentials.location</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>OAuth2 credentials for authenticating with the
|
||||
Google Cloud Pub/Sub API, if different from the ones in the
|
||||
<a class="link" href="multi_spring-cloud-gcp-core.html" title="150. Spring Cloud GCP Core">Spring Cloud GCP Core Module</a></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"> </td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.credentials.encoded-key</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Base64-encoded contents of OAuth2 account private key for authenticating with the
|
||||
Google Cloud Pub/Sub API, if different from the ones in the
|
||||
<a class="link" href="multi_spring-cloud-gcp-core.html" title="150. Spring Cloud GCP Core">Spring Cloud GCP Core Module</a></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"> </td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.credentials.scopes</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><a class="link" href="https://developers.google.com/identity/protocols/googlescopes" target="_top">OAuth2 scope</a> for Spring Cloud GCP
|
||||
Pub/Sub credentials</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p><a class="link" href="https://www.googleapis.com/auth/pubsub" target="_top">https://www.googleapis.com/auth/pubsub</a></p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.subscriber.parallel-pull-count</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>The number of pull workers</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>The available number of processors</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.subscriber.max-ack-extension-period</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>The maximum period a message ack deadline will be extended, in seconds</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>0</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.subscriber.pull-endpoint</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>The endpoint for synchronous pulling messages</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>pubsub.googleapis.com:443</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.[subscriber,publisher].retry.total-timeout-seconds</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>TotalTimeout has ultimate control over how long the logic should keep trying the remote call until it gives up completely.
|
||||
The higher the total timeout, the more retries can be attempted.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>0</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.[subscriber,publisher].retry.initial-retry-delay-second</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>InitialRetryDelay controls the delay before the first retry. Subsequent retries will use this
|
||||
value adjusted according to the RetryDelayMultiplier.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>0</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.[subscriber,publisher].retry.retry-delay-multiplier</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>RetryDelayMultiplier controls the change in retry delay. The retry delay of the previous call
|
||||
is multiplied by the RetryDelayMultiplier to calculate the retry delay for the next call.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>1</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.[subscriber,publisher].retry.max-retry-delay-seconds</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>MaxRetryDelay puts a limit on the value of the retry delay, so that the RetryDelayMultiplier
|
||||
can’t increase the retry delay higher than this amount.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>0</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.[subscriber,publisher].retry.max-attempts</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>MaxAttempts defines the maximum number of attempts to perform.
|
||||
If this value is greater than 0, and the number of attempts reaches this limit, the logic will
|
||||
give up retrying even if the total retry time is still lower than TotalTimeout.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>0</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.[subscriber,publisher].retry.jittered</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Jitter determines if the delay time should be randomized.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>true</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.[subscriber,publisher].retry.initial-rpc-timeout-seconds</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>InitialRpcTimeout controls the timeout for the initial RPC. Subsequent calls will use this
|
||||
value adjusted according to the RpcTimeoutMultiplier.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>0</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.[subscriber,publisher].retry.rpc-timeout-multiplier</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>RpcTimeoutMultiplier controls the change in RPC timeout. The timeout of the previous call is
|
||||
multiplied by the RpcTimeoutMultiplier to calculate the timeout for the next call.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>1</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.[subscriber,publisher].retry.max-rpc-timeout-seconds</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>MaxRpcTimeout puts a limit on the value of the RPC timeout, so that the RpcTimeoutMultiplier
|
||||
can’t increase the RPC timeout higher than this amount.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>0</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.[subscriber,publisher.batching].flow-control.max-outstanding-element-count</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Maximum number of outstanding elements to keep in memory before enforcing flow control.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>unlimited</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.[subscriber,publisher.batching].flow-control.max-outstanding-request-bytes</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Maximum number of outstanding bytes to keep in memory before enforcing flow control.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>unlimited</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.[subscriber,publisher.batching].flow-control.limit-exceeded-behavior</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>The behavior when the specified limits are exceeded.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Block</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.publisher.batching.element-count-threshold</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>The element count threshold to use for batching.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>unset (threshold does not apply)</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.publisher.batching.request-byte-threshold</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>The request byte threshold to use for batching.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>unset (threshold does not apply)</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.publisher.batching.delay-threshold-seconds</code></p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>The delay threshold to use for batching. After this amount of time has elapsed (counting
|
||||
from the first element added), the elements will be wrapped up in a batch and sent.</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>unset (threshold does not apply)</p></td></tr><tr><td style="border-right: 0.5pt solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.gcp.pubsub.publisher.batching.enabled</code></p></td><td style="border-right: 0.5pt solid ; " align="left" valign="top"><p>Enables batching.</p></td><td style="border-right: 0.5pt solid ; " align="left" valign="top"><p>No</p></td><td style="" align="left" valign="top"><p>false</p></td></tr></tbody></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_sample" href="#_sample"></a>151.4 Sample</h2></div></div></div><p>A <a class="link" href="https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-samples/spring-cloud-gcp-pubsub-sample" target="_top">sample application</a> is available.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_spring-cloud-gcp-core.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi_spring-cloud-gcp-reference.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_resources.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">150. Spring Cloud GCP Core </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 152. Spring Resources</td></tr></table></div></body></html>
|
||||
26
Greenwich.RC2/multi/multi__google_cloud_vision.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>163. Google Cloud Vision</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi_spring-cloud-gcp-reference.html" title="Part XVIII. Spring Cloud GCP"><link rel="prev" href="multi__cloud_identity_aware_proxy_iap_authentication.html" title="162. Cloud Identity-Aware Proxy (IAP) Authentication"><link rel="next" href="multi__cloud_foundry.html" title="164. Cloud Foundry"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">163. Google Cloud Vision</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__cloud_identity_aware_proxy_iap_authentication.html">Prev</a> </td><th width="60%" align="center">Part XVIII. Spring Cloud GCP</th><td width="20%" align="right"> <a accesskey="n" href="multi__cloud_foundry.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_google_cloud_vision" href="#_google_cloud_vision"></a>163. Google Cloud Vision</h2></div></div></div><p>The <a class="link" href="https://cloud.google.com/vision/" target="_top">Google Cloud Vision API</a> allows users to leverage powerful machine learning algorithms for images such as: image classification, face detection, reading text within images, and others.</p><p>Spring Cloud GCP provides:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">A convenience starter which automatically configures authentication settings and client objects needed to begin using the <a class="link" href="https://cloud.google.com/vision/" target="_top">Google Cloud Vision API</a>.</li><li class="listitem">A Cloud Vision Template which allows you to easily send images to the API as Spring Resources.</li></ul></div><p>Maven coordinates, using Spring Cloud GCP BOM:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-gcp-starter-vision<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p>Gradle coordinates:</p><pre class="screen">dependencies {
|
||||
compile group: 'org.springframework.cloud', name: 'spring-cloud-gcp-starter-vision'
|
||||
}</pre><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_cloud_vision_template" href="#_cloud_vision_template"></a>163.1 Cloud Vision Template</h2></div></div></div><p>The <code class="literal">CloudVisionTemplate</code> offers a simple way to use the Cloud Vision APIs with Spring Resources.</p><p>After you add the <code class="literal">spring-cloud-gcp-starter-vision</code> dependency to your project, you may <code class="literal">@Autowire</code> an instance of <code class="literal">CloudVisionTemplate</code> to use in your code.</p><p>The <code class="literal">CloudVisionTemplate</code> offers the following method for interfacing with Cloud Vision:</p><p><code class="literal">public AnnotateImageResponse analyzeImage(Resource imageResource, Feature.Type…​ featureTypes)</code></p><p><span class="strong"><strong>Parameters:</strong></span></p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">Resource imageResource</code> refers to the Spring Resource of the image object you wish to analyze.
|
||||
The Google Cloud Vision documentation provides a <a class="link" href="https://cloud.google.com/vision/docs/supported-files" target="_top">list of the image types that they support</a>.</li><li class="listitem"><code class="literal">Feature.Type…​ featureTypes</code> refers to a var-arg array of Cloud Vision Features to extract from the image.
|
||||
A feature refers to a kind of image analysis one wishes to perform on an image, such as label detection, OCR recognition, facial detection, etc.
|
||||
One may specify multiple features to analyze within one request.
|
||||
A full list of Cloud Vision Features is provided in the <a class="link" href="https://cloud.google.com/vision/docs/features" target="_top">Cloud Vision Feature docs</a>.</li></ul></div><p><span class="strong"><strong>Returns:</strong></span></p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p class="simpara"><a class="link" href="https://cloud.google.com/vision/docs/reference/rpc/google.cloud.vision.v1#google.cloud.vision.v1.AnnotateImageResponse" target="_top"><code class="literal">AnnotateImageResponse</code></a> contains the results of all the feature analyses that were specified in the request.
|
||||
For each feature type that you provide in the request, <code class="literal">AnnotateImageResponse</code> provides a getter method to get the result of that feature analysis.
|
||||
For example, if you analyzed an image using the <code class="literal">LABEL_DETECTION</code> feature, then you would retrieve the results from the response using <code class="literal">annotateImageResponse.getLabelAnnotationsList()</code>.</p><p class="simpara"><code class="literal">AnnotateImageResponse</code> is provided by the Google Cloud Vision libraries; you may consult the <a class="link" href="https://cloud.google.com/vision/docs/reference/rpc/google.cloud.vision.v1#google.cloud.vision.v1.AnnotateImageResponse" target="_top">RPC reference</a> or <a class="link" href="http://googleapis.github.io/googleapis/java/all/latest/apidocs/com/google/cloud/vision/v1/AnnotateImageResponse.html" target="_top">Javadoc</a> as a reference.
|
||||
Additionally, you may consult the <a class="link" href="https://cloud.google.com/vision/docs/" target="_top">Cloud Vision docs</a> to familiarize yourself with the concepts and features of the API.</p></li></ul></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_detect_image_labels_example" href="#_detect_image_labels_example"></a>163.2 Detect Image Labels Example</h2></div></div></div><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> ResourceLoader resourceLoader;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> CloudVisionTemplate cloudVisionTemplate;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> processImage() {
|
||||
Resource imageResource = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.resourceLoader.getResource(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"my_image.jpg"</span>);
|
||||
AnnotateImageResponse response = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.cloudVisionTemplate.analyzeImage(
|
||||
imageResource, Type.LABEL_DETECTION);
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Image Classification results: "</span> + response.getLabelAnnotationsList());
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_sample_12" href="#_sample_12"></a>163.3 Sample</h2></div></div></div><p>A <a class="link" href="https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-samples/spring-cloud-gcp-vision-api-sample" target="_top">Sample Spring Boot Application</a> is provided to show how to use the Cloud Vision starter and template.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__cloud_identity_aware_proxy_iap_authentication.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi_spring-cloud-gcp-reference.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__cloud_foundry.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">162. Cloud Identity-Aware Proxy (IAP) Authentication </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 164. Cloud Foundry</td></tr></table></div></body></html>
|
||||
5
Greenwich.RC2/multi/multi__health_indicator_5.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>36. Health Indicator</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="prev" href="multi__testing.html" title="35. Testing"><link rel="next" href="multi_spring-cloud-stream-overview-metrics-emitter.html" title="37. Metrics Emitter"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">36. Health Indicator</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__testing.html">Prev</a> </td><th width="60%" align="center">Part V. Spring Cloud Stream</th><td width="20%" align="right"> <a accesskey="n" href="multi_spring-cloud-stream-overview-metrics-emitter.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_health_indicator_5" href="#_health_indicator_5"></a>36. Health Indicator</h2></div></div></div><p>Spring Cloud Stream provides a health indicator for binders.
|
||||
It is registered under the name <code class="literal">binders</code> and can be enabled or disabled by setting the <code class="literal">management.health.binders.enabled</code> property.</p><p>By default <code class="literal">management.health.binders.enabled</code> is set to <code class="literal">false</code>.
|
||||
Setting <code class="literal">management.health.binders.enabled</code> to <code class="literal">true</code> enables the health indicator, allowing you to access the <code class="literal">/health</code> endpoint to retrieve the binder health indicators.</p><p>Health indicators are binder-specific and certain binder implementations may not necessarily provide a health indicator.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__testing.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_stream.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_spring-cloud-stream-overview-metrics-emitter.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">35. Testing </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 37. Metrics Emitter</td></tr></table></div></body></html>
|
||||
7
Greenwich.RC2/multi/multi__http_clients.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>21. HTTP Clients</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_netflix.html" title="Part III. Spring Cloud Netflix"><link rel="prev" href="multi_retrying-failed-requests.html" title="20. Retrying Failed Requests"><link rel="next" href="multi__modules_in_maintenance_mode.html" title="22. Modules In Maintenance Mode"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">21. HTTP Clients</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_retrying-failed-requests.html">Prev</a> </td><th width="60%" align="center">Part III. Spring Cloud Netflix</th><td width="20%" align="right"> <a accesskey="n" href="multi__modules_in_maintenance_mode.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_http_clients" href="#_http_clients"></a>21. HTTP Clients</h2></div></div></div><p>Spring Cloud Netflix automatically creates the HTTP client used by Ribbon, Feign, and Zuul for you.
|
||||
However, you can also provide your own HTTP clients customized as you need them to be.
|
||||
To do so, you can create a bean of type <code class="literal">ClosableHttpClient</code> if you
|
||||
are using the Apache Http Cient or <code class="literal">OkHttpClient</code> if you are using OK HTTP.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>When you create your own HTTP client, you are also responsible for implementing the correct connection management strategies for these clients.
|
||||
Doing so improperly can result in resource management issues.</p></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_retrying-failed-requests.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_netflix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__modules_in_maintenance_mode.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">20. Retrying Failed Requests </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 22. Modules In Maintenance Mode</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,63 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>15. Hystrix Timeouts And Ribbon Clients</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_netflix.html" title="Part III. Spring Cloud Netflix"><link rel="prev" href="multi__circuit_breaker_hystrix_dashboard.html" title="14. Circuit Breaker: Hystrix Dashboard"><link rel="next" href="multi_spring-cloud-ribbon.html" title="16. Client Side Load Balancer: Ribbon"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">15. Hystrix Timeouts And Ribbon Clients</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__circuit_breaker_hystrix_dashboard.html">Prev</a> </td><th width="60%" align="center">Part III. Spring Cloud Netflix</th><td width="20%" align="right"> <a accesskey="n" href="multi_spring-cloud-ribbon.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_hystrix_timeouts_and_ribbon_clients" href="#_hystrix_timeouts_and_ribbon_clients"></a>15. Hystrix Timeouts And Ribbon Clients</h2></div></div></div><p>When using Hystrix commands that wrap Ribbon clients you want to make sure your Hystrix timeout
|
||||
is configured to be longer than the configured Ribbon timeout, including any potential
|
||||
retries that might be made. For example, if your Ribbon connection timeout is one second and
|
||||
the Ribbon client might retry the request three times, than your Hystrix timeout should
|
||||
be slightly more than three seconds.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="netflix-hystrix-dashboard-starter" href="#netflix-hystrix-dashboard-starter"></a>15.1 How to Include the Hystrix Dashboard</h2></div></div></div><p>To include the Hystrix Dashboard in your project, use the starter with a group ID of <code class="literal">org.springframework.cloud</code> and an artifact ID of <code class="literal">spring-cloud-starter-netflix-hystrix-dashboard</code>.
|
||||
See the <a class="link" href="http://projects.spring.io/spring-cloud/" target="_top">Spring Cloud Project page</a> for details on setting up your build system with the current Spring Cloud Release Train.</p><p>To run the Hystrix Dashboard, annotate your Spring Boot main class with <code class="literal">@EnableHystrixDashboard</code>.
|
||||
Then visit <code class="literal">/hystrix</code> and point the dashboard to an individual instance’s <code class="literal">/hystrix.stream</code> endpoint in a Hystrix client application.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>When connecting to a <code class="literal">/hystrix.stream</code> endpoint that uses HTTPS, the certificate used by the server must be trusted by the JVM.
|
||||
If the certificate is not trusted, you must import the certificate into the JVM in order for the Hystrix Dashboard to make a successful connection to the stream endpoint.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_turbine" href="#_turbine"></a>15.2 Turbine</h2></div></div></div><p>Looking at an individual instance’s Hystrix data is not very useful in terms of the overall health of the system. <a class="link" href="https://github.com/Netflix/Turbine" target="_top">Turbine</a> is an application that aggregates all of the relevant <code class="literal">/hystrix.stream</code> endpoints into a combined <code class="literal">/turbine.stream</code> for use in the Hystrix Dashboard.
|
||||
Individual instances are located through Eureka.
|
||||
Running Turbine requires annotating your main class with the <code class="literal">@EnableTurbine</code> annotation (for example, by using spring-cloud-starter-netflix-turbine to set up the classpath).
|
||||
All of the documented configuration properties from <a class="link" href="https://github.com/Netflix/Turbine/wiki/Configuration-(1.x)" target="_top">the Turbine 1 wiki</a> apply.
|
||||
The only difference is that the <code class="literal">turbine.instanceUrlSuffix</code> does not need the port prepended, as this is handled automatically unless <code class="literal">turbine.instanceInsertPort=false</code>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>By default, Turbine looks for the <code class="literal">/hystrix.stream</code> endpoint on a registered instance by looking up its <code class="literal">hostName</code> and <code class="literal">port</code> entries in Eureka and then appending <code class="literal">/hystrix.stream</code> to it.
|
||||
If the instance’s metadata contains <code class="literal">management.port</code>, it is used instead of the <code class="literal">port</code> value for the <code class="literal">/hystrix.stream</code> endpoint.
|
||||
By default, the metadata entry called <code class="literal">management.port</code> is equal to the <code class="literal">management.port</code> configuration property.
|
||||
It can be overridden though with following configuration:</p></td></tr></table></div><pre class="screen">eureka:
|
||||
instance:
|
||||
metadata-map:
|
||||
management.port: ${management.port:8081}</pre><p>The <code class="literal">turbine.appConfig</code> configuration key is a list of Eureka serviceIds that turbine uses to lookup instances.
|
||||
The turbine stream is then used in the Hystrix dashboard with a URL similar to the following:</p><p><code class="literal"><a class="link" href="http://my.turbine.server:8080/turbine.stream?cluster=CLUSTERNAME" target="_top">http://my.turbine.server:8080/turbine.stream?cluster=CLUSTERNAME</a></code></p><p>The cluster parameter can be omitted if the name is <code class="literal">default</code>.
|
||||
The <code class="literal">cluster</code> parameter must match an entry in <code class="literal">turbine.aggregator.clusterConfig</code>.
|
||||
Values returned from Eureka are upper-case. Consequently, the following example works if there is an application called <code class="literal">customers</code> registered with Eureka:</p><pre class="screen">turbine:
|
||||
aggregator:
|
||||
clusterConfig: CUSTOMERS
|
||||
appConfig: customers</pre><p>If you need to customize which cluster names should be used by Turbine (because you do not want to store cluster names in
|
||||
<code class="literal">turbine.aggregator.clusterConfig</code> configuration), provide a bean of type <code class="literal">TurbineClustersProvider</code>.</p><p>The <code class="literal">clusterName</code> can be customized by a SPEL expression in <code class="literal">turbine.clusterNameExpression</code> with root as an instance of <code class="literal">InstanceInfo</code>.
|
||||
The default value is <code class="literal">appName</code>, which means that the Eureka <code class="literal">serviceId</code> becomes the cluster key (that is, the <code class="literal">InstanceInfo</code> for customers has an <code class="literal">appName</code> of <code class="literal">CUSTOMERS</code>).
|
||||
A different example is <code class="literal">turbine.clusterNameExpression=aSGName</code>, which gets the cluster name from the AWS ASG name.
|
||||
The following listing shows another example:</p><pre class="screen">turbine:
|
||||
aggregator:
|
||||
clusterConfig: SYSTEM,USER
|
||||
appConfig: customers,stores,ui,admin
|
||||
clusterNameExpression: metadata['cluster']</pre><p>In the preceding example, the cluster name from four services is pulled from their metadata map and is expected to have values that include <code class="literal">SYSTEM</code> and <code class="literal">USER</code>.</p><p>To use the “default” cluster for all apps, you need a string literal expression (with single quotes and escaped with double quotes if it is in YAML as well):</p><pre class="screen">turbine:
|
||||
appConfig: customers,stores
|
||||
clusterNameExpression: "'default'"</pre><p>Spring Cloud provides a <code class="literal">spring-cloud-starter-netflix-turbine</code> that has all the dependencies you need to get a Turbine server running. To add Turbine, create a Spring Boot application and annotate it with <code class="literal">@EnableTurbine</code>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>By default, Spring Cloud lets Turbine use the host and port to allow multiple processes per host, per cluster.
|
||||
If you want the native Netflix behavior built into Turbine to <span class="emphasis"><em>not</em></span> allow multiple processes per host, per cluster (the key to the instance ID is the hostname), set <code class="literal">turbine.combineHostPort=false</code>.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_clusters_endpoint" href="#_clusters_endpoint"></a>15.2.1 Clusters Endpoint</h3></div></div></div><p>In some situations it might be useful for other applications to know what custers have been configured
|
||||
in Turbine. To support this you can use the <code class="literal">/clusters</code> endpoint which will return a JSON array of
|
||||
all the configured clusters.</p><p><b>GET /clusters. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">[</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">{</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"name"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"RACES"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"link"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://localhost:8383/turbine.stream?cluster=RACES"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">},</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">{</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"name"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"WEB"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"link"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://localhost:8383/turbine.stream?cluster=WEB"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">}</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">]</span></pre><p>
|
||||
</p><p>This endpoint can be disabled by setting <code class="literal">turbine.endpoints.clusters.enabled</code> to <code class="literal">false</code>.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_turbine_stream" href="#_turbine_stream"></a>15.3 Turbine Stream</h2></div></div></div><p>In some environments (such as in a PaaS setting), the classic Turbine model of pulling metrics from all the distributed Hystrix commands does not work.
|
||||
In that case, you might want to have your Hystrix commands push metrics to Turbine. Spring Cloud enables that with messaging.
|
||||
To do so on the client, add a dependency to <code class="literal">spring-cloud-netflix-hystrix-stream</code> and the <code class="literal">spring-cloud-starter-stream-*</code> of your choice.
|
||||
See the <a class="link" href="https://docs.spring.io/spring-cloud-stream/docs/current/reference/htmlsingle/" target="_top">Spring Cloud Stream documentation</a> for details on the brokers and how to configure the client credentials. It should work out of the box for a local broker.</p><p>On the server side, create a Spring Boot application and annotate it with <code class="literal">@EnableTurbineStream</code>.
|
||||
The Turbine Stream server requires the use of Spring Webflux, therefore <code class="literal">spring-boot-starter-webflux</code> needs to be included in your project.
|
||||
By default <code class="literal">spring-boot-starter-webflux</code> is included when adding <code class="literal">spring-cloud-starter-netflix-turbine-stream</code> to your application.</p><p>You can then point the Hystrix Dashboard to the Turbine Stream Server instead of individual Hystrix streams.
|
||||
If Turbine Stream is running on port 8989 on myhost, then put <code class="literal"><a class="link" href="http://myhost:8989" target="_top">http://myhost:8989</a></code> in the stream input field in the Hystrix Dashboard.
|
||||
Circuits are prefixed by their respective <code class="literal">serviceId</code>, followed by a dot (<code class="literal">.</code>), and then the circuit name.</p><p>Spring Cloud provides a <code class="literal">spring-cloud-starter-netflix-turbine-stream</code> that has all the dependencies you need to get a Turbine Stream server running.
|
||||
You can then add the Stream binder of your choice — such as <code class="literal">spring-cloud-starter-stream-rabbit</code>.</p><p>Turbine Stream server also supports the <code class="literal">cluster</code> parameter.
|
||||
Unlike Turbine server, Turbine Stream uses eureka serviceIds as cluster names and these are not configurable.</p><p>If Turbine Stream server is running on port 8989 on <code class="literal">my.turbine.server</code> and you have two eureka serviceIds <code class="literal">customers</code> and <code class="literal">products</code> in your environment, the following URLs will be available on your Turbine Stream server. <code class="literal">default</code> and empty cluster name will provide all metrics that Turbine Stream server receives.</p><pre class="screen">http://my.turbine.sever:8989/turbine.stream?cluster=customers
|
||||
http://my.turbine.sever:8989/turbine.stream?cluster=products
|
||||
http://my.turbine.sever:8989/turbine.stream?cluster=default
|
||||
http://my.turbine.sever:8989/turbine.stream</pre><p>So, you can use eureka serviceIds as cluster names for your Turbine dashboard (or any compatible dashboard).
|
||||
You don’t need to configure any properties like <code class="literal">turbine.appConfig</code>, <code class="literal">turbine.clusterNameExpression</code> and <code class="literal">turbine.aggregator.clusterConfig</code> for your Turbine Stream server.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Turbine Stream server gathers all metrics from the configured input channel with Spring Cloud Stream. It means that it doesn’t gather Hystrix metrics actively from each instance. It just can provide metrics that were already gathered into the input channel by each instance.</p></td></tr></table></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__circuit_breaker_hystrix_dashboard.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_netflix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_spring-cloud-ribbon.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">14. Circuit Breaker: Hystrix Dashboard </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 16. Client Side Load Balancer: Ribbon</td></tr></table></div></body></html>
|
||||
6
Greenwich.RC2/multi/multi__instrumentation.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>57. Instrumentation</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__current_span.html" title="56. Current Span"><link rel="next" href="multi__span_lifecycle.html" title="58. Span lifecycle"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">57. Instrumentation</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__current_span.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__span_lifecycle.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_instrumentation" href="#_instrumentation"></a>57. Instrumentation</h2></div></div></div><p>Spring Cloud Sleuth automatically instruments all your Spring applications, so you should not have to do anything to activate it.
|
||||
The instrumentation is added by using a variety of technologies according to the stack that is available. For example, for a servlet web application, we use a <code class="literal">Filter</code>, and, for Spring Integration, we use <code class="literal">ChannelInterceptors</code>.</p><p>You can customize the keys used in span tags.
|
||||
To limit the volume of span data, an HTTP request is, by default, tagged only with a handful of metadata, such as the status code, the host, and the URL.
|
||||
You can add request headers by configuring <code class="literal">spring.sleuth.keys.http.headers</code> (a list of header names).</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Tags are collected and exported only if there is a <code class="literal">Sampler</code> that allows it. By default, there is no such <code class="literal">Sampler</code>, to ensure that there is no danger of accidentally collecting too much data without configuring something).</p></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__current_span.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__span_lifecycle.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">56. Current Span </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 58. Span lifecycle</td></tr></table></div></body></html>
|
||||
181
Greenwich.RC2/multi/multi__integrations.html
Normal file
@@ -0,0 +1,181 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>64. Integrations</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__zipkin_stream_span_consumer.html" title="63. Zipkin Stream Span Consumer"><link rel="next" href="multi__running_examples.html" title="65. Running examples"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">64. Integrations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__zipkin_stream_span_consumer.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__running_examples.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_integrations" href="#_integrations"></a>64. Integrations</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_opentracing" href="#_opentracing"></a>64.1 OpenTracing</h2></div></div></div><p>Spring Cloud Sleuth is compatible with <a class="link" href="http://opentracing.io/" target="_top">OpenTracing</a>.
|
||||
If you have OpenTracing on the classpath, we automatically register the OpenTracing <code class="literal">Tracer</code> bean.
|
||||
If you wish to disable this, set <code class="literal">spring.sleuth.opentracing.enabled</code> to <code class="literal">false</code></p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_runnable_and_callable" href="#_runnable_and_callable"></a>64.2 Runnable and Callable</h2></div></div></div><p>If you wrap your logic in <code class="literal">Runnable</code> or <code class="literal">Callable</code>, you can wrap those classes in their Sleuth representative, as shown in the following example for <code class="literal">Runnable</code>:</p><pre class="programlisting">Runnable runnable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Runnable() {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> run() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// do some work</span>
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String toString() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"spanNameFromToStringMethod"</span>;
|
||||
}
|
||||
};
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Manual `TraceRunnable` creation with explicit "calculateTax" Span name</span>
|
||||
Runnable traceRunnable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TraceRunnable(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracing, spanNamer, runnable,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"calculateTax"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Wrapping `Runnable` with `Tracing`. That way the current span will be available</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// in the thread of `Runnable`</span>
|
||||
Runnable traceRunnableFromTracer = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracing.currentTraceContext()
|
||||
.wrap(runnable);</pre><p>The following example shows how to do so for <code class="literal">Callable</code>:</p><pre class="programlisting">Callable<String> callable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Callable<String>() {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String call() <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> someLogic();
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String toString() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"spanNameFromToStringMethod"</span>;
|
||||
}
|
||||
};
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Manual `TraceCallable` creation with explicit "calculateTax" Span name</span>
|
||||
Callable<String> traceCallable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TraceCallable<>(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracing, spanNamer,
|
||||
callable, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"calculateTax"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Wrapping `Callable` with `Tracing`. That way the current span will be available</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// in the thread of `Callable`</span>
|
||||
Callable<String> traceCallableFromTracer = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracing.currentTraceContext()
|
||||
.wrap(callable);</pre><p>That way, you ensure that a new span is created and closed for each execution.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_hystrix" href="#_hystrix"></a>64.3 Hystrix</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_custom_concurrency_strategy" href="#_custom_concurrency_strategy"></a>64.3.1 Custom Concurrency Strategy</h3></div></div></div><p>We register a custom <a class="link" href="https://github.com/Netflix/Hystrix/wiki/Plugins#concurrencystrategy" target="_top"><code class="literal">HystrixConcurrencyStrategy</code></a> called <code class="literal">TraceCallable</code> that wraps all <code class="literal">Callable</code> instances in their Sleuth representative.
|
||||
The strategy either starts or continues a span, depending on whether tracing was already going on before the Hystrix command was called.
|
||||
To disable the custom Hystrix Concurrency Strategy, set the <code class="literal">spring.sleuth.hystrix.strategy.enabled</code> to <code class="literal">false</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_manual_command_setting" href="#_manual_command_setting"></a>64.3.2 Manual Command setting</h3></div></div></div><p>Assume that you have the following <code class="literal">HystrixCommand</code>:</p><pre class="programlisting">HystrixCommand<String> hystrixCommand = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> HystrixCommand<String>(setter) {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">protected</span> String run() <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> someLogic();
|
||||
}
|
||||
};</pre><p>To pass the tracing information, you have to wrap the same logic in the Sleuth version of the <code class="literal">HystrixCommand</code>, which is called
|
||||
<code class="literal">TraceCommand</code>, as shown in the following example:</p><pre class="programlisting">TraceCommand<String> traceCommand = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TraceCommand<String>(tracer, setter) {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String doRun() <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> someLogic();
|
||||
}
|
||||
};</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_rxjava" href="#_rxjava"></a>64.4 RxJava</h2></div></div></div><p>We registering a custom <a class="link" href="https://github.com/ReactiveX/RxJava/wiki/Plugins#rxjavaschedulershook" target="_top"><code class="literal">RxJavaSchedulersHook</code></a> that wraps all <code class="literal">Action0</code> instances in their Sleuth representative, which is called <code class="literal">TraceAction</code>.
|
||||
The hook either starts or continues a span, depending on whether tracing was already going on before the Action was scheduled.
|
||||
To disable the custom <code class="literal">RxJavaSchedulersHook</code>, set the <code class="literal">spring.sleuth.rxjava.schedulers.hook.enabled</code> to <code class="literal">false</code>.</p><p>You can define a list of regular expressions for thread names for which you do not want spans to be created.
|
||||
To do so, provide a comma-separated list of regular expressions in the <code class="literal">spring.sleuth.rxjava.schedulers.ignoredthreads</code> property.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>The suggest approach to reactive programming and Sleuth is to use
|
||||
the Reactor support.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_http_integration" href="#_http_integration"></a>64.5 HTTP integration</h2></div></div></div><p>Features from this section can be disabled by setting the <code class="literal">spring.sleuth.web.enabled</code> property with value equal to <code class="literal">false</code>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_http_filter" href="#_http_filter"></a>64.5.1 HTTP Filter</h3></div></div></div><p>Through the <code class="literal">TracingFilter</code>, all sampled incoming requests result in creation of a Span.
|
||||
That Span’s name is <code class="literal">http:</code> + the path to which the request was sent.
|
||||
For example, if the request was sent to <code class="literal">/this/that</code> then the name will be <code class="literal">http:/this/that</code>.
|
||||
You can configure which URIs you would like to skip by setting the <code class="literal">spring.sleuth.web.skipPattern</code> property.
|
||||
If you have <code class="literal">ManagementServerProperties</code> on classpath, its value of <code class="literal">contextPath</code> gets appended to the provided skip pattern.
|
||||
If you want to reuse the Sleuth’s default skip patterns and just append your own, pass those patterns by using the <code class="literal">spring.sleuth.web.additionalSkipPattern</code>.</p><p>To change the order of tracing filter registration, please set the
|
||||
<code class="literal">spring.sleuth.web.filter-order</code> property.</p><p>To disable the filter that logs uncaught exceptions you can disable the
|
||||
<code class="literal">spring.sleuth.web.exception-throwing-filter-enabled</code> property.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_handlerinterceptor" href="#_handlerinterceptor"></a>64.5.2 HandlerInterceptor</h3></div></div></div><p>Since we want the span names to be precise, we use a <code class="literal">TraceHandlerInterceptor</code> that either wraps an existing <code class="literal">HandlerInterceptor</code> or is added directly to the list of existing <code class="literal">HandlerInterceptors</code>.
|
||||
The <code class="literal">TraceHandlerInterceptor</code> adds a special request attribute to the given <code class="literal">HttpServletRequest</code>.
|
||||
If the the <code class="literal">TracingFilter</code> does not see this attribute, it creates a “fallback” span, which is an additional span created on the server side so that the trace is presented properly in the UI.
|
||||
If that happens, there is probably missing instrumentation.
|
||||
In that case, please file an issue in Spring Cloud Sleuth.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_async_servlet_support" href="#_async_servlet_support"></a>64.5.3 Async Servlet support</h3></div></div></div><p>If your controller returns a <code class="literal">Callable</code> or a <code class="literal">WebAsyncTask</code>, Spring Cloud Sleuth continues the existing span instead of creating a new one.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_webflux_support" href="#_webflux_support"></a>64.5.4 WebFlux support</h3></div></div></div><p>Through <code class="literal">TraceWebFilter</code>, all sampled incoming requests result in creation of a Span.
|
||||
That Span’s name is <code class="literal">http:</code> + the path to which the request was sent.
|
||||
For example, if the request was sent to <code class="literal">/this/that</code>, the name is <code class="literal">http:/this/that</code>.
|
||||
You can configure which URIs you would like to skip by using the <code class="literal">spring.sleuth.web.skipPattern</code> property.
|
||||
If you have <code class="literal">ManagementServerProperties</code> on the classpath, its value of <code class="literal">contextPath</code> gets appended to the provided skip pattern.
|
||||
If you want to reuse Sleuth’s default skip patterns and append your own, pass those patterns by using the <code class="literal">spring.sleuth.web.additionalSkipPattern</code>.</p><p>To change the order of tracing filter registration, please set the
|
||||
<code class="literal">spring.sleuth.web.filter-order</code> property.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_dubbo_rpc_support" href="#_dubbo_rpc_support"></a>64.5.5 Dubbo RPC support</h3></div></div></div><p>Via the integration with Brave, Spring Cloud Sleuth supports <a class="link" href="http://dubbo.io/" target="_top">Dubbo</a>.
|
||||
It’s enough to add the <code class="literal">brave-instrumentation-dubbo-rpc</code> dependency:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>io.zipkin.brave<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>brave-instrumentation-dubbo-rpc<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p>You need to also set a <code class="literal">dubbo.properties</code> file with the following contents:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">dubbo.provider.filter</span>=tracing
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">dubbo.consumer.filter</span>=tracing</pre><p>You can read more about Brave - Dubbo integration <a class="link" href="https://github.com/openzipkin/brave/tree/master/instrumentation/dubbo-rpc" target="_top">here</a>.
|
||||
An example of Spring Cloud Sleuth and Dubbo can be found <a class="link" href="https://github.com/openzipkin/sleuth-webmvc-example/compare/add-dubbo-tracing" target="_top">here</a>.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_http_client_integration" href="#_http_client_integration"></a>64.6 HTTP Client Integration</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_synchronous_rest_template" href="#_synchronous_rest_template"></a>64.6.1 Synchronous Rest Template</h3></div></div></div><p>We inject a <code class="literal">RestTemplate</code> interceptor to ensure that all the tracing information is passed to the requests.
|
||||
Each time a call is made, a new Span is created.
|
||||
It gets closed upon receiving the response.
|
||||
To block the synchronous <code class="literal">RestTemplate</code> features, set <code class="literal">spring.sleuth.web.client.enabled</code> to <code class="literal">false</code>.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>You have to register <code class="literal">RestTemplate</code> as a bean so that the interceptors get injected.
|
||||
If you create a <code class="literal">RestTemplate</code> instance with a <code class="literal">new</code> keyword, the instrumentation does NOT work.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_asynchronous_rest_template" href="#_asynchronous_rest_template"></a>64.6.2 Asynchronous Rest Template</h3></div></div></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Starting with Sleuth <code class="literal">2.0.0</code>, we no longer register a bean of <code class="literal">AsyncRestTemplate</code> type.
|
||||
It is up to you to create such a bean.
|
||||
Then we instrument it.</p></td></tr></table></div><p>To block the <code class="literal">AsyncRestTemplate</code> features, set <code class="literal">spring.sleuth.web.async.client.enabled</code> to <code class="literal">false</code>.
|
||||
To disable creation of the default <code class="literal">TraceAsyncClientHttpRequestFactoryWrapper</code>, set <code class="literal">spring.sleuth.web.async.client.factory.enabled</code>
|
||||
to <code class="literal">false</code>.
|
||||
If you do not want to create <code class="literal">AsyncRestClient</code> at all, set <code class="literal">spring.sleuth.web.async.client.template.enabled</code> to <code class="literal">false</code>.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_multiple_asynchronous_rest_templates" href="#_multiple_asynchronous_rest_templates"></a>Multiple Asynchronous Rest Templates</h4></div></div></div><p>Sometimes you need to use multiple implementations of the Asynchronous Rest Template.
|
||||
In the following snippet, you can see an example of how to set up such a custom <code class="literal">AsyncRestTemplate</code>:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Config {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean(name = "customAsyncRestTemplate")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> AsyncRestTemplate traceAsyncRestTemplate() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> AsyncRestTemplate(asyncClientFactory(),
|
||||
clientHttpRequestFactory());
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> ClientHttpRequestFactory clientHttpRequestFactory() {
|
||||
ClientHttpRequestFactory clientHttpRequestFactory = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> CustomClientHttpRequestFactory();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// CUSTOMIZE HERE</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> clientHttpRequestFactory;
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> AsyncClientHttpRequestFactory asyncClientFactory() {
|
||||
AsyncClientHttpRequestFactory factory = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> CustomAsyncClientHttpRequestFactory();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// CUSTOMIZE HERE</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> factory;
|
||||
}
|
||||
|
||||
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="__literal_webclient_literal" href="#__literal_webclient_literal"></a>64.6.3 <code class="literal">WebClient</code></h3></div></div></div><p>We inject a <code class="literal">ExchangeFilterFunction</code> implementation that creates a span and, through on-success and on-error callbacks, takes care of closing client-side spans.</p><p>To block this feature, set <code class="literal">spring.sleuth.web.client.enabled</code> to <code class="literal">false</code>.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>You have to register <code class="literal">WebClient</code> as a bean so that the tracing instrumentation gets applied.
|
||||
If you create a <code class="literal">WebClient</code> instance with a <code class="literal">new</code> keyword, the instrumentation does NOT work.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_traverson" href="#_traverson"></a>64.6.4 Traverson</h3></div></div></div><p>If you use the <a class="link" href="http://docs.spring.io/spring-hateoas/docs/current/reference/html/#client.traverson" target="_top">Traverson</a> library, you can inject a <code class="literal">RestTemplate</code> as a bean into your Traverson object.
|
||||
Since <code class="literal">RestTemplate</code> is already intercepted, you get full support for tracing in your client. The following pseudo code
|
||||
shows how to do that:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> RestTemplate restTemplate;
|
||||
|
||||
Traverson traverson = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Traverson(URI.create(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://some/address"</span>),
|
||||
MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8).setRestOperations(restTemplate);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// use Traverson</span></pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_apache_literal_httpclientbuilder_literal_and_literal_httpasyncclientbuilder_literal" href="#_apache_literal_httpclientbuilder_literal_and_literal_httpasyncclientbuilder_literal"></a>64.6.5 Apache <code class="literal">HttpClientBuilder</code> and <code class="literal">HttpAsyncClientBuilder</code></h3></div></div></div><p>We instrument the <code class="literal">HttpClientBuilder</code> and <code class="literal">HttpAsyncClientBuilder</code> so that
|
||||
tracing context gets injected to the sent requests.</p><p>To block these features, set <code class="literal">spring.sleuth.web.client.enabled</code> to <code class="literal">false</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_netty_literal_httpclient_literal" href="#_netty_literal_httpclient_literal"></a>64.6.6 Netty <code class="literal">HttpClient</code></h3></div></div></div><p>We instrument the Netty’s <code class="literal">HttpClient</code>.</p><p>To block this feature, set <code class="literal">spring.sleuth.web.client.enabled</code> to <code class="literal">false</code>.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>You have to register <code class="literal">HttpClient</code> as a bean so that the instrumentation happens.
|
||||
If you create a <code class="literal">HttpClient</code> instance with a <code class="literal">new</code> keyword, the instrumentation does NOT work.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="__literal_userinforesttemplatecustomizer_literal" href="#__literal_userinforesttemplatecustomizer_literal"></a>64.6.7 <code class="literal">UserInfoRestTemplateCustomizer</code></h3></div></div></div><p>We instrument the Spring Security’s <code class="literal">UserInfoRestTemplateCustomizer</code>.</p><p>To block this feature, set <code class="literal">spring.sleuth.web.client.enabled</code> to <code class="literal">false</code>.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_feign" href="#_feign"></a>64.7 Feign</h2></div></div></div><p>By default, Spring Cloud Sleuth provides integration with Feign through <code class="literal">TraceFeignClientAutoConfiguration</code>.
|
||||
You can disable it entirely by setting <code class="literal">spring.sleuth.feign.enabled</code> to <code class="literal">false</code>.
|
||||
If you do so, no Feign-related instrumentation take place.</p><p>Part of Feign instrumentation is done through a <code class="literal">FeignBeanPostProcessor</code>.
|
||||
You can disable it by setting <code class="literal">spring.sleuth.feign.processor.enabled</code> to <code class="literal">false</code>.
|
||||
If you set it to <code class="literal">false</code>, Spring Cloud Sleuth does not instrument any of your custom Feign components.
|
||||
However, all the default instrumentation is still there.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_grpc" href="#_grpc"></a>64.8 gRPC</h2></div></div></div><p>Spring Cloud Sleuth provides instrumentation for <a class="link" href="https://grpc.io/" target="_top">gRPC</a> through <code class="literal">TraceGrpcAutoConfiguration</code>. You can disable it entirely by setting <code class="literal">spring.sleuth.grpc.enabled</code> to <code class="literal">false</code>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_dependencies" href="#_dependencies"></a>64.8.1 Dependencies</h3></div></div></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>The gRPC integration relies on two external libraries to instrument clients and servers and both of those libraries must be on the class path to enable the instrumentation.</p></td></tr></table></div><p>Maven:</p><pre class="screen"> <dependency>
|
||||
<groupId>io.github.lognet</groupId>
|
||||
<artifactId>grpc-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.brave</groupId>
|
||||
<artifactId>brave-instrumentation-grpc</artifactId>
|
||||
</dependency></pre><p>Gradle:</p><pre class="screen"> compile("io.github.lognet:grpc-spring-boot-starter")
|
||||
compile("io.zipkin.brave:brave-instrumentation-grpc")</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_server_instrumentation" href="#_server_instrumentation"></a>64.8.2 Server Instrumentation</h3></div></div></div><p>Spring Cloud Sleuth leverages grpc-spring-boot-starter to register Brave’s gRPC server interceptor with all services annotated with <code class="literal">@GRpcService</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_client_instrumentation" href="#_client_instrumentation"></a>64.8.3 Client Instrumentation</h3></div></div></div><p>gRPC clients leverage a <code class="literal">ManagedChannelBuilder</code> to construct a <code class="literal">ManagedChannel</code> used to communicate to the gRPC server. The native <code class="literal">ManagedChannelBuilder</code> provides static methods as entry points for construction of <code class="literal">ManagedChannel</code> instances, however, this mechanism is outside the influence of the Spring application context.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Spring Cloud Sleuth provides a <code class="literal">SpringAwareManagedChannelBuilder</code> that can be customized through the Spring application context and injected by gRPC clients. <span class="strong"><strong>This builder must be used when creating <code class="literal">ManagedChannel</code> instances.</strong></span></p></td></tr></table></div><p>Sleuth creates a <code class="literal">TracingManagedChannelBuilderCustomizer</code> which inject Brave’s client interceptor into the <code class="literal">SpringAwareManagedChannelBuilder</code>.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_asynchronous_communication" href="#_asynchronous_communication"></a>64.9 Asynchronous Communication</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="__literal_async_literal_annotated_methods" href="#__literal_async_literal_annotated_methods"></a>64.9.1 <code class="literal">@Async</code> Annotated methods</h3></div></div></div><p>In Spring Cloud Sleuth, we instrument async-related components so that the tracing information is passed between threads.
|
||||
You can disable this behavior by setting the value of <code class="literal">spring.sleuth.async.enabled</code> to <code class="literal">false</code>.</p><p>If you annotate your method with <code class="literal">@Async</code>, we automatically create a new Span with the following characteristics:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">If the method is annotated with <code class="literal">@SpanName</code>, the value of the annotation is the Span’s name.</li><li class="listitem">If the method is not annotated with <code class="literal">@SpanName</code>, the Span name is the annotated method name.</li><li class="listitem">The span is tagged with the method’s class name and method name.</li></ul></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="__literal_scheduled_literal_annotated_methods" href="#__literal_scheduled_literal_annotated_methods"></a>64.9.2 <code class="literal">@Scheduled</code> Annotated Methods</h3></div></div></div><p>In Spring Cloud Sleuth, we instrument scheduled method execution so that the tracing information is passed between threads.
|
||||
You can disable this behavior by setting the value of <code class="literal">spring.sleuth.scheduled.enabled</code> to <code class="literal">false</code>.</p><p>If you annotate your method with <code class="literal">@Scheduled</code>, we automatically create a new span with the following characteristics:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">The span name is the annotated method name.</li><li class="listitem">The span is tagged with the method’s class name and method name.</li></ul></div><p>If you want to skip span creation for some <code class="literal">@Scheduled</code> annotated classes, you can set the <code class="literal">spring.sleuth.scheduled.skipPattern</code> with a regular expression that matches the fully qualified name of the <code class="literal">@Scheduled</code> annotated class.
|
||||
If you use <code class="literal">spring-cloud-sleuth-stream</code> and <code class="literal">spring-cloud-netflix-hystrix-stream</code> together, a span is created for each Hystrix metrics and sent to Zipkin.
|
||||
This behavior may be annoying. That’s why, by default, <code class="literal">spring.sleuth.scheduled.skipPattern=org.springframework.cloud.netflix.hystrix.stream.HystrixStreamTask</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_executor_executorservice_and_scheduledexecutorservice" href="#_executor_executorservice_and_scheduledexecutorservice"></a>64.9.3 Executor, ExecutorService, and ScheduledExecutorService</h3></div></div></div><p>We provide <code class="literal">LazyTraceExecutor</code>, <code class="literal">TraceableExecutorService</code>, and <code class="literal">TraceableScheduledExecutorService</code>. Those implementations create spans each time a new task is submitted, invoked, or scheduled.</p><p>The following example shows how to pass tracing information with <code class="literal">TraceableExecutorService</code> when working with <code class="literal">CompletableFuture</code>:</p><pre class="programlisting">CompletableFuture<Long> completableFuture = CompletableFuture.supplyAsync(() -> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// perform some logic</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span class="hl-number">1</span>_<span class="hl-number">000</span>_<span class="hl-number">000L</span>;
|
||||
}, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TraceableExecutorService(beanFactory, executorService,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// 'calculateTax' explicitly names the span - this param is optional</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"calculateTax"</span>));</pre><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Sleuth does not work with <code class="literal">parallelStream()</code> out of the box.
|
||||
If you want to have the tracing information propagated through the stream, you have to use the approach with <code class="literal">supplyAsync(…​)</code>, as shown earlier.</p></td></tr></table></div><p>If there are beans that implement the <code class="literal">Executor</code> interface that you would like
|
||||
to exclude from span creation, you can use the <code class="literal">spring.sleuth.async.ignored-beans</code>
|
||||
property where you can provide a list of bean names.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_customization_of_executors" href="#_customization_of_executors"></a>Customization of Executors</h4></div></div></div><p>Sometimes, you need to set up a custom instance of the <code class="literal">AsyncExecutor</code>.
|
||||
The following example shows how to set up such a custom <code class="literal">Executor</code>:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAsync</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// add the infrastructure role to ensure that the bean gets auto-proxied</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@Role(BeanDefinition.ROLE_INFRASTRUCTURE)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> CustomExecutorConfig <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> AsyncConfigurerSupport {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
BeanFactory beanFactory;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Executor getAsyncExecutor() {
|
||||
ThreadPoolTaskExecutor executor = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ThreadPoolTaskExecutor();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// CUSTOMIZE HERE</span>
|
||||
executor.setCorePoolSize(<span class="hl-number">7</span>);
|
||||
executor.setMaxPoolSize(<span class="hl-number">42</span>);
|
||||
executor.setQueueCapacity(<span class="hl-number">11</span>);
|
||||
executor.setThreadNamePrefix(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"MyExecutor-"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// DON'T FORGET TO INITIALIZE</span>
|
||||
executor.initialize();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> LazyTraceExecutor(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.beanFactory, executor);
|
||||
}
|
||||
|
||||
}</pre><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>To ensure that your configuration gets post processed, remember
|
||||
to add the <code class="literal">@Role(BeanDefinition.ROLE_INFRASTRUCTURE)</code> on your
|
||||
<code class="literal">@Configuration</code> class</p></td></tr></table></div></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_messaging" href="#_messaging"></a>64.10 Messaging</h2></div></div></div><p>Features from this section can be disabled by setting the <code class="literal">spring.sleuth.messaging.enabled</code> property with value equal to <code class="literal">false</code>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_spring_integration_and_spring_cloud_stream" href="#_spring_integration_and_spring_cloud_stream"></a>64.10.1 Spring Integration and Spring Cloud Stream</h3></div></div></div><p>Spring Cloud Sleuth integrates with <a class="link" href="http://projects.spring.io/spring-integration/" target="_top">Spring Integration</a>.
|
||||
It creates spans for publish and subscribe events.
|
||||
To disable Spring Integration instrumentation, set <code class="literal">spring.sleuth.integration.enabled</code> to <code class="literal">false</code>.</p><p>You can provide the <code class="literal">spring.sleuth.integration.patterns</code> pattern to explicitly provide the names of channels that you want to include for tracing.
|
||||
By default, all channels but <code class="literal">hystrixStreamOutput</code> channel are included.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>When using the <code class="literal">Executor</code> to build a Spring Integration <code class="literal">IntegrationFlow</code>, you must use the untraced version of the <code class="literal">Executor</code>.
|
||||
Decorating the Spring Integration Executor Channel with <code class="literal">TraceableExecutorService</code> causes the spans to be improperly closed.</p></td></tr></table></div><p>If you want to customize the way tracing context is read from and written to message headers,
|
||||
it’s enough for you to register beans of types:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">Propagation.Setter<MessageHeaderAccessor, String></code> - for writing headers to the message</li><li class="listitem"><code class="literal">Propagation.Getter<MessageHeaderAccessor, String></code> - for reading headers from the message</li></ul></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_spring_rabbitmq" href="#_spring_rabbitmq"></a>64.10.2 Spring RabbitMq</h3></div></div></div><p>We instrument the <code class="literal">RabbitTemplate</code> so that tracing headers get injected
|
||||
into the message.</p><p>To block this feature, set <code class="literal">spring.sleuth.messaging.rabbit.enabled</code> to <code class="literal">false</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_spring_kafka" href="#_spring_kafka"></a>64.10.3 Spring Kafka</h3></div></div></div><p>We instrument the Spring Kafka’s <code class="literal">ProducerFactory</code> and <code class="literal">ConsumerFactory</code>
|
||||
so that tracing headers get injected into the created Spring Kafka’s
|
||||
<code class="literal">Producer</code> and <code class="literal">Consumer</code>.</p><p>To block this feature, set <code class="literal">spring.sleuth.messaging.kafka.enabled</code> to <code class="literal">false</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_spring_jms" href="#_spring_jms"></a>64.10.4 Spring JMS</h3></div></div></div><p>We instrument the <code class="literal">JmsTemplate</code> so that tracing headers get injected
|
||||
into the message. We also support <code class="literal">@JmsListener</code> annotated methods on the consumer side.</p><p>To block this feature, set <code class="literal">spring.sleuth.messaging.jms.enabled</code> to <code class="literal">false</code>.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>We don’t support baggage propagation for JMS</p></td></tr></table></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_zuul_2" href="#_zuul_2"></a>64.11 Zuul</h2></div></div></div><p>We instrument the Zuul Ribbon integration by enriching the Ribbon requests with tracing information.
|
||||
To disable Zuul support, set the <code class="literal">spring.sleuth.zuul.enabled</code> property to <code class="literal">false</code>.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__zipkin_stream_span_consumer.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__running_examples.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">63. Zipkin Stream Span Consumer </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 65. Running examples</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,37 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>34. Inter-Application Communication</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="prev" href="multi_schema-evolution.html" title="33. Schema Evolution Support"><link rel="next" href="multi__testing.html" title="35. Testing"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">34. Inter-Application Communication</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_schema-evolution.html">Prev</a> </td><th width="60%" align="center">Part V. Spring Cloud Stream</th><td width="20%" align="right"> <a accesskey="n" href="multi__testing.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_inter_application_communication" href="#_inter_application_communication"></a>34. Inter-Application Communication</h2></div></div></div><p>Spring Cloud Stream enables communication between applications. Inter-application communication is a complex issue spanning several concerns, as described in the following topics:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">“<a class="xref" href="multi__inter_application_communication.html#spring-cloud-stream-overview-connecting-multiple-application-instances" title="34.1 Connecting Multiple Application Instances">Section 34.1, “Connecting Multiple Application Instances”</a>”</li><li class="listitem">“<a class="xref" href="multi__inter_application_communication.html#spring-cloud-stream-overview-instance-index-instance-count" title="34.2 Instance Index and Instance Count">Section 34.2, “Instance Index and Instance Count”</a>”</li><li class="listitem">“<a class="xref" href="multi__inter_application_communication.html#spring-cloud-stream-overview-partitioning" title="34.3 Partitioning">Section 34.3, “Partitioning”</a>”</li></ul></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="spring-cloud-stream-overview-connecting-multiple-application-instances" href="#spring-cloud-stream-overview-connecting-multiple-application-instances"></a>34.1 Connecting Multiple Application Instances</h2></div></div></div><p>While Spring Cloud Stream makes it easy for individual Spring Boot applications to connect to messaging systems, the typical scenario for Spring Cloud Stream is the creation of multi-application pipelines, where microservice applications send data to each other.
|
||||
You can achieve this scenario by correlating the input and output destinations of “adjacent” applications.</p><p>Suppose a design calls for the Time Source application to send data to the Log Sink application. You could use a common destination named <code class="literal">ticktock</code> for bindings within both applications.</p><p>Time Source (that has the channel name <code class="literal">output</code>) would set the following property:</p><pre class="screen">spring.cloud.stream.bindings.output.destination=ticktock</pre><p>Log Sink (that has the channel name <code class="literal">input</code>) would set the following property:</p><pre class="screen">spring.cloud.stream.bindings.input.destination=ticktock</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="spring-cloud-stream-overview-instance-index-instance-count" href="#spring-cloud-stream-overview-instance-index-instance-count"></a>34.2 Instance Index and Instance Count</h2></div></div></div><p>When scaling up Spring Cloud Stream applications, each instance can receive information about how many other instances of the same application exist and what its own instance index is.
|
||||
Spring Cloud Stream does this through the <code class="literal">spring.cloud.stream.instanceCount</code> and <code class="literal">spring.cloud.stream.instanceIndex</code> properties.
|
||||
For example, if there are three instances of a HDFS sink application, all three instances have <code class="literal">spring.cloud.stream.instanceCount</code> set to <code class="literal">3</code>, and the individual applications have <code class="literal">spring.cloud.stream.instanceIndex</code> set to <code class="literal">0</code>, <code class="literal">1</code>, and <code class="literal">2</code>, respectively.</p><p>When Spring Cloud Stream applications are deployed through Spring Cloud Data Flow, these properties are configured automatically; when Spring Cloud Stream applications are launched independently, these properties must be set correctly.
|
||||
By default, <code class="literal">spring.cloud.stream.instanceCount</code> is <code class="literal">1</code>, and <code class="literal">spring.cloud.stream.instanceIndex</code> is <code class="literal">0</code>.</p><p>In a scaled-up scenario, correct configuration of these two properties is important for addressing partitioning behavior (see below) in general, and the two properties are always required by certain binders (for example, the Kafka binder) in order to ensure that data are split correctly across multiple consumer instances.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="spring-cloud-stream-overview-partitioning" href="#spring-cloud-stream-overview-partitioning"></a>34.3 Partitioning</h2></div></div></div><p>Partitioning in Spring Cloud Stream consists of two tasks:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">“<a class="xref" href="multi__inter_application_communication.html#spring-cloud-stream-overview-configuring-output-bindings-partitioning" title="34.3.1 Configuring Output Bindings for Partitioning">Section 34.3.1, “Configuring Output Bindings for Partitioning”</a>”</li><li class="listitem">“<a class="xref" href="multi__inter_application_communication.html#spring-cloud-stream-overview-configuring-input-bindings-partitioning" title="34.3.2 Configuring Input Bindings for Partitioning">Section 34.3.2, “Configuring Input Bindings for Partitioning”</a>”</li></ul></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="spring-cloud-stream-overview-configuring-output-bindings-partitioning" href="#spring-cloud-stream-overview-configuring-output-bindings-partitioning"></a>34.3.1 Configuring Output Bindings for Partitioning</h3></div></div></div><p>You can configure an output binding to send partitioned data by setting one and only one of its <code class="literal">partitionKeyExpression</code> or <code class="literal">partitionKeyExtractorName</code> properties, as well as its <code class="literal">partitionCount</code> property.</p><p>For example, the following is a valid and typical configuration:</p><pre class="screen">spring.cloud.stream.bindings.output.producer.partitionKeyExpression=payload.id
|
||||
spring.cloud.stream.bindings.output.producer.partitionCount=5</pre><p>Based on that example configuration, data is sent to the target partition by using the following logic.</p><p>A partition key’s value is calculated for each message sent to a partitioned output channel based on the <code class="literal">partitionKeyExpression</code>.
|
||||
The <code class="literal">partitionKeyExpression</code> is a SpEL expression that is evaluated against the outbound message for extracting the partitioning key.</p><p>If a SpEL expression is not sufficient for your needs, you can instead calculate the partition key value by providing an implementation of <code class="literal">org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy</code> and configuring it as a bean (by using the <code class="literal">@Bean</code> annotation).
|
||||
If you have more then one bean of type <code class="literal">org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy</code> available in the Application Context, you can further filter it by specifying its name with the <code class="literal">partitionKeyExtractorName</code> property, as shown in the following example:</p><pre class="screen">--spring.cloud.stream.bindings.output.producer.partitionKeyExtractorName=customPartitionKeyExtractor
|
||||
--spring.cloud.stream.bindings.output.producer.partitionCount=5
|
||||
. . .
|
||||
@Bean
|
||||
public CustomPartitionKeyExtractorClass customPartitionKeyExtractor() {
|
||||
return new CustomPartitionKeyExtractorClass();
|
||||
}</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>In previous versions of Spring Cloud Stream, you could specify the implementation of <code class="literal">org.springframework.cloud.stream.binder.PartitionKeyExtractorStrategy</code> by setting the <code class="literal">spring.cloud.stream.bindings.output.producer.partitionKeyExtractorClass</code> property.
|
||||
Since version 2.0, this property is deprecated, and support for it will be removed in a future version.</p></td></tr></table></div><p>Once the message key is calculated, the partition selection process determines the target partition as a value between <code class="literal">0</code> and <code class="literal">partitionCount - 1</code>.
|
||||
The default calculation, applicable in most scenarios, is based on the following formula: <code class="literal">key.hashCode() % partitionCount</code>.
|
||||
This can be customized on the binding, either by setting a SpEL expression to be evaluated against the 'key' (through the <code class="literal">partitionSelectorExpression</code> property) or by configuring an implementation of <code class="literal">org.springframework.cloud.stream.binder.PartitionSelectorStrategy</code> as a bean (by using the @Bean annotation).
|
||||
Similar to the <code class="literal">PartitionKeyExtractorStrategy</code>, you can further filter it by using the <code class="literal">spring.cloud.stream.bindings.output.producer.partitionSelectorName</code> property when more than one bean of this type is available in the Application Context, as shown in the following example:</p><pre class="screen">--spring.cloud.stream.bindings.output.producer.partitionSelectorName=customPartitionSelector
|
||||
. . .
|
||||
@Bean
|
||||
public CustomPartitionSelectorClass customPartitionSelector() {
|
||||
return new CustomPartitionSelectorClass();
|
||||
}</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>In previous versions of Spring Cloud Stream you could specify the implementation of <code class="literal">org.springframework.cloud.stream.binder.PartitionSelectorStrategy</code> by setting the <code class="literal">spring.cloud.stream.bindings.output.producer.partitionSelectorClass</code> property.
|
||||
Since version 2.0, this property is deprecated and support for it will be removed in a future version.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="spring-cloud-stream-overview-configuring-input-bindings-partitioning" href="#spring-cloud-stream-overview-configuring-input-bindings-partitioning"></a>34.3.2 Configuring Input Bindings for Partitioning</h3></div></div></div><p>An input binding (with the channel name <code class="literal">input</code>) is configured to receive partitioned data by setting its <code class="literal">partitioned</code> property, as well as the <code class="literal">instanceIndex</code> and <code class="literal">instanceCount</code> properties on the application itself, as shown in the following example:</p><pre class="screen">spring.cloud.stream.bindings.input.consumer.partitioned=true
|
||||
spring.cloud.stream.instanceIndex=3
|
||||
spring.cloud.stream.instanceCount=5</pre><p>The <code class="literal">instanceCount</code> value represents the total number of application instances between which the data should be partitioned.
|
||||
The <code class="literal">instanceIndex</code> must be a unique value across the multiple instances, with a value between <code class="literal">0</code> and <code class="literal">instanceCount - 1</code>.
|
||||
The instance index helps each application instance to identify the unique partition(s) from which it receives data.
|
||||
It is required by binders using technology that does not support partitioning natively.
|
||||
For example, with RabbitMQ, there is a queue for each partition, with the queue name containing the instance index.
|
||||
With Kafka, if <code class="literal">autoRebalanceEnabled</code> is <code class="literal">true</code> (default), Kafka takes care of distributing partitions across instances, and these properties are not required.
|
||||
If <code class="literal">autoRebalanceEnabled</code> is set to false, the <code class="literal">instanceCount</code> and <code class="literal">instanceIndex</code> are used by the binder to determine which partition(s) the instance subscribes to (you must have at least as many partitions as there are instances).
|
||||
The binder allocates the partitions instead of Kafka.
|
||||
This might be useful if you want messages for a particular partition to always go to the same instance.
|
||||
When a binder configuration requires them, it is important to set both values correctly in order to ensure that all of the data is consumed and that the application instances receive mutually exclusive datasets.</p><p>While a scenario in which using multiple instances for partitioned data processing may be complex to set up in a standalone case, Spring Cloud Dataflow can simplify the process significantly by populating both the input and output values correctly and by letting you rely on the runtime infrastructure to provide information about the instance index and instance count.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_schema-evolution.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_stream.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__testing.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">33. Schema Evolution Support </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 35. Testing</td></tr></table></div></body></html>
|
||||
244
Greenwich.RC2/multi/multi__introduction.html
Normal file
@@ -0,0 +1,244 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>50. Introduction</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="next" href="multi__additional_resources.html" title="51. Additional Resources"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">50. Introduction</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_sleuth.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__additional_resources.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_introduction" href="#_introduction"></a>50. Introduction</h2></div></div></div><p>Spring Cloud Sleuth implements a distributed tracing solution for <a class="link" href="http://cloud.spring.io" target="_top">Spring Cloud</a>.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_terminology" href="#_terminology"></a>50.1 Terminology</h2></div></div></div><p>Spring Cloud Sleuth borrows <a class="link" href="http://research.google.com/pubs/pub36356.html" target="_top">Dapper’s</a> terminology.</p><p><span class="strong"><strong>Span</strong></span>: The basic unit of work. For example, sending an RPC is a new span, as is sending a response to an RPC.
|
||||
Spans are identified by a unique 64-bit ID for the span and another 64-bit ID for the trace the span is a part of.
|
||||
Spans also have other data, such as descriptions, timestamped events, key-value annotations (tags), the ID of the span that caused them, and process IDs (normally IP addresses).</p><p>Spans can be started and stopped, and they keep track of their timing information.
|
||||
Once you create a span, you must stop it at some point in the future.</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>The initial span that starts a trace is called a <code class="literal">root span</code>. The value of the ID
|
||||
of that span is equal to the trace ID.</p></td></tr></table></div><p><span class="strong"><strong>Trace:</strong></span> A set of spans forming a tree-like structure.
|
||||
For example, if you run a distributed big-data store, a trace might be formed by a <code class="literal">PUT</code> request.</p><p><span class="strong"><strong>Annotation:</strong></span> Used to record the existence of an event in time. With
|
||||
<a class="link" href="https://github.com/openzipkin/brave" target="_top">Brave</a> instrumentation, we no longer need to set special events
|
||||
for <a class="link" href="https://zipkin.io/" target="_top">Zipkin</a> to understand who the client and server are, where
|
||||
the request started, and where it ended. For learning purposes,
|
||||
however, we mark these events to highlight what kind
|
||||
of an action took place.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><span class="strong"><strong>cs</strong></span>: Client Sent. The client has made a request. This annotation indicates the start of the span.</li><li class="listitem"><span class="strong"><strong>sr</strong></span>: Server Received: The server side got the request and started processing it.
|
||||
Subtracting the <code class="literal">cs</code> timestamp from this timestamp reveals the network latency.</li><li class="listitem"><span class="strong"><strong>ss</strong></span>: Server Sent. Annotated upon completion of request processing (when the response got sent back to the client).
|
||||
Subtracting the <code class="literal">sr</code> timestamp from this timestamp reveals the time needed by the server side to process the request.</li><li class="listitem"><span class="strong"><strong>cr</strong></span>: Client Received. Signifies the end of the span.
|
||||
The client has successfully received the response from the server side.
|
||||
Subtracting the <code class="literal">cs</code> timestamp from this timestamp reveals the whole time needed by the client to receive the response from the server.</li></ul></div><p>The following image shows how <span class="strong"><strong>Span</strong></span> and <span class="strong"><strong>Trace</strong></span> look in a system, together with the Zipkin annotations:</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-sleuth/master/docs/src/main/asciidoc/images/trace-id.png" alt="Trace Info propagation"></div></div><p>Each color of a note signifies a span (there are seven spans - from <span class="strong"><strong>A</strong></span> to <span class="strong"><strong>G</strong></span>).
|
||||
Consider the following note:</p><pre class="screen">Trace Id = X
|
||||
Span Id = D
|
||||
Client Sent</pre><p>This note indicates that the current span has <span class="strong"><strong>Trace Id</strong></span> set to <span class="strong"><strong>X</strong></span> and <span class="strong"><strong>Span Id</strong></span> set to <span class="strong"><strong>D</strong></span>.
|
||||
Also, the <code class="literal">Client Sent</code> event took place.</p><p>The following image shows how parent-child relationships of spans look:</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-sleuth/master/docs/src/main/asciidoc/images/parents.png" alt="Parent child relationship"></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_purpose" href="#_purpose"></a>50.2 Purpose</h2></div></div></div><p>The following sections refer to the example shown in the preceding image.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_distributed_tracing_with_zipkin" href="#_distributed_tracing_with_zipkin"></a>50.2.1 Distributed Tracing with Zipkin</h3></div></div></div><p>This example has seven spans.
|
||||
If you go to traces in Zipkin, you can see this number in the second trace, as shown in the following image:</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-sleuth/master/docs/src/main/asciidoc/images/zipkin-traces.png" alt="Traces"></div></div><p>However, if you pick a particular trace, you can see four spans, as shown in the following image:</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-sleuth/master/docs/src/main/asciidoc/images/zipkin-ui.png" alt="Traces Info propagation"></div></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>When you pick a particular trace, you see merged spans.
|
||||
That means that, if there were two spans sent to Zipkin with Server Received and Server Sent or Client Received and Client Sent annotations, they are presented as a single span.</p></td></tr></table></div><p>Why is there a difference between the seven and four spans in this case?</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">One span comes from the <code class="literal">http:/start</code> span. It has the Server Received (<code class="literal">sr</code>) and Server Sent (<code class="literal">ss</code>) annotations.</li><li class="listitem">Two spans come from the RPC call from <code class="literal">service1</code> to <code class="literal">service2</code> to the <code class="literal">http:/foo</code> endpoint.
|
||||
The Client Sent (<code class="literal">cs</code>) and Client Received (<code class="literal">cr</code>) events took place on the <code class="literal">service1</code> side.
|
||||
Server Received (<code class="literal">sr</code>) and Server Sent (<code class="literal">ss</code>) events took place on the <code class="literal">service2</code> side.
|
||||
These two spans form one logical span related to an RPC call.</li><li class="listitem">Two spans come from the RPC call from <code class="literal">service2</code> to <code class="literal">service3</code> to the <code class="literal">http:/bar</code> endpoint.
|
||||
The Client Sent (<code class="literal">cs</code>) and Client Received (<code class="literal">cr</code>) events took place on the <code class="literal">service2</code> side.
|
||||
The Server Received (<code class="literal">sr</code>) and Server Sent (<code class="literal">ss</code>) events took place on the <code class="literal">service3</code> side.
|
||||
These two spans form one logical span related to an RPC call.</li><li class="listitem">Two spans come from the RPC call from <code class="literal">service2</code> to <code class="literal">service4</code> to the <code class="literal">http:/baz</code> endpoint.
|
||||
The Client Sent (<code class="literal">cs</code>) and Client Received (<code class="literal">cr</code>) events took place on the <code class="literal">service2</code> side.
|
||||
Server Received (<code class="literal">sr</code>) and Server Sent (<code class="literal">ss</code>) events took place on the <code class="literal">service4</code> side.
|
||||
These two spans form one logical span related to an RPC call.</li></ul></div><p>So, if we count the physical spans, we have one from <code class="literal">http:/start</code>, two from <code class="literal">service1</code> calling <code class="literal">service2</code>, two from <code class="literal">service2</code>
|
||||
calling <code class="literal">service3</code>, and two from <code class="literal">service2</code> calling <code class="literal">service4</code>. In sum, we have a total of seven spans.</p><p>Logically, we see the information of four total Spans because we have one span related to the incoming request
|
||||
to <code class="literal">service1</code> and three spans related to RPC calls.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_visualizing_errors" href="#_visualizing_errors"></a>50.2.2 Visualizing errors</h3></div></div></div><p>Zipkin lets you visualize errors in your trace.
|
||||
When an exception was thrown and was not caught, we set proper tags on the span, which Zipkin can then properly colorize.
|
||||
You could see in the list of traces one trace that is red. That appears because an exception was thrown.</p><p>If you click that trace, you see a similar picture, as follows:</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-sleuth/master/docs/src/main/asciidoc/images/zipkin-error-traces.png" alt="Error Traces"></div></div><p>If you then click on one of the spans, you see the following</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-sleuth/master/docs/src/main/asciidoc/images/zipkin-error-trace-screenshot.png" alt="Error Traces Info propagation"></div></div><p>The span shows the reason for the error and the whole stack trace related to it.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_distributed_tracing_with_brave" href="#_distributed_tracing_with_brave"></a>50.2.3 Distributed Tracing with Brave</h3></div></div></div><p>Starting with version <code class="literal">2.0.0</code>, Spring Cloud Sleuth uses <a class="link" href="https://github.com/openzipkin/brave" target="_top">Brave</a> as the tracing library.
|
||||
Consequently, Sleuth no longer takes care of storing the context but delegates that work to Brave.</p><p>Due to the fact that Sleuth had different naming and tagging conventions than Brave, we decided to follow Brave’s conventions from now on.
|
||||
However, if you want to use the legacy Sleuth approaches, you can set the <code class="literal">spring.sleuth.http.legacy.enabled</code> property to <code class="literal">true</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_live_examples" href="#_live_examples"></a>50.2.4 Live examples</h3></div></div></div><div class="figure"><a name="d0e16152" href="#d0e16152"></a><p class="title"><b>Figure 50.1. Click the Pivotal Web Services icon to see it live!</b></p><div class="figure-contents"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-sleuth/master/docs/src/main/asciidoc/images/pws.png" alt="Zipkin deployed on Pivotal Web Services"></div></div></div><br class="figure-break"><p><a class="link" href="http://docssleuth-zipkin-server.cfapps.io/" target="_top">Click here to see it live!</a></p><p>The dependency graph in Zipkin should resemble the following image:</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-sleuth/master/docs/src/main/asciidoc/images/dependencies.png" alt="Dependencies"></div></div><div class="figure"><a name="d0e16173" href="#d0e16173"></a><p class="title"><b>Figure 50.2. Click the Pivotal Web Services icon to see it live!</b></p><div class="figure-contents"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-sleuth/master/docs/src/main/asciidoc/images/pws.png" alt="Zipkin deployed on Pivotal Web Services"></div></div></div><br class="figure-break"><p><a class="link" href="http://docssleuth-zipkin-server.cfapps.io/dependency" target="_top">Click here to see it live!</a></p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_log_correlation" href="#_log_correlation"></a>50.2.5 Log correlation</h3></div></div></div><p>When using grep to read the logs of those four applications by scanning for a trace ID equal to (for example) <code class="literal">2485ec27856c56f4</code>, you get output resembling the following:</p><pre class="screen">service1.log:2016-02-26 11:15:47.561 INFO [service1,2485ec27856c56f4,2485ec27856c56f4,true] 68058 --- [nio-8081-exec-1] i.s.c.sleuth.docs.service1.Application : Hello from service1. Calling service2
|
||||
service2.log:2016-02-26 11:15:47.710 INFO [service2,2485ec27856c56f4,9aa10ee6fbde75fa,true] 68059 --- [nio-8082-exec-1] i.s.c.sleuth.docs.service2.Application : Hello from service2. Calling service3 and then service4
|
||||
service3.log:2016-02-26 11:15:47.895 INFO [service3,2485ec27856c56f4,1210be13194bfe5,true] 68060 --- [nio-8083-exec-1] i.s.c.sleuth.docs.service3.Application : Hello from service3
|
||||
service2.log:2016-02-26 11:15:47.924 INFO [service2,2485ec27856c56f4,9aa10ee6fbde75fa,true] 68059 --- [nio-8082-exec-1] i.s.c.sleuth.docs.service2.Application : Got response from service3 [Hello from service3]
|
||||
service4.log:2016-02-26 11:15:48.134 INFO [service4,2485ec27856c56f4,1b1845262ffba49d,true] 68061 --- [nio-8084-exec-1] i.s.c.sleuth.docs.service4.Application : Hello from service4
|
||||
service2.log:2016-02-26 11:15:48.156 INFO [service2,2485ec27856c56f4,9aa10ee6fbde75fa,true] 68059 --- [nio-8082-exec-1] i.s.c.sleuth.docs.service2.Application : Got response from service4 [Hello from service4]
|
||||
service1.log:2016-02-26 11:15:48.182 INFO [service1,2485ec27856c56f4,2485ec27856c56f4,true] 68058 --- [nio-8081-exec-1] i.s.c.sleuth.docs.service1.Application : Got response from service2 [Hello from service2, response from service3 [Hello from service3] and from service4 [Hello from service4]]</pre><p>If you use a log aggregating tool (such as <a class="link" href="https://www.elastic.co/products/kibana" target="_top">Kibana</a>, <a class="link" href="http://www.splunk.com/" target="_top">Splunk</a>, and others), you can order the events that took place.
|
||||
An example from Kibana would resemble the following image:</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-sleuth/master/docs/src/main/asciidoc/images/kibana.png" alt="Log correlation with Kibana"></div></div><p>If you want to use <a class="link" href="https://www.elastic.co/guide/en/logstash/current/index.html" target="_top">Logstash</a>, the following listing shows the Grok pattern for Logstash:</p><pre class="screen">filter {
|
||||
# pattern matching logback pattern
|
||||
grok {
|
||||
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp}\s+%{LOGLEVEL:severity}\s+\[%{DATA:service},%{DATA:trace},%{DATA:span},%{DATA:exportable}\]\s+%{DATA:pid}\s+---\s+\[%{DATA:thread}\]\s+%{DATA:class}\s+:\s+%{GREEDYDATA:rest}" }
|
||||
}
|
||||
}</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>If you want to use Grok together with the logs from Cloud Foundry, you have to use the following pattern:</p></td></tr></table></div><pre class="screen">filter {
|
||||
# pattern matching logback pattern
|
||||
grok {
|
||||
match => { "message" => "(?m)OUT\s+%{TIMESTAMP_ISO8601:timestamp}\s+%{LOGLEVEL:severity}\s+\[%{DATA:service},%{DATA:trace},%{DATA:span},%{DATA:exportable}\]\s+%{DATA:pid}\s+---\s+\[%{DATA:thread}\]\s+%{DATA:class}\s+:\s+%{GREEDYDATA:rest}" }
|
||||
}
|
||||
}</pre><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_json_logback_with_logstash" href="#_json_logback_with_logstash"></a>JSON Logback with Logstash</h4></div></div></div><p>Often, you do not want to store your logs in a text file but in a JSON file that Logstash can immediately pick.
|
||||
To do so, you have to do the following (for readability, we pass the dependencies in the <code class="literal">groupId:artifactId:version</code> notation).</p><p><span class="strong"><strong>Dependencies Setup</strong></span></p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">Ensure that Logback is on the classpath (<code class="literal">ch.qos.logback:logback-core</code>).</li><li class="listitem">Add Logstash Logback encode. For example, to use version <code class="literal">4.6</code>, add <code class="literal">net.logstash.logback:logstash-logback-encoder:4.6</code>.</li></ol></div><p><span class="strong"><strong>Logback Setup</strong></span></p><p>Consider the following example of a Logback configuration file (named <a class="link" href="https://github.com/spring-cloud-samples/sleuth-documentation-apps/blob/master/service1/src/main/resources/logback-spring.xml" target="_top">logback-spring.xml</a>).</p><pre class="programlisting"><span class="hl-directive" style="color: maroon"><?xml version="1.0" encoding="UTF-8"?></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><configuration></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><include</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">resource</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"org/springframework/boot/logging/logback/defaults.xml"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">/></span>
|
||||
​
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><springProperty</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">scope</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"context"</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">name</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"springAppName"</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">source</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"spring.application.name"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">/></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- Example for logging into the build folder of your project --></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><property</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">name</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"LOG_FILE"</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">value</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"${BUILD_FOLDER:-build}/${springAppName}"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">/></span>​
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- You can override this to have a custom pattern --></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><property</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">name</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"CONSOLE_LOG_PATTERN"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">value</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">/></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- Appender to log to console --></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><appender</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">name</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"console"</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">class</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"ch.qos.logback.core.ConsoleAppender"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><filter</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">class</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"ch.qos.logback.classic.filter.ThresholdFilter"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- Minimum logging level to be presented in the console logs--></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><level></span>DEBUG<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></level></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></filter></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><encoder></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><pattern></span>${CONSOLE_LOG_PATTERN}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></pattern></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><charset></span>utf8<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></charset></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></encoder></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></appender></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- Appender to log to file --></span>​
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><appender</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">name</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"flatfile"</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">class</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"ch.qos.logback.core.rolling.RollingFileAppender"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><file></span>${LOG_FILE}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></file></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><rollingPolicy</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">class</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><fileNamePattern></span>${LOG_FILE}.%d{yyyy-MM-dd}.gz<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></fileNamePattern></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><maxHistory></span>7<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></maxHistory></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></rollingPolicy></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><encoder></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><pattern></span>${CONSOLE_LOG_PATTERN}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></pattern></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><charset></span>utf8<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></charset></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></encoder></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></appender></span>
|
||||
​
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- Appender to log to file in a JSON format --></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><appender</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">name</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"logstash"</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">class</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"ch.qos.logback.core.rolling.RollingFileAppender"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><file></span>${LOG_FILE}.json<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></file></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><rollingPolicy</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">class</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"ch.qos.logback.core.rolling.TimeBasedRollingPolicy"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><fileNamePattern></span>${LOG_FILE}.json.%d{yyyy-MM-dd}.gz<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></fileNamePattern></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><maxHistory></span>7<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></maxHistory></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></rollingPolicy></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><encoder</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">class</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><providers></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><timestamp></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><timeZone></span>UTC<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></timeZone></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></timestamp></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><pattern></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><pattern></span>
|
||||
{
|
||||
"severity": "%level",
|
||||
"service": "${springAppName:-}",
|
||||
"trace": "%X{X-B3-TraceId:-}",
|
||||
"span": "%X{X-B3-SpanId:-}",
|
||||
"parent": "%X{X-B3-ParentSpanId:-}",
|
||||
"exportable": "%X{X-Span-Export:-}",
|
||||
"pid": "${PID:-}",
|
||||
"thread": "%thread",
|
||||
"class": "%logger{40}",
|
||||
"rest": "%message"
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></pattern></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></pattern></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></providers></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></encoder></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></appender></span>
|
||||
​
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><root</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">level</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"INFO"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><appender-ref</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">ref</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"console"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">/></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- uncomment this to have also JSON logs --></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!--<appender-ref ref="logstash"/>--></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!--<appender-ref ref="flatfile"/>--></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></root></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></configuration></span></pre><p>That Logback configuration file:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Logs information from the application in a JSON format to a <code class="literal">build/${spring.application.name}.json</code> file.</li><li class="listitem">Has commented out two additional appenders: console and standard log file.</li><li class="listitem">Has the same logging pattern as the one presented in the previous section.</li></ul></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>If you use a custom <code class="literal">logback-spring.xml</code>, you must pass the <code class="literal">spring.application.name</code> in the <code class="literal">bootstrap</code> rather than the <code class="literal">application</code> property file.
|
||||
Otherwise, your custom logback file does not properly read the property.</p></td></tr></table></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_propagating_span_context" href="#_propagating_span_context"></a>50.2.6 Propagating Span Context</h3></div></div></div><p>The span context is the state that must get propagated to any child spans across process boundaries.
|
||||
Part of the Span Context is the Baggage. The trace and span IDs are a required part of the span context.
|
||||
Baggage is an optional part.</p><p>Baggage is a set of key:value pairs stored in the span context.
|
||||
Baggage travels together with the trace and is attached to every span.
|
||||
Spring Cloud Sleuth understands that a header is baggage-related if the HTTP header is prefixed with <code class="literal">baggage-</code> and, for messaging, it starts with <code class="literal">baggage_</code>.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>There is currently no limitation of the count or size of baggage items.
|
||||
However, keep in mind that too many can decrease system throughput or increase RPC latency.
|
||||
In extreme cases, too much baggage can crash the application, due to exceeding transport-level message or header capacity.</p></td></tr></table></div><p>The following example shows setting baggage on a span:</p><pre class="programlisting">Span initialSpan = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracer.nextSpan().name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"span"</span>).start();
|
||||
ExtraFieldPropagation.set(initialSpan.context(), <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"bar"</span>);
|
||||
ExtraFieldPropagation.set(initialSpan.context(), <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"UPPER_CASE"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"someValue"</span>);</pre><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_baggage_versus_span_tags" href="#_baggage_versus_span_tags"></a>Baggage versus Span Tags</h4></div></div></div><p>Baggage travels with the trace (every child span contains the baggage of its parent).
|
||||
Zipkin has no knowledge of baggage and does not receive that information.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Starting from Sleuth 2.0.0 you have to pass the baggage key names explicitly
|
||||
in your project configuration. Read more about that setup <a class="link" href="multi__propagation.html#prefixed-fields" title="54.1.1 Prefixed fields">here</a></p></td></tr></table></div><p>Tags are attached to a specific span. In other words, they are presented only for that particular span.
|
||||
However, you can search by tag to find the trace, assuming a span having the searched tag value exists.</p><p>If you want to be able to lookup a span based on baggage, you should add a corresponding entry as a tag in the root span.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>The span must be in scope.</p></td></tr></table></div><p>The following listing shows integration tests that use baggage:</p><p><b>The setup. </b>
|
||||
</p><pre class="programlisting">spring.sleuth:
|
||||
baggage-keys:
|
||||
- baz
|
||||
- bizarrecase
|
||||
propagation-keys:
|
||||
- foo
|
||||
- upper_case</pre><p>
|
||||
</p><p><b>The code. </b>
|
||||
</p><pre class="programlisting">initialSpan.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo"</span>,
|
||||
ExtraFieldPropagation.get(initialSpan.context(), <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo"</span>));
|
||||
initialSpan.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"UPPER_CASE"</span>,
|
||||
ExtraFieldPropagation.get(initialSpan.context(), <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"UPPER_CASE"</span>));</pre><p>
|
||||
</p></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="sleuth-adding-project" href="#sleuth-adding-project"></a>50.3 Adding Sleuth to the Project</h2></div></div></div><p>This section addresses how to add Sleuth to your project with either Maven or Gradle.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>To ensure that your application name is properly displayed in Zipkin, set the <code class="literal">spring.application.name</code> property in <code class="literal">bootstrap.yml</code>.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_only_sleuth_log_correlation" href="#_only_sleuth_log_correlation"></a>50.3.1 Only Sleuth (log correlation)</h3></div></div></div><p>If you want to use only Spring Cloud Sleuth without the Zipkin integration, add the <code class="literal">spring-cloud-starter-sleuth</code> module to your project.</p><p>The following example shows how to add Sleuth with Maven:</p><p class="primary"><b>Maven. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencyManagement></span> <a name="CO1-1" href="#CO1-1"></a><span><img src="images/callouts/1.png" alt="1" border="0"></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-dependencies<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>${release.train.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><type></span>pom<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></type></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><scope></span>import<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></scope></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencyManagement></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span> <a name="CO1-2" href="#CO1-2"></a><span><img src="images/callouts/2.png" alt="2" border="0"></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-sleuth<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p class="primary">
|
||||
</p><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO1-1"><span><img src="images/callouts/1.png" alt="1" border="0"></span></a> </p></td><td valign="top" align="left"><p>We recommend that you add the dependency management through the Spring BOM so that you need not manage versions yourself.</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO1-2"><span><img src="images/callouts/2.png" alt="2" border="0"></span></a> </p></td><td valign="top" align="left"><p>Add the dependency to <code class="literal">spring-cloud-starter-sleuth</code>.</p></td></tr></table></div><p>The following example shows how to add Sleuth with Gradle:</p><p class="secondary"><b>Gradle. </b>
|
||||
</p><pre class="programlisting">dependencyManagement { <a name="CO2-1" href="#CO2-1"></a><span><img src="images/callouts/1.png" alt="1" border="0"></span>
|
||||
imports {
|
||||
mavenBom <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"</span>
|
||||
}
|
||||
}
|
||||
|
||||
dependencies { <a name="CO2-2" href="#CO2-2"></a><span><img src="images/callouts/2.png" alt="2" border="0"></span>
|
||||
compile <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"org.springframework.cloud:spring-cloud-starter-sleuth"</span>
|
||||
}</pre><p class="secondary">
|
||||
</p><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO2-1"><span><img src="images/callouts/1.png" alt="1" border="0"></span></a> </p></td><td valign="top" align="left"><p>We recommend that you add the dependency management through the Spring BOM so that you need not manage versions yourself.</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO2-2"><span><img src="images/callouts/2.png" alt="2" border="0"></span></a> </p></td><td valign="top" align="left"><p>Add the dependency to <code class="literal">spring-cloud-starter-sleuth</code>.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_sleuth_with_zipkin_via_http" href="#_sleuth_with_zipkin_via_http"></a>50.3.2 Sleuth with Zipkin via HTTP</h3></div></div></div><p>If you want both Sleuth and Zipkin, add the <code class="literal">spring-cloud-starter-zipkin</code> dependency.</p><p>The following example shows how to do so for Maven:</p><p class="primary"><b>Maven. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencyManagement></span> <a name="CO3-1" href="#CO3-1"></a><span><img src="images/callouts/1.png" alt="1" border="0"></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-dependencies<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>${release.train.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><type></span>pom<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></type></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><scope></span>import<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></scope></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencyManagement></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span> <a name="CO3-2" href="#CO3-2"></a><span><img src="images/callouts/2.png" alt="2" border="0"></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-zipkin<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p class="primary">
|
||||
</p><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-1"><span><img src="images/callouts/1.png" alt="1" border="0"></span></a> </p></td><td valign="top" align="left"><p>We recommend that you add the dependency management through the Spring BOM so that you need not manage versions yourself.</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-2"><span><img src="images/callouts/2.png" alt="2" border="0"></span></a> </p></td><td valign="top" align="left"><p>Add the dependency to <code class="literal">spring-cloud-starter-zipkin</code>.</p></td></tr></table></div><p>The following example shows how to do so for Gradle:</p><p class="secondary"><b>Gradle. </b>
|
||||
</p><pre class="programlisting">dependencyManagement { <a name="CO4-1" href="#CO4-1"></a><span><img src="images/callouts/1.png" alt="1" border="0"></span>
|
||||
imports {
|
||||
mavenBom <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"</span>
|
||||
}
|
||||
}
|
||||
|
||||
dependencies { <a name="CO4-2" href="#CO4-2"></a><span><img src="images/callouts/2.png" alt="2" border="0"></span>
|
||||
compile <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"org.springframework.cloud:spring-cloud-starter-zipkin"</span>
|
||||
}</pre><p class="secondary">
|
||||
</p><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO4-1"><span><img src="images/callouts/1.png" alt="1" border="0"></span></a> </p></td><td valign="top" align="left"><p>We recommend that you add the dependency management through the Spring BOM so that you need not manage versions yourself.</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO4-2"><span><img src="images/callouts/2.png" alt="2" border="0"></span></a> </p></td><td valign="top" align="left"><p>Add the dependency to <code class="literal">spring-cloud-starter-zipkin</code>.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_sleuth_with_zipkin_over_rabbitmq_or_kafka" href="#_sleuth_with_zipkin_over_rabbitmq_or_kafka"></a>50.3.3 Sleuth with Zipkin over RabbitMQ or Kafka</h3></div></div></div><p>If you want to use RabbitMQ or Kafka instead of HTTP, add the <code class="literal">spring-rabbit</code> or <code class="literal">spring-kafka</code> dependency.
|
||||
The default destination name is <code class="literal">zipkin</code>.</p><p>If using Kafka, you must set the property <code class="literal">spring.zipkin.sender.type</code> property accordingly:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.zipkin.sender.type</span>: kafka</pre><div class="caution" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Caution"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="images/caution.png"></td><th align="left">Caution</th></tr><tr><td align="left" valign="top"><p><code class="literal">spring-cloud-sleuth-stream</code> is deprecated and incompatible with these destinations.</p></td></tr></table></div><p>If you want Sleuth over RabbitMQ, add the <code class="literal">spring-cloud-starter-zipkin</code> and <code class="literal">spring-rabbit</code>
|
||||
dependencies.</p><p>The following example shows how to do so for Gradle:</p><p class="primary"><b>Maven. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencyManagement></span> <a name="CO5-1" href="#CO5-1"></a><span><img src="images/callouts/1.png" alt="1" border="0"></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-dependencies<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>${release.train.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><type></span>pom<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></type></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><scope></span>import<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></scope></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencyManagement></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span> <a name="CO5-2" href="#CO5-2"></a><span><img src="images/callouts/2.png" alt="2" border="0"></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-zipkin<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span> <a name="CO5-3" href="#CO5-3"></a><span><img src="images/callouts/3.png" alt="3" border="0"></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.amqp<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-rabbit<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p class="primary">
|
||||
</p><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO5-1"><span><img src="images/callouts/1.png" alt="1" border="0"></span></a> </p></td><td valign="top" align="left"><p>We recommend that you add the dependency management through the Spring BOM so that you need not manage versions yourself.</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO5-2"><span><img src="images/callouts/2.png" alt="2" border="0"></span></a> </p></td><td valign="top" align="left"><p>Add the dependency to <code class="literal">spring-cloud-starter-zipkin</code>. That way, all nested dependencies get downloaded.</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO5-3"><span><img src="images/callouts/3.png" alt="3" border="0"></span></a> </p></td><td valign="top" align="left"><p>To automatically configure RabbitMQ, add the <code class="literal">spring-rabbit</code> dependency.</p></td></tr></table></div><p class="secondary"><b>Gradle. </b>
|
||||
</p><pre class="programlisting">dependencyManagement { <a name="CO6-1" href="#CO6-1"></a><span><img src="images/callouts/1.png" alt="1" border="0"></span>
|
||||
imports {
|
||||
mavenBom <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"</span>
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"org.springframework.cloud:spring-cloud-starter-zipkin"</span> <a name="CO6-2" href="#CO6-2"></a><span><img src="images/callouts/2.png" alt="2" border="0"></span>
|
||||
compile <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"org.springframework.amqp:spring-rabbit"</span> <a name="CO6-3" href="#CO6-3"></a><span><img src="images/callouts/3.png" alt="3" border="0"></span>
|
||||
}</pre><p class="secondary">
|
||||
</p><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO6-1"><span><img src="images/callouts/1.png" alt="1" border="0"></span></a> </p></td><td valign="top" align="left"><p>We recommend that you add the dependency management through the Spring BOM so that you need not manage versions yourself.</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO6-2"><span><img src="images/callouts/2.png" alt="2" border="0"></span></a> </p></td><td valign="top" align="left"><p>Add the dependency to <code class="literal">spring-cloud-starter-zipkin</code>. That way, all nested dependencies get downloaded.</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO6-3"><span><img src="images/callouts/3.png" alt="3" border="0"></span></a> </p></td><td valign="top" align="left"><p>To automatically configure RabbitMQ, add the <code class="literal">spring-rabbit</code> dependency.</p></td></tr></table></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_sleuth.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__additional_resources.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part VIII. Spring Cloud Sleuth </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 51. Additional Resources</td></tr></table></div></body></html>
|
||||
27
Greenwich.RC2/multi/multi__introduction_2.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>124. Introduction</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_function_2.html" title="Part XVI. Spring Cloud Function"><link rel="prev" href="multi__spring_cloud_function_2.html" title="Part XVI. Spring Cloud Function"><link rel="next" href="multi__getting_started.html" title="125. Getting Started"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">124. Introduction</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_function_2.html">Prev</a> </td><th width="60%" align="center">Part XVI. Spring Cloud Function</th><td width="20%" align="right"> <a accesskey="n" href="multi__getting_started.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_introduction_2" href="#_introduction_2"></a>124. Introduction</h2></div></div></div><p>Spring Cloud Function is a project with the following high-level goals:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Promote the implementation of business logic via functions.</li><li class="listitem">Decouple the development lifecycle of business logic from any specific runtime target so that the same code can run as a web endpoint, a stream processor, or a task.</li><li class="listitem">Support a uniform programming model across serverless providers, as well as the ability to run standalone (locally or in a PaaS).</li><li class="listitem">Enable Spring Boot features (auto-configuration, dependency injection, metrics) on serverless providers.</li></ul></div><p>It abstracts away all of the transport details and
|
||||
infrastructure, allowing the developer to keep all the familiar tools
|
||||
and processes, and focus firmly on business logic.</p><p>Here’s a complete, executable, testable Spring Boot application
|
||||
(implementing a simple string manipulation):</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Function<Flux<String>, Flux<String>> uppercase() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> flux -> flux.map(value -> value.toUpperCase());
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(Application.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
}
|
||||
}</pre><p>It’s just a Spring Boot application, so it can be built, run and
|
||||
tested, locally and in a CI build, the same way as any other Spring
|
||||
Boot application. The <code class="literal">Function</code> is from <code class="literal">java.util</code> and <code class="literal">Flux</code> is a
|
||||
<a class="link" href="http://www.reactive-streams.org/" target="_top">Reactive Streams</a> <code class="literal">Publisher</code> from
|
||||
<a class="link" href="https://projectreactor.io/" target="_top">Project Reactor</a>. The function can be
|
||||
accessed over HTTP or messaging.</p><p>Spring Cloud Function has 4 main features:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">Wrappers for <code class="literal">@Beans</code> of type <code class="literal">Function</code>, <code class="literal">Consumer</code> and
|
||||
<code class="literal">Supplier</code>, exposing them to the outside world as either HTTP
|
||||
endpoints and/or message stream listeners/publishers with RabbitMQ, Kafka etc.</li><li class="listitem">Compiling strings which are Java function bodies into bytecode, and
|
||||
then turning them into <code class="literal">@Beans</code> that can be wrapped as above.</li><li class="listitem">Deploying a JAR file containing such an application context with an
|
||||
isolated classloader, so that you can pack them together in a single
|
||||
JVM.</li><li class="listitem">Adapters for <a class="link" href="https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-adapters/spring-cloud-function-adapter-aws" target="_top">AWS Lambda</a>, <a class="link" href="https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-adapters/spring-cloud-function-adapter-azure" target="_top">Azure</a>, <a class="link" href="https://github.com/spring-cloud/spring-cloud-function/tree/master/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk" target="_top">Apache OpenWhisk</a> and possibly other "serverless" service providers.</li></ol></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>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 <a class="link" href="https://github.com/spring-cloud/spring-cloud-function/tree/master/docs/src/main/asciidoc" target="_top">github</a>.</p></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_function_2.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_function_2.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__getting_started.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part XVI. Spring Cloud Function </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 125. Getting Started</td></tr></table></div></body></html>
|
||||
3
Greenwich.RC2/multi/multi__introduction_4.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>147. Introduction</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi_spring-cloud-gcp-reference.html" title="Part XVIII. Spring Cloud GCP"><link rel="prev" href="multi_spring-cloud-gcp-reference.html" title="Part XVIII. Spring Cloud GCP"><link rel="next" href="multi__dependency_management.html" title="148. Dependency Management"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">147. Introduction</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_spring-cloud-gcp-reference.html">Prev</a> </td><th width="60%" align="center">Part XVIII. Spring Cloud GCP</th><td width="20%" align="right"> <a accesskey="n" href="multi__dependency_management.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_introduction_4" href="#_introduction_4"></a>147. Introduction</h2></div></div></div><p>The Spring Cloud GCP project aims at making the Spring Framework a first-class citizen of Google Cloud Platform (GCP).</p><p>Currently, Spring Cloud GCP lets you leverage the power and simplicity of the Spring framework to:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">Publish and subscribe to Google Cloud Pub/Sub topics</li><li class="listitem">Configure Spring JDBC with a few properties to use Google Cloud SQL</li><li class="listitem">Write and read from Spring Resources backed up by Google Cloud Storage</li><li class="listitem">Exchange messages with Spring Integration using Google Cloud Pub/Sub on the background</li><li class="listitem">Trace the execution of your app with Spring Cloud Sleuth and Google Stackdriver Trace</li><li class="listitem">Configure your app with Spring Cloud Config, backed up by the Google Runtime Configuration API</li><li class="listitem">Consume and produce Google Cloud Storage data via Spring Integration GCS Channel Adapters</li></ol></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_spring-cloud-gcp-reference.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi_spring-cloud-gcp-reference.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__dependency_management.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part XVIII. Spring Cloud GCP </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 148. Dependency Management</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,14 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>139. Kubernetes Ecosystem Awareness</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_kubernetes.html" title="Part XVII. Spring Cloud Kubernetes"><link rel="prev" href="multi__ribbon_discovery_in_kubernetes.html" title="138. Ribbon discovery in Kubernetes"><link rel="next" href="multi__pod_health_indicator.html" title="140. Pod Health Indicator"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">139. Kubernetes Ecosystem Awareness</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__ribbon_discovery_in_kubernetes.html">Prev</a> </td><th width="60%" align="center">Part XVII. Spring Cloud Kubernetes</th><td width="20%" align="right"> <a accesskey="n" href="multi__pod_health_indicator.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_kubernetes_ecosystem_awareness" href="#_kubernetes_ecosystem_awareness"></a>139. Kubernetes Ecosystem Awareness</h2></div></div></div><p>All of the features described above will work equally well regardless of whether your application is running inside
|
||||
Kubernetes or not. This is really helpful for development and troubleshooting.
|
||||
From a development point of view, this is really helpful as you can start your Spring Boot application and debug one
|
||||
of the modules part of this project. It is not required to deploy it in Kubernetes
|
||||
as the code of the project relies on the
|
||||
<a class="link" href="https://github.com/fabric8io/kubernetes-client" target="_top">Fabric8 Kubernetes Java client</a> which is a fluent DSL able to
|
||||
communicate using <code class="literal">http</code> protocol to the REST API of Kubernetes Server.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_kubernetes_profile_autoconfiguration" href="#_kubernetes_profile_autoconfiguration"></a>139.1 Kubernetes Profile Autoconfiguration</h2></div></div></div><p>When the application runs as a pod inside Kubernetes a Spring profile named <code class="literal">kubernetes</code> will automatically get activated.
|
||||
This allows the developer to customize the configuration, to define beans that will be applied when the Spring Boot application is deployed
|
||||
within the Kubernetes platform <span class="strong"><strong>(e.g. different dev and prod configuration)</strong></span>.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_istio_awareness" href="#_istio_awareness"></a>139.2 Istio Awareness</h2></div></div></div><p>When including the <span class="strong"><strong>spring-cloud-kubernetes-istio</strong></span> module into the application classpath a new profile will be added to the application,
|
||||
if the application is running inside a Kubernetes Cluster with <a class="link" href="http://istio.io" target="_top">Istio</a> installed. Then you can use
|
||||
spring <span class="strong"><strong>@Profile("istio")</strong></span> annotations into your Beans and <span class="strong"><strong>@Configuration</strong></span>'s.</p><p>The Istio awareness module uses the <span class="strong"><strong>me.snowdrop:istio-client</strong></span> to interact with Istio APIs enabling us to discover traffic rules, circuit breakers, etc.
|
||||
Making it easy for our Spring Boot applications to consume this data to dynamically configure themselves according the environment.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__ribbon_discovery_in_kubernetes.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_kubernetes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__pod_health_indicator.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">138. Ribbon discovery in Kubernetes </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 140. Pod Health Indicator</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,4 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>136. Kubernetes native service discovery</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_kubernetes.html" title="Part XVII. Spring Cloud Kubernetes"><link rel="prev" href="multi__discoveryclient_for_kubernetes.html" title="135. DiscoveryClient for Kubernetes"><link rel="next" href="multi__kubernetes_propertysource_implementations.html" title="137. Kubernetes PropertySource implementations"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">136. Kubernetes native service discovery</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__discoveryclient_for_kubernetes.html">Prev</a> </td><th width="60%" align="center">Part XVII. Spring Cloud Kubernetes</th><td width="20%" align="right"> <a accesskey="n" href="multi__kubernetes_propertysource_implementations.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_kubernetes_native_service_discovery" href="#_kubernetes_native_service_discovery"></a>136. Kubernetes native service discovery</h2></div></div></div><p>Kubernetes itself is capable of (server side) service discovery (see: <a class="link" href="https://kubernetes.io/docs/concepts/services-networking/service/#discovering-services" target="_top">https://kubernetes.io/docs/concepts/services-networking/service/#discovering-services</a>).
|
||||
Using native kubernetes service discovery ensures compatibility with additional tooling, like: istio <a class="link" href="https://istio.io" target="_top">https://istio.io</a> (service mesh, capable of load balancing, ribbon, circuit breaker, failover and much more).</p><p>The caller service just needs to refer to names resolvable in particular kubernetes cluster then. Simplest implementation might use the spring <code class="literal">RestTemplate</code> referring to fully qualified domain name (FQDN) <code class="literal"><a class="link" href="http://{service-name}.{namespace}.svc.{cluster}.local:{service-port}" target="_top">http://{service-name}.{namespace}.svc.{cluster}.local:{service-port}</a></code>.</p><p>Additionally, hystrix can be used for:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">circuit breaker implementation on the caller side, just by annotating the spring boot application class: <code class="literal">@EnableCircuitBreaker</code></li><li class="listitem">and for the fallback functionality, annotating the respective method via: <code class="literal">@HystrixCommand(fallbackMethod=</code> does the job.</li></ul></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__discoveryclient_for_kubernetes.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_kubernetes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__kubernetes_propertysource_implementations.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">135. DiscoveryClient for Kubernetes </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 137. Kubernetes PropertySource implementations</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,214 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>137. Kubernetes PropertySource implementations</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_kubernetes.html" title="Part XVII. Spring Cloud Kubernetes"><link rel="prev" href="multi__kubernetes_native_service_discovery.html" title="136. Kubernetes native service discovery"><link rel="next" href="multi__ribbon_discovery_in_kubernetes.html" title="138. Ribbon discovery in Kubernetes"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">137. Kubernetes PropertySource implementations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__kubernetes_native_service_discovery.html">Prev</a> </td><th width="60%" align="center">Part XVII. Spring Cloud Kubernetes</th><td width="20%" align="right"> <a accesskey="n" href="multi__ribbon_discovery_in_kubernetes.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_kubernetes_propertysource_implementations" href="#_kubernetes_propertysource_implementations"></a>137. Kubernetes PropertySource implementations</h2></div></div></div><p>The most common approach to configure your Spring Boot application is to create an <code class="literal">application.properties|yaml</code> or
|
||||
an <code class="literal">application-profile.properties|yaml</code> file containing key-value pairs providing customization values to your
|
||||
application or Spring Boot starters. Users may override these properties by specifying system properties or environment
|
||||
variables.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_configmap_propertysource" href="#_configmap_propertysource"></a>137.1 ConfigMap PropertySource</h2></div></div></div><p>Kubernetes provides a resource named <a class="link" href="http://kubernetes.io/docs/user-guide/configmap/" target="_top">ConfigMap</a> to externalize the
|
||||
parameters to pass to your application in the form of key-value pairs or embedded <code class="literal">application.properties|yaml</code> files.
|
||||
The <a class="link" href="./spring-cloud-kubernetes-config" target="_top">Spring Cloud Kubernetes Config</a> project makes Kubernetes `ConfigMap`s available
|
||||
during application bootstrapping and triggers hot reloading of beans or Spring context when changes are detected on
|
||||
observed `ConfigMap`s.</p><p>The default behavior is to create a <code class="literal">ConfigMapPropertySource</code> based on a Kubernetes <code class="literal">ConfigMap</code> which has <code class="literal">metadata.name</code> of either the name of
|
||||
your Spring application (as defined by its <code class="literal">spring.application.name</code> property) or a custom name defined within the
|
||||
<code class="literal">bootstrap.properties</code> file under the following key <code class="literal">spring.cloud.kubernetes.config.name</code>.</p><p>However, more advanced configuration are possible where multiple ConfigMaps can be used
|
||||
This is made possible by the <code class="literal">spring.cloud.kubernetes.config.sources</code> list.
|
||||
For example one could define the following ConfigMaps</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> application</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: cloud-k8s-app
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> kubernetes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> config</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: default-name
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> namespace</span>: default-namespace
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> sources</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"># Spring Cloud Kubernetes will lookup a ConfigMap named c1 in namespace default-namespace</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: c1
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"># Spring Cloud Kubernetes will lookup a ConfigMap named default-name in whatever namespace n2</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - namespace</span>: n2
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"># Spring Cloud Kubernetes will lookup a ConfigMap named c3 in namespace n3</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - namespace</span>: n3
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: c3</pre><p>In the example above, it <code class="literal">spring.cloud.kubernetes.config.namespace</code> had not been set,
|
||||
then the ConfigMap named <code class="literal">c1</code> would be looked up in the namespace that the application runs</p><p>Any matching <code class="literal">ConfigMap</code> that is found, will be processed as follows:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">apply individual configuration properties.</li><li class="listitem">apply as <code class="literal">yaml</code> the content of any property named <code class="literal">application.yaml</code></li><li class="listitem">apply as properties file the content of any property named <code class="literal">application.properties</code></li></ul></div><p>The single exception to the aforementioned flow is when the <code class="literal">ConfigMap</code> contains a <span class="strong"><strong>single</strong></span> key that indicates
|
||||
the file is a YAML or Properties file. In that case the name of the key does NOT have to be <code class="literal">application.yaml</code> or
|
||||
<code class="literal">application.properties</code> (it can be anything) and the value of the property will be treated correctly.
|
||||
This features facilitates the use case where the <code class="literal">ConfigMap</code> was created using something like:</p><p><code class="literal">kubectl create configmap game-config --from-file=/path/to/app-config.yaml</code></p><p>Example:</p><p>Let’s assume that we have a Spring Boot application named <code class="literal">demo</code> that uses properties to read its thread pool
|
||||
configuration.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">pool.size.core</code></li><li class="listitem"><code class="literal">pool.size.maximum</code></li></ul></div><p>This can be externalized to config map in <code class="literal">yaml</code> format:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: ConfigMap
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">metadata</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: demo
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">data</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> pool.size.core</span>: <span class="hl-number">1</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> pool.size.max</span>: <span class="hl-number">16</span></pre><p>Individual properties work fine for most cases but sometimes embedded <code class="literal">yaml</code> is more convenient. In this case we will
|
||||
use a single property named <code class="literal">application.yaml</code> to embed our <code class="literal">yaml</code>:</p><pre class="literallayout"> ```yaml
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: demo
|
||||
data:
|
||||
application.yaml: |-
|
||||
pool:
|
||||
size:
|
||||
core: 1
|
||||
max:16</pre><pre class="screen">The following also works:
|
||||
|
||||
```yaml
|
||||
kind: ConfigMap
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: demo
|
||||
data:
|
||||
custom-name.yaml: |-
|
||||
pool:
|
||||
size:
|
||||
core: 1
|
||||
max:16</pre><p>Spring Boot applications can also be configured differently depending on active profiles which will be merged together
|
||||
when the ConfigMap is read. It is possible to provide different property values for different profiles using an
|
||||
<code class="literal">application.properties|yaml</code> property, specifying profile-specific values each in their own document
|
||||
(indicated by the <code class="literal">---</code> sequence) as follows:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: ConfigMap
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">metadata</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: demo
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">data</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> application.yml</span>: |-
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> greeting</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Hello to the World
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> farewell</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Goodbye
|
||||
---
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> profiles</span>: development
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> greeting</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Hello to the Developers
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> farewell</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Goodbye to the Developers
|
||||
---
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> profiles</span>: production
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> greeting</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Hello to the Ops</pre><p>In the above case, the configuration loaded into your Spring Application with the <code class="literal">development</code> profile will be:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> greeting</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Hello to the Developers
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> farewell</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Goodbye to the Developers</pre><p>whereas if the <code class="literal">production</code> profile is active, the configuration will be:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> greeting</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Hello to the Ops
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> farewell</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Goodbye</pre><p>If both profiles are active, the property which appears last within the configmap will overwrite preceding values.</p><p>To tell to Spring Boot which <code class="literal">profile</code> should be enabled at bootstrap, a system property can be passed to the Java
|
||||
command launching your Spring Boot application using an env variable that you will define with the OpenShift
|
||||
<code class="literal">DeploymentConfig</code> or Kubernetes <code class="literal">ReplicationConfig</code> resource file as follows:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: DeploymentConfig
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spec</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> replicas</span>: <span class="hl-number">1</span>
|
||||
...
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> spec</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> containers</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - env</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: JAVA_APP_DIR
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> value</span>: /deployments
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: JAVA_OPTIONS
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> value</span>: -Dspring.profiles.active=developer</pre><p><span class="strong"><strong>Notes:</strong></span>
|
||||
- check the security configuration section, to access config maps from inside a pod you need to have the correct
|
||||
Kubernetes service accounts, roles and role bindings.</p><p>Another option for using ConfigMaps, is to mount them into the Pod running the Spring Cloud Kubernetes application
|
||||
and have Spring Cloud Kubernetes read them from the file system.
|
||||
This behavior is controlled by the <code class="literal">spring.cloud.kubernetes.config.paths</code> property and can be used in
|
||||
addition to or instead of the mechanism described earlier.
|
||||
Multiple (exact) file paths can be specified in <code class="literal">spring.cloud.kubernetes.config.paths</code> by using the <code class="literal">,</code> delimiter</p><div class="table"><a name="d0e35422" href="#d0e35422"></a><p class="title"><b>Table 137.1. Properties:</b></p><div class="table-contents"><table summary="Properties:" style="border-collapse: collapse;border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; "><colgroup><col class="col_1"><col class="col_2"><col class="col_3"><col class="col_4"></colgroup><thead><tr><th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top">Name</th><th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top">Type</th><th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top">Default</th><th style="border-bottom: 0.5pt solid ; " align="left" valign="top">Description</th></tr></thead><tfoot><tr><th style="border-right: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.config.enableApi</p></th><th style="border-right: 0.5pt solid ; " align="left" valign="top"><p>Boolean</p></th><th style="border-right: 0.5pt solid ; " align="left" valign="top"><p>true</p></th><th style="" align="left" valign="top"><p>Enable/Disable consuming ConfigMaps via APIs</p></th></tr></tfoot><tbody><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.config.enabled</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Boolean</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>true</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Enable Secrets PropertySource</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.config.name</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>String</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>${spring.application.name}</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Sets the name of ConfigMap to lookup</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.config.namespace</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>String</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Client namespace</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Sets the Kubernetes namespace where to lookup</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.config.paths</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>List</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>null</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Sets the paths where ConfigMaps are mounted</p></td></tr></tbody></table></div></div><br class="table-break"></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_secrets_propertysource" href="#_secrets_propertysource"></a>137.2 Secrets PropertySource</h2></div></div></div><p>Kubernetes has the notion of [Secrets](<a class="link" href="https://kubernetes.io/docs/concepts/configuration/secret/" target="_top">https://kubernetes.io/docs/concepts/configuration/secret/</a>) for storing
|
||||
sensitive data such as password, OAuth tokens, etc. This project provides integration with <code class="literal">Secrets</code> to make secrets
|
||||
accessible by Spring Boot applications. This feature can be explicitly enabled/disabled using the <code class="literal">spring.cloud.kubernetes.secrets.enabled</code> property.</p><p>The <code class="literal">SecretsPropertySource</code> when enabled will lookup Kubernetes for <code class="literal">Secrets</code> from the following sources:
|
||||
1. reading recursively from secrets mounts
|
||||
2. named after the application (as defined by <code class="literal">spring.application.name</code>)
|
||||
3. matching some labels</p><p>Please note that by default, consuming Secrets via API (points 2 and 3 above) <span class="strong"><strong>is not enabled</strong></span> for security reasons
|
||||
and it is recommend that containers share secrets via mounted volumes. Otherwise proper RBAC security configurations must be provided
|
||||
to make sure that unauthorized access to Secrets occurs.</p><p>If the secrets are found their data is made available to the application.</p><p><span class="strong"><strong>Example:</strong></span></p><p>Let’s assume that we have a spring boot application named <code class="literal">demo</code> that uses properties to read its database
|
||||
configuration. We can create a Kubernetes secret using the following command:</p><pre class="screen">oc create secret generic db-secret --from-literal=username=user --from-literal=password=p455w0rd</pre><p>This would create the following secret (shown using <code class="literal">oc get secrets db-secret -o yaml</code>):</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">data</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> password</span>: cDQ1NXcwcmQ=
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> username</span>: dXNlcg==
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: Secret
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">metadata</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> creationTimestamp</span>: <span class="hl-number">2017</span>-<span class="hl-number">07</span>-<span class="hl-number">04</span>T09:<span class="hl-number">15</span>:<span class="hl-number">57</span>Z
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: db-secret
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> namespace</span>: default
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> resourceVersion</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"357496"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> selfLink</span>: /api/v1/namespaces/default/secrets/db-secret
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uid</span>: <span class="hl-number">63</span>c89263-<span class="hl-number">6099</span>-<span class="hl-number">11e7</span>-b3da-<span class="hl-number">76d</span>6186905a8
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">type</span>: Opaque</pre><p>Note that the data contains Base64-encoded versions of the literal provided by the create command.</p><p>This secret can then be used by your application for example by exporting the secret’s value as environment variables:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: Deployment
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">metadata</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: ${project.artifactId<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">}</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spec</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> template</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> spec</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> containers</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - env</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: DB_USERNAME
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> valueFrom</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> secretKeyRef</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: db-secret
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> key</span>: username
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: DB_PASSWORD
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> valueFrom</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> secretKeyRef</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: db-secret
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> key</span>: password</pre><p>You can select the Secrets to consume in a number of ways:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p class="simpara">By listing the directories where secrets are mapped:
|
||||
<code class="literal">`
|
||||
-Dspring.cloud.kubernetes.secrets.paths=/etc/secrets/db-secret,etc/secrets/postgresql
|
||||
</code>`</p><pre class="literallayout">If you have all the secrets mapped to a common root, you can set them like:</pre><pre class="literallayout">```
|
||||
-Dspring.cloud.kubernetes.secrets.paths=/etc/secrets
|
||||
```</pre></li><li class="listitem">By setting a named secret:
|
||||
<code class="literal">`
|
||||
-Dspring.cloud.kubernetes.secrets.name=db-secret
|
||||
</code>`</li><li class="listitem">By defining a list of labels:
|
||||
<code class="literal">`
|
||||
-Dspring.cloud.kubernetes.secrets.labels.broker=activemq
|
||||
-Dspring.cloud.kubernetes.secrets.labels.db=postgresql
|
||||
</code>`</li></ol></div><div class="table"><a name="d0e35587" href="#d0e35587"></a><p class="title"><b>Table 137.2. Properties:</b></p><div class="table-contents"><table summary="Properties:" style="border-collapse: collapse;border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; "><colgroup><col class="col_1"><col class="col_2"><col class="col_3"><col class="col_4"></colgroup><thead><tr><th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top">Name</th><th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top">Type</th><th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top">Default</th><th style="border-bottom: 0.5pt solid ; " align="left" valign="top">Description</th></tr></thead><tfoot><tr><th style="border-right: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.secrets.enableApi</p></th><th style="border-right: 0.5pt solid ; " align="left" valign="top"><p>Boolean</p></th><th style="border-right: 0.5pt solid ; " align="left" valign="top"><p>false</p></th><th style="" align="left" valign="top"><p>Enable/Disable consuming secrets via APIs (examples 2 and 3)</p></th></tr></tfoot><tbody><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.secrets.enabled</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Boolean</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>true</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Enable Secrets PropertySource</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.secrets.name</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>String</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>${spring.application.name}</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Sets the name of the secret to lookup</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.secrets.namespace</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>String</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Client namespace</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Sets the Kubernetes namespace where to lookup</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.secrets.labels</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Map</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>null</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Sets the labels used to lookup secrets</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.secrets.paths</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>List</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>null</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Sets the paths where secrets are mounted (example 1)</p></td></tr></tbody></table></div></div><br class="table-break"><p><span class="strong"><strong>Notes:</strong></span>
|
||||
- The property <code class="literal">spring.cloud.kubernetes.secrets.labels</code> behaves as defined by
|
||||
<a class="link" href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding#map-based-binding" target="_top">Map-based binding</a>.
|
||||
- The property <code class="literal">spring.cloud.kubernetes.secrets.paths</code> behaves as defined by
|
||||
<a class="link" href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding#collection-based-binding" target="_top">Collection-based binding</a>.
|
||||
- Access to secrets via API may be restricted for security reasons, the preferred way is to mount secret to the POD.</p><p>Example of application using secrets (though it hasn’t been updated to use the new <code class="literal">spring-cloud-kubernetes</code> project):
|
||||
<a class="link" href="https://github.com/fabric8-quickstarts/spring-boot-camel-config" target="_top">spring-boot-camel-config</a></p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_propertysource_reload" href="#_propertysource_reload"></a>137.3 PropertySource Reload</h2></div></div></div><p>Some applications may need to detect changes on external property sources and update their internal status to reflect the new configuration.
|
||||
The reload feature of Spring Cloud Kubernetes is able to trigger an application reload when a related <code class="literal">ConfigMap</code> or
|
||||
<code class="literal">Secret</code> changes.</p><p>This feature is disabled by default and can be enabled using the configuration property <code class="literal">spring.cloud.kubernetes.reload.enabled=true</code>
|
||||
(eg. in the <span class="strong"><strong>application.properties</strong></span> file).</p><p>The following levels of reload are supported (property <code class="literal">spring.cloud.kubernetes.reload.strategy</code>):
|
||||
- <span class="strong"><strong><code class="literal">refresh</code> (default)</strong></span>: only configuration beans annotated with <code class="literal">@ConfigurationProperties</code> or <code class="literal">@RefreshScope</code> are reloaded.
|
||||
This reload level leverages the refresh feature of Spring Cloud Context.
|
||||
- <span class="strong"><strong><code class="literal">restart_context</code></strong></span>: the whole Spring <span class="emphasis"><em>ApplicationContext</em></span> is gracefully restarted. Beans are recreated with the new configuration.
|
||||
- <span class="strong"><strong><code class="literal">shutdown</code></strong></span>: the Spring <span class="emphasis"><em>ApplicationContext</em></span> is shut down to activate a restart of the container.
|
||||
When using this level, make sure that the lifecycle of all non-daemon threads is bound to the ApplicationContext
|
||||
and that a replication controller or replica set is configured to restart the pod.</p><p>Example:</p><p>Assuming that the reload feature is enabled with default settings (<span class="strong"><strong><code class="literal">refresh</code></strong></span> mode), the following bean will be refreshed when the config map changes:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@ConfigurationProperties(prefix = "bean")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyConfig {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> String message = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"a message that can be changed live"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// getter and setters</span>
|
||||
|
||||
}</pre><p>A way to see that changes effectively happen is creating another bean that prints the message periodically.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Component</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyBean {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> MyConfig config;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Scheduled(fixedDelay = 5000)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> hello() {
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"The message is: "</span> + config.getMessage());
|
||||
}
|
||||
}</pre><p>The message printed by the application can be changed using a <code class="literal">ConfigMap</code> as follows:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: ConfigMap
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">metadata</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: reload-example
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">data</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> application.properties</span>: |-
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> bean.message</span>=Hello World!</pre><p>Any change to the property named <code class="literal">bean.message</code> in the <code class="literal">ConfigMap</code> associated to the pod will be reflected in the
|
||||
output. More generally speaking, changes associated to properties prefixed with the value defined by the <code class="literal">prefix</code>
|
||||
field of the <code class="literal">@ConfigurationProperties</code> annotation will be detected and reflected in the application.
|
||||
[Associating a <code class="literal">ConfigMap</code> to a pod](#configmap-propertysource) is explained above.</p><p>The full example is available in [spring-cloud-kubernetes-reload-example](spring-cloud-kubernetes-examples/kubernetes-reload-example).</p><p>The reload feature supports two operating modes:
|
||||
- <span class="strong"><strong>event (default)</strong></span>: watches for changes in config maps or secrets using the Kubernetes API (web socket).
|
||||
Any event will produce a re-check on the configuration and a reload in case of changes.
|
||||
The <code class="literal">view</code> role on the service account is required in order to listen for config map changes. A higher level role (eg. <code class="literal">edit</code>) is required for secrets
|
||||
(secrets are not monitored by default).
|
||||
- <span class="strong"><strong>polling</strong></span>: re-creates the configuration periodically from config maps and secrets to see if it has changed.
|
||||
The polling period can be configured using the property <code class="literal">spring.cloud.kubernetes.reload.period</code> and defaults to <span class="strong"><strong>15 seconds</strong></span>.
|
||||
It requires the same role as the monitored property source.
|
||||
This means, for example, that using polling on file mounted secret sources does not require particular privileges.</p><div class="table"><a name="d0e35817" href="#d0e35817"></a><p class="title"><b>Table 137.3. Properties:</b></p><div class="table-contents"><table summary="Properties:" style="border-collapse: collapse;border-top: 0.5pt solid ; border-bottom: 0.5pt solid ; "><colgroup><col class="col_1"><col class="col_2"><col class="col_3"><col class="col_4"></colgroup><thead><tr><th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top">Name</th><th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top">Type</th><th style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top">Default</th><th style="border-bottom: 0.5pt solid ; " align="left" valign="top">Description</th></tr></thead><tfoot><tr><th style="border-right: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.reload.period</p></th><th style="border-right: 0.5pt solid ; " align="left" valign="top"><p>Duration</p></th><th style="border-right: 0.5pt solid ; " align="left" valign="top"><p>15s</p></th><th style="" align="left" valign="top"><p>The period for verifying changes when using the <span class="strong"><strong>polling</strong></span> strategy</p></th></tr></tfoot><tbody><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.reload.enabled</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Boolean</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>false</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Enables monitoring of property sources and configuration reload</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.reload.monitoring-config-maps</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Boolean</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>true</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Allow monitoring changes in config maps</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.reload.monitoring-secrets</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Boolean</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>false</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Allow monitoring changes in secrets</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.reload.strategy</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Enum</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>refresh</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>The strategy to use when firing a reload (<span class="strong"><strong>refresh</strong></span>, <span class="strong"><strong>restart_context</strong></span>, <span class="strong"><strong>shutdown</strong></span>)</p></td></tr><tr><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>spring.cloud.kubernetes.reload.mode</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Enum</p></td><td style="border-right: 0.5pt solid ; border-bottom: 0.5pt solid ; " align="left" valign="top"><p>event</p></td><td style="border-bottom: 0.5pt solid ; " align="left" valign="top"><p>Specifies how to listen for changes in property sources (<span class="strong"><strong>event</strong></span>, <span class="strong"><strong>polling</strong></span>)</p></td></tr></tbody></table></div></div><br class="table-break"><p><span class="strong"><strong>Notes</strong></span>:
|
||||
- Properties under <span class="strong"><strong>spring.cloud.kubernetes.reload.</strong></span> should not be used 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 using the <span class="strong"><strong>refresh</strong></span> level.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__kubernetes_native_service_discovery.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_kubernetes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__ribbon_discovery_in_kubernetes.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">136. Kubernetes native service discovery </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 138. Ribbon discovery in Kubernetes</td></tr></table></div></body></html>
|
||||
3
Greenwich.RC2/multi/multi__leader_election.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>141. Leader Election</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_kubernetes.html" title="Part XVII. Spring Cloud Kubernetes"><link rel="prev" href="multi__pod_health_indicator.html" title="140. Pod Health Indicator"><link rel="next" href="multi__security_configurations_inside_kubernetes.html" title="142. Security Configurations inside Kubernetes"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">141. Leader Election</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__pod_health_indicator.html">Prev</a> </td><th width="60%" align="center">Part XVII. Spring Cloud Kubernetes</th><td width="20%" align="right"> <a accesskey="n" href="multi__security_configurations_inside_kubernetes.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_leader_election" href="#_leader_election"></a>141. Leader Election</h2></div></div></div><p><TBD></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__pod_health_indicator.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_kubernetes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__security_configurations_inside_kubernetes.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">140. Pod Health Indicator </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 142. Security Configurations inside Kubernetes</td></tr></table></div></body></html>
|
||||
6
Greenwich.RC2/multi/multi__links.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>98. Links</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_contract.html" title="Part XIII. Spring Cloud Contract"><link rel="prev" href="multi__migrations.html" title="97. Migrations"><link rel="next" href="multi__spring_cloud_vault.html" title="Part XIV. Spring Cloud Vault"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">98. Links</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__migrations.html">Prev</a> </td><th width="60%" align="center">Part XIII. Spring Cloud Contract</th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_vault.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_links" href="#_links"></a>98. Links</h2></div></div></div><p>The following links may be helpful when working with Spring Cloud Contract:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="link" href="https://github.com/spring-cloud/spring-cloud-contract/" target="_top">Spring Cloud Contract Github
|
||||
Repository</a></li><li class="listitem"><a class="link" href="https://github.com/spring-cloud-samples/spring-cloud-contract-samples/" target="_top">Spring Cloud
|
||||
Contract Samples</a></li><li class="listitem"><a class="link" href="https://gitter.im/spring-cloud/spring-cloud-contract" target="_top">Spring Cloud Contract Gitter</a></li><li class="listitem"><a class="link" href="https://www.youtube.com/watch?v=sAAklvxmPmk" target="_top">Spring Cloud Contract WJUG Presentation by
|
||||
Marcin Grzejszczak</a></li></ul></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__migrations.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_contract.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_vault.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">97. Migrations </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part XIV. Spring Cloud Vault</td></tr></table></div></body></html>
|
||||
35
Greenwich.RC2/multi/multi__main_concepts.html
Normal file
@@ -0,0 +1,35 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>28. Main Concepts</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="prev" href="multi_spring-cloud-stream-overview-introducing.html" title="27. Introducing Spring Cloud Stream"><link rel="next" href="multi__programming_model.html" title="29. Programming Model"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">28. Main Concepts</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_spring-cloud-stream-overview-introducing.html">Prev</a> </td><th width="60%" align="center">Part V. Spring Cloud Stream</th><td width="20%" align="right"> <a accesskey="n" href="multi__programming_model.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_main_concepts" href="#_main_concepts"></a>28. Main Concepts</h2></div></div></div><p>Spring Cloud Stream provides a number of abstractions and primitives that simplify the writing of message-driven microservice applications.
|
||||
This section gives an overview of the following:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="link" href="multi__main_concepts.html#spring-cloud-stream-overview-application-model" title="28.1 Application Model">Spring Cloud Stream’s application model</a></li><li class="listitem"><a class="xref" href="multi__main_concepts.html#spring-cloud-stream-overview-binder-abstraction" title="28.2 The Binder Abstraction">Section 28.2, “The Binder Abstraction”</a></li><li class="listitem"><a class="link" href="multi__main_concepts.html#spring-cloud-stream-overview-persistent-publish-subscribe-support" title="28.3 Persistent Publish-Subscribe Support">Persistent publish-subscribe support</a></li><li class="listitem"><a class="link" href="multi__main_concepts.html#consumer-groups" title="28.4 Consumer Groups">Consumer group support</a></li><li class="listitem"><a class="link" href="multi__main_concepts.html#partitioning" title="28.6 Partitioning Support">Partitioning support</a></li><li class="listitem"><a class="link" href="multi_spring-cloud-stream-overview-binders.html#spring-cloud-stream-overview-binder-api" title="30.2 Binder SPI">A pluggable Binder SPI</a></li></ul></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="spring-cloud-stream-overview-application-model" href="#spring-cloud-stream-overview-application-model"></a>28.1 Application Model</h2></div></div></div><p>A Spring Cloud Stream application consists of a middleware-neutral core.
|
||||
The application communicates with the outside world through input and output channels injected into it by Spring Cloud Stream.
|
||||
Channels are connected to external brokers through middleware-specific Binder implementations.</p><div class="figure"><a name="d0e7976" href="#d0e7976"></a><p class="title"><b>Figure 28.1. Spring Cloud Stream Application</b></p><div class="figure-contents"><div class="mediaobject" align="center"><img src="images/SCSt-with-binder.png" align="middle" alt="SCSt with binder"></div></div></div><br class="figure-break"><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_fat_jar" href="#_fat_jar"></a>28.1.1 Fat JAR</h3></div></div></div><p>Spring Cloud Stream applications can be run in stand-alone mode from your IDE for testing.
|
||||
To run a Spring Cloud Stream application in production, you can create an executable (or “fat”) JAR by using the standard Spring Boot tooling provided for Maven or Gradle. See the <a class="link" href="https://docs.spring.io/spring-boot/docs/current/reference/html/howto-build.html#howto-create-an-executable-jar-with-maven" target="_top">Spring Boot Reference Guide</a> for more details.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="spring-cloud-stream-overview-binder-abstraction" href="#spring-cloud-stream-overview-binder-abstraction"></a>28.2 The Binder Abstraction</h2></div></div></div><p>Spring Cloud Stream provides Binder implementations for <a class="link" href="https://github.com/spring-cloud/spring-cloud-stream-binder-kafka" target="_top">Kafka</a> and <a class="link" href="https://github.com/spring-cloud/spring-cloud-stream-binder-rabbit" target="_top">Rabbit MQ</a>.
|
||||
Spring Cloud Stream also includes a <a class="link" href="https://github.com/spring-cloud/spring-cloud-stream/blob/master/spring-cloud-stream-test-support/src/main/java/org/springframework/cloud/stream/test/binder/TestSupportBinder.java" target="_top">TestSupportBinder</a>, which leaves a channel unmodified so that tests can interact with channels directly and reliably assert on what is received.
|
||||
You can also use the extensible API to write your own Binder.</p><p>Spring Cloud Stream uses Spring Boot for configuration, and the Binder abstraction makes it possible for a Spring Cloud Stream application to be flexible in how it connects to middleware.
|
||||
For example, deployers can dynamically choose, at runtime, the destinations (such as the Kafka topics or RabbitMQ exchanges) to which channels connect.
|
||||
Such configuration can be provided through external configuration properties and in any form supported by Spring Boot (including application arguments, environment variables, and <code class="literal">application.yml</code> or <code class="literal">application.properties</code> files).
|
||||
In the sink example from the <a class="xref" href="multi_spring-cloud-stream-overview-introducing.html" title="27. Introducing Spring Cloud Stream">Chapter 27, <i>Introducing Spring Cloud Stream</i></a> section, setting the <code class="literal">spring.cloud.stream.bindings.input.destination</code> application property to <code class="literal">raw-sensor-data</code> causes it to read from the <code class="literal">raw-sensor-data</code> Kafka topic or from a queue bound to the <code class="literal">raw-sensor-data</code> RabbitMQ exchange.</p><p>Spring Cloud Stream automatically detects and uses a binder found on the classpath.
|
||||
You can use different types of middleware with the same code.
|
||||
To do so, include a different binder at build time.
|
||||
For more complex use cases, you can also package multiple binders with your application and have it choose the binder( and even whether to use different binders for different channels) at runtime.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="spring-cloud-stream-overview-persistent-publish-subscribe-support" href="#spring-cloud-stream-overview-persistent-publish-subscribe-support"></a>28.3 Persistent Publish-Subscribe Support</h2></div></div></div><p>Communication between applications follows a publish-subscribe model, where data is broadcast through shared topics.
|
||||
This can be seen in the following figure, which shows a typical deployment for a set of interacting Spring Cloud Stream applications.</p><div class="figure"><a name="d0e8036" href="#d0e8036"></a><p class="title"><b>Figure 28.2. Spring Cloud Stream Publish-Subscribe</b></p><div class="figure-contents"><div class="mediaobject" align="center"><img src="images/SCSt-sensors.png" align="middle" alt="SCSt sensors"></div></div></div><br class="figure-break"><p>Data reported by sensors to an HTTP endpoint is sent to a common destination named <code class="literal">raw-sensor-data</code>.
|
||||
From the destination, it is independently processed by a microservice application that computes time-windowed averages and by another microservice application that ingests the raw data into HDFS (Hadoop Distributed File System).
|
||||
In order to process the data, both applications declare the topic as their input at runtime.</p><p>The publish-subscribe communication model reduces the complexity of both the producer and the consumer and lets new applications be added to the topology without disruption of the existing flow.
|
||||
For example, downstream from the average-calculating application, you can add an application that calculates the highest temperature values for display and monitoring.
|
||||
You can then add another application that interprets the same flow of averages for fault detection.
|
||||
Doing all communication through shared topics rather than point-to-point queues reduces coupling between microservices.</p><p>While the concept of publish-subscribe messaging is not new, Spring Cloud Stream takes the extra step of making it an opinionated choice for its application model.
|
||||
By using native middleware support, Spring Cloud Stream also simplifies use of the publish-subscribe model across different platforms.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="consumer-groups" href="#consumer-groups"></a>28.4 Consumer Groups</h2></div></div></div><p>While the publish-subscribe model makes it easy to connect applications through shared topics, the ability to scale up by creating multiple instances of a given application is equally important.
|
||||
When doing so, different instances of an application are placed in a competing consumer relationship, where only one of the instances is expected to handle a given message.</p><p>Spring Cloud Stream models this behavior through the concept of a consumer group.
|
||||
(Spring Cloud Stream consumer groups are similar to and inspired by Kafka consumer groups.)
|
||||
Each consumer binding can use the <code class="literal">spring.cloud.stream.bindings.<channelName>.group</code> property to specify a group name.
|
||||
For the consumers shown in the following figure, this property would be set as <code class="literal">spring.cloud.stream.bindings.<channelName>.group=hdfsWrite</code> or <code class="literal">spring.cloud.stream.bindings.<channelName>.group=average</code>.</p><div class="figure"><a name="d0e8070" href="#d0e8070"></a><p class="title"><b>Figure 28.3. Spring Cloud Stream Consumer Groups</b></p><div class="figure-contents"><div class="mediaobject" align="center"><img src="images/SCSt-groups.png" align="middle" alt="SCSt groups"></div></div></div><br class="figure-break"><p>All groups that subscribe to a given destination receive a copy of published data, but only one member of each group receives a given message from that destination.
|
||||
By default, when a group is not specified, Spring Cloud Stream assigns the application to an anonymous and independent single-member consumer group that is in a publish-subscribe relationship with all other consumer groups.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="consumer-types" href="#consumer-types"></a>28.5 Consumer Types</h2></div></div></div><p>Two types of consumer are supported:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Message-driven (sometimes referred to as Asynchronous)</li><li class="listitem">Polled (sometimes referred to as Synchronous)</li></ul></div><p>Prior to version 2.0, only asynchronous consumers were supported. A message is delivered as soon as it is available and a thread is available to process it.</p><p>When you wish to control the rate at which messages are processed, you might want to use a synchronous consumer.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="durability" href="#durability"></a>28.5.1 Durability</h3></div></div></div><p>Consistent with the opinionated application model of Spring Cloud Stream, consumer group subscriptions are durable.
|
||||
That is, a binder implementation ensures that group subscriptions are persistent and that, once at least one subscription for a group has been created, the group receives messages, even if they are sent while all applications in the group are stopped.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Anonymous subscriptions are non-durable by nature.
|
||||
For some binder implementations (such as RabbitMQ), it is possible to have non-durable group subscriptions.</p></td></tr></table></div><p>In general, it is preferable to always specify a consumer group when binding an application to a given destination.
|
||||
When scaling up a Spring Cloud Stream application, you must specify a consumer group for each of its input bindings.
|
||||
Doing so prevents the application’s instances from receiving duplicate messages (unless that behavior is desired, which is unusual).</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="partitioning" href="#partitioning"></a>28.6 Partitioning Support</h2></div></div></div><p>Spring Cloud Stream provides support for partitioning data between multiple instances of a given application.
|
||||
In a partitioned scenario, the physical communication medium (such as the broker topic) is viewed as being structured into multiple partitions.
|
||||
One or more producer application instances send data to multiple consumer application instances and ensure that data identified by common characteristics are processed by the same consumer instance.</p><p>Spring Cloud Stream provides a common abstraction for implementing partitioned processing use cases in a uniform fashion.
|
||||
Partitioning can thus be used whether the broker itself is naturally partitioned (for example, Kafka) or not (for example, RabbitMQ).</p><div class="figure"><a name="d0e8114" href="#d0e8114"></a><p class="title"><b>Figure 28.4. Spring Cloud Stream Partitioning</b></p><div class="figure-contents"><div class="mediaobject" align="center"><img src="images/SCSt-partitioning.png" align="middle" alt="SCSt partitioning"></div></div></div><br class="figure-break"><p>Partitioning is a critical concept in stateful processing, where it is critical (for either performance or consistency reasons) to ensure that all related data is processed together.
|
||||
For example, in the time-windowed average calculation example, it is important that all measurements from any given sensor are processed by the same application instance.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>To set up a partitioned processing scenario, you must configure both the data-producing and the data-consuming ends.</p></td></tr></table></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_spring-cloud-stream-overview-introducing.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_stream.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__programming_model.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">27. Introducing Spring Cloud Stream </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 29. Programming Model</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,45 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>60. Managing Spans with Annotations</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__naming_spans.html" title="59. Naming spans"><link rel="next" href="multi__customizations.html" title="61. Customizations"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">60. Managing Spans with Annotations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__naming_spans.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__customizations.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_managing_spans_with_annotations" href="#_managing_spans_with_annotations"></a>60. Managing Spans with Annotations</h2></div></div></div><p>You can manage spans with a variety of annotations.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_rationale" href="#_rationale"></a>60.1 Rationale</h2></div></div></div><p>There are a number of good reasons to manage spans with annotations, including:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">API-agnostic means to collaborate with a span. Use of annotations lets users add to a span with no library dependency on a span api.
|
||||
Doing so lets Sleuth change its core API to create less impact to user code.</li><li class="listitem">Reduced surface area for basic span operations. Without this feature, you must use the span api, which has lifecycle commands that could be used incorrectly.
|
||||
By only exposing scope, tag, and log functionality, you can collaborate without accidentally breaking span lifecycle.</li><li class="listitem">Collaboration with runtime generated code. With libraries such as Spring Data and Feign, the implementations of interfaces are generated at runtime.
|
||||
Consequently, span wrapping of objects was tedious.
|
||||
Now you can provide annotations over interfaces and the arguments of those interfaces.</li></ul></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_creating_new_spans" href="#_creating_new_spans"></a>60.2 Creating New Spans</h2></div></div></div><p>If you do not want to create local spans manually, you can use the <code class="literal">@NewSpan</code> annotation.
|
||||
Also, we provide the <code class="literal">@SpanTag</code> annotation to add tags in an automated fashion.</p><p>Now we can consider some examples of usage.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@NewSpan</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> testMethod();</pre><p>Annotating the method without any parameter leads to creating a new span whose name equals the annotated method name.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@NewSpan("customNameOnTestMethod4")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> testMethod4();</pre><p>If you provide the value in the annotation (either directly or by setting the <code class="literal">name</code> parameter), the created span has the provided value as the name.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// method declaration</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@NewSpan(name = "customNameOnTestMethod5")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> testMethod5(<em><span class="hl-annotation" style="color: gray">@SpanTag("testTag")</span></em> String param);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// and method execution</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.testBean.testMethod5(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"test"</span>);</pre><p>You can combine both the name and a tag. Let’s focus on the latter.
|
||||
In this case, the value of the annotated method’s parameter runtime value becomes the value of the tag.
|
||||
In our sample, the tag key is <code class="literal">testTag</code>, and the tag value is <code class="literal">test</code>.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@NewSpan(name = "customNameOnTestMethod3")</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> testMethod3() {
|
||||
}</pre><p>You can place the <code class="literal">@NewSpan</code> annotation on both the class and an interface.
|
||||
If you override the interface’s method and provide a different value for the <code class="literal">@NewSpan</code> annotation, the most
|
||||
concrete one wins (in this case <code class="literal">customNameOnTestMethod3</code> is set).</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_continuing_spans" href="#_continuing_spans"></a>60.3 Continuing Spans</h2></div></div></div><p>If you want to add tags and annotations to an existing span, you can use the <code class="literal">@ContinueSpan</code> annotation, as shown in the following example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// method declaration</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@ContinueSpan(log = "testMethod11")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> testMethod11(<em><span class="hl-annotation" style="color: gray">@SpanTag("testTag11")</span></em> String param);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// method execution</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.testBean.testMethod11(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"test"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.testBean.testMethod13();</pre><p>(Note that, in contrast with the <code class="literal">@NewSpan</code> annotation ,you can also add logs with the <code class="literal">log</code> parameter.)</p><p>That way, the span gets continued and:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Log entries named <code class="literal">testMethod11.before</code> and <code class="literal">testMethod11.after</code> are created.</li><li class="listitem">If an exception is thrown, a log entry named <code class="literal">testMethod11.afterFailure</code> is also created.</li><li class="listitem">A tag with a key of <code class="literal">testTag11</code> and a value of <code class="literal">test</code> is created.</li></ul></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_advanced_tag_setting" href="#_advanced_tag_setting"></a>60.4 Advanced Tag Setting</h2></div></div></div><p>There are 3 different ways to add tags to a span. All of them are controlled by the <code class="literal">SpanTag</code> annotation.
|
||||
The precedence is as follows:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">Try with a bean of <code class="literal">TagValueResolver</code> type and a provided name.</li><li class="listitem">If the bean name has not been provided, try to evaluate an expression.
|
||||
We search for a <code class="literal">TagValueExpressionResolver</code> bean.
|
||||
The default implementation uses SPEL expression resolution.
|
||||
<span class="strong"><strong>IMPORTANT</strong></span> You can only reference properties from the SPEL expression. Method execution is not allowed due to security constraints.</li><li class="listitem">If we do not find any expression to evaluate, return the <code class="literal">toString()</code> value of the parameter.</li></ol></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_custom_extractor" href="#_custom_extractor"></a>60.4.1 Custom extractor</h3></div></div></div><p>The value of the tag for the following method is computed by an implementation of <code class="literal">TagValueResolver</code> interface.
|
||||
Its class name has to be passed as the value of the <code class="literal">resolver</code> attribute.</p><p>Consider the following annotated method:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@NewSpan</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> getAnnotationForTagValueResolver(
|
||||
<em><span class="hl-annotation" style="color: gray">@SpanTag(key = "test", resolver = TagValueResolver.class)</span></em> String test) {
|
||||
}</pre><p>Now further consider the following <code class="literal">TagValueResolver</code> bean implementation:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean(name = "myCustomTagValueResolver")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> TagValueResolver tagValueResolver() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> parameter -> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Value from myCustomTagValueResolver"</span>;
|
||||
}</pre><p>The two preceding examples lead to setting a tag value equal to <code class="literal">Value from myCustomTagValueResolver</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_resolving_expressions_for_a_value" href="#_resolving_expressions_for_a_value"></a>60.4.2 Resolving Expressions for a Value</h3></div></div></div><p>Consider the following annotated method:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@NewSpan</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> getAnnotationForTagValueExpression(
|
||||
<em><span class="hl-annotation" style="color: gray">@SpanTag(key = "test", expression = "'hello' + ' characters'")</span></em> String test) {
|
||||
}</pre><p>No custom implementation of a <code class="literal">TagValueExpressionResolver</code> leads to evaluation of the SPEL expression, and a tag with a value of <code class="literal">4 characters</code> is set on the span.
|
||||
If you want to use some other expression resolution mechanism, you can create your own implementation of the bean.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_using_the_literal_tostring_literal_method" href="#_using_the_literal_tostring_literal_method"></a>60.4.3 Using the <code class="literal">toString()</code> method</h3></div></div></div><p>Consider the following annotated method:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@NewSpan</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> getAnnotationForArgumentToString(<em><span class="hl-annotation" style="color: gray">@SpanTag("test")</span></em> Long param) {
|
||||
}</pre><p>Running the preceding method with a value of <code class="literal">15</code> leads to setting a tag with a String value of <code class="literal">"15"</code>.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__naming_spans.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__customizations.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">59. Naming spans </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 61. Customizations</td></tr></table></div></body></html>
|
||||
96
Greenwich.RC2/multi/multi__migrations.html
Normal file
@@ -0,0 +1,96 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>97. Migrations</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_contract.html" title="Part XIII. Spring Cloud Contract"><link rel="prev" href="multi__spring_cloud_contract_wiremock.html" title="96. Spring Cloud Contract WireMock"><link rel="next" href="multi__links.html" title="98. Links"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">97. Migrations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_contract_wiremock.html">Prev</a> </td><th width="60%" align="center">Part XIII. Spring Cloud Contract</th><td width="20%" align="right"> <a accesskey="n" href="multi__links.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_migrations" href="#_migrations"></a>97. Migrations</h2></div></div></div><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>For up to date migration guides please visit
|
||||
the project’s <a class="link" href="https://github.com/spring-cloud/spring-cloud-contract/wiki/" target="_top">wiki page</a>.</p></td></tr></table></div><p>This section covers migrating from one version of Spring Cloud Contract Verifier to the
|
||||
next version. It covers the following versions upgrade paths:</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="cloud-verifier-1.0-1.1" href="#cloud-verifier-1.0-1.1"></a>97.1 1.0.x → 1.1.x</h2></div></div></div><p>This section covers upgrading from version 1.0 to version 1.1.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_new_structure_of_generated_stubs" href="#_new_structure_of_generated_stubs"></a>97.1.1 New structure of generated stubs</h3></div></div></div><p>In <code class="literal">1.1.x</code> we have introduced a change to the structure of generated stubs. If you have
|
||||
been using the <code class="literal">@AutoConfigureWireMock</code> notation to use the stubs from the classpath,
|
||||
it no longer works. The following example shows how the <code class="literal">@AutoConfigureWireMock</code> notation
|
||||
used to work:</p><pre class="programlisting">@AutoConfigureWireMock(stubs = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"classpath:/customer-stubs/mappings"</span>, port = <span class="hl-number">8084</span>)</pre><p>You must either change the location of the stubs to:
|
||||
<code class="literal">classpath:…​/META-INF/groupId/artifactId/version/mappings</code> or use the new
|
||||
classpath-based <code class="literal">@AutoConfigureStubRunner</code>, as shown in the following example:</p><pre class="programlisting">@AutoConfigureWireMock(stubs = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"classpath:customer-stubs/META-INF/travel.components/customer-contract/1.0.2-SNAPSHOT/mappings/"</span>, port = <span class="hl-number">8084</span>)</pre><p>If you do not want to use <code class="literal">@AutoConfigureStubRunner</code> and you want to remain with the old
|
||||
structure, set your plugin tasks accordingly. The following example would work for the
|
||||
structure presented in the previous snippet.</p><p class="primary"><b>Maven. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- start of pom.xml --></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><properties></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- we don't want the verifier to do a jar for us --></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><spring.cloud.contract.verifier.skip></span>true<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></spring.cloud.contract.verifier.skip></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></properties></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- ... --></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- You need to set up the assembly plugin --></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><build></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><plugins></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><plugin></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.apache.maven.plugins<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>maven-assembly-plugin<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><executions></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><execution></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><id></span>stub<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></id></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><phase></span>prepare-package<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></phase></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><goals></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><goal></span>single<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></goal></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></goals></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><inherited></span>false<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></inherited></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><configuration></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><attach></span>true<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></attach></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><descriptor></span>$../../../../src/assembly/stub.xml<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></descriptor></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></configuration></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></execution></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></executions></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></plugin></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></plugins></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></build></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- end of pom.xml --></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- start of stub.xml--></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><assembly</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">xmlns</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">xmlns:xsi</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">xsi:schemaLocation</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><id></span>stubs<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></id></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><formats></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><format></span>jar<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></format></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></formats></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><includeBaseDirectory></span>false<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></includeBaseDirectory></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><fileSets></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><fileSet></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><directory></span>${project.build.directory}/snippets/stubs<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></directory></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><outputDirectory></span>customer-stubs/mappings<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></outputDirectory></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><includes></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><include></span>**/*<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></include></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></includes></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></fileSet></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><fileSet></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><directory></span>$../../../../src/test/resources/contracts<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></directory></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><outputDirectory></span>customer-stubs/contracts<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></outputDirectory></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><includes></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><include></span>**/*.groovy<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></include></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></includes></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></fileSet></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></fileSets></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></assembly></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- end of stub.xml--></span></pre><p class="primary">
|
||||
</p><p class="secondary"><b>Gradle. </b>
|
||||
</p><pre class="programlisting">task copyStubs(type: Copy, dependsOn: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'generateWireMockClientStubs'</span>) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Preserve directory structure from 1.0.X of spring-cloud-contract</span>
|
||||
from <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"${project.buildDir}/resources/main/customer-stubs/META-INF/${project.group}/${project.name}/${project.version}"</span>
|
||||
into <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"${project.buildDir}/resources/main/customer-stubs"</span>
|
||||
}</pre><p class="secondary">
|
||||
</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="cloud-verifier-1.1-1.2" href="#cloud-verifier-1.1-1.2"></a>97.2 1.1.x → 1.2.x</h2></div></div></div><p>This section covers upgrading from version 1.1 to version 1.2.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_custom_literal_httpserverstub_literal" href="#_custom_literal_httpserverstub_literal"></a>97.2.1 Custom <code class="literal">HttpServerStub</code></h3></div></div></div><p><code class="literal">HttpServerStub</code> includes a method that was not in version 1.1. The method is
|
||||
<code class="literal">String registeredMappings()</code> If you have classes that implement <code class="literal">HttpServerStub</code>, you
|
||||
now have to implement the <code class="literal">registeredMappings()</code> method. It should return a <code class="literal">String</code>
|
||||
representing all mappings available in a single <code class="literal">HttpServerStub</code>.</p><p>See <a class="link" href="https://github.com/spring-cloud/spring-cloud-contract/issues/355" target="_top">issue 355</a> for more
|
||||
detail.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_new_packages_for_generated_tests" href="#_new_packages_for_generated_tests"></a>97.2.2 New packages for generated tests</h3></div></div></div><p>The flow for setting the generated tests package name will look like this:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Set <code class="literal">basePackageForTests</code></li><li class="listitem">If <code class="literal">basePackageForTests</code> was not set, pick the package from <code class="literal">baseClassForTests</code></li><li class="listitem">If <code class="literal">baseClassForTests</code> was not set, pick <code class="literal">packageWithBaseClasses</code></li><li class="listitem">If nothing got set, pick the default value:
|
||||
<code class="literal">org.springframework.cloud.contract.verifier.tests</code></li></ul></div><p>See <a class="link" href="https://github.com/spring-cloud/spring-cloud-contract/issues/260" target="_top">issue 260</a> for more
|
||||
detail.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_new_methods_in_templateprocessor" href="#_new_methods_in_templateprocessor"></a>97.2.3 New Methods in TemplateProcessor</h3></div></div></div><p>In order to add support for <code class="literal">fromRequest.path</code>, the following methods had to be added to the
|
||||
<code class="literal">TemplateProcessor</code> interface:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">path()</code></li><li class="listitem"><code class="literal">path(int index)</code></li></ul></div><p>See <a class="link" href="https://github.com/spring-cloud/spring-cloud-contract/issues/388" target="_top">issue 388</a> for more
|
||||
detail.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_restassured_3_0" href="#_restassured_3_0"></a>97.2.4 RestAssured 3.0</h3></div></div></div><p>Rest Assured, used in the generated test classes, got bumped to <code class="literal">3.0</code>. If
|
||||
you manually set versions of Spring Cloud Contract and the release train
|
||||
you might see the following exception:</p><pre class="programlisting">Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:<span class="hl-number">3.1</span>:testCompile (default-testCompile) on project some-project: Compilation failure: Compilation failure:
|
||||
[ERROR] /some/path/SomeClass.java:[<span class="hl-number">4</span>,<span class="hl-number">39</span>] package com.jayway.restassured.response does not exist</pre><p>This exception will occur due to the fact that the tests got generated with
|
||||
an old version of plugin and at test execution time you have an incompatible
|
||||
version of the release train (and vice versa).</p><p>Done via <a class="link" href="https://github.com/spring-cloud/spring-cloud-contract/issues/267" target="_top">issue 267</a></p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="cloud-verifier-1.2-2.0" href="#cloud-verifier-1.2-2.0"></a>97.3 1.2.x → 2.0.x</h2></div></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_contract_wiremock.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_contract.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__links.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">96. Spring Cloud Contract WireMock </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 98. Links</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,5 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>22. Modules In Maintenance Mode</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_netflix.html" title="Part III. Spring Cloud Netflix"><link rel="prev" href="multi__http_clients.html" title="21. HTTP Clients"><link rel="next" href="multi__spring_cloud_openfeign.html" title="Part IV. Spring Cloud OpenFeign"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">22. Modules In Maintenance Mode</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__http_clients.html">Prev</a> </td><th width="60%" align="center">Part III. Spring Cloud Netflix</th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_openfeign.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_modules_in_maintenance_mode" href="#_modules_in_maintenance_mode"></a>22. Modules In Maintenance Mode</h2></div></div></div><p>Placing a module in maintenance mode means that the Spring Cloud team will no longer be adding new features to the module.
|
||||
We will fix blocker bugs and security issues, and we will also consider and review small pull requests from the community.</p><p>We intend to continue to support these modules for a period of at least a year from the general availability
|
||||
of the Greenwich release train.</p><p>The following Spring Cloud Netflix modules and corresponding starters will be placed into maintenance mode:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">spring-cloud-netflix-archaius</li><li class="listitem">spring-cloud-netflix-hystrix-contract</li><li class="listitem">spring-cloud-netflix-hystrix-dashboard</li><li class="listitem">spring-cloud-netflix-hystrix-stream</li><li class="listitem">spring-cloud-netflix-hystrix</li><li class="listitem">spring-cloud-netflix-ribbon</li><li class="listitem">spring-cloud-netflix-turbine-stream</li><li class="listitem">spring-cloud-netflix-turbine</li><li class="listitem">spring-cloud-netflix-zuul</li></ul></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>This does not include the Eureka or concurrency-limits modules.</p></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__http_clients.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_netflix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_openfeign.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">21. HTTP Clients </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part IV. Spring Cloud OpenFeign</td></tr></table></div></body></html>
|
||||
117
Greenwich.RC2/multi/multi__more_detail.html
Normal file
@@ -0,0 +1,117 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>82. More Detail</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_security.html" title="Part XI. Spring Cloud Security"><link rel="prev" href="multi__quickstart.html" title="81. Quickstart"><link rel="next" href="multi__configuring_authentication_downstream_of_a_zuul_proxy.html" title="83. Configuring Authentication Downstream of a Zuul Proxy"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">82. More Detail</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__quickstart.html">Prev</a> </td><th width="60%" align="center">Part XI. Spring Cloud Security</th><td width="20%" align="right"> <a accesskey="n" href="multi__configuring_authentication_downstream_of_a_zuul_proxy.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_more_detail" href="#_more_detail"></a>82. More Detail</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_single_sign_on" href="#_single_sign_on"></a>82.1 Single Sign On</h2></div></div></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>All of the OAuth2 SSO and resource server features moved to Spring Boot
|
||||
in version 1.3. You can find documentation in the
|
||||
<a class="link" href="http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/" target="_top">Spring Boot user guide</a>.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_token_relay" href="#_token_relay"></a>82.2 Token Relay</h2></div></div></div><p>A Token Relay is where an OAuth2 consumer acts as a Client and
|
||||
forwards the incoming token to outgoing resource requests. The
|
||||
consumer can be a pure Client (like an SSO application) or a Resource
|
||||
Server.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_client_token_relay_in_spring_cloud_gateway" href="#_client_token_relay_in_spring_cloud_gateway"></a>82.2.1 Client Token Relay in Spring Cloud Gateway</h3></div></div></div><p>If your app also has a
|
||||
<a class="link" href="https://cloud.spring.io/spring-cloud-static/current/single/spring-cloud.html#_spring_cloud_gateway" target="_top">Spring
|
||||
Cloud Gateway</a> embedded reverse proxy then you
|
||||
can ask it to forward OAuth2 access tokens downstream to the services
|
||||
it is proxying. Thus the SSO app above can be enhanced simply like
|
||||
this:</p><p><b>App.java. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> TokenRelayGatewayFilterFactory filterFactory;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> builder.routes()
|
||||
.route(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"resource"</span>, r -> r.path(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/resource"</span>)
|
||||
.filters(f -> f.filter(filterFactory.apply()))
|
||||
.uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://localhost:9000"</span>))
|
||||
.build();
|
||||
}</pre><p>
|
||||
</p><p>or this</p><p><b>application.yaml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> gateway</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> routes</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - id</span>: resource
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: http://localhost:<span class="hl-number">9000</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> predicates</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - Path</span>=/resource
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> filters</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - TokenRelay</span>=</pre><p>
|
||||
</p><p>and it will (in addition to logging the user in and grabbing a token)
|
||||
pass the authentication token downstream to the services (in this case
|
||||
<code class="literal">/resource</code>).</p><p>To enable this for Spring Cloud Gateway add the following dependencies</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">org.springframework.boot:spring-boot-starter-oauth2-client</code></li><li class="listitem"><code class="literal">org.springframework.cloud:spring-cloud-starter-security</code></li></ul></div><p>How does it work? The
|
||||
<a class="link" href="https://github.com/spring-cloud/spring-cloud-security/tree/master/src/main/java/org/springframework/cloud/security/oauth2/gateway/TokenRelayGatewayFilterFactory.java" target="_top">filter</a>
|
||||
extracts an access token from the currently authenticated user,
|
||||
and puts it in a request header for the downstream requests.</p><p>For a full working sample see <a class="link" href="https://github.com/spring-cloud-samples/sample-gateway-oauth2login" target="_top">this project</a>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_client_token_relay" href="#_client_token_relay"></a>82.2.2 Client Token Relay</h3></div></div></div><p>If your app is a user facing OAuth2 client (i.e. has declared
|
||||
<code class="literal">@EnableOAuth2Sso</code> or <code class="literal">@EnableOAuth2Client</code>) then it has an
|
||||
<code class="literal">OAuth2ClientContext</code> in request scope from Spring Boot. You can
|
||||
create your own <code class="literal">OAuth2RestTemplate</code> from this context and an
|
||||
autowired <code class="literal">OAuth2ProtectedResourceDetails</code>, and then the context will
|
||||
always forward the access token downstream, also refreshing the access
|
||||
token automatically if it expires. (These are features of Spring
|
||||
Security and Spring Boot.)</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Spring Boot (1.4.1) does not create an
|
||||
<code class="literal">OAuth2ProtectedResourceDetails</code> automatically if you are using
|
||||
<code class="literal">client_credentials</code> tokens. In that case you need to create your own
|
||||
<code class="literal">ClientCredentialsResourceDetails</code> and configure it with
|
||||
<code class="literal">@ConfigurationProperties("security.oauth2.client")</code>.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_client_token_relay_in_zuul_proxy" href="#_client_token_relay_in_zuul_proxy"></a>82.2.3 Client Token Relay in Zuul Proxy</h3></div></div></div><p>If your app also has a
|
||||
<a class="link" href="http://cloud.spring.io/spring-cloud.html#netflix-zuul-reverse-proxy" target="_top">Spring
|
||||
Cloud Zuul</a> embedded reverse proxy (using <code class="literal">@EnableZuulProxy</code>) then you
|
||||
can ask it to forward OAuth2 access tokens downstream to the services
|
||||
it is proxying. Thus the SSO app above can be enhanced simply like
|
||||
this:</p><p><b>app.groovy. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Controller</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableOAuth2Sso</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableZuulProxy</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
||||
|
||||
}</pre><p>
|
||||
</p><p>and it will (in addition to logging the user in and grabbing a token)
|
||||
pass the authentication token downstream to the <code class="literal">/proxy/*</code>
|
||||
services. If those services are implemented with
|
||||
<code class="literal">@EnableResourceServer</code> then they will get a valid token in the
|
||||
correct header.</p><p>How does it work? The <code class="literal">@EnableOAuth2Sso</code> annotation pulls in
|
||||
<code class="literal">spring-cloud-starter-security</code> (which you could do manually in a
|
||||
traditional app), and that in turn triggers some autoconfiguration for
|
||||
a <code class="literal">ZuulFilter</code>, which itself is activated because Zuul is on the
|
||||
classpath (via <code class="literal">@EnableZuulProxy</code>). The
|
||||
<a class="link" href="https://github.com/spring-cloud/spring-cloud-security/tree/master/src/main/java/org/springframework/cloud/security/oauth2/proxy/OAuth2TokenRelayFilter.java" target="_top">filter</a>
|
||||
just extracts an access token from the currently authenticated user,
|
||||
and puts it in a request header for the downstream requests.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_resource_server_token_relay" href="#_resource_server_token_relay"></a>82.2.4 Resource Server Token Relay</h3></div></div></div><p>If your app has <code class="literal">@EnableResourceServer</code> you might want to relay the
|
||||
incoming token downstream to other services. If you use a
|
||||
<code class="literal">RestTemplate</code> to contact the downstream services then this is just a
|
||||
matter of how to create the template with the right context.</p><p>If your service uses <code class="literal">UserInfoTokenServices</code> to authenticate incoming
|
||||
tokens (i.e. it is using the <code class="literal">security.oauth2.user-info-uri</code>
|
||||
configuration), then you can simply create an <code class="literal">OAuth2RestTemplate</code>
|
||||
using an autowired <code class="literal">OAuth2ClientContext</code> (it will be populated by the
|
||||
authentication process before it hits the backend code). Equivalently
|
||||
(with Spring Boot 1.4), you could inject a
|
||||
<code class="literal">UserInfoRestTemplateFactory</code> and grab its <code class="literal">OAuth2RestTemplate</code> in
|
||||
your configuration. For example:</p><p><b>MyConfiguration.java. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> OAuth2RestTemplate restTemplate(UserInfoRestTemplateFactory factory) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> factory.getUserInfoRestTemplate();
|
||||
}</pre><p>
|
||||
</p><p>This rest template will then have the same <code class="literal">OAuth2ClientContext</code>
|
||||
(request-scoped) that is used by the authentication filter, so you can
|
||||
use it to send requests with the same access token.</p><p>If your app is not using <code class="literal">UserInfoTokenServices</code> but is still a client
|
||||
(i.e. it declares <code class="literal">@EnableOAuth2Client</code> or <code class="literal">@EnableOAuth2Sso</code>), then
|
||||
with Spring Security Cloud any <code class="literal">OAuth2RestOperations</code> that the user
|
||||
creates from an <code class="literal">@Autowired</code> <code class="literal">@OAuth2Context</code> will also forward
|
||||
tokens. This feature is implemented by default as an MVC handler
|
||||
interceptor, so it only works in Spring MVC. If you are not using MVC
|
||||
you could use a custom filter or AOP interceptor wrapping an
|
||||
<code class="literal">AccessTokenContextRelay</code> to provide the same feature.</p><p>Here’s a basic
|
||||
example showing the use of an autowired rest template created
|
||||
elsewhere ("foo.com" is a Resource Server accepting the same tokens as
|
||||
the surrounding app):</p><p><b>MyController.java. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> OAuth2RestOperations restTemplate;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestMapping("/relay")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String relay() {
|
||||
ResponseEntity<String> response =
|
||||
restTemplate.getForEntity(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"https://foo.com/bar"</span>, String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Success! ("</span> + response.getBody() + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">")"</span>;
|
||||
}</pre><p>
|
||||
</p><p>If you don’t want to forward tokens (and that is a valid
|
||||
choice, since you might want to act as yourself, rather than the
|
||||
client that sent you the token), then you only need to create your own
|
||||
<code class="literal">OAuth2Context</code> instead of autowiring the default one.</p><p>Feign clients will also pick up an interceptor that uses the
|
||||
<code class="literal">OAuth2ClientContext</code> if it is available, so they should also do a
|
||||
token relay anywhere where a <code class="literal">RestTemplate</code> would.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__quickstart.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_security.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__configuring_authentication_downstream_of_a_zuul_proxy.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">81. Quickstart </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 83. Configuring Authentication Downstream of a Zuul Proxy</td></tr></table></div></body></html>
|
||||
32
Greenwich.RC2/multi/multi__naming_spans.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>59. Naming spans</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__span_lifecycle.html" title="58. Span lifecycle"><link rel="next" href="multi__managing_spans_with_annotations.html" title="60. Managing Spans with Annotations"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">59. Naming spans</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__span_lifecycle.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__managing_spans_with_annotations.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_naming_spans" href="#_naming_spans"></a>59. Naming spans</h2></div></div></div><p>Picking a span name is not a trivial task. A span name should depict an operation name.
|
||||
The name should be low cardinality, so it should not include identifiers.</p><p>Since there is a lot of instrumentation going on, some span names are artificial:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">controller-method-name</code> when received by a Controller with a method name of <code class="literal">controllerMethodName</code></li><li class="listitem"><code class="literal">async</code> for asynchronous operations done with wrapped <code class="literal">Callable</code> and <code class="literal">Runnable</code> interfaces.</li><li class="listitem">Methods annotated with <code class="literal">@Scheduled</code> return the simple name of the class.</li></ul></div><p>Fortunately, for asynchronous processing, you can provide explicit naming.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="__literal_spanname_literal_annotation" href="#__literal_spanname_literal_annotation"></a>59.1 <code class="literal">@SpanName</code> Annotation</h2></div></div></div><p>You can name the span explicitly by using the <code class="literal">@SpanName</code> annotation, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpanName("calculateTax")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> TaxCountingRunnable <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">implements</span> Runnable {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> run() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// perform logic</span>
|
||||
}
|
||||
|
||||
}</pre><p>In this case, when processed in the following manner, the span is named <code class="literal">calculateTax</code>:</p><pre class="programlisting">Runnable runnable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TraceRunnable(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracing, spanNamer,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TaxCountingRunnable());
|
||||
Future<?> future = executorService.submit(runnable);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// ... some additional logic ...</span>
|
||||
future.get();</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="__literal_tostring_literal_method" href="#__literal_tostring_literal_method"></a>59.2 <code class="literal">toString()</code> method</h2></div></div></div><p>It is pretty rare to create separate classes for <code class="literal">Runnable</code> or <code class="literal">Callable</code>.
|
||||
Typically, one creates an anonymous instance of those classes.
|
||||
You cannot annotate such classes.
|
||||
To overcome that limitation, if there is no <code class="literal">@SpanName</code> annotation present, we check whether the class has a custom implementation of the <code class="literal">toString()</code> method.</p><p>Running such code leads to creating a span named <code class="literal">calculateTax</code>, as shown in the following example:</p><pre class="programlisting">Runnable runnable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TraceRunnable(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracing, spanNamer, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Runnable() {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> run() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// perform logic</span>
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String toString() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"calculateTax"</span>;
|
||||
}
|
||||
});
|
||||
Future<?> future = executorService.submit(runnable);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// ... some additional logic ...</span>
|
||||
future.get();</pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__span_lifecycle.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__managing_spans_with_annotations.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">58. Span lifecycle </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 60. Managing Spans with Annotations</td></tr></table></div></body></html>
|
||||
3
Greenwich.RC2/multi/multi__other_resources.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>144. Other Resources</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_kubernetes.html" title="Part XVII. Spring Cloud Kubernetes"><link rel="prev" href="multi__examples_2.html" title="143. Examples"><link rel="next" href="multi__building.html" title="145. Building"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">144. Other Resources</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__examples_2.html">Prev</a> </td><th width="60%" align="center">Part XVII. Spring Cloud Kubernetes</th><td width="20%" align="right"> <a accesskey="n" href="multi__building.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_other_resources" href="#_other_resources"></a>144. Other Resources</h2></div></div></div><p>Here you can find other resources such as presentations(slides) and videos about Spring Cloud Kubernetes.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="link" href="https://salaboy.com/2018/09/27/the-s1p-experience/" target="_top">S1P Spring Cloud on PKS</a></li><li class="listitem"><a class="link" href="https://salaboy.com/2018/07/18/ljc-july-18-spring-cloud-docker-k8s/" target="_top">Spring Cloud, Docker, Kubernetes → London Java Community July 2018</a></li></ul></div><p>Please feel free to submit other resources via PR to <a class="link" href="http://github.com/spring-cloud/spring-cloud-kubernetes" target="_top">this repository</a>.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__examples_2.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_kubernetes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__building.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">143. Examples </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 145. Building</td></tr></table></div></body></html>
|
||||
4
Greenwich.RC2/multi/multi__pod_health_indicator.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>140. Pod Health Indicator</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_kubernetes.html" title="Part XVII. Spring Cloud Kubernetes"><link rel="prev" href="multi__kubernetes_ecosystem_awareness.html" title="139. Kubernetes Ecosystem Awareness"><link rel="next" href="multi__leader_election.html" title="141. Leader Election"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">140. Pod Health Indicator</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__kubernetes_ecosystem_awareness.html">Prev</a> </td><th width="60%" align="center">Part XVII. Spring Cloud Kubernetes</th><td width="20%" align="right"> <a accesskey="n" href="multi__leader_election.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_pod_health_indicator" href="#_pod_health_indicator"></a>140. Pod Health Indicator</h2></div></div></div><p>Spring Boot uses <a class="link" href="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" target="_top">HealthIndicator</a> to expose info about the health of an application.
|
||||
That makes it really useful for exposing health related information to the user and are also a good fit for use as <a class="link" href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/" target="_top">readiness probes</a>.</p><p>The Kubernetes health indicator which is part of the core module exposes the following info:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">pod name, ip address, namespace, service account, node name and its ip address</li><li class="listitem">flag that indicates if the Spring Boot application is internal or external to Kubernetes</li></ul></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__kubernetes_ecosystem_awareness.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_kubernetes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__leader_election.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">139. Kubernetes Ecosystem Awareness </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 141. Leader Election</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,58 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>19. Polyglot support with Sidecar</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_netflix.html" title="Part III. Spring Cloud Netflix"><link rel="prev" href="multi__router_and_filter_zuul.html" title="18. Router and Filter: Zuul"><link rel="next" href="multi_retrying-failed-requests.html" title="20. Retrying Failed Requests"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">19. Polyglot support with Sidecar</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__router_and_filter_zuul.html">Prev</a> </td><th width="60%" align="center">Part III. Spring Cloud Netflix</th><td width="20%" align="right"> <a accesskey="n" href="multi_retrying-failed-requests.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_polyglot_support_with_sidecar" href="#_polyglot_support_with_sidecar"></a>19. Polyglot support with Sidecar</h2></div></div></div><p>Do you have non-JVM languages with which you want to take advantage of Eureka, Ribbon, and Config Server?
|
||||
The Spring Cloud Netflix Sidecar was inspired by <a class="link" href="https://github.com/Netflix/Prana" target="_top">Netflix Prana</a>.
|
||||
It includes an HTTP API to get all of the instances (by host and port) for a given service.
|
||||
You can also proxy service calls through an embedded Zuul proxy that gets its route entries from Eureka.
|
||||
The Spring Cloud Config Server can be accessed directly through host lookup or through the Zuul Proxy.
|
||||
The non-JVM application should implement a health check so the Sidecar can report to Eureka whether the app is up or down.</p><p>To include Sidecar in your project, use the dependency with a group ID of <code class="literal">org.springframework.cloud</code>
|
||||
and artifact ID or <code class="literal">spring-cloud-netflix-sidecar</code>.</p><p>To enable the Sidecar, create a Spring Boot application with <code class="literal">@EnableSidecar</code>.
|
||||
This annotation includes <code class="literal">@EnableCircuitBreaker</code>, <code class="literal">@EnableDiscoveryClient</code>, and <code class="literal">@EnableZuulProxy</code>.
|
||||
Run the resulting application on the same host as the non-JVM application.</p><p>To configure the side car, add <code class="literal">sidecar.port</code> and <code class="literal">sidecar.health-uri</code> to <code class="literal">application.yml</code>.
|
||||
The <code class="literal">sidecar.port</code> property is the port on which the non-JVM application listens.
|
||||
This is so the Sidecar can properly register the application with Eureka.
|
||||
The <code class="literal">sidecar.health-uri</code> is a URI accessible on the non-JVM application that mimics a Spring Boot health indicator.
|
||||
It should return a JSON document that resembles the following:</p><p><b>health-uri-document. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">{</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"status"</span>:<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"UP"</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">}</span></pre><p>
|
||||
</p><p>The following application.yml example shows sample configuration for a Sidecar application:</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">server</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> port</span>: <span class="hl-number">5678</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> application</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: sidecar
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">sidecar</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> port</span>: <span class="hl-number">8000</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> health-uri</span>: http://localhost:<span class="hl-number">8000</span>/health.json</pre><p>
|
||||
</p><p>The API for the <code class="literal">DiscoveryClient.getInstances()</code> method is <code class="literal">/hosts/{serviceId}</code>.
|
||||
The following example response for <code class="literal">/hosts/customers</code> returns two instances on different hosts:</p><p><b>/hosts/customers. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">[</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">{</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"host"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"myhost"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"port"</span>: <span class="hl-number">9000</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"uri"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://myhost:9000"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"serviceId"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"CUSTOMERS"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"secure"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">false</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">},</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">{</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"host"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"myhost2"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"port"</span>: <span class="hl-number">9000</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"uri"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://myhost2:9000"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"serviceId"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"CUSTOMERS"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">,</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"secure"</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">false</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">}</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">]</span></pre><p>
|
||||
</p><p>This API is accessible to the non-JVM application (if the sidecar is on port 5678) at <code class="literal"><a class="link" href="http://localhost:5678/hosts/{serviceId}" target="_top">http://localhost:5678/hosts/{serviceId}</a></code>.</p><p>The Zuul proxy automatically adds routes for each service known in Eureka to <code class="literal">/<serviceId></code>, so the customers service is available at <code class="literal">/customers</code>.
|
||||
The non-JVM application can access the customer service at <code class="literal"><a class="link" href="http://localhost:5678/customers" target="_top">http://localhost:5678/customers</a></code> (assuming the sidecar is listening on port 5678).</p><p>If the Config Server is registered with Eureka, the non-JVM application can access it through the Zuul proxy.
|
||||
If the <code class="literal">serviceId</code> of the ConfigServer is <code class="literal">configserver</code> and the Sidecar is on port 5678, then it can be accessed at <a class="link" href="http://localhost:5678/configserver" target="_top">http://localhost:5678/configserver</a>.</p><p>Non-JVM applications can take advantage of the Config Server’s ability to return YAML documents.
|
||||
For example, a call to <a class="link" href="http://sidecar.local.spring.io:5678/configserver/default-master.yml" target="_top">http://sidecar.local.spring.io:5678/configserver/default-master.yml</a>
|
||||
might result in a YAML document resembling the following:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">eureka</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> client</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> serviceUrl</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> defaultZone</span>: http://localhost:<span class="hl-number">8761</span>/eureka/
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> password</span>: password
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">info</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> description</span>: Spring Cloud Samples
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> url</span>: https://github.com/spring-cloud-samples</pre><p>To enable the health check request to accept all certificates when using HTTPs set <code class="literal">sidecar.accept-all-ssl-certificates</code> to `true.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__router_and_filter_zuul.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_netflix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_retrying-failed-requests.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">18. Router and Filter: Zuul </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 20. Retrying Failed Requests</td></tr></table></div></body></html>
|
||||
395
Greenwich.RC2/multi/multi__programming_model.html
Normal file
@@ -0,0 +1,395 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>29. Programming Model</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="prev" href="multi__main_concepts.html" title="28. Main Concepts"><link rel="next" href="multi_spring-cloud-stream-overview-binders.html" title="30. Binders"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">29. Programming Model</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__main_concepts.html">Prev</a> </td><th width="60%" align="center">Part V. Spring Cloud Stream</th><td width="20%" align="right"> <a accesskey="n" href="multi_spring-cloud-stream-overview-binders.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_programming_model" href="#_programming_model"></a>29. Programming Model</h2></div></div></div><p>To understand the programming model, you should be familiar with the following core concepts:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><span class="strong"><strong>Destination Binders:</strong></span> Components responsible to provide integration with the external messaging systems.</li><li class="listitem"><span class="strong"><strong>Destination Bindings:</strong></span> Bridge between the external messaging systems and application provided <span class="emphasis"><em>Producers</em></span> and <span class="emphasis"><em>Consumers</em></span> of messages (created by the Destination Binders).</li><li class="listitem"><span class="strong"><strong>Message:</strong></span> The canonical data structure used by producers and consumers to communicate with Destination Binders (and thus other applications via external messaging systems).</li></ul></div><div class="informalfigure"><div class="mediaobject" align="center"><img src="images/SCSt-overview.png" align="middle" alt="SCSt overview"></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_destination_binders" href="#_destination_binders"></a>29.1 Destination Binders</h2></div></div></div><p>Destination Binders are extension components of Spring Cloud Stream responsible for providing the necessary configuration and implementation to facilitate
|
||||
integration with external messaging systems.
|
||||
This integration is responsible for connectivity, delegation, and routing of messages to and from producers and consumers, data type conversion,
|
||||
invocation of the user code, and more.</p><p>Binders handle a lot of the boiler plate responsibilities that would otherwise fall on your shoulders. However, to accomplish that, the binder still needs
|
||||
some help in the form of minimalistic yet required set of instructions from the user, which typically come in the form of some type of configuration.</p><p>While it is out of scope of this section to discuss all of the available binder and binding configuration options (the rest of the manual covers them extensively),
|
||||
<span class="emphasis"><em>Destination Binding</em></span> does require special attention. The next section discusses it in detail.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_destination_bindings" href="#_destination_bindings"></a>29.2 Destination Bindings</h2></div></div></div><p>As stated earlier, <span class="emphasis"><em>Destination Bindings</em></span> provide a bridge between the external messaging system and application-provided <span class="emphasis"><em>Producers</em></span> and <span class="emphasis"><em>Consumers</em></span>.</p><p>Applying the @EnableBinding annotation to one of the application’s configuration classes defines a destination binding.
|
||||
The <code class="literal">@EnableBinding</code> annotation itself is meta-annotated with <code class="literal">@Configuration</code> and triggers the configuration of the Spring Cloud Stream infrastructure.</p><p>The following example shows a fully configured and functioning Spring Cloud Stream application that receives the payload of the message from the <code class="literal">INPUT</code>
|
||||
destination as a <code class="literal">String</code> type (see <a class="xref" href="multi_content-type-management.html" title="32. Content Type Negotiation">Chapter 32, <i>Content Type Negotiation</i></a> section), logs it to the console and sends it to the <code class="literal">OUTPUT</code> destination after converting it to upper case.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Processor.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(MyApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Processor.INPUT)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@SendTo(Processor.OUTPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String handle(String value) {
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Received: "</span> + value);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> value.toUpperCase();
|
||||
}
|
||||
}</pre><p>As you can see the <code class="literal">@EnableBinding</code> annotation can take one or more interface classes as parameters. The parameters are referred to as <span class="emphasis"><em>bindings</em></span>,
|
||||
and they contain methods representing <span class="emphasis"><em>bindable components</em></span>.
|
||||
These components are typically message channels (see <a class="link" href="https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-messaging.html" target="_top">Spring Messaging</a>)
|
||||
for channel-based binders (such as Rabbit, Kafka, and others). However other types of bindings can
|
||||
provide support for the native features of the corresponding technology. For example Kafka Streams binder (formerly known as KStream) allows native bindings directly to Kafka Streams
|
||||
(see <a class="link" href="https://docs.spring.io/autorepo/docs/spring-cloud-stream-binder-kafka-docs/1.1.0.M1/reference/htmlsingle/" target="_top">Kafka Streams</a> for more details).</p><p>Spring Cloud Stream already provides <span class="emphasis"><em>binding</em></span> interfaces for typical message exchange contracts, which include:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><span class="strong"><strong>Sink:</strong></span> Identifies the contract for the message consumer by providing the destination from which the message is consumed.</li><li class="listitem"><span class="strong"><strong>Source:</strong></span> Identifies the contract for the message producer by providing the destination to which the produced message is sent.</li><li class="listitem"><span class="strong"><strong>Processor:</strong></span> Encapsulates both the sink and the source contracts by exposing two destinations that allow consumption and production of messages.</li></ul></div><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> Sink {
|
||||
|
||||
String INPUT = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"input"</span>;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Input(Sink.INPUT)</span></em>
|
||||
SubscribableChannel input();
|
||||
}</pre><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> Source {
|
||||
|
||||
String OUTPUT = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"output"</span>;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Output(Source.OUTPUT)</span></em>
|
||||
MessageChannel output();
|
||||
}</pre><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> Processor <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> Source, Sink {}</pre><p>While the preceding example satisfies the majority of cases, you can also define your own contracts by defining your own bindings interfaces and use <code class="literal">@Input</code> and <code class="literal">@Output</code>
|
||||
annotations to identify the actual <span class="emphasis"><em>bindable components</em></span>.</p><p>For example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> Barista {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Input</span></em>
|
||||
SubscribableChannel orders();
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Output</span></em>
|
||||
MessageChannel hotDrinks();
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Output</span></em>
|
||||
MessageChannel coldDrinks();
|
||||
}</pre><p>Using the interface shown in the preceding example as a parameter to <code class="literal">@EnableBinding</code> triggers the creation of the three bound channels named <code class="literal">orders</code>, <code class="literal">hotDrinks</code>, and <code class="literal">coldDrinks</code>,
|
||||
respectively.</p><p>You can provide as many binding interfaces as you need, as arguments to the <code class="literal">@EnableBinding</code> annotation, as shown in the following example:</p><pre class="programlisting">@EnableBinding(value = { Orders.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, Payment.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> })</pre><p>In Spring Cloud Stream, the bindable <code class="literal">MessageChannel</code> components are the Spring Messaging <code class="literal">MessageChannel</code> (for outbound) and its extension, <code class="literal">SubscribableChannel</code>,
|
||||
(for inbound).</p><p><span class="strong"><strong>Pollable Destination Binding</strong></span></p><p>While the previously described bindings support event-based message consumption, sometimes you need more control, such as rate of consumption.</p><p>Starting with version 2.0, you can now bind a pollable consumer:</p><p>The following example shows how to bind a pollable consumer:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> PolledBarista {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Input</span></em>
|
||||
PollableMessageSource orders();
|
||||
. . .
|
||||
}</pre><p>In this case, an implementation of <code class="literal">PollableMessageSource</code> is bound to the <code class="literal">orders</code> “channel”. See <a class="xref" href="multi__programming_model.html#spring-cloud-streams-overview-using-polled-consumers" title="29.3.5 Using Polled Consumers">Section 29.3.5, “Using Polled Consumers”</a> for more details.</p><p><span class="strong"><strong>Customizing Channel Names</strong></span></p><p>By using the <code class="literal">@Input</code> and <code class="literal">@Output</code> annotations, you can specify a customized channel name for the channel, as shown in the following example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> Barista {
|
||||
<em><span class="hl-annotation" style="color: gray">@Input("inboundOrders")</span></em>
|
||||
SubscribableChannel orders();
|
||||
}</pre><p>In the preceding example, the created bound channel is named <code class="literal">inboundOrders</code>.</p><p>Normally, you need not access individual channels or bindings directly (other then configuring them via <code class="literal">@EnableBinding</code> annotation). However there may be
|
||||
times, such as testing or other corner cases, when you do.</p><p>Aside from generating channels for each binding and registering them as Spring beans, for each bound interface, Spring Cloud Stream generates a bean that implements the interface.
|
||||
That means you can have access to the interfaces representing the bindings or individual channels by auto-wiring either in your application, as shown in the following two examples:</p><p><span class="emphasis"><em>Autowire Binding interface</em></span></p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowire</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> Source source
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> sayHello(String name) {
|
||||
source.output().send(MessageBuilder.withPayload(name).build());
|
||||
}</pre><p><span class="emphasis"><em>Autowire individual channel</em></span></p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowire</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> MessageChannel output;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> sayHello(String name) {
|
||||
output.send(MessageBuilder.withPayload(name).build());
|
||||
}</pre><p>You can also use standard Spring’s <code class="literal">@Qualifier</code> annotation for cases when channel names are customized or in multiple-channel scenarios that require specifically named channels.</p><p>The following example shows how to use the @Qualifier annotation in this way:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowire</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Qualifier("myChannel")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> MessageChannel output;</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="spring-cloud-stream-overview-producing-consuming-messages" href="#spring-cloud-stream-overview-producing-consuming-messages"></a>29.3 Producing and Consuming Messages</h2></div></div></div><p>You can write a Spring Cloud Stream application by using either Spring Integration annotations or Spring Cloud Stream native annotation.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_spring_integration_support" href="#_spring_integration_support"></a>29.3.1 Spring Integration Support</h3></div></div></div><p>Spring Cloud Stream is built on the concepts and patterns defined by <a class="link" href="http://www.enterpriseintegrationpatterns.com/" target="_top">Enterprise Integration Patterns</a> and relies
|
||||
in its internal implementation on an already established and popular implementation of Enterprise Integration Patterns within the Spring portfolio of projects:
|
||||
<a class="link" href="https://projects.spring.io/spring-integration/" target="_top">Spring Integration</a> framework.</p><p>So its only natural for it to support the foundation, semantics, and configuration options that are already established by Spring Integration</p><p>For example, you can attach the output channel of a <code class="literal">Source</code> to a <code class="literal">MessageSource</code> and use the familiar <code class="literal">@InboundChannelAdapter</code> annotation, as follows:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding(Source.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> TimerSource {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@InboundChannelAdapter(value = Source.OUTPUT, poller = @Poller(fixedDelay = "10", maxMessagesPerPoll = "1"))</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> MessageSource<String> timerMessageSource() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> () -> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> GenericMessage<>(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Hello Spring Cloud Stream"</span>);
|
||||
}
|
||||
}</pre><p>Similarly, you can use @Transformer or @ServiceActivator while providing an implementation of a message handler method for a <span class="emphasis"><em>Processor</em></span> binding contract, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding(Processor.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> TransformProcessor {
|
||||
<em><span class="hl-annotation" style="color: gray">@Transformer(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Object transform(String message) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> message.toUpperCase();
|
||||
}
|
||||
}</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>While this may be skipping ahead a bit, it is important to understand that, when you consume from the same binding using <code class="literal">@StreamListener</code> annotation, a pub-sub model is used.
|
||||
Each method annotated with <code class="literal">@StreamListener</code> receives its own copy of a message, and each one has its own consumer group.
|
||||
However, if you consume from the same binding by using one of the Spring Integration annotation (such as <code class="literal">@Aggregator</code>, <code class="literal">@Transformer</code>, or <code class="literal">@ServiceActivator</code>), those consume in a competing model.
|
||||
No individual consumer group is created for each subscription.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_using_streamlistener_annotation" href="#_using_streamlistener_annotation"></a>29.3.2 Using @StreamListener Annotation</h3></div></div></div><p>Complementary to its Spring Integration support, Spring Cloud Stream provides its own <code class="literal">@StreamListener</code> annotation, modeled after other Spring Messaging annotations
|
||||
(<code class="literal">@MessageMapping</code>, <code class="literal">@JmsListener</code>, <code class="literal">@RabbitListener</code>, and others) and provides conviniences, such as content-based routing and others.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding(Sink.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> VoteHandler {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
VotingService votingService;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Sink.INPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> handle(Vote vote) {
|
||||
votingService.record(vote);
|
||||
}
|
||||
}</pre><p>As with other Spring Messaging methods, method arguments can be annotated with <code class="literal">@Payload</code>, <code class="literal">@Headers</code>, and <code class="literal">@Header</code>.</p><p>For methods that return data, you must use the <code class="literal">@SendTo</code> annotation to specify the output binding destination for data returned by the method, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding(Processor.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> TransformProcessor {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
VotingService votingService;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Processor.INPUT)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@SendTo(Processor.OUTPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> VoteResult handle(Vote vote) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> votingService.record(vote);
|
||||
}
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_using_streamlistener_for_content_based_routing" href="#_using_streamlistener_for_content_based_routing"></a>29.3.3 Using @StreamListener for Content-based routing</h3></div></div></div><p>Spring Cloud Stream supports dispatching messages to multiple handler methods annotated with <code class="literal">@StreamListener</code> based on conditions.</p><p>In order to be eligible to support conditional dispatching, a method must satisfy the follow conditions:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">It must not return a value.</li><li class="listitem">It must be an individual message handling method (reactive API methods are not supported).</li></ul></div><p>The condition is specified by a SpEL expression in the <code class="literal">condition</code> argument of the annotation and is evaluated for each message.
|
||||
All the handlers that match the condition are invoked in the same thread, and no assumption must be made about the order in which the invocations take place.</p><p>In the following example of a <code class="literal">@StreamListener</code> with dispatching conditions, all the messages bearing a header <code class="literal">type</code> with the value <code class="literal">bogey</code> are dispatched to the
|
||||
<code class="literal">receiveBogey</code> method, and all the messages bearing a header <code class="literal">type</code> with the value <code class="literal">bacall</code> are dispatched to the <code class="literal">receiveBacall</code> method.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding(Sink.class)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> TestPojoWithAnnotatedArguments {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(target = Sink.INPUT, condition = "headers['type']=='bogey'")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> receiveBogey(<em><span class="hl-annotation" style="color: gray">@Payload</span></em> BogeyPojo bogeyPojo) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// handle the message</span>
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(target = Sink.INPUT, condition = "headers['type']=='bacall'")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> receiveBacall(<em><span class="hl-annotation" style="color: gray">@Payload</span></em> BacallPojo bacallPojo) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// handle the message</span>
|
||||
}
|
||||
}</pre><p><span class="strong"><strong>Content Type Negotiation in the Context of <code class="literal">condition</code></strong></span></p><p>It is important to understand some of the mechanics behind content-based routing using the <code class="literal">condition</code> argument of <code class="literal">@StreamListener</code>, especially in the context of the type of the message as a whole.
|
||||
It may also help if you familiarize yourself with the <a class="xref" href="multi_content-type-management.html" title="32. Content Type Negotiation">Chapter 32, <i>Content Type Negotiation</i></a> before you proceed.</p><p>Consider the following scenario:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding(Sink.class)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> CatsAndDogs {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(target = Sink.INPUT, condition = "payload.class.simpleName=='Dog'")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> bark(Dog dog) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// handle the message</span>
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(target = Sink.INPUT, condition = "payload.class.simpleName=='Cat'")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> purr(Cat cat) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// handle the message</span>
|
||||
}
|
||||
}</pre><p>The preceding code is perfectly valid. It compiles and deploys without any issues, yet it never produces the result you expect.</p><p>That is because you are testing something that does not yet exist in a state you expect. That is because the payload of the message is not yet converted from the
|
||||
wire format (<code class="literal">byte[]</code>) to the desired type.
|
||||
In other words, it has not yet gone through the type conversion process described in the <a class="xref" href="multi_content-type-management.html" title="32. Content Type Negotiation">Chapter 32, <i>Content Type Negotiation</i></a>.</p><p>So, unless you use a SPeL expression that evaluates raw data (for example, the value of the first byte in the byte array), use message header-based expressions
|
||||
(such as <code class="literal">condition = "headers['type']=='dog'"</code>).</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>At the moment, dispatching through <code class="literal">@StreamListener</code> conditions is supported only for channel-based binders (not for reactive programming)
|
||||
support.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_spring_cloud_function" href="#_spring_cloud_function"></a>29.3.4 Spring Cloud Function support</h3></div></div></div><p>Since Spring Cloud Stream v2.1, another alternative for defining <span class="emphasis"><em>stream handlers</em></span> and <span class="emphasis"><em>sources</em></span> is to use build-in
|
||||
support for <a class="link" href="https://cloud.spring.io/spring-cloud-function/" target="_top">Spring Cloud Function</a> where they can be expressed as beans of
|
||||
type <code class="literal">java.util.function.[Supplier/Function/Consumer]</code>.</p><p>To specify which functional bean to bind to the external destination(s) exposed by the bindings, you must provide <code class="literal">spring.cloud.stream.function.definition</code> property.</p><p>Here is the example of the Processor application exposing message handler as <code class="literal">java.util.function.Function</code></p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Processor.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyFunctionBootApp {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(MyFunctionBootApp.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"--spring.cloud.stream.function.definition=toUpperCase"</span>);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Function<String, String> toUpperCase() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> s -> s.toUpperCase();
|
||||
}
|
||||
}</pre><p>In the above you we simply define a bean of type <code class="literal">java.util.function.Function</code> called <span class="emphasis"><em>toUpperCase</em></span> and identify it as a bean to be used as message handler
|
||||
whose 'input' and 'output' must be bound to the external destinations exposed by the Processor binding.</p><p>Below are the examples of simple functional applications to support Source, Processor and Sink.</p><p>Here is the example of a Source application defined as <code class="literal">java.util.function.Supplier</code></p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Source.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> SourceFromSupplier {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(SourceFromSupplier.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"--spring.cloud.stream.function.definition=date"</span>);
|
||||
}
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Supplier<Date> date() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> () -> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Date(<span class="hl-number">12345L</span>);
|
||||
}
|
||||
}</pre><p>Here is the example of a Processor application defined as <code class="literal">java.util.function.Function</code></p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Processor.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> ProcessorFromFunction {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(ProcessorFromFunction.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"--spring.cloud.stream.function.definition=toUpperCase"</span>);
|
||||
}
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Function<String, String> toUpperCase() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> s -> s.toUpperCase();
|
||||
}
|
||||
}</pre><p>Here is the example of a Sink application defined as <code class="literal">java.util.function.Consumer</code></p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Sink.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> SinkFromConsumer {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(SinkFromConsumer.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"--spring.cloud.stream.function.definition=sink"</span>);
|
||||
}
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Consumer<String> sink() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> System.out::println;
|
||||
}
|
||||
}</pre><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_functional_composition" href="#_functional_composition"></a>Functional Composition</h4></div></div></div><p>Using this programming model you can also benefit from functional composition where you can dynamically compose complex handlers from a set of simple functions.
|
||||
As an example let’s add the following function bean to the application defined above</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Function<String, String> wrapInQuotes() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> s -> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"\""</span> + s + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"\""</span>;
|
||||
}</pre><p>and modify the <code class="literal">spring.cloud.stream.function.definition</code> property to reflect your intention to compose a new function from both ‘toUpperCase’ and ‘wrapInQuotes’.
|
||||
To do that Spring Cloud Function allows you to use <code class="literal">|</code> (pipe) symbol. So to finish our example our property will now look like this:</p><pre class="programlisting">—spring.cloud.stream.function.definition=toUpperCase|wrapInQuotes</pre></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="spring-cloud-streams-overview-using-polled-consumers" href="#spring-cloud-streams-overview-using-polled-consumers"></a>29.3.5 Using Polled Consumers</h3></div></div></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_overview" href="#_overview"></a>Overview</h4></div></div></div><p>When using polled consumers, you poll the <code class="literal">PollableMessageSource</code> on demand.
|
||||
Consider the following example of a polled consumer:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> PolledConsumer {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Input</span></em>
|
||||
PollableMessageSource destIn();
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Output</span></em>
|
||||
MessageChannel destOut();
|
||||
|
||||
}</pre><p>Given the polled consumer in the preceding example, you might use it as follows:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> ApplicationRunner poller(PollableMessageSource destIn, MessageChannel destOut) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> args -> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">while</span> (someCondition()) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (!destIn.poll(m -> {
|
||||
String newPayload = ((String) m.getPayload()).toUpperCase();
|
||||
destOut.send(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> GenericMessage<>(newPayload));
|
||||
})) {
|
||||
Thread.sleep(<span class="hl-number">1000</span>);
|
||||
}
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">catch</span> (Exception e) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// handle failure</span>
|
||||
}
|
||||
}
|
||||
};
|
||||
}</pre><p>The <code class="literal">PollableMessageSource.poll()</code> method takes a <code class="literal">MessageHandler</code> argument (often a lambda expression, as shown here).
|
||||
It returns <code class="literal">true</code> if the message was received and successfully processed.</p><p>As with message-driven consumers, if the <code class="literal">MessageHandler</code> throws an exception, messages are published to error channels, as discussed in “<a class="xref" href="">???</a>”.</p><p>Normally, the <code class="literal">poll()</code> method acknowledges the message when the <code class="literal">MessageHandler</code> exits.
|
||||
If the method exits abnormally, the message is rejected (not re-queued), but see <a class="xref" href="multi__programming_model.html#polled-errors" title="Handling Errors">the section called “Handling Errors”</a>.
|
||||
You can override that behavior by taking responsibility for the acknowledgment, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> ApplicationRunner poller(PollableMessageSource dest1In, MessageChannel dest2Out) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> args -> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">while</span> (someCondition()) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (!dest1In.poll(m -> {
|
||||
StaticMessageHeaderAccessor.getAcknowledgmentCallback(m).noAutoAck();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// e.g. hand off to another thread which can perform the ack</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// or acknowledge(Status.REQUEUE)</span>
|
||||
|
||||
})) {
|
||||
Thread.sleep(<span class="hl-number">1000</span>);
|
||||
}
|
||||
}
|
||||
};
|
||||
}</pre><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>You must <code class="literal">ack</code> (or <code class="literal">nack</code>) the message at some point, to avoid resource leaks.</p></td></tr></table></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Some messaging systems (such as Apache Kafka) maintain a simple offset in a log. If a delivery fails and is re-queued with <code class="literal">StaticMessageHeaderAccessor.getAcknowledgmentCallback(m).acknowledge(Status.REQUEUE);</code>, any later successfully ack’d messages are redelivered.</p></td></tr></table></div><p>There is also an overloaded <code class="literal">poll</code> method, for which the definition is as follows:</p><pre class="programlisting">poll(MessageHandler handler, ParameterizedTypeReference<?> type)</pre><p>The <code class="literal">type</code> is a conversion hint that allows the incoming message payload to be converted, as shown in the following example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> result = pollableSource.poll(received -> {
|
||||
Map<String, Foo> payload = (Map<String, Foo>) received.getPayload();
|
||||
...
|
||||
|
||||
}, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ParameterizedTypeReference<Map<String, Foo>>() {});</pre></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="polled-errors" href="#polled-errors"></a>Handling Errors</h4></div></div></div><p>By default, an error channel is configured for the pollable source; if the callback throws an exception, an <code class="literal">ErrorMessage</code> is sent to the error channel (<code class="literal"><destination>.<group>.errors</code>); this error channel is also bridged to the global Spring Integration <code class="literal">errorChannel</code>.</p><p>You can subscribe to either error channel with a <code class="literal">@ServiceActivator</code> to handle errors; without a subscription, the error will simply be logged and the message will be acknowledged as successful.
|
||||
If the error channel service activator throws an exception, the message will be rejected (by default) and won’t be redelivered.
|
||||
If the service activator throws a <code class="literal">RequeueCurrentMessageException</code>, the message will be requeued at the broker and will be again retrieved on a subsequent poll.</p><p>If the listener throws a <code class="literal">RequeueCurrentMessageException</code> directly, the message will be requeued, as discussed above, and will not be sent to the error channels.</p></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="spring-cloud-stream-overview-error-handling" href="#spring-cloud-stream-overview-error-handling"></a>29.4 Error Handling</h2></div></div></div><p>Errors happen, and Spring Cloud Stream provides several flexible mechanisms to handle them.
|
||||
The error handling comes in two flavors:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><span class="strong"><strong>application:</strong></span> The error handling is done within the application (custom error handler).</li><li class="listitem"><span class="strong"><strong>system:</strong></span> The error handling is delegated to the binder (re-queue, DL, and others). Note that the techniques are dependent on binder implementation and the
|
||||
capability of the underlying messaging middleware.</li></ul></div><p>Spring Cloud Stream uses the <a class="link" href="https://github.com/spring-projects/spring-retry" target="_top">Spring Retry</a> library to facilitate successful message processing. See <a class="xref" href="multi__programming_model.html#_retry_template" title="29.4.3 Retry Template">Section 29.4.3, “Retry Template”</a> for more details.
|
||||
However, when all fails, the exceptions thrown by the message handlers are propagated back to the binder. At that point, binder invokes custom error handler or communicates
|
||||
the error back to the messaging system (re-queue, DLQ, and others).</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_application_error_handling" href="#_application_error_handling"></a>29.4.1 Application Error Handling</h3></div></div></div><p>There are two types of application-level error handling. Errors can be handled at each binding subscription or a global handler can handle all the binding subscription errors. Let’s review the details.</p><div class="figure"><a name="d0e8750" href="#d0e8750"></a><p class="title"><b>Figure 29.1. A Spring Cloud Stream Sink Application with Custom and Global Error Handlers</b></p><div class="figure-contents"><div class="mediaobject" align="center"><img src="images/custom_vs_global_error_channels.png" align="middle" alt="custom vs global error channels"></div></div></div><br class="figure-break"><p>For each input binding, Spring Cloud Stream creates a dedicated error channel with the following semantics <code class="literal"><destinationName>.errors</code>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The <code class="literal"><destinationName></code> consists of the name of the binding (such as <code class="literal">input</code>) and the name of the group (such as <code class="literal">myGroup</code>).</p></td></tr></table></div><p>Consider the following:</p><pre class="programlisting">spring.cloud.stream.bindings.input.group=myGroup</pre><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@StreamListener(Sink.INPUT)</span></em> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// destination name 'input.myGroup'</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> handle(Person value) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throw</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> RuntimeException(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"BOOM!"</span>);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@ServiceActivator(inputChannel = Processor.INPUT + ".myGroup.errors")</span></em> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//channel name 'input.myGroup.errors'</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> error(Message<?> message) {
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Handling ERROR: "</span> + message);
|
||||
}</pre><p>In the preceding example the destination name is <code class="literal">input.myGroup</code> and the dedicated error channel name is <code class="literal">input.myGroup.errors</code>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The use of @StreamListener annotation is intended specifically to define bindings that bridge internal channels and external destinations. Given that the destination
|
||||
specific error channel does NOT have an associated external destination, such channel is a prerogative of Spring Integration (SI). This means that the handler
|
||||
for such destination must be defined using one of the SI handler annotations (i.e., @ServiceActivator, @Transformer etc.).</p></td></tr></table></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>If <code class="literal">group</code> is not specified anonymous group is used (something like <code class="literal">input.anonymous.2K37rb06Q6m2r51-SPIDDQ</code>), which is not suitable for error
|
||||
handling scenarious, since you don’t know what it’s going to be until the destination is created.</p></td></tr></table></div><p>Also, in the event you are binding to the existing destination such as:</p><pre class="programlisting">spring.cloud.stream.bindings.input.destination=myFooDestination
|
||||
spring.cloud.stream.bindings.input.group=myGroup</pre><p>the full destination name is <code class="literal">myFooDestination.myGroup</code> and then the dedicated error channel name is <code class="literal">myFooDestination.myGroup.errors</code>.</p><p>Back to the example…​</p><p>The <code class="literal">handle(..)</code> method, which subscribes to the channel named <code class="literal">input</code>, throws an exception. Given there is also a subscriber to the error channel <code class="literal">input.myGroup.errors</code>
|
||||
all error messages are handled by this subscriber.</p><p>If you have multiple bindings, you may want to have a single error handler. Spring Cloud Stream automatically provides support for
|
||||
a <span class="emphasis"><em>global error channel</em></span> by bridging each individual error channel to the channel named <code class="literal">errorChannel</code>, allowing a single subscriber to handle all errors,
|
||||
as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@StreamListener("errorChannel")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> error(Message<?> message) {
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Handling ERROR: "</span> + message);
|
||||
}</pre><p>This may be a convenient option if error handling logic is the same regardless of which handler produced the error.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_system_error_handling" href="#_system_error_handling"></a>29.4.2 System Error Handling</h3></div></div></div><p>System-level error handling implies that the errors are communicated back to the messaging system and, given that not every messaging system
|
||||
is the same, the capabilities may differ from binder to binder.</p><p>That said, in this section we explain the general idea behind system level error handling and use Rabbit binder as an example. NOTE: Kafka binder provides similar
|
||||
support, although some configuration properties do differ. Also, for more details and configuration options, see the individual binder’s documentation.</p><p>If no internal error handlers are configured, the errors propagate to the binders, and the binders subsequently propagate those errors back to the messaging system.
|
||||
Depending on the capabilities of the messaging system such a system may <span class="emphasis"><em>drop</em></span> the message, <span class="emphasis"><em>re-queue</em></span> the message for re-processing or <span class="emphasis"><em>send the failed message to DLQ</em></span>.
|
||||
Both Rabbit and Kafka support these concepts. However, other binders may not, so refer to your individual binder’s documentation for details on supported system-level
|
||||
error-handling options.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_drop_failed_messages" href="#_drop_failed_messages"></a>Drop Failed Messages</h4></div></div></div><p>By default, if no additional system-level configuration is provided, the messaging system drops the failed message.
|
||||
While acceptable in some cases, for most cases, it is not, and we need some recovery mechanism to avoid message loss.</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_dlq_dead_letter_queue" href="#_dlq_dead_letter_queue"></a>DLQ - Dead Letter Queue</h4></div></div></div><p>DLQ allows failed messages to be sent to a special destination: - <span class="emphasis"><em>Dead Letter Queue</em></span>.</p><p>When configured, failed messages are sent to this destination for subsequent re-processing or auditing and reconciliation.</p><p>For example, continuing on the previous example and to set up the DLQ with Rabbit binder, you need to set the following property:</p><pre class="programlisting">spring.cloud.stream.rabbit.bindings.input.consumer.auto-bind-dlq=true</pre><p>Keep in mind that, in the above property, <code class="literal">input</code> corresponds to the name of the input destination binding.
|
||||
The <code class="literal">consumer</code> indicates that it is a consumer property and <code class="literal">auto-bind-dlq</code> instructs the binder to configure DLQ for <code class="literal">input</code>
|
||||
destination, which results in an additional Rabbit queue named <code class="literal">input.myGroup.dlq</code>.</p><p>Once configured, all failed messages are routed to this queue with an error message similar to the following:</p><pre class="programlisting">delivery_mode: 1
|
||||
headers:
|
||||
x-death:
|
||||
count: 1
|
||||
reason: rejected
|
||||
queue: input.hello
|
||||
time: 1522328151
|
||||
exchange:
|
||||
routing-keys: input.myGroup
|
||||
Payload {"name”:"Bob"}</pre><p>As you can see from the above, your original message is preserved for further actions.</p><p>However, one thing you may have noticed is that there is limited information on the original issue with the message processing. For example, you do not see a stack
|
||||
trace corresponding to the original error.
|
||||
To get more relevant information about the original error, you must set an additional property:</p><pre class="programlisting">spring.cloud.stream.rabbit.bindings.input.consumer.republish-to-dlq=true</pre><p>Doing so forces the internal error handler to intercept the error message and add additional information to it before publishing it to DLQ.
|
||||
Once configured, you can see that the error message contains more information relevant to the original error, as follows:</p><pre class="programlisting">delivery_mode: 2
|
||||
headers:
|
||||
x-original-exchange:
|
||||
x-exception-message: has an error
|
||||
x-original-routingKey: input.myGroup
|
||||
x-exception-stacktrace: org.springframework.messaging.MessageHandlingException: nested exception is
|
||||
org.springframework.messaging.MessagingException: has an error, failedMessage=GenericMessage [payload=byte[15],
|
||||
headers={amqp_receivedDeliveryMode=NON_PERSISTENT, amqp_receivedRoutingKey=input.hello, amqp_deliveryTag=1,
|
||||
deliveryAttempt=3, amqp_consumerQueue=input.hello, amqp_redelivered=false, id=a15231e6-3f80-677b-5ad7-d4b1e61e486e,
|
||||
amqp_consumerTag=amq.ctag-skBFapilvtZhDsn0k3ZmQg, contentType=application/json, timestamp=1522327846136}]
|
||||
at org.spring...integ...han...MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:107)
|
||||
at. . . . .
|
||||
Payload {"name”:"Bob"}</pre><p>This effectively combines application-level and system-level error handling to further assist with downstream troubleshooting mechanics.</p></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_re_queue_failed_messages" href="#_re_queue_failed_messages"></a>Re-queue Failed Messages</h4></div></div></div><p>As mentioned earlier, the currently supported binders (Rabbit and Kafka) rely on <code class="literal">RetryTemplate</code> to facilitate successful message processing. See <a class="xref" href="multi__programming_model.html#_retry_template" title="29.4.3 Retry Template">Section 29.4.3, “Retry Template”</a> for details.
|
||||
However, for cases when <code class="literal">max-attempts</code> property is set to 1, internal reprocessing of the message is disabled. At this point, you can facilitate message re-processing (re-tries)
|
||||
by instructing the messaging system to re-queue the failed message. Once re-queued, the failed message is sent back to the original handler, essentially creating a retry loop.</p><p>This option may be feasible for cases where the nature of the error is related to some sporadic yet short-term unavailability of some resource.</p><p>To accomplish that, you must set the following properties:</p><pre class="programlisting">spring.cloud.stream.bindings.input.consumer.max-attempts=1
|
||||
spring.cloud.stream.rabbit.bindings.input.consumer.requeue-rejected=true</pre><p>In the preceding example, the <code class="literal">max-attempts</code> set to 1 essentially disabling internal re-tries and <code class="literal">requeue-rejected</code> (short for <span class="emphasis"><em>requeue rejected messages</em></span>) is set to <code class="literal">true</code>.
|
||||
Once set, the failed message is resubmitted to the same handler and loops continuously or until the handler throws <code class="literal">AmqpRejectAndDontRequeueException</code>
|
||||
essentially allowing you to build your own re-try logic within the handler itself.</p></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_retry_template" href="#_retry_template"></a>29.4.3 Retry Template</h3></div></div></div><p>The <code class="literal">RetryTemplate</code> is part of the <a class="link" href="https://github.com/spring-projects/spring-retry" target="_top">Spring Retry</a> library.
|
||||
While it is out of scope of this document to cover all of the capabilities of the <code class="literal">RetryTemplate</code>, we will mention the following consumer properties that are specifically related to
|
||||
the <code class="literal">RetryTemplate</code>:</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">maxAttempts</span></dt><dd><p class="simpara">The number of attempts to process the message.</p><p class="simpara">Default: 3.</p></dd><dt><span class="term">backOffInitialInterval</span></dt><dd><p class="simpara">The backoff initial interval on retry.</p><p class="simpara">Default 1000 milliseconds.</p></dd><dt><span class="term">backOffMaxInterval</span></dt><dd><p class="simpara">The maximum backoff interval.</p><p class="simpara">Default 10000 milliseconds.</p></dd><dt><span class="term">backOffMultiplier</span></dt><dd><p class="simpara">The backoff multiplier.</p><p class="simpara">Default 2.0.</p></dd><dt><span class="term">defaultRetryable</span></dt><dd><p class="simpara">Whether exceptions thrown by the listener that are not listed in the <code class="literal">retryableExceptions</code> are retryable.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">retryableExceptions</span></dt><dd><p class="simpara">A map of Throwable class names in the key and a boolean in the value.
|
||||
Specify those exceptions (and subclasses) that will or won’t be retried.
|
||||
Also see <code class="literal">defaultRetriable</code>.
|
||||
Example: <code class="literal">spring.cloud.stream.bindings.input.consumer.retryable-exceptions.java.lang.IllegalStateException=false</code>.</p><p class="simpara">Default: empty.</p></dd></dl></div><p>While the preceding settings are sufficient for majority of the customization requirements, they may not satisfy certain complex requirements at, which
|
||||
point you may want to provide your own instance of the <code class="literal">RetryTemplate</code>. To do so configure it as a bean in your application configuration. The application provided
|
||||
instance will override the one provided by the framework. Also, to avoid conflicts you must qualify the instance of the <code class="literal">RetryTemplate</code> you want to be used by the binder
|
||||
as <code class="literal">@StreamRetryTemplate</code>. For example,</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@StreamRetryTemplate</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> RetryTemplate myRetryTemplate() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> RetryTemplate();
|
||||
}</pre><p>As you can see from the above example you don’t need to annotate it with <code class="literal">@Bean</code> since <code class="literal">@StreamRetryTemplate</code> is a qualified <code class="literal">@Bean</code>.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="spring-cloud-stream-overview-reactive-programming-support" href="#spring-cloud-stream-overview-reactive-programming-support"></a>29.5 Reactive Programming Support</h2></div></div></div><p>Spring Cloud Stream also supports the use of reactive APIs where incoming and outgoing data is handled as continuous data flows.
|
||||
Support for reactive APIs is available through <code class="literal">spring-cloud-stream-reactive</code>, which needs to be added explicitly to your project.</p><p>The programming model with reactive APIs is declarative. Instead of specifying how each individual message should be handled, you can use operators that describe functional transformations from inbound to outbound data flows.</p><p>At present Spring Cloud Stream supports the only the <a class="link" href="https://projectreactor.io/" target="_top">Reactor API</a>.
|
||||
In the future, we intend to support a more generic model based on Reactive Streams.</p><p>The reactive programming model also uses the <code class="literal">@StreamListener</code> annotation for setting up reactive handlers.
|
||||
The differences are that:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">The <code class="literal">@StreamListener</code> annotation must not specify an input or output, as they are provided as arguments and return values from the method.</li><li class="listitem">The arguments of the method must be annotated with <code class="literal">@Input</code> and <code class="literal">@Output</code>, indicating which input or output the incoming and outgoing data flows connect to, respectively.</li><li class="listitem">The return value of the method, if any, is annotated with <code class="literal">@Output</code>, indicating the input where data should be sent.</li></ul></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Reactive programming support requires Java 1.8.</p></td></tr></table></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>As of Spring Cloud Stream 1.1.1 and later (starting with release train Brooklyn.SR2), reactive programming support requires the use of Reactor 3.0.4.RELEASE and higher.
|
||||
Earlier Reactor versions (including 3.0.1.RELEASE, 3.0.2.RELEASE and 3.0.3.RELEASE) are not supported.
|
||||
<code class="literal">spring-cloud-stream-reactive</code> transitively retrieves the proper version, but it is possible for the project structure to manage the version of the <code class="literal">io.projectreactor:reactor-core</code> to an earlier release, especially when using Maven.
|
||||
This is the case for projects generated by using Spring Initializr with Spring Boot 1.x, which overrides the Reactor version to <code class="literal">2.0.8.RELEASE</code>.
|
||||
In such cases, you must ensure that the proper version of the artifact is released.
|
||||
You can do so by adding a direct dependency on <code class="literal">io.projectreactor:reactor-core</code> with a version of <code class="literal">3.0.4.RELEASE</code> or later to your project.</p></td></tr></table></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The use of term, “reactive”, currently refers to the reactive APIs being used and not to the execution model being reactive (that is, the bound endpoints still use a 'push' rather than a 'pull' model). While some backpressure support is provided by the use of Reactor, we do intend, in a future release, to support entirely reactive pipelines by the use of native reactive clients for the connected middleware.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_reactor_based_handlers" href="#_reactor_based_handlers"></a>29.5.1 Reactor-based Handlers</h3></div></div></div><p>A Reactor-based handler can have the following argument types:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">For arguments annotated with <code class="literal">@Input</code>, it supports the Reactor <code class="literal">Flux</code> type.
|
||||
The parameterization of the inbound Flux follows the same rules as in the case of individual message handling: It can be the entire <code class="literal">Message</code>, a POJO that can be the <code class="literal">Message</code> payload, or a POJO that is the result of a transformation based on the <code class="literal">Message</code> content-type header. Multiple inputs are provided.</li><li class="listitem">For arguments annotated with <code class="literal">Output</code>, it supports the <code class="literal">FluxSender</code> type, which connects a <code class="literal">Flux</code> produced by the method with an output. Generally speaking, specifying outputs as arguments is only recommended when the method can have multiple outputs.</li></ul></div><p>A Reactor-based handler supports a return type of <code class="literal">Flux</code>. In that case, it must be annotated with <code class="literal">@Output</code>. We recommend using the return value of the method when a single output <code class="literal">Flux</code> is available.</p><p>The following example shows a Reactor-based <code class="literal">Processor</code>:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding(Processor.class)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> UppercaseTransformer {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Output(Processor.OUTPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Flux<String> receive(<em><span class="hl-annotation" style="color: gray">@Input(Processor.INPUT)</span></em> Flux<String> input) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> input.map(s -> s.toUpperCase());
|
||||
}
|
||||
}</pre><p>The same processor using output arguments looks like the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding(Processor.class)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> UppercaseTransformer {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> receive(<em><span class="hl-annotation" style="color: gray">@Input(Processor.INPUT)</span></em> Flux<String> input,
|
||||
<em><span class="hl-annotation" style="color: gray">@Output(Processor.OUTPUT)</span></em> FluxSender output) {
|
||||
output.send(input.map(s -> s.toUpperCase()));
|
||||
}
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_reactive_sources" href="#_reactive_sources"></a>29.5.2 Reactive Sources</h3></div></div></div><p>Spring Cloud Stream reactive support also provides the ability for creating reactive sources through the <code class="literal">@StreamEmitter</code> annotation.
|
||||
By using the <code class="literal">@StreamEmitter</code> annotation, a regular source may be converted to a reactive one.
|
||||
<code class="literal">@StreamEmitter</code> is a method level annotation that marks a method to be an emitter to outputs declared with <code class="literal">@EnableBinding</code>.
|
||||
You cannot use the <code class="literal">@Input</code> annotation along with <code class="literal">@StreamEmitter</code>, as the methods marked with this annotation are not listening for any input. Rather, methods marked with <code class="literal">@StreamEmitter</code> generate output.
|
||||
Following the same programming model used in <code class="literal">@StreamListener</code>, <code class="literal">@StreamEmitter</code> also allows flexible ways of using the <code class="literal">@Output</code> annotation, depending on whether the method has any arguments, a return type, and other considerations.</p><p>The remainder of this section contains examples of using the <code class="literal">@StreamEmitter</code> annotation in various styles.</p><p>The following example emits the <code class="literal">Hello, World</code> message every millisecond and publishes to a Reactor <code class="literal">Flux</code>:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding(Source.class)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> HelloWorldEmitter {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamEmitter</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Output(Source.OUTPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Flux<String> emit() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> Flux.intervalMillis(<span class="hl-number">1</span>)
|
||||
.map(l -> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Hello World"</span>);
|
||||
}
|
||||
}</pre><p>In the preceding example, the resulting messages in the <code class="literal">Flux</code> are sent to the output channel of the <code class="literal">Source</code>.</p><p>The next example is another flavor of an <code class="literal">@StreamEmmitter</code> that sends a Reactor <code class="literal">Flux</code>.
|
||||
Instead of returning a <code class="literal">Flux</code>, the following method uses a <code class="literal">FluxSender</code> to programmatically send a <code class="literal">Flux</code> from a source:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding(Source.class)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> HelloWorldEmitter {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamEmitter</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Output(Source.OUTPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> emit(FluxSender output) {
|
||||
output.send(Flux.intervalMillis(<span class="hl-number">1</span>)
|
||||
.map(l -> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Hello World"</span>));
|
||||
}
|
||||
}</pre><p>The next example is exactly same as the above snippet in functionality and style.
|
||||
However, instead of using an explicit <code class="literal">@Output</code> annotation on the method, it uses the annotation on the method parameter.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding(Source.class)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> HelloWorldEmitter {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamEmitter</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> emit(<em><span class="hl-annotation" style="color: gray">@Output(Source.OUTPUT)</span></em> FluxSender output) {
|
||||
output.send(Flux.intervalMillis(<span class="hl-number">1</span>)
|
||||
.map(l -> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Hello World"</span>));
|
||||
}
|
||||
}</pre><p>The last example in this section is yet another flavor of writing reacting sources by using the Reactive Streams Publisher API and taking advantage of the support for it in <a class="link" href="https://github.com/spring-projects/spring-integration-java-dsl/wiki/Spring-Integration-Java-DSL-Reference" target="_top">Spring Integration Java DSL</a>.
|
||||
The <code class="literal">Publisher</code> in the following example still uses Reactor <code class="literal">Flux</code> under the hood, but, from an application perspective, that is transparent to the user and only needs Reactive Streams and Java DSL for Spring Integration:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@EnableBinding(Source.class)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> HelloWorldEmitter {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamEmitter</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Output(Source.OUTPUT)</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Publisher<Message<String>> emit() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> IntegrationFlows.from(() ->
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> GenericMessage<>(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Hello World"</span>),
|
||||
e -> e.poller(p -> p.fixedDelay(<span class="hl-number">1</span>)))
|
||||
.toReactivePublisher();
|
||||
}
|
||||
}</pre></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__main_concepts.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_stream.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_spring-cloud-stream-overview-binders.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">28. Main Concepts </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 30. Binders</td></tr></table></div></body></html>
|
||||
96
Greenwich.RC2/multi/multi__propagation.html
Normal file
@@ -0,0 +1,96 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>54. Propagation</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_sleuth.html" title="Part VIII. Spring Cloud Sleuth"><link rel="prev" href="multi__sampling.html" title="53. Sampling"><link rel="next" href="multi__current_tracing_component.html" title="55. Current Tracing Component"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">54. Propagation</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__sampling.html">Prev</a> </td><th width="60%" align="center">Part VIII. Spring Cloud Sleuth</th><td width="20%" align="right"> <a accesskey="n" href="multi__current_tracing_component.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_propagation" href="#_propagation"></a>54. Propagation</h2></div></div></div><p>Propagation is needed to ensure activities originating from the same root are collected together in the same trace.
|
||||
The most common propagation approach is to copy a trace context from a client by sending an RPC request to a server receiving it.</p><p>For example, when a downstream HTTP call is made, its trace context is encoded as request headers and sent along with it, as shown in the following image:</p><pre class="screen"> Client Span Server Span
|
||||
┌──────────────────┐ ┌──────────────────┐
|
||||
│ │ │ │
|
||||
│ TraceContext │ Http Request Headers │ TraceContext │
|
||||
│ ┌──────────────┐ │ ┌───────────────────┐ │ ┌──────────────┐ │
|
||||
│ │ TraceId │ │ │ X─B3─TraceId │ │ │ TraceId │ │
|
||||
│ │ │ │ │ │ │ │ │ │
|
||||
│ │ ParentSpanId │ │ Extract │ X─B3─ParentSpanId │ Inject │ │ ParentSpanId │ │
|
||||
│ │ ├─┼─────────>│ ├────────┼>│ │ │
|
||||
│ │ SpanId │ │ │ X─B3─SpanId │ │ │ SpanId │ │
|
||||
│ │ │ │ │ │ │ │ │ │
|
||||
│ │ Sampled │ │ │ X─B3─Sampled │ │ │ Sampled │ │
|
||||
│ └──────────────┘ │ └───────────────────┘ │ └──────────────┘ │
|
||||
│ │ │ │
|
||||
└──────────────────┘ └──────────────────┘</pre><p>The names above are from <a class="link" href="https://github.com/openzipkin/b3-propagation" target="_top">B3 Propagation</a>, which is built-in to Brave and has implementations in many languages and frameworks.</p><p>Most users use a framework interceptor to automate propagation.
|
||||
The next two examples show how that might work for a client and a server.</p><p>The following example shows how client-side propagation might work:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracing tracing;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// configure a function that injects a trace context into a request</span>
|
||||
injector = tracing.propagation().injector(Request.Builder::addHeader);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// before a request is sent, add the current span's context to it</span>
|
||||
injector.inject(span.context(), request);</pre><p>The following example shows how server-side propagation might work:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracing tracing;
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// configure a function that extracts the trace context from a request</span>
|
||||
extractor = tracing.propagation().extractor(Request::getHeader);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when a server receives a request, it joins or starts a new trace</span>
|
||||
span = tracer.nextSpan(extractor.extract(request));</pre><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_propagating_extra_fields" href="#_propagating_extra_fields"></a>54.1 Propagating extra fields</h2></div></div></div><p>Sometimes you need to propagate extra fields, such as a request ID or an alternate trace context.
|
||||
For example, if you are in a Cloud Foundry environment, you might want to pass the request ID, as shown in the following example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when you initialize the builder, define the extra field you want to propagate</span>
|
||||
Tracing.newBuilder().propagationFactory(
|
||||
ExtraFieldPropagation.newFactory(B3Propagation.FACTORY, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-vcap-request-id"</span>)
|
||||
);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// later, you can tag that request ID or use it in log correlation</span>
|
||||
requestId = ExtraFieldPropagation.get(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-vcap-request-id"</span>);</pre><p>You may also need to propagate a trace context that you are not using.
|
||||
For example, you may be in an Amazon Web Services environment but not be reporting data to X-Ray.
|
||||
To ensure X-Ray can co-exist correctly, pass-through its tracing header, as shown in the following example:</p><pre class="programlisting">tracingBuilder.propagationFactory(
|
||||
ExtraFieldPropagation.newFactory(B3Propagation.FACTORY, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-amzn-trace-id"</span>)
|
||||
);</pre><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>In Spring Cloud Sleuth all elements of the tracing builder <code class="literal">Tracing.newBuilder()</code>
|
||||
are defined as beans. So if you want to pass a custom <code class="literal">PropagationFactory</code>, it’s enough
|
||||
for you to create a bean of that type and we will set it in the <code class="literal">Tracing</code> bean.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="prefixed-fields" href="#prefixed-fields"></a>54.1.1 Prefixed fields</h3></div></div></div><p>If they follow a common pattern, you can also prefix fields.
|
||||
The following example shows how to propagate <code class="literal">x-vcap-request-id</code> the field as-is but send the <code class="literal">country-code</code> and <code class="literal">user-id</code> fields on the wire as <code class="literal">x-baggage-country-code</code> and <code class="literal">x-baggage-user-id</code>, respectively:</p><pre class="programlisting">Tracing.newBuilder().propagationFactory(
|
||||
ExtraFieldPropagation.newFactoryBuilder(B3Propagation.FACTORY)
|
||||
.addField(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-vcap-request-id"</span>)
|
||||
.addPrefixedFields(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-baggage-"</span>, Arrays.asList(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"country-code"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"user-id"</span>))
|
||||
.build()
|
||||
);</pre><p>Later, you can call the following code to affect the country code of the current trace context:</p><pre class="programlisting">ExtraFieldPropagation.set(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-country-code"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"FO"</span>);
|
||||
String countryCode = ExtraFieldPropagation.get(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-country-code"</span>);</pre><p>Alternatively, if you have a reference to a trace context, you can use it explicitly, as shown in the following example:</p><pre class="programlisting">ExtraFieldPropagation.set(span.context(), <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-country-code"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"FO"</span>);
|
||||
String countryCode = ExtraFieldPropagation.get(span.context(), <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-country-code"</span>);</pre><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>A difference from previous versions of Sleuth is that, with Brave, you must pass the list of baggage keys.
|
||||
There are two properties to achieve this.
|
||||
With the <code class="literal">spring.sleuth.baggage-keys</code>, you set keys that get prefixed with <code class="literal">baggage-</code> for HTTP calls and <code class="literal">baggage_</code> for messaging.
|
||||
You can also use the <code class="literal">spring.sleuth.propagation-keys</code> property to pass a list of prefixed keys that are whitelisted without any prefix.
|
||||
Notice that there’s no <code class="literal">x-</code> in front of the header keys.</p></td></tr></table></div><p>In order to automatically set the baggage values to Slf4j’s MDC, you have to set
|
||||
the <code class="literal">spring.sleuth.log.slf4j.whitelisted-mdc-keys</code> property with a list of whitelisted
|
||||
baggage and propagation keys. E.g. <code class="literal">spring.sleuth.log.slf4j.whitelisted-mdc-keys=foo</code> will set the value of the <code class="literal">foo</code> baggage into MDC.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Remember that adding entries to MDC can drastically decrease the performance of your application!</p></td></tr></table></div><p>If you want to add the baggage entries as tags, to make it possible to search for spans via the baggage entries, you can set the value of
|
||||
<code class="literal">spring.sleuth.propagation.tag.whitelisted-keys</code> with a list of whitelisted baggage keys. To disable the feature you have to pass the <code class="literal">spring.sleuth.propagation.tag.enabled=false</code> property.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_extracting_a_propagated_context" href="#_extracting_a_propagated_context"></a>54.1.2 Extracting a Propagated Context</h3></div></div></div><p>The <code class="literal">TraceContext.Extractor<C></code> reads trace identifiers and sampling status from an incoming request or message.
|
||||
The carrier is usually a request object or headers.</p><p>This utility is used in standard instrumentation (such as <code class="literal">HttpServerHandler</code>) but can also be used for custom RPC or messaging code.</p><p><code class="literal">TraceContextOrSamplingFlags</code> is usually used only with <code class="literal">Tracer.nextSpan(extracted)</code>, unless you are
|
||||
sharing span IDs between a client and a server.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_sharing_span_ids_between_client_and_server" href="#_sharing_span_ids_between_client_and_server"></a>54.1.3 Sharing span IDs between Client and Server</h3></div></div></div><p>A normal instrumentation pattern is to create a span representing the server side of an RPC.
|
||||
<code class="literal">Extractor.extract</code> might return a complete trace context when applied to an incoming client request.
|
||||
<code class="literal">Tracer.joinSpan</code> attempts to continue this trace, using the same span ID if supported or creating a child span
|
||||
if not. When the span ID is shared, the reported data includes a flag saying so.</p><p>The following image shows an example of B3 propagation:</p><pre class="screen"> ┌───────────────────┐ ┌───────────────────┐
|
||||
Incoming Headers │ TraceContext │ │ TraceContext │
|
||||
┌───────────────────┐(extract)│ ┌───────────────┐ │(join)│ ┌───────────────┐ │
|
||||
│ X─B3-TraceId │─────────┼─┼> TraceId │ │──────┼─┼> TraceId │ │
|
||||
│ │ │ │ │ │ │ │ │ │
|
||||
│ X─B3-ParentSpanId │─────────┼─┼> ParentSpanId │ │──────┼─┼> ParentSpanId │ │
|
||||
│ │ │ │ │ │ │ │ │ │
|
||||
│ X─B3-SpanId │─────────┼─┼> SpanId │ │──────┼─┼> SpanId │ │
|
||||
└───────────────────┘ │ │ │ │ │ │ │ │
|
||||
│ │ │ │ │ │ Shared: true │ │
|
||||
│ └───────────────┘ │ │ └───────────────┘ │
|
||||
└───────────────────┘ └───────────────────┘</pre><p>Some propagation systems forward only the parent span ID, detected when <code class="literal">Propagation.Factory.supportsJoin() == false</code>.
|
||||
In this case, a new span ID is always provisioned, and the incoming context determines the parent ID.</p><p>The following image shows an example of AWS propagation:</p><pre class="screen"> ┌───────────────────┐ ┌───────────────────┐
|
||||
x-amzn-trace-id │ TraceContext │ │ TraceContext │
|
||||
┌───────────────────┐(extract)│ ┌───────────────┐ │(join)│ ┌───────────────┐ │
|
||||
│ Root │─────────┼─┼> TraceId │ │──────┼─┼> TraceId │ │
|
||||
│ │ │ │ │ │ │ │ │ │
|
||||
│ Parent │─────────┼─┼> SpanId │ │──────┼─┼> ParentSpanId │ │
|
||||
└───────────────────┘ │ └───────────────┘ │ │ │ │ │
|
||||
└───────────────────┘ │ │ SpanId: New │ │
|
||||
│ └───────────────┘ │
|
||||
└───────────────────┘</pre><p>Note: Some span reporters do not support sharing span IDs.
|
||||
For example, if you set <code class="literal">Tracing.Builder.spanReporter(amazonXrayOrGoogleStackdrive)</code>, you should disable join by setting <code class="literal">Tracing.Builder.supportsJoin(false)</code>.
|
||||
Doing so forces a new child span on <code class="literal">Tracer.joinSpan()</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_implementing_propagation" href="#_implementing_propagation"></a>54.1.4 Implementing Propagation</h3></div></div></div><p><code class="literal">TraceContext.Extractor<C></code> is implemented by a <code class="literal">Propagation.Factory</code> plugin.
|
||||
Internally, this code creates the union type, <code class="literal">TraceContextOrSamplingFlags</code>, with one of the following:
|
||||
* <code class="literal">TraceContext</code> if trace and span IDs were present.
|
||||
* <code class="literal">TraceIdContext</code> if a trace ID was present but span IDs were not present.
|
||||
* <code class="literal">SamplingFlags</code> if no identifiers were present.</p><p>Some <code class="literal">Propagation</code> implementations carry extra data from the point of extraction (for example, reading incoming headers) to injection (for example, writing outgoing headers).
|
||||
For example, it might carry a request ID.
|
||||
When implementations have extra data, they handle it as follows:
|
||||
* If a <code class="literal">TraceContext</code> were extracted, add the extra data as <code class="literal">TraceContext.extra()</code>.
|
||||
* Otherwise, add it as <code class="literal">TraceContextOrSamplingFlags.extra()</code>, which <code class="literal">Tracer.nextSpan</code> handles.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__sampling.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_sleuth.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__current_tracing_component.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">53. Sampling </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 55. Current Tracing Component</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,11 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>9. Push Notifications and Spring Cloud Bus</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_config.html" title="Part II. Spring Cloud Config"><link rel="prev" href="multi__embedding_the_config_server.html" title="8. Embedding the Config Server"><link rel="next" href="multi__spring_cloud_config_client.html" title="10. Spring Cloud Config Client"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">9. Push Notifications and Spring Cloud Bus</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__embedding_the_config_server.html">Prev</a> </td><th width="60%" align="center">Part II. Spring Cloud Config</th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_config_client.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_push_notifications_and_spring_cloud_bus" href="#_push_notifications_and_spring_cloud_bus"></a>9. Push Notifications and Spring Cloud Bus</h2></div></div></div><p>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.
|
||||
For instance, <a class="link" href="https://developer.github.com/v3/activity/events/types/#pushevent" target="_top">Github</a> uses a POST to the webhook with a JSON body containing a list of commits and a header (<code class="literal">X-Github-Event</code>) set to <code class="literal">push</code>.
|
||||
If you add a dependency on the <code class="literal">spring-cloud-config-monitor</code> library and activate the Spring Cloud Bus in your Config Server, then a <code class="literal">/monitor</code> endpoint is enabled.</p><p>When the webhook is activated, the Config Server sends a <code class="literal">RefreshRemoteApplicationEvent</code> targeted at the applications it thinks might have changed.
|
||||
The change detection can be strategized.
|
||||
However, by default, it looks for changes in files that match the application name (for example, <code class="literal">foo.properties</code> is targeted at the <code class="literal">foo</code> application, while <code class="literal">application.properties</code> is targeted at all applications).
|
||||
The strategy to use when you want to override the behavior is <code class="literal">PropertyPathNotificationExtractor</code>, which accepts the request headers and body as parameters and returns a list of file paths that changed.</p><p>The default configuration works out of the box with Github, Gitlab, Gitea, Gitee, Gogs or Bitbucket.
|
||||
In addition to the JSON notifications from Github, Gitlab, Gitee, or Bitbucket, you can trigger a change notification by POSTing to <code class="literal">/monitor</code> with form-encoded body parameters in the pattern of <code class="literal">path={name}</code>.
|
||||
Doing so broadcasts to applications matching the <code class="literal">{name}</code> pattern (which can contain wildcards).</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The <code class="literal">RefreshRemoteApplicationEvent</code> is transmitted only if the <code class="literal">spring-cloud-bus</code> is activated in both the Config Server and in the client application.</p></td></tr></table></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The 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.</p></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__embedding_the_config_server.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_config.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_config_client.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">8. Embedding the Config Server </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 10. Spring Cloud Config Client</td></tr></table></div></body></html>
|
||||
83
Greenwich.RC2/multi/multi__quick_start.html
Normal file
@@ -0,0 +1,83 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>4. Quick Start</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_config.html" title="Part II. Spring Cloud Config"><link rel="prev" href="multi__spring_cloud_config.html" title="Part II. Spring Cloud Config"><link rel="next" href="multi__spring_cloud_config_server.html" title="5. Spring Cloud Config Server"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4. Quick Start</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_config.html">Prev</a> </td><th width="60%" align="center">Part II. Spring Cloud Config</th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_config_server.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_quick_start" href="#_quick_start"></a>4. Quick Start</h2></div></div></div><p>This quick start walks through using both the server and the client of Spring Cloud Config Server.</p><p>First, start the server, as follows:</p><pre class="screen">$ cd spring-cloud-config-server
|
||||
$ ../mvnw spring-boot:run</pre><p>The server is a Spring Boot application, so you can run it from your IDE if you prefer to do so (the main class is <code class="literal">ConfigServerApplication</code>).</p><p>Next try out a client, as follows:</p><pre class="screen">$ curl localhost:8888/foo/development
|
||||
{"name":"foo","label":"master","propertySources":[
|
||||
{"name":"https://github.com/scratches/config-repo/foo-development.properties","source":{"bar":"spam"}},
|
||||
{"name":"https://github.com/scratches/config-repo/foo.properties","source":{"foo":"bar"}}
|
||||
]}</pre><p>The default strategy for locating property sources is to clone a git repository (at <code class="literal">spring.cloud.config.server.git.uri</code>) and use it to initialize a mini <code class="literal">SpringApplication</code>.
|
||||
The mini-application’s <code class="literal">Environment</code> is used to enumerate property sources and publish them at a JSON endpoint.</p><p>The HTTP service has resources in the following form:</p><pre class="screen">/{application}/{profile}[/{label}]
|
||||
/{application}-{profile}.yml
|
||||
/{label}/{application}-{profile}.yml
|
||||
/{application}-{profile}.properties
|
||||
/{label}/{application}-{profile}.properties</pre><p>where <code class="literal">application</code> is injected as the <code class="literal">spring.config.name</code> in the <code class="literal">SpringApplication</code> (what is normally <code class="literal">application</code> in a regular Spring Boot app), <code class="literal">profile</code> is an active profile (or comma-separated list of properties), and <code class="literal">label</code> is an optional git label (defaults to <code class="literal">master</code>.)</p><p>Spring Cloud Config Server pulls configuration for remote clients from a git repository (which must be provided), as shown in the following example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> config</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> server</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> git</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uri</span>: https://github.com/spring-cloud-samples/config-repo</pre><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_client_side_usage" href="#_client_side_usage"></a>4.1 Client Side Usage</h2></div></div></div><p>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 <code class="literal">org.springframework.cloud:spring-cloud-starter-config</code>.
|
||||
There is also a parent pom and BOM (<code class="literal">spring-cloud-starter-parent</code>) for Maven users and a Spring IO version management properties file for Gradle and Spring CLI users. The following example shows a typical Maven configuration:</p><p><b>pom.xml. </b>
|
||||
</p><pre class="programlisting"> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><parent></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-starter-parent<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>{spring-boot-docs-version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><relativePath /></span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- lookup parent from repository --></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></parent></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencyManagement></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-dependencies<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>{spring-cloud-version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><type></span>pom<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></type></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><scope></span>import<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></scope></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencyManagement></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependencies></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-config<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-starter-test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><scope></span>test<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></scope></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependencies></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><build></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><plugins></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><plugin></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.boot<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-boot-maven-plugin<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></plugin></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></plugins></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></build></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"><!-- repositories also needed for snapshots and milestones --></span></pre><p>
|
||||
</p><p>Now you can create a standard Spring Boot application, such as the following HTTP server:</p><pre class="screen">@SpringBootApplication
|
||||
@RestController
|
||||
public class Application {
|
||||
|
||||
@RequestMapping("/")
|
||||
public String home() {
|
||||
return "Hello World!";
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}</pre><p>When this HTTP server runs, it picks up the external configuration from the default local config server (if it is running) on port 8888.
|
||||
To modify the startup behavior, you can change the location of the config server by using <code class="literal">bootstrap.properties</code> (similar to <code class="literal">application.properties</code> but for the bootstrap phase of an application context), as shown in the following example:</p><pre class="screen">spring.cloud.config.uri: http://myconfigserver.com</pre><p>By default, if no application name is set, <code class="literal">application</code> will be used. To modify the name, the following property can be added to the <code class="literal">bootstrap.properties</code> file:</p><pre class="screen">spring.application.name: myapp</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>When setting the property <code class="literal">${spring.application.name}</code> do not prefix your app name with the reserved word <code class="literal">application-</code> to prevent issues resolving the correct property source.</p></td></tr></table></div><p>The bootstrap properties show up in the <code class="literal">/env</code> endpoint as a high-priority property source, as shown in the following example.</p><pre class="screen">$ curl localhost:8080/env
|
||||
{
|
||||
"profiles":[],
|
||||
"configService:https://github.com/spring-cloud-samples/config-repo/bar.properties":{"foo":"bar"},
|
||||
"servletContextInitParams":{},
|
||||
"systemProperties":{...},
|
||||
...
|
||||
}</pre><p>A property source called <code class="literal">``configService:<URL of remote repository>/<file name></code> contains the <code class="literal">foo</code> property with a value of <code class="literal">bar</code> and is highest priority.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The URL in the property source name is the git repository, not the config server URL.</p></td></tr></table></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_config.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_config.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_config_server.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part II. Spring Cloud Config </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 5. Spring Cloud Config Server</td></tr></table></div></body></html>
|
||||
53
Greenwich.RC2/multi/multi__quick_start_2.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>25. Quick Start</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_stream.html" title="Part V. Spring Cloud Stream"><link rel="prev" href="multi__a_brief_history_of_spring_s_data_integration_journey.html" title="24. A Brief History of Spring’s Data Integration Journey"><link rel="next" href="multi__what_s_new_in_2_0.html" title="26. What’s New in 2.0?"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">25. Quick Start</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__a_brief_history_of_spring_s_data_integration_journey.html">Prev</a> </td><th width="60%" align="center">Part V. Spring Cloud Stream</th><td width="20%" align="right"> <a accesskey="n" href="multi__what_s_new_in_2_0.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_quick_start_2" href="#_quick_start_2"></a>25. Quick Start</h2></div></div></div><p>You can try Spring Cloud Stream in less then 5 min even before you jump into any details by following this three-step guide.</p><p>We show you how to create a Spring Cloud Stream application that receives messages coming from the messaging middleware of your choice (more on this later) and logs received messages to the console.
|
||||
We call it <code class="literal">LoggingConsumer</code>.
|
||||
While not very practical, it provides a good introduction to some of the main concepts
|
||||
and abstractions, making it easier to digest the rest of this user guide.</p><p>The three steps are as follows:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><a class="xref" href="multi__quick_start_2.html#spring-cloud-stream-preface-creating-sample-application" title="25.1 Creating a Sample Application by Using Spring Initializr">Section 25.1, “Creating a Sample Application by Using Spring Initializr”</a></li><li class="listitem"><a class="xref" href="multi__quick_start_2.html#spring-cloud-stream-preface-importing-project" title="25.2 Importing the Project into Your IDE">Section 25.2, “Importing the Project into Your IDE”</a></li><li class="listitem"><a class="xref" href="multi__quick_start_2.html#spring-cloud-stream-preface-adding-message-handler" title="25.3 Adding a Message Handler, Building, and Running">Section 25.3, “Adding a Message Handler, Building, and Running”</a></li></ol></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="spring-cloud-stream-preface-creating-sample-application" href="#spring-cloud-stream-preface-creating-sample-application"></a>25.1 Creating a Sample Application by Using Spring Initializr</h2></div></div></div><p>To get started, visit the <a class="link" href="https://start.spring.io" target="_top">Spring Initializr</a>. From there, you can generate our <code class="literal">LoggingConsumer</code> application. To do so:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">In the <span class="strong"><strong>Dependencies</strong></span> section, start typing <code class="literal">stream</code>.
|
||||
When the “Cloud Stream” option should appears, select it.</li><li class="listitem">Start typing either 'kafka' or 'rabbit'.</li><li class="listitem"><p class="simpara">Select “Kafka” or “RabbitMQ”.</p><p class="simpara">Basically, you choose the messaging middleware to which your application binds.
|
||||
We recommend using the one you have already installed or feel more comfortable with installing and running.
|
||||
Also, as you can see from the Initilaizer screen, there are a few other options you can choose.
|
||||
For example, you can choose Gradle as your build tool instead of Maven (the default).</p></li><li class="listitem"><p class="simpara">In the <span class="strong"><strong>Artifact</strong></span> field, type 'logging-consumer'.</p><p class="simpara">The value of the <span class="strong"><strong>Artifact</strong></span> field becomes the application name.
|
||||
If you chose RabbitMQ for the middleware, your Spring Initializr should now be as follows:</p><div class="informalfigure"><div class="mediaobject"><img src="images/stream-initializr.png" alt="stream initializr"></div></div></li><li class="listitem"><p class="simpara">Click the <span class="strong"><strong>Generate Project</strong></span> button.</p><p class="simpara">Doing so downloads the zipped version of the generated project to your hard drive.</p></li><li class="listitem">Unzip the file into the folder you want to use as your project directory.</li></ol></div><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>We encourage you to explore the many possibilities available in the Spring Initializr.
|
||||
It lets you create many different kinds of Spring applications.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="spring-cloud-stream-preface-importing-project" href="#spring-cloud-stream-preface-importing-project"></a>25.2 Importing the Project into Your IDE</h2></div></div></div><p>Now you can import the project into your IDE.
|
||||
Keep in mind that, depending on the IDE, you may need to follow a specific import procedure.
|
||||
For example, depending on how the project was generated (Maven or Gradle), you may need to follow specific import procedure (for example, in Eclipse or STS, you need to use File → Import → Maven → Existing Maven Project).</p><p>Once imported, the project must have no errors of any kind. Also, <code class="literal">src/main/java</code> should contain <code class="literal">com.example.loggingconsumer.LoggingConsumerApplication</code>.</p><p>Technically, at this point, you can run the application’s main class.
|
||||
It is already a valid Spring Boot application.
|
||||
However, it does not do anything, so we want to add some code.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="spring-cloud-stream-preface-adding-message-handler" href="#spring-cloud-stream-preface-adding-message-handler"></a>25.3 Adding a Message Handler, Building, and Running</h2></div></div></div><p>Modify the <code class="literal">com.example.loggingconsumer.LoggingConsumerApplication</code> class to look as follows:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Sink.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> LoggingConsumerApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(LoggingConsumerApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Sink.INPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> handle(Person person) {
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Received: "</span> + person);
|
||||
}
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Person {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> String name;
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String getName() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> name;
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> setName(String name) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.name = name;
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String toString() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.name;
|
||||
}
|
||||
}
|
||||
}</pre><p>As you can see from the preceding listing:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">We have enabled <code class="literal">Sink</code> binding (input-no-output) by using <code class="literal">@EnableBinding(Sink.class)</code>.
|
||||
Doing so signals to the framework to initiate binding to the messaging middleware, where it automatically creates the destination (that is, queue, topic, and others) that are bound to the <code class="literal">Sink.INPUT</code> channel.</li><li class="listitem">We have added a <code class="literal">handler</code> method to receive incoming messages of type <code class="literal">Person</code>.
|
||||
Doing so lets you see one of the core features of the framework: It tries to automatically convert incoming message payloads to type <code class="literal">Person</code>.</li></ul></div><p>You now have a fully functional Spring Cloud Stream application that does listens for messages.
|
||||
From here, for simplicity, we assume you selected RabbitMQ in <a class="link" href="multi__quick_start_2.html#spring-cloud-stream-preface-creating-sample-application" title="25.1 Creating a Sample Application by Using Spring Initializr">step one</a>.
|
||||
Assuming you have RabbitMQ installed and running, you can start the application by running its <code class="literal">main</code> method in your IDE.</p><p>You should see following output:</p><pre class="screen"> --- [ main] c.s.b.r.p.RabbitExchangeQueueProvisioner : declaring queue for inbound: input.anonymous.CbMIwdkJSBO1ZoPDOtHtCg, bound to: input
|
||||
--- [ main] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: [localhost:5672]
|
||||
--- [ main] o.s.a.r.c.CachingConnectionFactory : Created new connection: rabbitConnectionFactory#2a3a299:0/SimpleConnection@66c83fc8. . .
|
||||
. . .
|
||||
--- [ main] o.s.i.a.i.AmqpInboundChannelAdapter : started inbound.input.anonymous.CbMIwdkJSBO1ZoPDOtHtCg
|
||||
. . .
|
||||
--- [ main] c.e.l.LoggingConsumerApplication : Started LoggingConsumerApplication in 2.531 seconds (JVM running for 2.897)</pre><p>Go to the RabbitMQ management console or any other RabbitMQ client and send a message to <code class="literal">input.anonymous.CbMIwdkJSBO1ZoPDOtHtCg</code>.
|
||||
The <code class="literal">anonymous.CbMIwdkJSBO1ZoPDOtHtCg</code> part represents the group name and is generated, so it is bound to be different in your environment.
|
||||
For something more predictable, you can use an explicit group name by setting <code class="literal">spring.cloud.stream.bindings.input.group=hello</code> (or whatever name you like).</p><p>The contents of the message should be a JSON representation of the <code class="literal">Person</code> class, as follows:</p><pre class="literallayout">{"name":"Sam Spade"}</pre><p>Then, in your console, you should see:</p><p><code class="literal">Received: Sam Spade</code></p><p>You can also build and package your application into a boot jar (by using <code class="literal">./mvnw clean install</code>) and run the built JAR by using the <code class="literal">java -jar</code> command.</p><p>Now you have a working (albeit very basic) Spring Cloud Stream application.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__a_brief_history_of_spring_s_data_integration_journey.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_stream.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__what_s_new_in_2_0.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">24. A Brief History of Spring’s Data Integration Journey </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 26. What’s New in 2.0?</td></tr></table></div></body></html>
|
||||
23
Greenwich.RC2/multi/multi__quick_start_3.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>42. Quick Start</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_bus.html" title="Part VII. Spring Cloud Bus"><link rel="prev" href="multi__spring_cloud_bus.html" title="Part VII. Spring Cloud Bus"><link rel="next" href="multi__bus_endpoints.html" title="43. Bus Endpoints"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">42. Quick Start</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_bus.html">Prev</a> </td><th width="60%" align="center">Part VII. Spring Cloud Bus</th><td width="20%" align="right"> <a accesskey="n" href="multi__bus_endpoints.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_quick_start_3" href="#_quick_start_3"></a>42. Quick Start</h2></div></div></div><p>Spring Cloud Bus works by adding Spring Boot autconfiguration if it detects itself on the
|
||||
classpath. To enable the bus, add <code class="literal">spring-cloud-starter-bus-amqp</code> or
|
||||
<code class="literal">spring-cloud-starter-bus-kafka</code> to your dependency management. Spring Cloud takes care of
|
||||
the rest. Make sure the broker (RabbitMQ or Kafka) is available and configured. When
|
||||
running on localhost, you need not do anything. If you run remotely, use Spring Cloud
|
||||
Connectors or Spring Boot conventions to define the broker credentials, as shown in the
|
||||
following example for Rabbit:</p><p><b>application.yml. </b>
|
||||
</p><pre class="screen">spring:
|
||||
rabbitmq:
|
||||
host: mybroker.com
|
||||
port: 5672
|
||||
username: user
|
||||
password: secret</pre><p>
|
||||
</p><p>The bus currently supports sending messages to all nodes listening or all nodes for a
|
||||
particular service (as defined by Eureka). The <code class="literal">/bus/*</code> actuator namespace has some HTTP
|
||||
endpoints. Currently, two are implemented. The first, <code class="literal">/bus/env</code>, sends key/value pairs to
|
||||
update each node’s Spring Environment. The second, <code class="literal">/bus/refresh</code>, reloads each
|
||||
application’s configuration, as though they had all been pinged on their <code class="literal">/refresh</code>
|
||||
endpoint.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>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 <code class="literal">spring-cloud-bus</code>.</p></td></tr></table></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_bus.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_bus.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__bus_endpoints.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part VII. Spring Cloud Bus </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 43. Bus Endpoints</td></tr></table></div></body></html>
|
||||
37
Greenwich.RC2/multi/multi__quick_start_4.html
Normal file
@@ -0,0 +1,37 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>99. Quick Start</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_vault.html" title="Part XIV. Spring Cloud Vault"><link rel="prev" href="multi__spring_cloud_vault.html" title="Part XIV. Spring Cloud Vault"><link rel="next" href="multi__client_side_usage_2.html" title="100. Client Side Usage"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">99. Quick Start</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_vault.html">Prev</a> </td><th width="60%" align="center">Part XIV. Spring Cloud Vault</th><td width="20%" align="right"> <a accesskey="n" href="multi__client_side_usage_2.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_quick_start_4" href="#_quick_start_4"></a>99. Quick Start</h2></div></div></div><p><span class="strong"><strong>Prerequisites</strong></span></p><p>To get started with Vault and this guide you need a
|
||||
*NIX-like operating systems that provides:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">wget</code>, <code class="literal">openssl</code> and <code class="literal">unzip</code></li><li class="listitem">at least Java 7 and a properly configured <code class="literal">JAVA_HOME</code> environment variable</li></ul></div><p><span class="strong"><strong>Install Vault</strong></span></p><pre class="programlisting">$ src/<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">test</span>/bash/install_vault.sh</pre><p><span class="strong"><strong>Create SSL certificates for Vault</strong></span></p><pre class="programlisting">$ src/<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">test</span>/bash/create_certificates.sh</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p><code class="literal">create_certificates.sh</code> creates certificates in <code class="literal">work/ca</code> and a JKS truststore <code class="literal">work/keystore.jks</code>. If you want to run Spring Cloud Vault using this quickstart guide you need to configure the truststore the <code class="literal">spring.cloud.vault.ssl.trust-store</code> property to <code class="literal">file:work/keystore.jks</code>.</p></td></tr></table></div><p><a name="quickstart.vault.start" href="#quickstart.vault.start"></a><span class="strong"><strong>Start Vault server</strong></span></p><pre class="programlisting">$ src/<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">test</span>/bash/local_run_vault.sh</pre><p>Vault is started listening on <code class="literal">0.0.0.0:8200</code> using the <code class="literal">inmem</code> storage and
|
||||
<code class="literal">https</code>.
|
||||
Vault is sealed and not initialized when starting up.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>If you want to run tests, leave Vault uninitialized. The tests will
|
||||
initialize Vault and create a root token <code class="literal">00000000-0000-0000-0000-000000000000</code>.</p></td></tr></table></div><p>If you want to use Vault for your application or give it a try then you need to initialize it first.</p><pre class="programlisting">$ <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">export</span> VAULT_ADDR=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"https://localhost:8200"</span>
|
||||
$ <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">export</span> VAULT_SKIP_VERIFY=true <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"># Don't do this for production</span>
|
||||
$ vault init</pre><p>You should see something like:</p><pre class="programlisting">Key <span class="hl-number">1</span>: <span class="hl-number">7149</span>c6a2e16b8833f6eb1e76df03e47f6113a3288b3093faf5033d44f0e70fe701
|
||||
Key <span class="hl-number">2</span>: <span class="hl-number">901</span>c534c7988c18c20435a85213c683bdcf0efcd82e38e2893779f152978c18c02
|
||||
Key <span class="hl-number">3</span>: <span class="hl-number">03</span>ff3948575b1165a20c20ee7c3e6edf04f4cdbe0e82dbff5be49c63f98bc03a03
|
||||
Key <span class="hl-number">4</span>: <span class="hl-number">216</span>ae5cc3ddaf93ceb8e1d15bb9fc3176653f5b738f5f3d1ee00cd7dccbe926e04
|
||||
Key <span class="hl-number">5</span>: b2898fc8130929d569c1677ee69dc5f3be57d7c4b494a6062693ce0b1c4d93d805
|
||||
Initial Root Token: <span class="hl-number">19</span>aefa97-cccc-bbbb-aaaa-<span class="hl-number">225940</span>e63d76
|
||||
|
||||
Vault initialized with <span class="hl-number">5</span> keys and a key threshold of <span class="hl-number">3.</span> Please
|
||||
securely distribute the above keys. When the Vault is re-sealed,
|
||||
restarted, or stopped, you must provide at least <span class="hl-number">3</span> of these keys
|
||||
to unseal it again.
|
||||
|
||||
Vault does not store the master key. Without at least <span class="hl-number">3</span> keys,
|
||||
your Vault will remain permanently sealed.</pre><p>Vault will initialize and return a set of unsealing keys and the root token.
|
||||
Pick 3 keys and unseal Vault. Store the Vault token in the <code class="literal">VAULT_TOKEN</code>
|
||||
environment variable.</p><pre class="programlisting">$ vault unseal (Key <span class="hl-number">1</span>)
|
||||
$ vault unseal (Key <span class="hl-number">2</span>)
|
||||
$ vault unseal (Key <span class="hl-number">3</span>)
|
||||
$ <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">export</span> VAULT_TOKEN=(Root token)
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"># Required to run Spring Cloud Vault tests after manual initialization</span>
|
||||
$ vault token-create -id=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"00000000-0000-0000-0000-000000000000"</span> -policy=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"root"</span></pre><p>Spring Cloud Vault accesses different resources. By default, the secret
|
||||
backend is enabled which accesses secret config settings via JSON endpoints.</p><p>The HTTP service has resources in the form:</p><pre class="screen">/secret/{application}/{profile}
|
||||
/secret/{application}
|
||||
/secret/{defaultContext}/{profile}
|
||||
/secret/{defaultContext}</pre><p>where the "application" is injected as the <code class="literal">spring.application.name</code> in the
|
||||
<code class="literal">SpringApplication</code> (i.e. what is normally "application" in a regular
|
||||
Spring Boot app), "profile" is an active profile (or comma-separated
|
||||
list of properties). Properties retrieved from Vault will be used "as-is"
|
||||
without further prefixing of the property names.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_vault.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_vault.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__client_side_usage_2.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part XIV. Spring Cloud Vault </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 100. Client Side Usage</td></tr></table></div></body></html>
|
||||
72
Greenwich.RC2/multi/multi__quickstart.html
Normal file
@@ -0,0 +1,72 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>81. Quickstart</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_security.html" title="Part XI. Spring Cloud Security"><link rel="prev" href="multi__spring_cloud_security.html" title="Part XI. Spring Cloud Security"><link rel="next" href="multi__more_detail.html" title="82. More Detail"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">81. Quickstart</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_security.html">Prev</a> </td><th width="60%" align="center">Part XI. Spring Cloud Security</th><td width="20%" align="right"> <a accesskey="n" href="multi__more_detail.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_quickstart" href="#_quickstart"></a>81. Quickstart</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_oauth2_single_sign_on" href="#_oauth2_single_sign_on"></a>81.1 OAuth2 Single Sign On</h2></div></div></div><p>Here’s a Spring Cloud "Hello World" app with HTTP Basic
|
||||
authentication and a single user account:</p><p><b>app.groovy. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Grab('spring-boot-starter-security')</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Controller</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestMapping('/')</span></em>
|
||||
String home() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'Hello World'</span>
|
||||
}
|
||||
|
||||
}</pre><p>
|
||||
</p><p>You can run it with <code class="literal">spring run app.groovy</code> and watch the logs for the password (username is "user"). So far this is just the default for a Spring Boot app.</p><p>Here’s a Spring Cloud app with OAuth2 SSO:</p><p><b>app.groovy. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Controller</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableOAuth2Sso</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestMapping('/')</span></em>
|
||||
String home() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'Hello World'</span>
|
||||
}
|
||||
|
||||
}</pre><p>
|
||||
</p><p>Spot the difference? This app will actually behave exactly the same as
|
||||
the previous one, because it doesn’t know it’s OAuth2 credentals
|
||||
yet.</p><p>You can register an app in github quite easily, so try that if you
|
||||
want a production app on your own domain. If you are happy to test on
|
||||
localhost:8080, then set up these properties in your application
|
||||
configuration:</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">security</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> oauth2</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> client</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> clientId</span>: bd1c0a783ccdd1c9b9e4
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> clientSecret</span>: <span class="hl-number">1</span>a9030fbca47a5b2c28e92f19050bb77824b5ad1
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> accessTokenUri</span>: https://github.com/login/oauth/access_token
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> userAuthorizationUri</span>: https://github.com/login/oauth/authorize
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> clientAuthenticationScheme</span>: form
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> resource</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> userInfoUri</span>: https://api.github.com/user
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> preferTokenInfo</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">false</span></pre><p>
|
||||
</p><p>run the app above and it will redirect to github for authorization. If
|
||||
you are already signed into github you won’t even notice that it has
|
||||
authenticated. These credentials will only work if your app is
|
||||
running on port 8080.</p><p>To limit the scope that the client asks for when it obtains an access token
|
||||
you can set <code class="literal">security.oauth2.client.scope</code> (comma separated or an array in YAML). By
|
||||
default the scope is empty and it is up to to Authorization Server to
|
||||
decide what the defaults should be, usually depending on the settings in
|
||||
the client registration that it holds.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The examples above are all Groovy scripts. If you want to write the
|
||||
same code in Java (or Groovy) you need to add Spring Security OAuth2
|
||||
to the classpath (e.g. see the
|
||||
<a class="link" href="https://github.com/spring-cloud-samples/sso" target="_top">sample here</a>).</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_oauth2_protected_resource" href="#_oauth2_protected_resource"></a>81.2 OAuth2 Protected Resource</h2></div></div></div><p>You want to protect an API resource with an OAuth2 token? Here’s a
|
||||
simple example (paired with the client above):</p><p><b>app.groovy. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Grab('spring-cloud-starter-security')</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@RestController</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableResourceServer</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RequestMapping('/')</span></em>
|
||||
def home() {
|
||||
[message: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'Hello World'</span>]
|
||||
}
|
||||
|
||||
}</pre><p>
|
||||
</p><p>and</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">security</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> oauth2</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> resource</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> userInfoUri</span>: https://api.github.com/user
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> preferTokenInfo</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">false</span></pre><p>
|
||||
</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_security.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_security.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__more_detail.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part XI. Spring Cloud Security </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 82. More Detail</td></tr></table></div></body></html>
|
||||
428
Greenwich.RC2/multi/multi__rabbitmq_binder.html
Normal file
@@ -0,0 +1,428 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>41. RabbitMQ Binder</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__binder_implementations.html" title="Part VI. Binder Implementations"><link rel="prev" href="multi__apache_kafka_streams_binder.html" title="40. Apache Kafka Streams Binder"><link rel="next" href="multi__spring_cloud_bus.html" title="Part VII. Spring Cloud Bus"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">41. RabbitMQ Binder</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__apache_kafka_streams_binder.html">Prev</a> </td><th width="60%" align="center">Part VI. Binder Implementations</th><td width="20%" align="right"> <a accesskey="n" href="multi__spring_cloud_bus.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_rabbitmq_binder" href="#_rabbitmq_binder"></a>41. RabbitMQ Binder</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_usage_3" href="#_usage_3"></a>41.1 Usage</h2></div></div></div><p>To use the RabbitMQ binder, you can add it to your Spring Cloud Stream application, by using the following Maven coordinates:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-stream-binder-rabbit<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p>Alternatively, you can use the Spring Cloud Stream RabbitMQ Starter, as follows:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-stream-rabbit<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_rabbitmq_binder_overview" href="#_rabbitmq_binder_overview"></a>41.2 RabbitMQ Binder Overview</h2></div></div></div><p>The following simplified diagram shows how the RabbitMQ binder operates:</p><div class="figure"><a name="d0e13595" href="#d0e13595"></a><p class="title"><b>Figure 41.1. RabbitMQ Binder</b></p><div class="figure-contents"><div class="mediaobject"><img src="images/rabbit-binder.png" alt="rabbit binder"></div></div></div><br class="figure-break"><p>By default, the RabbitMQ Binder implementation maps each destination to a <code class="literal">TopicExchange</code>.
|
||||
For each consumer group, a <code class="literal">Queue</code> is bound to that <code class="literal">TopicExchange</code>.
|
||||
Each consumer instance has a corresponding RabbitMQ <code class="literal">Consumer</code> instance for its group’s <code class="literal">Queue</code>.
|
||||
For partitioned producers and consumers, the queues are suffixed with the partition index and use the partition index as the routing key.
|
||||
For anonymous consumers (those with no <code class="literal">group</code> property), an auto-delete queue (with a randomized unique name) is used.</p><p>By using the optional <code class="literal">autoBindDlq</code> option, you can configure the binder to create and configure dead-letter queues (DLQs) (and a dead-letter exchange <code class="literal">DLX</code>, as well as routing infrastructure).
|
||||
By default, the dead letter queue has the name of the destination, appended with <code class="literal">.dlq</code>.
|
||||
If retry is enabled (<code class="literal">maxAttempts > 1</code>), failed messages are delivered to the DLQ after retries are exhausted.
|
||||
If retry is disabled (<code class="literal">maxAttempts = 1</code>), you should set <code class="literal">requeueRejected</code> to <code class="literal">false</code> (the default) so that failed messages are routed to the DLQ, instead of being re-queued.
|
||||
In addition, <code class="literal">republishToDlq</code> causes the binder to publish a failed message to the DLQ (instead of rejecting it).
|
||||
This feature lets additional information (such as the stack trace in the <code class="literal">x-exception-stacktrace</code> header) be added to the message in headers.
|
||||
This option does not need retry enabled.
|
||||
You can republish a failed message after just one attempt.
|
||||
Starting with version 1.2, you can configure the delivery mode of republished messages.
|
||||
See the <a class="link" href="multi__rabbitmq_binder.html#spring-cloud-stream-rabbit-republish-delivery-mode"><code class="literal">republishDeliveryMode</code> property</a>.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Setting <code class="literal">requeueRejected</code> to <code class="literal">true</code> (with <code class="literal">republishToDlq=false</code> ) causes the message to be re-queued and redelivered continually, which is likely not what you want unless the reason for the failure is transient.
|
||||
In general, you should enable retry within the binder by setting <code class="literal">maxAttempts</code> to greater than one or by setting <code class="literal">republishToDlq</code> to <code class="literal">true</code>.</p></td></tr></table></div><p>See <a class="xref" href="multi__rabbitmq_binder.html#rabbit-binder-properties" title="41.3.1 RabbitMQ Binder Properties">Section 41.3.1, “RabbitMQ Binder Properties”</a> for more information about these properties.</p><p>The framework does not provide any standard mechanism to consume dead-letter messages (or to re-route them back to the primary queue).
|
||||
Some options are described in <a class="xref" href="multi__rabbitmq_binder.html#rabbit-dlq-processing" title="41.6 Dead-Letter Queue Processing">Section 41.6, “Dead-Letter Queue Processing”</a>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>When multiple RabbitMQ binders are used in a Spring Cloud Stream application, it is important to disable 'RabbitAutoConfiguration' to avoid the same configuration from <code class="literal">RabbitAutoConfiguration</code> being applied to the two binders.
|
||||
You can exclude the class by using the <code class="literal">@SpringBootApplication</code> annotation.</p></td></tr></table></div><p>Starting with version 2.0, the <code class="literal">RabbitMessageChannelBinder</code> sets the <code class="literal">RabbitTemplate.userPublisherConnection</code> property to <code class="literal">true</code> so that the non-transactional producers avoid deadlocks on consumers, which can happen if cached connections are blocked because of a <a class="link" href="https://www.rabbitmq.com/memory.html" target="_top">memory alarm</a> on the broker.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Currently, a <code class="literal">multiplex</code> consumer (a single consumer listening to multiple queues) is only supported for message-driven conssumers; polled consumers can only retrieve messages from a single queue.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_configuration_options_4" href="#_configuration_options_4"></a>41.3 Configuration Options</h2></div></div></div><p>This section contains settings specific to the RabbitMQ Binder and bound channels.</p><p>For general binding configuration options and properties, see the <a class="link" href="https://github.com/spring-cloud/spring-cloud-stream/blob/master/spring-cloud-stream-core-docs/src/main/asciidoc/spring-cloud-stream-overview.adoc#configuration-options" target="_top">Spring Cloud Stream core documentation</a>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="rabbit-binder-properties" href="#rabbit-binder-properties"></a>41.3.1 RabbitMQ Binder Properties</h3></div></div></div><p>By default, the RabbitMQ binder uses Spring Boot’s <code class="literal">ConnectionFactory</code>.
|
||||
Conseuqently, it supports all Spring Boot configuration options for RabbitMQ.
|
||||
(For reference, see the <a class="link" href="http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#common-application-properties" target="_top">Spring Boot documentation</a>).
|
||||
RabbitMQ configuration options use the <code class="literal">spring.rabbitmq</code> prefix.</p><p>In addition to Spring Boot options, the RabbitMQ binder supports the following properties:</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">spring.cloud.stream.rabbit.binder.adminAddresses</span></dt><dd><p class="simpara">A comma-separated list of RabbitMQ management plugin URLs.
|
||||
Only used when <code class="literal">nodes</code> contains more than one entry.
|
||||
Each entry in this list must have a corresponding entry in <code class="literal">spring.rabbitmq.addresses</code>.
|
||||
Only needed if you use a RabbitMQ cluster and wish to consume from the node that hosts the queue.
|
||||
See <a class="link" href="https://docs.spring.io/spring-amqp/reference/html/_reference.html#queue-affinity" target="_top">Queue Affinity and the LocalizedQueueConnectionFactory</a> for more information.</p><p class="simpara">Default: empty.</p></dd><dt><span class="term">spring.cloud.stream.rabbit.binder.nodes</span></dt><dd><p class="simpara">A comma-separated list of RabbitMQ node names.
|
||||
When more than one entry, used to locate the server address where a queue is located.
|
||||
Each entry in this list must have a corresponding entry in <code class="literal">spring.rabbitmq.addresses</code>.
|
||||
Only needed if you use a RabbitMQ cluster and wish to consume from the node that hosts the queue.
|
||||
See <a class="link" href="https://docs.spring.io/spring-amqp/reference/html/_reference.html#queue-affinity" target="_top">Queue Affinity and the LocalizedQueueConnectionFactory</a> for more information.</p><p class="simpara">Default: empty.</p></dd><dt><span class="term">spring.cloud.stream.rabbit.binder.compressionLevel</span></dt><dd><p class="simpara">The compression level for compressed bindings.
|
||||
See <code class="literal">java.util.zip.Deflater</code>.</p><p class="simpara">Default: <code class="literal">1</code> (BEST_LEVEL).</p></dd><dt><span class="term">spring.cloud.stream.binder.connection-name-prefix</span></dt><dd><p class="simpara">A connection name prefix used to name the connection(s) created by this binder.
|
||||
The name is this prefix followed by <code class="literal">#n</code>, where <code class="literal">n</code> increments each time a new connection is opened.</p><p class="simpara">Default: none (Spring AMQP default).</p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_rabbitmq_consumer_properties" href="#_rabbitmq_consumer_properties"></a>41.3.2 RabbitMQ Consumer Properties</h3></div></div></div><p>The following properties are available for Rabbit consumers only and must be prefixed with <code class="literal">spring.cloud.stream.rabbit.bindings.<channelName>.consumer.</code>.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">acknowledgeMode</span></dt><dd><p class="simpara">The acknowledge mode.</p><p class="simpara">Default: <code class="literal">AUTO</code>.</p></dd><dt><span class="term">autoBindDlq</span></dt><dd><p class="simpara">Whether to automatically declare the DLQ and bind it to the binder DLX.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">bindingRoutingKey</span></dt><dd><p class="simpara">The routing key with which to bind the queue to the exchange (if <code class="literal">bindQueue</code> is <code class="literal">true</code>).
|
||||
For partitioned destinations, <code class="literal">-<instanceIndex></code> is appended.</p><p class="simpara">Default: <code class="literal">#</code>.</p></dd><dt><span class="term">bindQueue</span></dt><dd><p class="simpara">Whether to bind the queue to the destination exchange.
|
||||
Set it to <code class="literal">false</code> if you have set up your own infrastructure and have previously created and bound the queue.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">consumerTagPrefix</span></dt><dd><p class="simpara">Used to create the consumer tag(s); will be appended by <code class="literal">#n</code> where <code class="literal">n</code> increments for each consumer created.
|
||||
Example: <code class="literal">${spring.application.name}-${spring.cloud.stream.bindings.input.group}-${spring.cloud.stream.instance-index}</code>.</p><p class="simpara">Default: none - the broker will generate random consumer tags.</p></dd><dt><span class="term">deadLetterQueueName</span></dt><dd><p class="simpara">The name of the DLQ</p><p class="simpara">Default: <code class="literal">prefix+destination.dlq</code></p></dd><dt><span class="term">deadLetterExchange</span></dt><dd><p class="simpara">A DLX to assign to the queue.
|
||||
Relevant only if <code class="literal">autoBindDlq</code> is <code class="literal">true</code>.</p><p class="simpara">Default: 'prefix+DLX'</p></dd><dt><span class="term">deadLetterExchangeType</span></dt><dd><p class="simpara">The type of the DLX to assign to the queue.
|
||||
Relevant only if <code class="literal">autoBindDlq</code> is <code class="literal">true</code>.</p><p class="simpara">Default: 'direct'</p></dd><dt><span class="term">deadLetterRoutingKey</span></dt><dd><p class="simpara">A dead letter routing key to assign to the queue.
|
||||
Relevant only if <code class="literal">autoBindDlq</code> is <code class="literal">true</code>.</p><p class="simpara">Default: <code class="literal">destination</code></p></dd><dt><span class="term">declareDlx</span></dt><dd><p class="simpara">Whether to declare the dead letter exchange for the destination.
|
||||
Relevant only if <code class="literal">autoBindDlq</code> is <code class="literal">true</code>.
|
||||
Set to <code class="literal">false</code> if you have a pre-configured DLX.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">declareExchange</span></dt><dd><p class="simpara">Whether to declare the exchange for the destination.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">delayedExchange</span></dt><dd><p class="simpara">Whether to declare the exchange as a <code class="literal">Delayed Message Exchange</code>.
|
||||
Requires the delayed message exchange plugin on the broker.
|
||||
The <code class="literal">x-delayed-type</code> argument is set to the <code class="literal">exchangeType</code>.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">dlqDeadLetterExchange</span></dt><dd><p class="simpara">If a DLQ is declared, a DLX to assign to that queue.</p><p class="simpara">Default: <code class="literal">none</code></p></dd><dt><span class="term">dlqDeadLetterRoutingKey</span></dt><dd><p class="simpara">If a DLQ is declared, a dead letter routing key to assign to that queue.</p><p class="simpara">Default: <code class="literal">none</code></p></dd><dt><span class="term">dlqExpires</span></dt><dd><p class="simpara">How long before an unused dead letter queue is deleted (in milliseconds).</p><p class="simpara">Default: <code class="literal">no expiration</code></p></dd><dt><span class="term">dlqLazy</span></dt><dd><p class="simpara">Declare the dead letter queue with the <code class="literal">x-queue-mode=lazy</code> argument.
|
||||
See <a class="link" href="https://www.rabbitmq.com/lazy-queues.html" target="_top">“Lazy Queues”</a>.
|
||||
Consider using a policy instead of this setting, because using a policy allows changing the setting without deleting the queue.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">dlqMaxLength</span></dt><dd><p class="simpara">Maximum number of messages in the dead letter queue.</p><p class="simpara">Default: <code class="literal">no limit</code></p></dd><dt><span class="term">dlqMaxLengthBytes</span></dt><dd><p class="simpara">Maximum number of total bytes in the dead letter queue from all messages.</p><p class="simpara">Default: <code class="literal">no limit</code></p></dd><dt><span class="term">dlqMaxPriority</span></dt><dd><p class="simpara">Maximum priority of messages in the dead letter queue (0-255).</p><p class="simpara">Default: <code class="literal">none</code></p></dd><dt><span class="term">dlqOverflowBehavior</span></dt><dd><p class="simpara">Action to take when <code class="literal">dlqMaxLength</code> or <code class="literal">dlqMaxLengthBytes</code> is exceeded; currently <code class="literal">drop-head</code> or <code class="literal">reject-publish</code> but refer to the RabbitMQ documentation.</p><p class="simpara">Default: <code class="literal">none</code></p></dd><dt><span class="term">dlqTtl</span></dt><dd><p class="simpara">Default time to live to apply to the dead letter queue when declared (in milliseconds).</p><p class="simpara">Default: <code class="literal">no limit</code></p></dd><dt><span class="term">durableSubscription</span></dt><dd><p class="simpara">Whether the subscription should be durable.
|
||||
Only effective if <code class="literal">group</code> is also set.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">exchangeAutoDelete</span></dt><dd><p class="simpara">If <code class="literal">declareExchange</code> is true, whether the exchange should be auto-deleted (that is, removed after the last queue is removed).</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">exchangeDurable</span></dt><dd><p class="simpara">If <code class="literal">declareExchange</code> is true, whether the exchange should be durable (that is, it survives broker restart).</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">exchangeType</span></dt><dd><p class="simpara">The exchange type: <code class="literal">direct</code>, <code class="literal">fanout</code> or <code class="literal">topic</code> for non-partitioned destinations and <code class="literal">direct</code> or <code class="literal">topic</code> for partitioned destinations.</p><p class="simpara">Default: <code class="literal">topic</code>.</p></dd><dt><span class="term">exclusive</span></dt><dd><p class="simpara">Whether to create an exclusive consumer.
|
||||
Concurrency should be 1 when this is <code class="literal">true</code>.
|
||||
Often used when strict ordering is required but enabling a hot standby instance to take over after a failure.
|
||||
See <code class="literal">recoveryInterval</code>, which controls how often a standby instance attempts to consume.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">expires</span></dt><dd><p class="simpara">How long before an unused queue is deleted (in milliseconds).</p><p class="simpara">Default: <code class="literal">no expiration</code></p></dd><dt><span class="term">failedDeclarationRetryInterval</span></dt><dd><p class="simpara">The interval (in milliseconds) between attempts to consume from a queue if it is missing.</p><p class="simpara">Default: 5000</p></dd><dt><span class="term">headerPatterns</span></dt><dd><p class="simpara">Patterns for headers to be mapped from inbound messages.</p><p class="simpara">Default: <code class="literal">['*']</code> (all headers).</p></dd><dt><span class="term">lazy</span></dt><dd><p class="simpara">Declare the queue with the <code class="literal">x-queue-mode=lazy</code> argument.
|
||||
See <a class="link" href="https://www.rabbitmq.com/lazy-queues.html" target="_top">“Lazy Queues”</a>.
|
||||
Consider using a policy instead of this setting, because using a policy allows changing the setting without deleting the queue.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">maxConcurrency</span></dt><dd><p class="simpara">The maximum number of consumers.</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">maxLength</span></dt><dd><p class="simpara">The maximum number of messages in the queue.</p><p class="simpara">Default: <code class="literal">no limit</code></p></dd><dt><span class="term">maxLengthBytes</span></dt><dd><p class="simpara">The maximum number of total bytes in the queue from all messages.</p><p class="simpara">Default: <code class="literal">no limit</code></p></dd><dt><span class="term">maxPriority</span></dt><dd><p class="simpara">The maximum priority of messages in the queue (0-255).</p><p class="simpara">Default: <code class="literal">none</code></p></dd><dt><span class="term">missingQueuesFatal</span></dt><dd><p class="simpara">When the queue cannot be found, whether to treat the condition as fatal and stop the listener container.
|
||||
Defaults to <code class="literal">false</code> so that the container keeps trying to consume from the queue — for example, when using a cluster and the node hosting a non-HA queue is down.</p><p class="simpara">Default: <code class="literal">false</code></p></dd><dt><span class="term">overflowBehavior</span></dt><dd><p class="simpara">Action to take when <code class="literal">maxLength</code> or <code class="literal">maxLengthBytes</code> is exceeded; currently <code class="literal">drop-head</code> or <code class="literal">reject-publish</code> but refer to the RabbitMQ documentation.</p><p class="simpara">Default: <code class="literal">none</code></p></dd><dt><span class="term">prefetch</span></dt><dd><p class="simpara">Prefetch count.</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd><dt><span class="term">prefix</span></dt><dd><p class="simpara">A prefix to be added to the name of the <code class="literal">destination</code> and queues.</p><p class="simpara">Default: "".</p></dd><dt><span class="term">queueDeclarationRetries</span></dt><dd><p class="simpara">The number of times to retry consuming from a queue if it is missing.
|
||||
Relevant only when <code class="literal">missingQueuesFatal</code> is <code class="literal">true</code>.
|
||||
Otherwise, the container keeps retrying indefinitely.</p><p class="simpara">Default: <code class="literal">3</code></p></dd><dt><span class="term">queueNameGroupOnly</span></dt><dd><p class="simpara">When true, consume from a queue with a name equal to the <code class="literal">group</code>.
|
||||
Otherwise the queue name is <code class="literal">destination.group</code>.
|
||||
This is useful, for example, when using Spring Cloud Stream to consume from an existing RabbitMQ queue.</p><p class="simpara">Default: false.</p></dd><dt><span class="term">recoveryInterval</span></dt><dd><p class="simpara">The interval between connection recovery attempts, in milliseconds.</p><p class="simpara">Default: <code class="literal">5000</code>.</p></dd><dt><span class="term">requeueRejected</span></dt><dd><p class="simpara">Whether delivery failures should be re-queued when retry is disabled or <code class="literal">republishToDlq</code> is <code class="literal">false</code>.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd></dl></div><div class="variablelist"><a name="spring-cloud-stream-rabbit-republish-delivery-mode" href="#spring-cloud-stream-rabbit-republish-delivery-mode"></a><dl class="variablelist"><dt><span class="term">republishDeliveryMode</span></dt><dd><p class="simpara">When <code class="literal">republishToDlq</code> is <code class="literal">true</code>, specifies the delivery mode of the republished message.</p><p class="simpara">Default: <code class="literal">DeliveryMode.PERSISTENT</code></p></dd><dt><span class="term">republishToDlq</span></dt><dd><p class="simpara">By default, messages that fail after retries are exhausted are rejected.
|
||||
If a dead-letter queue (DLQ) is configured, RabbitMQ routes the failed message (unchanged) to the DLQ.
|
||||
If set to <code class="literal">true</code>, the binder republishs failed messages to the DLQ with additional headers, including the exception message and stack trace from the cause of the final failure.</p><p class="simpara">Default: false</p></dd><dt><span class="term">transacted</span></dt><dd><p class="simpara">Whether to use transacted channels.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">ttl</span></dt><dd><p class="simpara">Default time to live to apply to the queue when declared (in milliseconds).</p><p class="simpara">Default: <code class="literal">no limit</code></p></dd><dt><span class="term">txSize</span></dt><dd><p class="simpara">The number of deliveries between acks.</p><p class="simpara">Default: <code class="literal">1</code>.</p></dd></dl></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_advanced_listener_container_configuration" href="#_advanced_listener_container_configuration"></a>41.3.3 Advanced Listener Container Configuration</h3></div></div></div><p>To set listener container properties that are not exposed as binder or binding properties, add a single bean of type <code class="literal">ListenerContainerCustomizer</code> to the application context.
|
||||
The binder and binding properties will be set and then the customizer will be called.
|
||||
The customizer (<code class="literal">configure()</code> method) is provided with the queue name as well as the consumer group as arguments.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_rabbit_producer_properties" href="#_rabbit_producer_properties"></a>41.3.4 Rabbit Producer Properties</h3></div></div></div><p>The following properties are available for Rabbit producers only and
|
||||
must be prefixed with <code class="literal">spring.cloud.stream.rabbit.bindings.<channelName>.producer.</code>.</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">autoBindDlq</span></dt><dd><p class="simpara">Whether to automatically declare the DLQ and bind it to the binder DLX.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">batchingEnabled</span></dt><dd><p class="simpara">Whether to enable message batching by producers.
|
||||
Messages are batched into one message according to the following properties (described in the next three entries in this list): 'batchSize', <code class="literal">batchBufferLimit</code>, and <code class="literal">batchTimeout</code>.
|
||||
See <a class="link" href="https://docs.spring.io/spring-amqp//reference/html/_reference.html#template-batching" target="_top">Batching</a> for more information.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">batchSize</span></dt><dd><p class="simpara">The number of messages to buffer when batching is enabled.</p><p class="simpara">Default: <code class="literal">100</code>.</p></dd><dt><span class="term">batchBufferLimit</span></dt><dd><p class="simpara">The maximum buffer size when batching is enabled.</p><p class="simpara">Default: <code class="literal">10000</code>.</p></dd><dt><span class="term">batchTimeout</span></dt><dd><p class="simpara">The batch timeout when batching is enabled.</p><p class="simpara">Default: <code class="literal">5000</code>.</p></dd><dt><span class="term">bindingRoutingKey</span></dt><dd><p class="simpara">The routing key with which to bind the queue to the exchange (if <code class="literal">bindQueue</code> is <code class="literal">true</code>).
|
||||
Only applies to non-partitioned destinations.
|
||||
Only applies if <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">#</code>.</p></dd><dt><span class="term">bindQueue</span></dt><dd><p class="simpara">Whether to bind the queue to the destination exchange.
|
||||
Set it to <code class="literal">false</code> if you have set up your own infrastructure and have previously created and bound the queue.
|
||||
Only applies if <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">compress</span></dt><dd><p class="simpara">Whether data should be compressed when sent.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">deadLetterQueueName</span></dt><dd><p class="simpara">The name of the DLQ
|
||||
Only applies if <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">prefix+destination.dlq</code></p></dd><dt><span class="term">deadLetterExchange</span></dt><dd><p class="simpara">A DLX to assign to the queue.
|
||||
Relevant only when <code class="literal">autoBindDlq</code> is <code class="literal">true</code>.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: 'prefix+DLX'</p></dd><dt><span class="term">deadLetterExchangeType</span></dt><dd><p class="simpara">The type of the DLX to assign to the queue.
|
||||
Relevant only if <code class="literal">autoBindDlq</code> is <code class="literal">true</code>.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: 'direct'</p></dd><dt><span class="term">deadLetterRoutingKey</span></dt><dd><p class="simpara">A dead letter routing key to assign to the queue.
|
||||
Relevant only when <code class="literal">autoBindDlq</code> is <code class="literal">true</code>.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">destination</code></p></dd><dt><span class="term">declareDlx</span></dt><dd><p class="simpara">Whether to declare the dead letter exchange for the destination.
|
||||
Relevant only if <code class="literal">autoBindDlq</code> is <code class="literal">true</code>.
|
||||
Set to <code class="literal">false</code> if you have a pre-configured DLX.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">declareExchange</span></dt><dd><p class="simpara">Whether to declare the exchange for the destination.</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">delayExpression</span></dt><dd><p class="simpara">A SpEL expression to evaluate the delay to apply to the message (<code class="literal">x-delay</code> header).
|
||||
It has no effect if the exchange is not a delayed message exchange.</p><p class="simpara">Default: No <code class="literal">x-delay</code> header is set.</p></dd><dt><span class="term">delayedExchange</span></dt><dd><p class="simpara">Whether to declare the exchange as a <code class="literal">Delayed Message Exchange</code>.
|
||||
Requires the delayed message exchange plugin on the broker.
|
||||
The <code class="literal">x-delayed-type</code> argument is set to the <code class="literal">exchangeType</code>.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">deliveryMode</span></dt><dd><p class="simpara">The delivery mode.</p><p class="simpara">Default: <code class="literal">PERSISTENT</code>.</p></dd><dt><span class="term">dlqDeadLetterExchange</span></dt><dd><p class="simpara">When a DLQ is declared, a DLX to assign to that queue.
|
||||
Applies only if <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">none</code></p></dd><dt><span class="term">dlqDeadLetterRoutingKey</span></dt><dd><p class="simpara">When a DLQ is declared, a dead letter routing key to assign to that queue.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">none</code></p></dd><dt><span class="term">dlqExpires</span></dt><dd><p class="simpara">How long (in milliseconds) before an unused dead letter queue is deleted.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">no expiration</code></p></dd><dt><span class="term">dlqLazy</span></dt><dd>Declare the dead letter queue with the <code class="literal">x-queue-mode=lazy</code> argument.
|
||||
See <a class="link" href="https://www.rabbitmq.com/lazy-queues.html" target="_top">“Lazy Queues”</a>.
|
||||
Consider using a policy instead of this setting, because using a policy allows changing the setting without deleting the queue.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</dd><dt><span class="term">dlqMaxLength</span></dt><dd><p class="simpara">Maximum number of messages in the dead letter queue.
|
||||
Applies only if <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">no limit</code></p></dd><dt><span class="term">dlqMaxLengthBytes</span></dt><dd><p class="simpara">Maximum number of total bytes in the dead letter queue from all messages.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">no limit</code></p></dd><dt><span class="term">dlqMaxPriority</span></dt><dd><p class="simpara">Maximum priority of messages in the dead letter queue (0-255)
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">none</code></p></dd><dt><span class="term">dlqTtl</span></dt><dd><p class="simpara">Default time (in milliseconds) to live to apply to the dead letter queue when declared.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">no limit</code></p></dd><dt><span class="term">exchangeAutoDelete</span></dt><dd><p class="simpara">If <code class="literal">declareExchange</code> is <code class="literal">true</code>, whether the exchange should be auto-delete (it is removed after the last queue is removed).</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">exchangeDurable</span></dt><dd><p class="simpara">If <code class="literal">declareExchange</code> is <code class="literal">true</code>, whether the exchange should be durable (survives broker restart).</p><p class="simpara">Default: <code class="literal">true</code>.</p></dd><dt><span class="term">exchangeType</span></dt><dd><p class="simpara">The exchange type: <code class="literal">direct</code>, <code class="literal">fanout</code> or <code class="literal">topic</code> for non-partitioned destinations and <code class="literal">direct</code> or <code class="literal">topic</code> for partitioned destinations.</p><p class="simpara">Default: <code class="literal">topic</code>.</p></dd><dt><span class="term">expires</span></dt><dd><p class="simpara">How long (in milliseconds) before an unused queue is deleted.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">no expiration</code></p></dd><dt><span class="term">headerPatterns</span></dt><dd><p class="simpara">Patterns for headers to be mapped to outbound messages.</p><p class="simpara">Default: <code class="literal">['*']</code> (all headers).</p></dd><dt><span class="term">lazy</span></dt><dd><p class="simpara">Declare the queue with the <code class="literal">x-queue-mode=lazy</code> argument.
|
||||
See <a class="link" href="https://www.rabbitmq.com/lazy-queues.html" target="_top">“Lazy Queues”</a>.
|
||||
Consider using a policy instead of this setting, because using a policy allows changing the setting without deleting the queue.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">maxLength</span></dt><dd><p class="simpara">Maximum number of messages in the queue.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">no limit</code></p></dd><dt><span class="term">maxLengthBytes</span></dt><dd><p class="simpara">Maximum number of total bytes in the queue from all messages.
|
||||
Only applies if <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">no limit</code></p></dd><dt><span class="term">maxPriority</span></dt><dd><p class="simpara">Maximum priority of messages in the queue (0-255).
|
||||
Only applies if <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">none</code></p></dd><dt><span class="term">prefix</span></dt><dd><p class="simpara">A prefix to be added to the name of the <code class="literal">destination</code> exchange.</p><p class="simpara">Default: "".</p></dd><dt><span class="term">queueNameGroupOnly</span></dt><dd><p class="simpara">When <code class="literal">true</code>, consume from a queue with a name equal to the <code class="literal">group</code>.
|
||||
Otherwise the queue name is <code class="literal">destination.group</code>.
|
||||
This is useful, for example, when using Spring Cloud Stream to consume from an existing RabbitMQ queue.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: false.</p></dd><dt><span class="term">routingKeyExpression</span></dt><dd><p class="simpara">A SpEL expression to determine the routing key to use when publishing messages.
|
||||
For a fixed routing key, use a literal expression, such as <code class="literal">routingKeyExpression='my.routingKey'</code> in a properties file or <code class="literal">routingKeyExpression: '''my.routingKey'''</code> in a YAML file.</p><p class="simpara">Default: <code class="literal">destination</code> or <code class="literal">destination-<partition></code> for partitioned destinations.</p></dd><dt><span class="term">transacted</span></dt><dd><p class="simpara">Whether to use transacted channels.</p><p class="simpara">Default: <code class="literal">false</code>.</p></dd><dt><span class="term">ttl</span></dt><dd><p class="simpara">Default time (in milliseconds) to live to apply to the queue when declared.
|
||||
Applies only when <code class="literal">requiredGroups</code> are provided and then only to those groups.</p><p class="simpara">Default: <code class="literal">no limit</code></p></dd></dl></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>In the case of RabbitMQ, content type headers can be set by external applications.
|
||||
Spring Cloud Stream supports them as part of an extended internal protocol used for any type of transport — including transports, such as Kafka (prior to 0.11), that do not natively support headers.</p></td></tr></table></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_retry_with_the_rabbitmq_binder" href="#_retry_with_the_rabbitmq_binder"></a>41.4 Retry With the RabbitMQ Binder</h2></div></div></div><p>When retry is enabled within the binder, the listener container thread is suspended for any back off periods that are configured.
|
||||
This might be important when strict ordering is required with a single consumer. However, for other use cases, it prevents other messages from being processed on that thread.
|
||||
An alternative to using binder retry is to set up dead lettering with time to live on the dead-letter queue (DLQ) as well as dead-letter configuration on the DLQ itself.
|
||||
See “<a class="xref" href="multi__rabbitmq_binder.html#rabbit-binder-properties" title="41.3.1 RabbitMQ Binder Properties">Section 41.3.1, “RabbitMQ Binder Properties”</a>” for more information about the properties discussed here.
|
||||
You can use the following example configuration to enable this feature:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Set <code class="literal">autoBindDlq</code> to <code class="literal">true</code>.
|
||||
The binder create a DLQ.
|
||||
Optionally, you can specify a name in <code class="literal">deadLetterQueueName</code>.</li><li class="listitem">Set <code class="literal">dlqTtl</code> to the back off time you want to wait between redeliveries.</li><li class="listitem">Set the <code class="literal">dlqDeadLetterExchange</code> to the default exchange.
|
||||
Expired messages from the DLQ are routed to the original queue, because the default <code class="literal">deadLetterRoutingKey</code> is the queue name (<code class="literal">destination.group</code>).
|
||||
Setting to the default exchange is achieved by setting the property with no value, as shown in the next example.</li></ul></div><p>To force a message to be dead-lettered, either throw an <code class="literal">AmqpRejectAndDontRequeueException</code> or set <code class="literal">requeueRejected</code> to <code class="literal">true</code> (the default) and throw any exception.</p><p>The loop continue without end, which is fine for transient problems, but you may want to give up after some number of attempts.
|
||||
Fortunately, RabbitMQ provides the <code class="literal">x-death</code> header, which lets you determine how many cycles have occurred.</p><p>To acknowledge a message after giving up, throw an <code class="literal">ImmediateAcknowledgeAmqpException</code>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_putting_it_all_together" href="#_putting_it_all_together"></a>41.4.1 Putting it All Together</h3></div></div></div><p>The following configuration creates an exchange <code class="literal">myDestination</code> with queue <code class="literal">myDestination.consumerGroup</code> bound to a topic exchange with a wildcard routing key <code class="literal">#</code>:</p><pre class="screen">---
|
||||
spring.cloud.stream.bindings.input.destination=myDestination
|
||||
spring.cloud.stream.bindings.input.group=consumerGroup
|
||||
#disable binder retries
|
||||
spring.cloud.stream.bindings.input.consumer.max-attempts=1
|
||||
#dlx/dlq setup
|
||||
spring.cloud.stream.rabbit.bindings.input.consumer.auto-bind-dlq=true
|
||||
spring.cloud.stream.rabbit.bindings.input.consumer.dlq-ttl=5000
|
||||
spring.cloud.stream.rabbit.bindings.input.consumer.dlq-dead-letter-exchange=
|
||||
---</pre><p>This configuration creates a DLQ bound to a direct exchange (<code class="literal">DLX</code>) with a routing key of <code class="literal">myDestination.consumerGroup</code>.
|
||||
When messages are rejected, they are routed to the DLQ.
|
||||
After 5 seconds, the message expires and is routed to the original queue by using the queue name as the routing key, as shown in the following example:</p><p><b>Spring Boot application. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Sink.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> XDeathApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
SpringApplication.run(XDeathApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Sink.INPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> listen(String in, <em><span class="hl-annotation" style="color: gray">@Header(name = "x-death", required = false)</span></em> Map<?,?> death) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (death != null && death.get(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"count"</span>).equals(<span class="hl-number">3L</span>)) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// giving up - don't send to DLX</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throw</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ImmediateAcknowledgeAmqpException(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Failed after 4 attempts"</span>);
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throw</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> AmqpRejectAndDontRequeueException(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"failed"</span>);
|
||||
}
|
||||
|
||||
}</pre><p>
|
||||
</p><p>Notice that the count property in the <code class="literal">x-death</code> header is a <code class="literal">Long</code>.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="rabbit-error-channels" href="#rabbit-error-channels"></a>41.5 Error Channels</h2></div></div></div><p>Starting with version 1.3, the binder unconditionally sends exceptions to an error channel for each consumer destination and can also be configured to send async producer send failures to an error channel.
|
||||
See “<a class="xref" href="">???</a>” for more information.</p><p>RabbitMQ has two types of send failures:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Returned messages,</li><li class="listitem">Negatively acknowledged <a class="link" href="https://www.rabbitmq.com/confirms.html" target="_top">Publisher Confirms</a>.</li></ul></div><p>The latter is rare.
|
||||
According to the RabbitMQ documentation "[A nack] will only be delivered if an internal error occurs in the Erlang process responsible for a queue.".</p><p>As well as enabling producer error channels (as described in “<a class="xref" href="">???</a>”), the RabbitMQ binder only sends messages to the channels if the connection factory is appropriately configured, as follows:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">ccf.setPublisherConfirms(true);</code></li><li class="listitem"><code class="literal">ccf.setPublisherReturns(true);</code></li></ul></div><p>When using Spring Boot configuration for the connection factory, set the following properties:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">spring.rabbitmq.publisher-confirms</code></li><li class="listitem"><code class="literal">spring.rabbitmq.publisher-returns</code></li></ul></div><p>The payload of the <code class="literal">ErrorMessage</code> for a returned message is a <code class="literal">ReturnedAmqpMessageException</code> with the following properties:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">failedMessage</code>: The spring-messaging <code class="literal">Message<?></code> that failed to be sent.</li><li class="listitem"><code class="literal">amqpMessage</code>: The raw spring-amqp <code class="literal">Message</code>.</li><li class="listitem"><code class="literal">replyCode</code>: An integer value indicating the reason for the failure (for example, 312 - No route).</li><li class="listitem"><code class="literal">replyText</code>: A text value indicating the reason for the failure (for example, <code class="literal">NO_ROUTE</code>).</li><li class="listitem"><code class="literal">exchange</code>: The exchange to which the message was published.</li><li class="listitem"><code class="literal">routingKey</code>: The routing key used when the message was published.</li></ul></div><p>For negatively acknowledged confirmations, the payload is a <code class="literal">NackedAmqpMessageException</code> with the following properties:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">failedMessage</code>: The spring-messaging <code class="literal">Message<?></code> that failed to be sent.</li><li class="listitem"><code class="literal">nackReason</code>: A reason (if available — you may need to examine the broker logs for more information).</li></ul></div><p>There is no automatic handling of these exceptions (such as sending to a <a class="link" href="multi__rabbitmq_binder.html#rabbit-dlq-processing" title="41.6 Dead-Letter Queue Processing">dead-letter queue</a>).
|
||||
You can consume these exceptions with your own Spring Integration flow.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="rabbit-dlq-processing" href="#rabbit-dlq-processing"></a>41.6 Dead-Letter Queue Processing</h2></div></div></div><p>Because you cannot anticipate how users would want to dispose of dead-lettered messages, the framework does not provide any standard mechanism to handle them.
|
||||
If the reason for the dead-lettering is transient, you may wish to route the messages back to the original queue.
|
||||
However, if the problem is a permanent issue, that could cause an infinite loop.
|
||||
The following Spring Boot application shows an example of how to route those messages back to the original queue but moves them to a third “parking lot” queue after three attempts.
|
||||
The second example uses the <a class="link" href="https://www.rabbitmq.com/blog/2015/04/16/scheduling-messages-with-rabbitmq/" target="_top">RabbitMQ Delayed Message Exchange</a> to introduce a delay to the re-queued message.
|
||||
In this example, the delay increases for each attempt.
|
||||
These examples use a <code class="literal">@RabbitListener</code> to receive messages from the DLQ.
|
||||
You could also use <code class="literal">RabbitTemplate.receive()</code> in a batch process.</p><p>The examples assume the original destination is <code class="literal">so8400in</code> and the consumer group is <code class="literal">so8400</code>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_non_partitioned_destinations" href="#_non_partitioned_destinations"></a>41.6.1 Non-Partitioned Destinations</h3></div></div></div><p>The first two examples are for when the destination is <span class="strong"><strong>not</strong></span> partitioned:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> ReRouteDlqApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String ORIGINAL_QUEUE = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"so8400in.so8400"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String DLQ = ORIGINAL_QUEUE + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">".dlq"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String PARKING_LOT = ORIGINAL_QUEUE + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">".parkingLot"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String X_RETRIES_HEADER = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-retries"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
ConfigurableApplicationContext context = SpringApplication.run(ReRouteDlqApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Hit enter to terminate"</span>);
|
||||
System.in.read();
|
||||
context.close();
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> RabbitTemplate rabbitTemplate;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RabbitListener(queues = DLQ)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> rePublish(Message failedMessage) {
|
||||
Integer retriesHeader = (Integer) failedMessage.getMessageProperties().getHeaders().get(X_RETRIES_HEADER);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (retriesHeader == null) {
|
||||
retriesHeader = Integer.valueOf(<span class="hl-number">0</span>);
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (retriesHeader < <span class="hl-number">3</span>) {
|
||||
failedMessage.getMessageProperties().getHeaders().put(X_RETRIES_HEADER, retriesHeader + <span class="hl-number">1</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.rabbitTemplate.send(ORIGINAL_QUEUE, failedMessage);
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">else</span> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.rabbitTemplate.send(PARKING_LOT, failedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Queue parkingLot() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Queue(PARKING_LOT);
|
||||
}
|
||||
|
||||
}</pre><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> ReRouteDlqApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String ORIGINAL_QUEUE = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"so8400in.so8400"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String DLQ = ORIGINAL_QUEUE + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">".dlq"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String PARKING_LOT = ORIGINAL_QUEUE + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">".parkingLot"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String X_RETRIES_HEADER = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-retries"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String DELAY_EXCHANGE = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"dlqReRouter"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
ConfigurableApplicationContext context = SpringApplication.run(ReRouteDlqApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Hit enter to terminate"</span>);
|
||||
System.in.read();
|
||||
context.close();
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> RabbitTemplate rabbitTemplate;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RabbitListener(queues = DLQ)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> rePublish(Message failedMessage) {
|
||||
Map<String, Object> headers = failedMessage.getMessageProperties().getHeaders();
|
||||
Integer retriesHeader = (Integer) headers.get(X_RETRIES_HEADER);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (retriesHeader == null) {
|
||||
retriesHeader = Integer.valueOf(<span class="hl-number">0</span>);
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (retriesHeader < <span class="hl-number">3</span>) {
|
||||
headers.put(X_RETRIES_HEADER, retriesHeader + <span class="hl-number">1</span>);
|
||||
headers.put(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-delay"</span>, <span class="hl-number">5000</span> * retriesHeader);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.rabbitTemplate.send(DELAY_EXCHANGE, ORIGINAL_QUEUE, failedMessage);
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">else</span> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.rabbitTemplate.send(PARKING_LOT, failedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> DirectExchange delayExchange() {
|
||||
DirectExchange exchange = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> DirectExchange(DELAY_EXCHANGE);
|
||||
exchange.setDelayed(true);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> exchange;
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Binding bindOriginalToDelay() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> BindingBuilder.bind(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Queue(ORIGINAL_QUEUE)).to(delayExchange()).with(ORIGINAL_QUEUE);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Queue parkingLot() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Queue(PARKING_LOT);
|
||||
}
|
||||
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_partitioned_destinations" href="#_partitioned_destinations"></a>41.6.2 Partitioned Destinations</h3></div></div></div><p>With partitioned destinations, there is one DLQ for all partitions. We determine the original queue from the headers.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="__literal_republishtodlq_false_literal" href="#__literal_republishtodlq_false_literal"></a><code class="literal">republishToDlq=false</code></h4></div></div></div><p>When <code class="literal">republishToDlq</code> is <code class="literal">false</code>, RabbitMQ publishes the message to the DLX/DLQ with an <code class="literal">x-death</code> header containing information about the original destination, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> ReRouteDlqApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String ORIGINAL_QUEUE = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"so8400in.so8400"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String DLQ = ORIGINAL_QUEUE + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">".dlq"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String PARKING_LOT = ORIGINAL_QUEUE + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">".parkingLot"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String X_DEATH_HEADER = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-death"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String X_RETRIES_HEADER = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-retries"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
ConfigurableApplicationContext context = SpringApplication.run(ReRouteDlqApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Hit enter to terminate"</span>);
|
||||
System.in.read();
|
||||
context.close();
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> RabbitTemplate rabbitTemplate;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@SuppressWarnings("unchecked")</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@RabbitListener(queues = DLQ)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> rePublish(Message failedMessage) {
|
||||
Map<String, Object> headers = failedMessage.getMessageProperties().getHeaders();
|
||||
Integer retriesHeader = (Integer) headers.get(X_RETRIES_HEADER);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (retriesHeader == null) {
|
||||
retriesHeader = Integer.valueOf(<span class="hl-number">0</span>);
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (retriesHeader < <span class="hl-number">3</span>) {
|
||||
headers.put(X_RETRIES_HEADER, retriesHeader + <span class="hl-number">1</span>);
|
||||
List<Map<String, ?>> xDeath = (List<Map<String, ?>>) headers.get(X_DEATH_HEADER);
|
||||
String exchange = (String) xDeath.get(<span class="hl-number">0</span>).get(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"exchange"</span>);
|
||||
List<String> routingKeys = (List<String>) xDeath.get(<span class="hl-number">0</span>).get(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"routing-keys"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.rabbitTemplate.send(exchange, routingKeys.get(<span class="hl-number">0</span>), failedMessage);
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">else</span> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.rabbitTemplate.send(PARKING_LOT, failedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Queue parkingLot() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Queue(PARKING_LOT);
|
||||
}
|
||||
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="__literal_republishtodlq_true_literal" href="#__literal_republishtodlq_true_literal"></a><code class="literal">republishToDlq=true</code></h4></div></div></div><p>When <code class="literal">republishToDlq</code> is <code class="literal">true</code>, the republishing recoverer adds the original exchange and routing key to headers, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> ReRouteDlqApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String ORIGINAL_QUEUE = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"so8400in.so8400"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String DLQ = ORIGINAL_QUEUE + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">".dlq"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String PARKING_LOT = ORIGINAL_QUEUE + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">".parkingLot"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String X_RETRIES_HEADER = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-retries"</span>;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String X_ORIGINAL_EXCHANGE_HEADER = RepublishMessageRecoverer.X_ORIGINAL_EXCHANGE;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String X_ORIGINAL_ROUTING_KEY_HEADER = RepublishMessageRecoverer.X_ORIGINAL_ROUTING_KEY;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
ConfigurableApplicationContext context = SpringApplication.run(ReRouteDlqApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Hit enter to terminate"</span>);
|
||||
System.in.read();
|
||||
context.close();
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> RabbitTemplate rabbitTemplate;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@RabbitListener(queues = DLQ)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> rePublish(Message failedMessage) {
|
||||
Map<String, Object> headers = failedMessage.getMessageProperties().getHeaders();
|
||||
Integer retriesHeader = (Integer) headers.get(X_RETRIES_HEADER);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (retriesHeader == null) {
|
||||
retriesHeader = Integer.valueOf(<span class="hl-number">0</span>);
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (retriesHeader < <span class="hl-number">3</span>) {
|
||||
headers.put(X_RETRIES_HEADER, retriesHeader + <span class="hl-number">1</span>);
|
||||
String exchange = (String) headers.get(X_ORIGINAL_EXCHANGE_HEADER);
|
||||
String originalRoutingKey = (String) headers.get(X_ORIGINAL_ROUTING_KEY_HEADER);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.rabbitTemplate.send(exchange, originalRoutingKey, failedMessage);
|
||||
}
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">else</span> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.rabbitTemplate.send(PARKING_LOT, failedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Queue parkingLot() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Queue(PARKING_LOT);
|
||||
}
|
||||
|
||||
}</pre></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_partitioning_with_the_rabbitmq_binder" href="#_partitioning_with_the_rabbitmq_binder"></a>41.7 Partitioning with the RabbitMQ Binder</h2></div></div></div><p>RabbitMQ does not support partitioning natively.</p><p>Sometimes, it is advantageous to send data to specific partitions — for example, when you want to strictly order message processing, all messages for a particular customer should go to the same partition.</p><p>The <code class="literal">RabbitMessageChannelBinder</code> provides partitioning by binding a queue for each partition to the destination exchange.</p><p>The following Java and YAML examples show how to configure the producer:</p><p><b>Producer. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Source.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> RabbitPartitionProducerApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> Random RANDOM = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Random(System.currentTimeMillis());
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> String[] data = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> String[] {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"abc1"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"def1"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"qux1"</span>,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"abc2"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"def2"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"qux2"</span>,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"abc3"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"def3"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"qux3"</span>,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"abc4"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"def4"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"qux4"</span>,
|
||||
};
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> SpringApplicationBuilder(RabbitPartitionProducerApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>)
|
||||
.web(false)
|
||||
.run(args);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@InboundChannelAdapter(channel = Source.OUTPUT, poller = @Poller(fixedRate = "5000"))</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Message<?> generate() {
|
||||
String value = data[RANDOM.nextInt(data.length)];
|
||||
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Sending: "</span> + value);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> MessageBuilder.withPayload(value)
|
||||
.setHeader(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"partitionKey"</span>, value)
|
||||
.build();
|
||||
}
|
||||
|
||||
}</pre><p>
|
||||
</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> stream</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> bindings</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> output</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> destination</span>: partitioned.destination
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> producer</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> partitioned</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">true</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> partition-key-expression</span>: headers[<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">'partitionKey'</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">]</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> partition-count</span>: <span class="hl-number">2</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> required-groups</span>:
|
||||
- myGroup</pre><p>
|
||||
</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The configuration in the prececing example uses the default partitioning (<code class="literal">key.hashCode() % partitionCount</code>).
|
||||
This may or may not provide a suitably balanced algorithm, depending on the key values.
|
||||
You can override this default by using the <code class="literal">partitionSelectorExpression</code> or <code class="literal">partitionSelectorClass</code> properties.</p><p>The <code class="literal">required-groups</code> property is required only if you need the consumer queues to be provisioned when the producer is deployed.
|
||||
Otherwise, any messages sent to a partition are lost until the corresponding consumer is deployed.</p></td></tr></table></div><p>The following configuration provisions a topic exchange:</p><div class="informalfigure"><div class="mediaobject"><img src="images/part-exchange.png" alt="part exchange"></div></div><p>The following queues are bound to that exchange:</p><div class="informalfigure"><div class="mediaobject"><img src="images/part-queues.png" alt="part queues"></div></div><p>The following bindings associate the queues to the exchange:</p><div class="informalfigure"><div class="mediaobject"><img src="images/part-bindings.png" alt="part bindings"></div></div><p>The following Java and YAML examples continue the previous examples and show how to configure the consumer:</p><p><b>Consumer. </b>
|
||||
</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableBinding(Sink.class)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> RabbitPartitionConsumerApplication {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> SpringApplicationBuilder(RabbitPartitionConsumerApplication.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>)
|
||||
.web(false)
|
||||
.run(args);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@StreamListener(Sink.INPUT)</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> listen(<em><span class="hl-annotation" style="color: gray">@Payload</span></em> String in, <em><span class="hl-annotation" style="color: gray">@Header(AmqpHeaders.CONSUMER_QUEUE)</span></em> String queue) {
|
||||
System.out.println(in + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">" received from queue "</span> + queue);
|
||||
}
|
||||
|
||||
}</pre><p>
|
||||
</p><p><b>application.yml. </b>
|
||||
</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> spring</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> stream</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> bindings</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> input</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> destination</span>: partitioned.destination
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> group</span>: myGroup
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> consumer</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> partitioned</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">true</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> instance-index</span>: <span class="hl-number">0</span></pre><p>
|
||||
</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>The <code class="literal">RabbitMessageChannelBinder</code> does not support dynamic scaling.
|
||||
There must be at least one consumer per partition.
|
||||
The consumer’s <code class="literal">instanceIndex</code> is used to indicate which partition is consumed.
|
||||
Platforms such as Cloud Foundry can have only one instance with an <code class="literal">instanceIndex</code>.</p></td></tr></table></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__apache_kafka_streams_binder.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__binder_implementations.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__spring_cloud_bus.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">40. Apache Kafka Streams Binder </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> Part VII. Spring Cloud Bus</td></tr></table></div></body></html>
|
||||
17
Greenwich.RC2/multi/multi__reactor_netty_access_logs.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>119. Reactor Netty Access Logs</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_gateway.html" title="Part XV. Spring Cloud Gateway"><link rel="prev" href="multi__configuration_2.html" title="118. Configuration"><link rel="next" href="multi__cors_configuration.html" title="120. CORS Configuration"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">119. Reactor Netty Access Logs</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__configuration_2.html">Prev</a> </td><th width="60%" align="center">Part XV. Spring Cloud Gateway</th><td width="20%" align="right"> <a accesskey="n" href="multi__cors_configuration.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_reactor_netty_access_logs" href="#_reactor_netty_access_logs"></a>119. Reactor Netty Access Logs</h2></div></div></div><p>To enable Reactor Netty access logs, set <code class="literal">-Dreactor.netty.http.server.accessLogEnabled=true</code>. (It must be a Java System Property, not a Spring Boot property).</p><p>The logging system can be configured to have a separate access log file. Below is an example logback configuration:</p><p><b>logback.xml. </b>
|
||||
</p><pre class="programlisting"> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><appender</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">name</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"accessLog"</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">class</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"ch.qos.logback.core.FileAppender"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><file></span>access_log.log<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></file></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><encoder></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><pattern></span>%msg%n<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></pattern></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></encoder></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></appender></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><appender</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">name</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"async"</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">class</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"ch.qos.logback.classic.AsyncAppender"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><appender-ref</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">ref</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"accessLog"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"> /></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></appender></span>
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><logger</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">name</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"reactor.netty.http.server.AccessLog"</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">level</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"INFO"</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">additivity</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"false"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><appender-ref</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">ref</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"async"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">/></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></logger></span></pre><p>
|
||||
</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__configuration_2.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_gateway.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__cors_configuration.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">118. Configuration </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 120. CORS Configuration</td></tr></table></div></body></html>
|
||||
@@ -0,0 +1,21 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>138. Ribbon discovery in Kubernetes</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_kubernetes.html" title="Part XVII. Spring Cloud Kubernetes"><link rel="prev" href="multi__kubernetes_propertysource_implementations.html" title="137. Kubernetes PropertySource implementations"><link rel="next" href="multi__kubernetes_ecosystem_awareness.html" title="139. Kubernetes Ecosystem Awareness"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">138. Ribbon discovery in Kubernetes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__kubernetes_propertysource_implementations.html">Prev</a> </td><th width="60%" align="center">Part XVII. Spring Cloud Kubernetes</th><td width="20%" align="right"> <a accesskey="n" href="multi__kubernetes_ecosystem_awareness.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="_ribbon_discovery_in_kubernetes" href="#_ribbon_discovery_in_kubernetes"></a>138. Ribbon discovery in Kubernetes</h2></div></div></div><p>Spring Cloud client applications calling a microservice should be interested on relying on a client load-balancing
|
||||
feature in order to automatically discover at which endpoint(s) it can reach a given service. This mechanism has been
|
||||
implemented within the [spring-cloud-kubernetes-ribbon](spring-cloud-kubernetes-ribbon/pom.xml) project where a
|
||||
Kubernetes client will populate a <a class="link" href="https://github.com/Netflix/ribbon" target="_top">Ribbon</a> <code class="literal">ServerList</code> containing information
|
||||
about such endpoints.</p><p>The implementation is part of the following starter that you can use by adding its dependency to your pom file:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-kubernetes-ribbon<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>${latest.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre><p>When the list of the endpoints is populated, the Kubernetes client will search the registered endpoints living in
|
||||
the current namespace/project matching the service name defined using the Ribbon Client annotation:</p><pre class="programlisting">@RibbonClient(name = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"name-service"</span>)</pre><p>You can configure Ribbon’s behavior by providing properties in your <code class="literal">application.properties</code> (via your application’s
|
||||
dedicated <code class="literal">ConfigMap</code>) using the following format: <code class="literal"><name of your service>.ribbon.<Ribbon configuration key></code> where:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal"><name of your service></code> corresponds to the service name you’re accessing over Ribbon, as configured using the
|
||||
<code class="literal">@RibbonClient</code> annotation (e.g. <code class="literal">name-service</code> in the example above)</li><li class="listitem"><code class="literal"><Ribbon configuration key></code> is one of the Ribbon configuration key defined by
|
||||
<a class="link" href="https://github.com/Netflix/ribbon/blob/master/ribbon-core/src/main/java/com/netflix/client/config/CommonClientConfigKey.java" target="_top">Ribbon’s CommonClientConfigKey class</a></li></ul></div><p>Additionally, the <code class="literal">spring-cloud-kubernetes-ribbon</code> project defines two additional configuration keys to further
|
||||
control how Ribbon interacts with Kubernetes. In particular, if an endpoint defines multiple ports, the default
|
||||
behavior is to use the first one found. To select more specifically which port to use, in a multi-port service, use
|
||||
the <code class="literal">PortName</code> key. If you want to specify in which Kubernetes' namespace the target service should be looked up, use
|
||||
the <code class="literal">KubernetesNamespace</code> key, remembering in both instances to prefix these keys with your service name and
|
||||
<code class="literal">ribbon</code> prefix as specified above.</p><p>Examples that are using this module for ribbon discovery are:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="link" href="./spring-cloud-kubernetes-examples/kubernetes-circuitbreaker-ribbon-example" target="_top">Spring Cloud Circuitbreaker and Ribbon</a></li><li class="listitem"><a class="link" href="https://github.com/fabric8-quickstarts/spring-boot-ribbon" target="_top">fabric8-quickstarts - Spring Boot - Ribbon</a></li><li class="listitem"><a class="link" href="https://github.com/fabric8io/kubeflix/tree/master/examples/loanbroker/bank" target="_top">Kubeflix - LoanBroker - Bank</a></li></ul></div><p><span class="strong"><strong>Note</strong></span>: The Ribbon discovery client can be disabled by setting this key within the application properties file
|
||||
<code class="literal">spring.cloud.kubernetes.ribbon.enabled=false</code>.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__kubernetes_propertysource_implementations.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_kubernetes.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi__kubernetes_ecosystem_awareness.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">137. Kubernetes PropertySource implementations </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 139. Kubernetes Ecosystem Awareness</td></tr></table></div></body></html>
|
||||