Common classes used in different Spring Cloud implementations
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

344 lines
51 KiB

<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>2.&nbsp;Spring Cloud Commons: Common Abstractions</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"><link rel="home" href="multi_spring-cloud-commons.html" title="Cloud Native Applications"><link rel="up" href="multi_spring-cloud-commons.html" title="Cloud Native Applications"><link rel="prev" href="multi__spring_cloud_context_application_context_services.html" title="1.&nbsp;Spring Cloud Context: Application Context Services"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.&nbsp;Spring Cloud Commons: Common Abstractions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__spring_cloud_context_application_context_services.html">Prev</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;</td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_spring_cloud_commons_common_abstractions" href="#_spring_cloud_commons_common_abstractions"></a>2.&nbsp;Spring Cloud Commons: Common Abstractions</h1></div></div></div><p>Patterns such as service discovery, load balancing, and circuit breakers lend themselves to a common abstraction layer that can be consumed by all Spring Cloud clients, independent of the implementation (for example, discovery with Eureka or Consul).</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_enablediscoveryclient" href="#_enablediscoveryclient"></a>2.1&nbsp;@EnableDiscoveryClient</h2></div></div></div><p>Spring Cloud Commons provides the <code class="literal">@EnableDiscoveryClient</code> annotation.
This looks for implementations of the <code class="literal">DiscoveryClient</code> interface with <code class="literal">META-INF/spring.factories</code>.
Implementations of the Discovery Client add a configuration class to <code class="literal">spring.factories</code> under the <code class="literal">org.springframework.cloud.client.discovery.EnableDiscoveryClient</code> key.
Examples of <code class="literal">DiscoveryClient</code> implementations include <a class="link" href="https://cloud.spring.io/spring-cloud-netflix/" target="_top">Spring Cloud Netflix Eureka</a>, <a class="link" href="https://cloud.spring.io/spring-cloud-consul/" target="_top">Spring Cloud Consul Discovery</a>, and <a class="link" href="https://cloud.spring.io/spring-cloud-zookeeper/" target="_top">Spring Cloud Zookeeper Discovery</a>.</p><p>By default, implementations of <code class="literal">DiscoveryClient</code> auto-register the local Spring Boot server with the remote discovery server.
This behavior can be disabled by setting <code class="literal">autoRegister=false</code> in <code class="literal">@EnableDiscoveryClient</code>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p><code class="literal">@EnableDiscoveryClient</code> is no longer required.
You can put a <code class="literal">DiscoveryClient</code> implementation on the classpath to cause the Spring Boot application to register with the service discovery server.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_health_indicator" href="#_health_indicator"></a>2.1.1&nbsp;Health Indicator</h3></div></div></div><p>Commons creates a Spring Boot <code class="literal">HealthIndicator</code> that <code class="literal">DiscoveryClient</code> implementations can participate in by implementing <code class="literal">DiscoveryHealthIndicator</code>.
To disable the composite <code class="literal">HealthIndicator</code>, set <code class="literal">spring.cloud.discovery.client.composite-indicator.enabled=false</code>.
A generic <code class="literal">HealthIndicator</code> based on <code class="literal">DiscoveryClient</code> is auto-configured (<code class="literal">DiscoveryClientHealthIndicator</code>).
To disable it, set <code class="literal">spring.cloud.discovery.client.health-indicator.enabled=false</code>.
To disable the description field of the <code class="literal">DiscoveryClientHealthIndicator</code>, set <code class="literal">spring.cloud.discovery.client.health-indicator.include-description=false</code>.
Otherwise, it can bubble up as the <code class="literal">description</code> of the rolled up <code class="literal">HealthIndicator</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_ordering_discoveryclient_instances" href="#_ordering_discoveryclient_instances"></a>2.1.2&nbsp;Ordering <code class="literal">DiscoveryClient</code> instances</h3></div></div></div><p><code class="literal">DiscoveryClient</code> interface extends <code class="literal">Ordered</code>. This is useful when using multiple discovery
clients, as it allows you to define the order of the returned discovery clients, similar to
how you can order the beans loaded by a Spring application. By default, the order of any <code class="literal">DiscoveryClient</code> is set to
<code class="literal">0</code>. If you want to set a different order for your custom <code class="literal">DiscoveryClient</code> implementations, you just need to override
the <code class="literal">getOrder()</code> method so that it returns the value that is suitable for your setup. Apart from this, you can use
properties to set the order of the <code class="literal">DiscoveryClient</code>
implementations provided by Spring Cloud, among others <code class="literal">ConsulDiscoveryClient</code>, <code class="literal">EurekaDiscoveryClient</code> and
<code class="literal">ZookeeperDiscoveryClient</code>. In order to do it, you just need to set the
<code class="literal">spring.cloud.{clientIdentifier}.discovery.order</code> (or <code class="literal">eureka.client.order</code> for Eureka) property to the desired value.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_serviceregistry" href="#_serviceregistry"></a>2.2&nbsp;ServiceRegistry</h2></div></div></div><p>Commons now provides a <code class="literal">ServiceRegistry</code> interface that provides methods such as <code class="literal">register(Registration)</code> and <code class="literal">deregister(Registration)</code>, which let you provide custom registered services.
<code class="literal">Registration</code> is a marker interface.</p><p>The following example shows the <code class="literal">ServiceRegistry</code> in use:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@EnableDiscoveryClient(autoRegister=false)</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyConfiguration {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> ServiceRegistry registry;
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> MyConfiguration(ServiceRegistry registry) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.registry = registry;
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// called through some external process, such as an event or a custom actuator endpoint</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> register() {
Registration registration = constructRegistration();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.registry.register(registration);
}
}</pre><p>Each <code class="literal">ServiceRegistry</code> implementation has its own <code class="literal">Registry</code> implementation.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">ZookeeperRegistration</code> used with <code class="literal">ZookeeperServiceRegistry</code></li><li class="listitem"><code class="literal">EurekaRegistration</code> used with <code class="literal">EurekaServiceRegistry</code></li><li class="listitem"><code class="literal">ConsulRegistration</code> used with <code class="literal">ConsulServiceRegistry</code></li></ul></div><p>If you are using the <code class="literal">ServiceRegistry</code> interface, you are going to need to pass the
correct <code class="literal">Registry</code> implementation for the <code class="literal">ServiceRegistry</code> implementation you
are using.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_serviceregistry_auto_registration" href="#_serviceregistry_auto_registration"></a>2.2.1&nbsp;ServiceRegistry Auto-Registration</h3></div></div></div><p>By default, the <code class="literal">ServiceRegistry</code> implementation auto-registers the running service.
To disable that behavior, you can set:
* <code class="literal">@EnableDiscoveryClient(autoRegister=false)</code> to permanently disable auto-registration.
* <code class="literal">spring.cloud.service-registry.auto-registration.enabled=false</code> to disable the behavior through configuration.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_serviceregistry_auto_registration_events" href="#_serviceregistry_auto_registration_events"></a>ServiceRegistry Auto-Registration Events</h4></div></div></div><p>There are two events that will be fired when a service auto-registers. The first event, called
<code class="literal">InstancePreRegisteredEvent</code>, is fired before the service is registered. The second
event, called <code class="literal">InstanceRegisteredEvent</code>, is fired after the service is registered. You can register an
<code class="literal">ApplicationListener</code>(s) to listen to and react to these events.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>These events will not be fired if <code class="literal">spring.cloud.service-registry.auto-registration.enabled</code> is set to <code class="literal">false</code>.</p></td></tr></table></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_service_registry_actuator_endpoint" href="#_service_registry_actuator_endpoint"></a>2.2.2&nbsp;Service Registry Actuator Endpoint</h3></div></div></div><p>Spring Cloud Commons provides a <code class="literal">/service-registry</code> actuator endpoint.
This endpoint relies on a <code class="literal">Registration</code> bean in the Spring Application Context.
Calling <code class="literal">/service-registry</code> with GET returns the status of the <code class="literal">Registration</code>.
Using POST to the same endpoint with a JSON body changes the status of the current <code class="literal">Registration</code> to the new value.
The JSON body has to include the <code class="literal">status</code> field with the preferred value.
Please see the documentation of the <code class="literal">ServiceRegistry</code> implementation you use for the allowed values when updating the status and the values returned for the status.
For instance, Eureka&#8217;s supported statuses are <code class="literal">UP</code>, <code class="literal">DOWN</code>, <code class="literal">OUT_OF_SERVICE</code>, and <code class="literal">UNKNOWN</code>.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spring_resttemplate_as_a_load_balancer_client" href="#_spring_resttemplate_as_a_load_balancer_client"></a>2.3&nbsp;Spring RestTemplate as a Load Balancer Client</h2></div></div></div><p><code class="literal">RestTemplate</code> can be automatically configured to use a Load-balancer client under the hood.
To create a load-balanced <code class="literal">RestTemplate</code>, create a <code class="literal">RestTemplate</code> <code class="literal">@Bean</code> and use the <code class="literal">@LoadBalanced</code> qualifier, as shown in the following example:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyConfiguration {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
RestTemplate restTemplate() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> RestTemplate();
}
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyClass {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> RestTemplate restTemplate;
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String doOtherStuff() {
String results = restTemplate.getForObject(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://stores/stores"</span>, String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> results;
}
}</pre><div class="caution" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Caution"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="images/caution.png"></td><th align="left">Caution</th></tr><tr><td align="left" valign="top"><p>A <code class="literal">RestTemplate</code> bean is no longer created through auto-configuration.
Individual applications must create it.</p></td></tr></table></div><p>The URI needs to use a virtual host name (that is, a service name, not a host name).
The Ribbon client is used to create a full physical address.
See <a class="link" href="https://github.com/spring-cloud/spring-cloud-netflix/blob/master/spring-cloud-netflix-ribbon/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonAutoConfiguration.java" target="_top">RibbonAutoConfiguration</a> for details of how the <code class="literal">RestTemplate</code> is set up.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>In order to use a load-balanced <code class="literal">RestTemplate</code>, you need to have a load-balancer implementation in your classpath.
The recommended implementation is <code class="literal">BlockingLoadBalancerClient</code>
- add <code class="literal">org.springframework.cloud:spring-cloud-loadbalancer</code> in order to use it.
The
<code class="literal">RibbonLoadBalancerClient</code> also can be used, but it&#8217;s now under maintenance and we do not recommend adding it to new projects.</p></td></tr></table></div><div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Warning"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="images/warning.png"></td><th align="left">Warning</th></tr><tr><td align="left" valign="top"><p>If you want to use <code class="literal">BlockingLoadBalancerClient</code>, make sure you do not have
<code class="literal">RibbonLoadBalancerClient</code> in the project classpath, as for backward compatibility reasons, it will be used by default.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spring_webclient_as_a_load_balancer_client" href="#_spring_webclient_as_a_load_balancer_client"></a>2.4&nbsp;Spring WebClient as a Load Balancer Client</h2></div></div></div><p><code class="literal">WebClient</code> can be automatically configured to use a load-balancer client.
To create a load-balanced <code class="literal">WebClient</code>, create a <code class="literal">WebClient.Builder</code> <code class="literal">@Bean</code> and use the <code class="literal">@LoadBalanced</code> qualifier, as shown in the following example:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyConfiguration {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> WebClient.Builder loadBalancedWebClientBuilder() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> WebClient.builder();
}
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyClass {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> WebClient.Builder webClientBuilder;
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Mono&lt;String&gt; doOtherStuff() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> webClientBuilder.build().get().uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://stores/stores"</span>)
.retrieve().bodyToMono(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
}
}</pre><p>The URI needs to use a virtual host name (that is, a service name, not a host name).
The Ribbon client is used to create a full physical address.</p><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>If you want to use a <code class="literal">@LoadBalanced WebClient.Builder</code>, you need to have a loadbalancer
implementation in the classpath. It is recommended that you add the
<code class="literal">org.springframework.cloud:spring-cloud-loadbalancer</code> dependency to your project.
Then, <code class="literal">ReactiveLoadBalancer</code> will be used underneath.
Alternatively, this functionality will also work with spring-cloud-starter-netflix-ribbon, but the request
will be handled by a non-reactive <code class="literal">LoadBalancerClient</code> under the hood. Additionally,
spring-cloud-starter-netflix-ribbon is already in maintenance mode, so we do not recommned
adding it to new projects.</p></td></tr></table></div><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>The <code class="literal">ReactorLoadBalancer</code> used underneath supports caching. If <code class="literal">cacheManager</code> is detected,
cached version of <code class="literal">ServiceInstanceSupplier</code> will be used. If not, we will retrieve instances
from discovery service without caching them. We recommend <a class="link" href="https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-caching.html" target="_top">enabling caching</a> in your project
if you use <code class="literal">ReactiveLoadBalancer</code>.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_retrying_failed_requests" href="#_retrying_failed_requests"></a>2.4.1&nbsp;Retrying Failed Requests</h3></div></div></div><p>A load-balanced <code class="literal">RestTemplate</code> can be configured to retry failed requests.
By default, this logic is disabled.
You can enable it by adding <a class="link" href="https://github.com/spring-projects/spring-retry" target="_top">Spring Retry</a> to your application&#8217;s classpath.
The load-balanced <code class="literal">RestTemplate</code> honors some of the Ribbon configuration values related to retrying failed requests.
You can use <code class="literal">client.ribbon.MaxAutoRetries</code>, <code class="literal">client.ribbon.MaxAutoRetriesNextServer</code>, and <code class="literal">client.ribbon.OkToRetryOnAllOperations</code> properties.
If you would like to disable the retry logic with Spring Retry on the classpath, you can set <code class="literal">spring.cloud.loadbalancer.retry.enabled=false</code>.
See the <a class="link" href="https://github.com/Netflix/ribbon/wiki/Getting-Started#the-properties-file-sample-clientproperties" target="_top">Ribbon documentation</a> for a description of what these properties do.</p><p>If you would like to implement a <code class="literal">BackOffPolicy</code> in your retries, you need to create a bean of type <code class="literal">LoadBalancedRetryFactory</code> and override the <code class="literal">createBackOffPolicy</code> method:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyConfiguration {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
LoadBalancedRetryFactory retryFactory() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> LoadBalancedRetryFactory() {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> BackOffPolicy createBackOffPolicy(String service) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ExponentialBackOffPolicy();
}
};
}
}</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p><code class="literal">client</code> in the preceding examples should be replaced with your Ribbon client&#8217;s name.</p></td></tr></table></div><p>If you want to add one or more <code class="literal">RetryListener</code> implementations to your retry functionality, you need to
create a bean of type <code class="literal">LoadBalancedRetryListenerFactory</code> and return the <code class="literal">RetryListener</code> array
you would like to use for a given service, as shown in the following example:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyConfiguration {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
LoadBalancedRetryListenerFactory retryListenerFactory() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> LoadBalancedRetryListenerFactory() {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> RetryListener[] createRetryListeners(String service) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> RetryListener[]{<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> RetryListener() {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> &lt;T, E <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> Throwable&gt; <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> open(RetryContext context, RetryCallback&lt;T, E&gt; callback) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//TODO Do you business...</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> true;
}
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> &lt;T, E <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> Throwable&gt; <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> close(RetryContext context, RetryCallback&lt;T, E&gt; callback, Throwable throwable) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//TODO Do you business...</span>
}
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> &lt;T, E <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> Throwable&gt; <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> onError(RetryContext context, RetryCallback&lt;T, E&gt; callback, Throwable throwable) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//TODO Do you business...</span>
}
}};
}
};
}
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_multiple_resttemplate_objects" href="#_multiple_resttemplate_objects"></a>2.5&nbsp;Multiple RestTemplate objects</h2></div></div></div><p>If you want a <code class="literal">RestTemplate</code> that is not load-balanced, create a <code class="literal">RestTemplate</code> bean and inject it.
To access the load-balanced <code class="literal">RestTemplate</code>, use the <code class="literal">@LoadBalanced</code> qualifier when you create your <code class="literal">@Bean</code>, as shown in the following example:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyConfiguration {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
RestTemplate loadBalanced() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> RestTemplate();
}
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Primary</xslthl:annotation>
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
RestTemplate restTemplate() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> RestTemplate();
}
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyClass {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> RestTemplate restTemplate;
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> RestTemplate loadBalanced;
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String doOtherStuff() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> loadBalanced.getForObject(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://stores/stores"</span>, String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String doStuff() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> restTemplate.getForObject(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"https://example.com"</span>, String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
}
}</pre><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Notice the use of the <code class="literal">@Primary</code> annotation on the plain <code class="literal">RestTemplate</code> declaration in the preceding example to disambiguate the unqualified <code class="literal">@Autowired</code> injection.</p></td></tr></table></div><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>If you see errors such as <code class="literal">java.lang.IllegalArgumentException: Can not set org.springframework.web.client.RestTemplate field com.my.app.Foo.restTemplate to com.sun.proxy.$Proxy89</code>, try injecting <code class="literal">RestOperations</code> or setting <code class="literal">spring.aop.proxyTargetClass=true</code>.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_multiple_webclient_objects" href="#_multiple_webclient_objects"></a>2.6&nbsp;Multiple WebClient Objects</h2></div></div></div><p>If you want a <code class="literal">WebClient</code> that is not load-balanced, create a <code class="literal">WebClient</code> bean and inject it.
To access the load-balanced <code class="literal">WebClient</code>, use the <code class="literal">@LoadBalanced</code> qualifier when you create your <code class="literal">@Bean</code>, as shown in the following example:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyConfiguration {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
WebClient.Builder loadBalanced() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> WebClient.builder();
}
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Primary</xslthl:annotation>
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
WebClient.Builder webClient() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> WebClient.builder();
}
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyClass {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> WebClient.Builder webClientBuilder;
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> WebClient.Builder loadBalanced;
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Mono&lt;String&gt; doOtherStuff() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> loadBalanced.build().get().uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://stores/stores"</span>)
.retrieve().bodyToMono(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Mono&lt;String&gt; doStuff() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> webClientBuilder.build().get().uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://example.com"</span>)
.retrieve().bodyToMono(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
}
}</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="loadbalanced-webclient" href="#loadbalanced-webclient"></a>2.7&nbsp;Spring WebFlux WebClient as a Load Balancer Client</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="webflux-with-reactive-loadbalancer" href="#webflux-with-reactive-loadbalancer"></a>2.7.1&nbsp;Spring WebFlux WebClient with Reactive Load Balancer</h3></div></div></div><p><code class="literal">WebClient</code> can be configured to use the <code class="literal">ReactiveLoadBalancer</code>.
If you add <code class="literal">org.springframework.cloud:spring-cloud-loadbalancer</code> to your project,
<code class="literal">ReactorLoadBalancerExchangeFilterFunction</code> is auto-configured if <code class="literal">spring-webflux</code> is on the classpath.
The following example shows how to configure a <code class="literal">WebClient</code> to use reactive load balancer under the hood:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyClass {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> ReactorLoadBalancerExchangeFilterFunction lbFunction;
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Mono&lt;String&gt; doOtherStuff() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> WebClient.builder().baseUrl(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://stores"</span>)
.filter(lbFunction)
.build()
.get()
.uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/stores"</span>)
.retrieve()
.bodyToMono(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
}
}</pre><p>The URI needs to use a virtual host name (that is, a service name, not a host name).
The <code class="literal">ReactorLoadBalancerClient</code> is used to create a full physical address.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_spring_webflux_webclient_with_non_reactive_load_balancer_client" href="#_spring_webflux_webclient_with_non_reactive_load_balancer_client"></a>2.7.2&nbsp;Spring WebFlux WebClient with non-reactive Load Balancer Client</h3></div></div></div><p>If you you don&#8217;t have <code class="literal">org.springframework.cloud:spring-cloud-loadbalancer</code> in your project,
but you do have spring-cloud-starter-netflix-ribbon, you can still use <code class="literal">WebClient</code> with <code class="literal">LoadBalancerClient</code>. <code class="literal">LoadBalancerExchangeFilterFunction</code>
will be auto-configured if <code class="literal">spring-webflux</code> is on the classpath. Please note, however, that this is
uses a non-reactive client under the hood.
The following example shows how to configure a <code class="literal">WebClient</code> to use load balancer:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyClass {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> LoadBalancerExchangeFilterFunction lbFunction;
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Mono&lt;String&gt; doOtherStuff() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> WebClient.builder().baseUrl(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://stores"</span>)
.filter(lbFunction)
.build()
.get()
.uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/stores"</span>)
.retrieve()
.bodyToMono(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
}
}</pre><p>The URI needs to use a virtual host name (that is, a service name, not a host name).
The <code class="literal">LoadBalancerClient</code> is used to create a full physical address.</p><p>WARN: This approach is now deprecated.
We suggest you use <a class="link" href="multi__spring_cloud_commons_common_abstractions.html#webflux-with-reactive-loadbalancer" title="2.7.1&nbsp;Spring WebFlux WebClient with Reactive Load Balancer">WebFlux with reactive Load-Balancer</a>
instead.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_passing_your_own_load_balancer_client_configuration" href="#_passing_your_own_load_balancer_client_configuration"></a>2.7.3&nbsp;Passing your own Load-Balancer Client configuration</h3></div></div></div><p>You can also use the <code class="literal">@LoadBalancerClient</code> annotation to pass your own load-balancer client configuration, passing the name of the load-balancer client and the configuration class, like so:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalancerClient(value = "stores", configuration = StoresLoadBalancerClientConfiguration.class)</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyConfiguration {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> WebClient.Builder loadBalancedWebClientBuilder() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> WebClient.builder();
}
}</pre><p>It is also possible to pass together multiple configurations (for more than one load-balancer client) via the <code class="literal">@LoadBalancerClients</code> annotation, as shown below:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalancerClients({@LoadBalancerClient(value = "stores", configuration = StoresLoadBalancerClientConfiguration.class), @LoadBalancerClient(value = "customers", configuration = CustomersLoadBalancerClientConfiguration.class)})</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyConfiguration {
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@LoadBalanced</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> WebClient.Builder loadBalancedWebClientBuilder() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> WebClient.builder();
}
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="ignore-network-interfaces" href="#ignore-network-interfaces"></a>2.8&nbsp;Ignore Network Interfaces</h2></div></div></div><p>Sometimes, it is useful to ignore certain named network interfaces so that they can be excluded from Service Discovery registration (for example, when running in a Docker container).
A list of regular expressions can be set to cause the desired network interfaces to be ignored.
The following configuration ignores the <code class="literal">docker0</code> interface and all interfaces that start with <code class="literal">veth</code>:</p><p><b>application.yml.&nbsp;</b>
</p><pre class="screen">spring:
cloud:
inetutils:
ignoredInterfaces:
- docker0
- veth.*</pre><p>
</p><p>You can also force the use of only specified network addresses by using a list of regular expressions, as shown in the following example:</p><p><b>bootstrap.yml.&nbsp;</b>
</p><pre class="screen">spring:
cloud:
inetutils:
preferredNetworks:
- 192.168
- 10.0</pre><p>
</p><p>You can also force the use of only site-local addresses, as shown in the following example:
.application.yml</p><pre class="screen">spring:
cloud:
inetutils:
useOnlySiteLocalInterfaces: true</pre><p>See <a class="link" href="https://docs.oracle.com/javase/8/docs/api/java/net/Inet4Address.html#isSiteLocalAddress--" target="_top">Inet4Address.html.isSiteLocalAddress()</a> for more details about what constitutes a site-local address.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="http-clients" href="#http-clients"></a>2.9&nbsp;HTTP Client Factories</h2></div></div></div><p>Spring Cloud Commons provides beans for creating both Apache HTTP clients (<code class="literal">ApacheHttpClientFactory</code>) and OK HTTP clients (<code class="literal">OkHttpClientFactory</code>).
The <code class="literal">OkHttpClientFactory</code> bean is created only if the OK HTTP jar is on the classpath.
In addition, Spring Cloud Commons provides beans for creating the connection managers used by both clients: <code class="literal">ApacheHttpClientConnectionManagerFactory</code> for the Apache HTTP client and <code class="literal">OkHttpClientConnectionPoolFactory</code> for the OK HTTP client.
If you would like to customize how the HTTP clients are created in downstream projects, you can provide your own implementation of these beans.
In addition, if you provide a bean of type <code class="literal">HttpClientBuilder</code> or <code class="literal">OkHttpClient.Builder</code>, the default factories use these builders as the basis for the builders returned to downstream projects.
You can also disable the creation of these beans by setting <code class="literal">spring.cloud.httpclientfactories.apache.enabled</code> or <code class="literal">spring.cloud.httpclientfactories.ok.enabled</code> to <code class="literal">false</code>.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="enabled-features" href="#enabled-features"></a>2.10&nbsp;Enabled Features</h2></div></div></div><p>Spring Cloud Commons provides a <code class="literal">/features</code> actuator endpoint.
This endpoint returns features available on the classpath and whether they are enabled.
The information returned includes the feature type, name, version, and vendor.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_feature_types" href="#_feature_types"></a>2.10.1&nbsp;Feature types</h3></div></div></div><p>There are two types of 'features': abstract and named.</p><p>Abstract features are features where an interface or abstract class is defined and that an implementation the creates, such as <code class="literal">DiscoveryClient</code>, <code class="literal">LoadBalancerClient</code>, or <code class="literal">LockService</code>.
The abstract class or interface is used to find a bean of that type in the context.
The version displayed is <code class="literal">bean.getClass().getPackage().getImplementationVersion()</code>.</p><p>Named features are features that do not have a particular class they implement, such as "Circuit Breaker", "API Gateway", "Spring Cloud Bus", and others. These features require a name and a bean type.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_declaring_features" href="#_declaring_features"></a>2.10.2&nbsp;Declaring features</h3></div></div></div><p>Any module can declare any number of <code class="literal">HasFeature</code> beans, as shown in the following examples:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> HasFeatures commonsFeatures() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> HasFeatures.abstractFeatures(DiscoveryClient.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, LoadBalancerClient.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>);
}
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> HasFeatures consulFeatures() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> HasFeatures.namedFeatures(
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> NamedFeature(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Spring Cloud Bus"</span>, ConsulBusAutoConfiguration.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>),
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> NamedFeature(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Circuit Breaker"</span>, HystrixCommandAspect.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>));
}
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
HasFeatures localFeatures() {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> HasFeatures.builder()
.abstractFeature(Foo.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>)
.namedFeature(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> NamedFeature(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Bar Feature"</span>, Bar.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>))
.abstractFeature(Baz.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>)
.build();
}</pre><p>Each of these beans should go in an appropriately guarded <code class="literal">@Configuration</code>.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spring_cloud_compatibility_verification" href="#_spring_cloud_compatibility_verification"></a>2.11&nbsp;Spring Cloud Compatibility Verification</h2></div></div></div><p>Due to the fact that some users have problem with setting up Spring Cloud application, we&#8217;ve decided
to add a compatibility verification mechanism. It will break if your current setup is not compatible
with Spring Cloud requirements, together with a report, showing what exactly went wrong.</p><p>At the moment we verify which version of Spring Boot is added to your classpath.</p><p>Example of a report</p><pre class="screen">***************************
APPLICATION FAILED TO START
***************************
Description:
Your project setup is incompatible with our requirements due to following reasons:
- Spring Boot [2.1.0.RELEASE] is not compatible with this Spring Cloud release train
Action:
Consider applying the following actions:
- Change Spring Boot version to one of the following versions [1.2.x, 1.3.x] .
You can find the latest Spring Boot versions here [https://spring.io/projects/spring-boot#learn].
If you want to learn more about the Spring Cloud Release train compatibility, you can visit this page [https://spring.io/projects/spring-cloud#overview] and check the [Release Trains] section.</pre><p>In order to disable this feature, set <code class="literal">spring.cloud.compatibility-verifier.enabled</code> to <code class="literal">false</code>.
If you want to override the compatible Spring Boot versions, just set the
<code class="literal">spring.cloud.compatibility-verifier.compatible-boot-versions</code> property with a comma separated list
of compatible Spring Boot versions.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__spring_cloud_context_application_context_services.html">Prev</a>&nbsp;</td><td width="20%" align="center">&nbsp;</td><td width="40%" align="right">&nbsp;</td></tr><tr><td width="40%" align="left" valign="top">1.&nbsp;Spring Cloud Context: Application Context Services&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud-commons.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;</td></tr></table></div></body></html>