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.
324 lines
67 KiB
324 lines
67 KiB
<html><head> |
|
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> |
|
<title>Cloud Native Applications</title><link rel="stylesheet" type="text/css" href="css/manual-singlepage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div lang="en" class="book"><div class="titlepage"><div><div><h1 class="title"><a name="d0e3"></a>Cloud Native Applications</h1></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="preface"><a href="#d0e9"></a></span></dt><dt><span class="chapter"><a href="#_spring_cloud_context_application_context_services">1. Spring Cloud Context: Application Context Services</a></span></dt><dd><dl><dt><span class="section"><a href="#_the_bootstrap_application_context">1.1. The Bootstrap Application Context</a></span></dt><dt><span class="section"><a href="#_application_context_hierarchies">1.2. Application Context Hierarchies</a></span></dt><dt><span class="section"><a href="#customizing-bootstrap-properties">1.3. Changing the Location of Bootstrap Properties</a></span></dt><dt><span class="section"><a href="#overriding-bootstrap-properties">1.4. Overriding the Values of Remote Properties</a></span></dt><dt><span class="section"><a href="#_customizing_the_bootstrap_configuration">1.5. Customizing the Bootstrap Configuration</a></span></dt><dt><span class="section"><a href="#customizing-bootstrap-property-sources">1.6. Customizing the Bootstrap Property Sources</a></span></dt><dt><span class="section"><a href="#_logging_configuration">1.7. Logging Configuration</a></span></dt><dt><span class="section"><a href="#_environment_changes">1.8. Environment Changes</a></span></dt><dt><span class="section"><a href="#refresh-scope">1.9. Refresh Scope</a></span></dt><dt><span class="section"><a href="#_encryption_and_decryption">1.10. Encryption and Decryption</a></span></dt><dt><span class="section"><a href="#_endpoints">1.11. Endpoints</a></span></dt></dl></dd><dt><span class="chapter"><a href="#_spring_cloud_commons_common_abstractions">2. Spring Cloud Commons: Common Abstractions</a></span></dt><dd><dl><dt><span class="section"><a href="#_enablediscoveryclient">2.1. @EnableDiscoveryClient</a></span></dt><dd><dl><dt><span class="section"><a href="#_health_indicator">2.1.1. Health Indicator</a></span></dt><dt><span class="section"><a href="#_ordering_discoveryclient_instances">2.1.2. Ordering <code class="literal">DiscoveryClient</code> instances</a></span></dt></dl></dd><dt><span class="section"><a href="#_serviceregistry">2.2. ServiceRegistry</a></span></dt><dd><dl><dt><span class="section"><a href="#_serviceregistry_auto_registration">2.2.1. ServiceRegistry Auto-Registration</a></span></dt><dt><span class="section"><a href="#_service_registry_actuator_endpoint">2.2.2. Service Registry Actuator Endpoint</a></span></dt></dl></dd><dt><span class="section"><a href="#_spring_resttemplate_as_a_load_balancer_client">2.3. Spring RestTemplate as a Load Balancer Client</a></span></dt><dt><span class="section"><a href="#_spring_webclient_as_a_load_balancer_client">2.4. Spring WebClient as a Load Balancer Client</a></span></dt><dd><dl><dt><span class="section"><a href="#_retrying_failed_requests">2.4.1. Retrying Failed Requests</a></span></dt></dl></dd><dt><span class="section"><a href="#_multiple_resttemplate_objects">2.5. Multiple RestTemplate objects</a></span></dt><dt><span class="section"><a href="#loadbalanced-webclient">2.6. Spring WebFlux WebClient as a Load Balancer Client</a></span></dt><dt><span class="section"><a href="#ignore-network-interfaces">2.7. Ignore Network Interfaces</a></span></dt><dt><span class="section"><a href="#http-clients">2.8. HTTP Client Factories</a></span></dt><dt><span class="section"><a href="#enabled-features">2.9. Enabled Features</a></span></dt><dd><dl><dt><span class="section"><a href="#_feature_types">2.9.1. Feature types</a></span></dt><dt><span class="section"><a href="#_declaring_features">2.9.2. Declaring features</a></span></dt></dl></dd></dl></dd></dl></div><div class="preface"><div class="titlepage"><div><div><h1 class="title"><a name="d0e9" href="#d0e9"></a></h1></div></div></div><p><a class="link" href="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 class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_spring_cloud_context_application_context_services" href="#_spring_cloud_context_application_context_services"></a>1. Spring Cloud Context: Application Context Services</h1></div></div></div><p>Spring Boot has an opinionated view of how to build an application with Spring. |
|
For instance, it has conventional locations for common configuration files and has endpoints for common management and monitoring tasks. |
|
Spring Cloud builds on top of that and adds a few features that probably all components in a system would use or occasionally need.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_the_bootstrap_application_context" href="#_the_bootstrap_application_context"></a>1.1 The Bootstrap Application Context</h2></div></div></div><p>A Spring Cloud application operates by creating a <span class="quote">“<span class="quote">bootstrap</span>”</span> context, which is a parent context for the main application. |
|
It is responsible for loading configuration properties from the external sources and for decrypting properties in the local external configuration files. |
|
The two contexts share an <code class="literal">Environment</code>, which is the source of external properties for any Spring application. |
|
By default, bootstrap properties (not <code class="literal">bootstrap.properties</code> but properties that are loaded during the bootstrap phase) are added with high precedence, so they cannot be overridden by local configuration.</p><p>The bootstrap context uses a different convention for locating external configuration than the main application context. |
|
Instead of <code class="literal">application.yml</code> (or <code class="literal">.properties</code>), you can use <code class="literal">bootstrap.yml</code>, keeping the external configuration for bootstrap and main context |
|
nicely separate. |
|
The following listing shows an example:</p><p><b>bootstrap.yml. </b> |
|
</p><pre class="screen">spring: |
|
application: |
|
name: foo |
|
cloud: |
|
config: |
|
uri: ${SPRING_CONFIG_URI:http://localhost:8888}</pre><p> |
|
</p><p>If your application needs any application-specific configuration from the server, it is a good idea to set the <code class="literal">spring.application.name</code> (in <code class="literal">bootstrap.yml</code> or <code class="literal">application.yml</code>).</p><p>You can disable the bootstrap process completely by setting <code class="literal">spring.cloud.bootstrap.enabled=false</code> (for example, in system properties).</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_application_context_hierarchies" href="#_application_context_hierarchies"></a>1.2 Application Context Hierarchies</h2></div></div></div><p>If you build an application context from <code class="literal">SpringApplication</code> or <code class="literal">SpringApplicationBuilder</code>, then the Bootstrap context is added as a parent to that context. |
|
It is a feature of Spring that child contexts inherit property sources and profiles from their parent, so the <span class="quote">“<span class="quote">main</span>”</span> application context contains additional property sources, compared to building the same context without Spring Cloud Config. |
|
The additional property sources are:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><span class="quote">“<span class="quote">bootstrap</span>”</span>: If any <code class="literal">PropertySourceLocators</code> are found in the Bootstrap context and if they have non-empty properties, an optional <code class="literal">CompositePropertySource</code> appears with high priority. |
|
An example would be properties from the Spring Cloud Config Server. |
|
See <span class="quote">“<span class="quote"><a class="xref" href="#customizing-bootstrap-property-sources" title="1.6 Customizing the Bootstrap Property Sources">Section 1.6, “Customizing the Bootstrap Property Sources”</a></span>”</span> for instructions on how to customize the contents of this property source.</li><li class="listitem"><span class="quote">“<span class="quote">applicationConfig: [classpath:bootstrap.yml]</span>”</span> (and related files if Spring profiles are active): If you have a <code class="literal">bootstrap.yml</code> (or <code class="literal">.properties</code>), those properties are used to configure the Bootstrap context. |
|
Then they get added to the child context when its parent is set. |
|
They have lower precedence than the <code class="literal">application.yml</code> (or <code class="literal">.properties</code>) and any other property sources that are added to the child as a normal part of the process of creating a Spring Boot application. |
|
See <span class="quote">“<span class="quote"><a class="xref" href="#customizing-bootstrap-properties" title="1.3 Changing the Location of Bootstrap Properties">Section 1.3, “Changing the Location of Bootstrap Properties”</a></span>”</span> for instructions on how to customize the contents of these property sources.</li></ul></div><p>Because of the ordering rules of property sources, the <span class="quote">“<span class="quote">bootstrap</span>”</span> entries take precedence. |
|
However, note that these do not contain any data from <code class="literal">bootstrap.yml</code>, which has very low precedence but can be used to set defaults.</p><p>You can extend the context hierarchy by setting the parent context of any <code class="literal">ApplicationContext</code> you create — for example, by using its own interface or with the <code class="literal">SpringApplicationBuilder</code> convenience methods (<code class="literal">parent()</code>, <code class="literal">child()</code> and <code class="literal">sibling()</code>). |
|
The bootstrap context is the parent of the most senior ancestor that you create yourself. |
|
Every context in the hierarchy has its own <span class="quote">“<span class="quote">bootstrap</span>”</span> (possibly empty) property source to avoid promoting values inadvertently from parents down to their descendants. |
|
If there is a Config Server, every context in the hierarchy can also (in principle) have a different <code class="literal">spring.application.name</code> and, hence, a different remote property source. |
|
Normal Spring application context behavior rules apply to property resolution: properties from a child context override those in |
|
the parent, by name and also by property source name. |
|
(If the child has a property source with the same name as the parent, the value from the parent is not included in the child).</p><p>Note that the <code class="literal">SpringApplicationBuilder</code> lets you share an <code class="literal">Environment</code> amongst the whole hierarchy, but that is not the default. |
|
Thus, sibling contexts, in particular, do not need to have the same profiles or property sources, even though they may share common values with their parent.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="customizing-bootstrap-properties" href="#customizing-bootstrap-properties"></a>1.3 Changing the Location of Bootstrap Properties</h2></div></div></div><p>The <code class="literal">bootstrap.yml</code> (or <code class="literal">.properties</code>) location can be specified by setting <code class="literal">spring.cloud.bootstrap.name</code> (default: <code class="literal">bootstrap</code>) or <code class="literal">spring.cloud.bootstrap.location</code> (default: empty) — for example, in System properties. |
|
Those properties behave like the <code class="literal">spring.config.*</code> variants with the same name. |
|
In fact, they are used to set up the bootstrap <code class="literal">ApplicationContext</code> by setting those properties in its <code class="literal">Environment</code>. |
|
If there is an active profile (from <code class="literal">spring.profiles.active</code> or through the <code class="literal">Environment</code> API in the |
|
context you are building), properties in that profile get loaded as well, the same as in a regular Spring Boot app — for example, from <code class="literal">bootstrap-development.properties</code> for a <code class="literal">development</code> profile.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="overriding-bootstrap-properties" href="#overriding-bootstrap-properties"></a>1.4 Overriding the Values of Remote Properties</h2></div></div></div><p>The property sources that are added to your application by the bootstrap context are often <span class="quote">“<span class="quote">remote</span>”</span> (from example, from Spring Cloud Config Server). |
|
By default, they cannot be overridden locally. |
|
If you want to let your applications override the remote properties with their own System properties or config files, the remote property source has to grant it permission by setting <code class="literal">spring.cloud.config.allowOverride=true</code> (it does not work to set this locally). |
|
Once that flag is set, two finer-grained settings control the location of the remote properties in relation to system properties and the application’s local configuration:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">spring.cloud.config.overrideNone=true</code>: Override from any local property source.</li><li class="listitem"><code class="literal">spring.cloud.config.overrideSystemProperties=false</code>: Only system properties, command line arguments, and environment variables (but not the local config files) should override the remote settings.</li></ul></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_customizing_the_bootstrap_configuration" href="#_customizing_the_bootstrap_configuration"></a>1.5 Customizing the Bootstrap Configuration</h2></div></div></div><p>The bootstrap context can be set to do anything you like by adding entries to <code class="literal">/META-INF/spring.factories</code> under a key named <code class="literal">org.springframework.cloud.bootstrap.BootstrapConfiguration</code>. |
|
This holds a comma-separated list of Spring <code class="literal">@Configuration</code> classes that are used to create the context. |
|
Any beans that you want to be available to the main application context for autowiring can be created here. |
|
There is a special contract for <code class="literal">@Beans</code> of type <code class="literal">ApplicationContextInitializer</code>. |
|
If you want to control the startup sequence, classes can be marked with an <code class="literal">@Order</code> annotation (the default order is <code class="literal">last</code>).</p><div class="warning" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Warning"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Warning]" src="images/warning.png"></td><th align="left">Warning</th></tr><tr><td align="left" valign="top"><p>When adding custom <code class="literal">BootstrapConfiguration</code>, be careful that the classes you add are not <code class="literal">@ComponentScanned</code> by mistake into your <span class="quote">“<span class="quote">main</span>”</span> application context, where they might not be needed. |
|
Use a separate package name for boot configuration classes and make sure that name is not already covered by your <code class="literal">@ComponentScan</code> or <code class="literal">@SpringBootApplication</code> annotated configuration classes.</p></td></tr></table></div><p>The bootstrap process ends by injecting initializers into the main <code class="literal">SpringApplication</code> instance (which is the normal Spring Boot startup sequence, whether it is running as a standalone application or deployed in an application server). |
|
First, a bootstrap context is created from the classes found in <code class="literal">spring.factories</code>. |
|
Then, all <code class="literal">@Beans</code> of type <code class="literal">ApplicationContextInitializer</code> are added to the main <code class="literal">SpringApplication</code> before it is started.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="customizing-bootstrap-property-sources" href="#customizing-bootstrap-property-sources"></a>1.6 Customizing the Bootstrap Property Sources</h2></div></div></div><p>The default property source for external configuration added by the bootstrap process is the Spring Cloud Config Server, but you can add additional sources by adding beans of type <code class="literal">PropertySourceLocator</code> to the bootstrap context (through <code class="literal">spring.factories</code>). |
|
For instance, you can insert additional properties from a different server or from a database.</p><p>As an example, consider the following custom locator:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</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> CustomPropertySourceLocator <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">implements</span> PropertySourceLocator { |
|
|
|
<em><span class="hl-annotation" style="color: gray">@Override</span></em> |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> PropertySource<?> locate(Environment environment) { |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> MapPropertySource(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"customProperty"</span>, |
|
Collections.<String, Object>singletonMap(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"property.from.sample.custom.source"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"worked as intended"</span>)); |
|
} |
|
|
|
}</pre><p>The <code class="literal">Environment</code> that is passed in is the one for the <code class="literal">ApplicationContext</code> about to be created — in other words, the one for which we supply additional property sources for. |
|
It already has its normal Spring Boot-provided property sources, so you can use those to locate a property source specific to this <code class="literal">Environment</code> (for example, by keying it on <code class="literal">spring.application.name</code>, as is done in the default Spring Cloud Config Server property source locator).</p><p>If you create a jar with this class in it and then add a <code class="literal">META-INF/spring.factories</code> containing the following, the <code class="literal">customProperty</code> <code class="literal">PropertySource</code> appears in any application that includes that jar on its classpath:</p><pre class="screen">org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_logging_configuration" href="#_logging_configuration"></a>1.7 Logging Configuration</h2></div></div></div><p>If you are going to use Spring Boot to configure log settings than |
|
you should place this configuration in `bootstrap.[yml | properties] |
|
if you would like it to apply to all events.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>For Spring Cloud to initialize logging configuration properly you cannot use a custom prefix. For example, |
|
using <code class="literal">custom.loggin.logpath</code> will not be recognized by Spring Cloud when initializing the logging system.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_environment_changes" href="#_environment_changes"></a>1.8 Environment Changes</h2></div></div></div><p>The application listens for an <code class="literal">EnvironmentChangeEvent</code> and reacts to the change in a couple of standard ways (additional <code class="literal">ApplicationListeners</code> can be added as <code class="literal">@Beans</code> by the user in the normal way). |
|
When an <code class="literal">EnvironmentChangeEvent</code> is observed, it has a list of key values that have changed, and the application uses those to:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Re-bind any <code class="literal">@ConfigurationProperties</code> beans in the context</li><li class="listitem">Set the logger levels for any properties in <code class="literal">logging.level.*</code></li></ul></div><p>Note that the Config Client does not, by default, poll for changes in the <code class="literal">Environment</code>. |
|
Generally, we would not recommend that approach for detecting changes (although you could set it up with a |
|
<code class="literal">@Scheduled</code> annotation). |
|
If you have a scaled-out client application, it is better to broadcast the <code class="literal">EnvironmentChangeEvent</code> to all the instances instead of having them polling for changes (for example, by using the <a class="link" href="https://github.com/spring-cloud/spring-cloud-bus" target="_top">Spring Cloud Bus</a>).</p><p>The <code class="literal">EnvironmentChangeEvent</code> covers a large class of refresh use cases, as long as you can actually make a change to the <code class="literal">Environment</code> and publish the event. |
|
Note that those APIs are public and part of core Spring). |
|
You can verify that the changes are bound to <code class="literal">@ConfigurationProperties</code> beans by visiting the <code class="literal">/configprops</code> endpoint (a normal Spring Boot Actuator feature). |
|
For instance, a <code class="literal">DataSource</code> can have its <code class="literal">maxPoolSize</code> changed at runtime (the default <code class="literal">DataSource</code> created by Spring Boot is an <code class="literal">@ConfigurationProperties</code> bean) and grow capacity dynamically. |
|
Re-binding <code class="literal">@ConfigurationProperties</code> does not cover another large class of use cases, where you need more control over the refresh and where you need a change to be atomic over the whole <code class="literal">ApplicationContext</code>. |
|
To address those concerns, we have <code class="literal">@RefreshScope</code>.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="refresh-scope" href="#refresh-scope"></a>1.9 Refresh Scope</h2></div></div></div><p>When there is a configuration change, a Spring <code class="literal">@Bean</code> that is marked as <code class="literal">@RefreshScope</code> gets special treatment. |
|
This feature addresses the problem of stateful beans that only get their configuration injected when they are initialized. |
|
For instance, if a <code class="literal">DataSource</code> has open connections when the database URL is changed via the <code class="literal">Environment</code>, you probably want the holders of those connections to be able to complete what they are doing. |
|
Then, the next time something borrows a connection from the pool, it gets one with the new URL.</p><p>Sometimes, it might even be mandatory to apply the <code class="literal">@RefreshScope</code> |
|
annotation on some beans which can be only initialized once. If a bean |
|
is "immutable", you will have to either annotate the bean with <code class="literal">@RefreshScope</code> |
|
or specify the classname under the property key |
|
<code class="literal">spring.cloud.refresh.extra-refreshable</code>.</p><p>Refresh scope beans are lazy proxies that initialize when they are used (that is, when a method is called), and the scope acts as a cache of initialized values. |
|
To force a bean to re-initialize on the next method call, you must invalidate its cache entry.</p><p>The <code class="literal">RefreshScope</code> is a bean in the context and has a public <code class="literal">refreshAll()</code> method to refresh all beans in the scope by clearing the target cache. |
|
The <code class="literal">/refresh</code> endpoint exposes this functionality (over HTTP or JMX). |
|
To refresh an individual bean by name, there is also a <code class="literal">refresh(String)</code> method.</p><p>To expose the <code class="literal">/refresh</code> endpoint, you need to add following configuration to your application:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">management</span>: |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> endpoints</span>: |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> web</span>: |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> exposure</span>: |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> include</span>: refresh</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p><code class="literal">@RefreshScope</code> works (technically) on an <code class="literal">@Configuration</code> class, but it might lead to surprising behavior. |
|
For example, it does not mean that all the <code class="literal">@Beans</code> defined in that class are themselves in <code class="literal">@RefreshScope</code>. |
|
Specifically, anything that depends on those beans cannot rely on them being updated when a refresh is initiated, unless it is itself in <code class="literal">@RefreshScope</code>. |
|
In that case, it is rebuilt on a refresh and its dependencies are re-injected. At that point, they are re-initialized from the refreshed <code class="literal">@Configuration</code>).</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_encryption_and_decryption" href="#_encryption_and_decryption"></a>1.10 Encryption and Decryption</h2></div></div></div><p>Spring Cloud has an <code class="literal">Environment</code> pre-processor for decrypting property values locally. |
|
It follows the same rules as the Config Server and has the same external configuration through <code class="literal">encrypt.*</code>. |
|
Thus, you can use encrypted values in the form of <code class="literal">{cipher}*</code> and, as long as there is a valid key, they are decrypted before the main application context gets the <code class="literal">Environment</code> settings. |
|
To use the encryption features in an application, you need to include Spring Security RSA in your classpath (Maven co-ordinates: "org.springframework.security:spring-security-rsa"), and you also need the full strength JCE extensions in your JVM.</p><p>If you get an exception due to "Illegal key size" and you use Sun’s JDK, you need to install the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files. |
|
See the following links for more information:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="link" href="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><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_endpoints" href="#_endpoints"></a>1.11 Endpoints</h2></div></div></div><p>For a Spring Boot Actuator application, some additional management endpoints are available. You can use:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">POST</code> to <code class="literal">/actuator/env</code> to update the <code class="literal">Environment</code> and rebind <code class="literal">@ConfigurationProperties</code> and log levels.</li><li class="listitem"><code class="literal">/actuator/refresh</code> to re-load the boot strap context and refresh the <code class="literal">@RefreshScope</code> beans.</li><li class="listitem"><code class="literal">/actuator/restart</code> to close the <code class="literal">ApplicationContext</code> and restart it (disabled by default).</li><li class="listitem"><code class="literal">/actuator/pause</code> and <code class="literal">/actuator/resume</code> for calling the <code class="literal">Lifecycle</code> methods (<code class="literal">stop()</code> and <code class="literal">start()</code> on the <code class="literal">ApplicationContext</code>).</li></ul></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>If you disable the <code class="literal">/actuator/restart</code> endpoint then the <code class="literal">/actuator/pause</code> and <code class="literal">/actuator/resume</code> endpoints |
|
will also be disabled since they are just a special case of <code class="literal">/actuator/restart</code>.</p></td></tr></table></div></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_spring_cloud_commons_common_abstractions" href="#_spring_cloud_commons_common_abstractions"></a>2. Spring Cloud Commons: Common Abstractions</h1></div></div></div><p>Patterns such as service discovery, load balancing, and circuit breakers lend themselves to a common abstraction layer that can be consumed by all Spring Cloud clients, independent of the implementation (for example, discovery with Eureka or Consul).</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_enablediscoveryclient" href="#_enablediscoveryclient"></a>2.1 @EnableDiscoveryClient</h2></div></div></div><p>Spring Cloud Commons provides the <code class="literal">@EnableDiscoveryClient</code> annotation. |
|
This looks for implementations of the <code class="literal">DiscoveryClient</code> interface with <code class="literal">META-INF/spring.factories</code>. |
|
Implementations of the Discovery Client add a configuration class to <code class="literal">spring.factories</code> under the <code class="literal">org.springframework.cloud.client.discovery.EnableDiscoveryClient</code> key. |
|
Examples of <code class="literal">DiscoveryClient</code> implementations include <a class="link" href="http://cloud.spring.io/spring-cloud-netflix/" target="_top">Spring Cloud Netflix Eureka</a>, <a class="link" href="http://cloud.spring.io/spring-cloud-consul/" target="_top">Spring Cloud Consul Discovery</a>, and <a class="link" href="http://cloud.spring.io/spring-cloud-zookeeper/" target="_top">Spring Cloud Zookeeper Discovery</a>.</p><p>By default, implementations of <code class="literal">DiscoveryClient</code> auto-register the local Spring Boot server with the remote discovery server. |
|
This behavior can be disabled by setting <code class="literal">autoRegister=false</code> in <code class="literal">@EnableDiscoveryClient</code>.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p><code class="literal">@EnableDiscoveryClient</code> is no longer required. |
|
You can put a <code class="literal">DiscoveryClient</code> implementation on the classpath to cause the Spring Boot application to register with the service discovery server.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_health_indicator" href="#_health_indicator"></a>2.1.1 Health Indicator</h3></div></div></div><p>Commons creates a Spring Boot <code class="literal">HealthIndicator</code> that <code class="literal">DiscoveryClient</code> implementations can participate in by implementing <code class="literal">DiscoveryHealthIndicator</code>. |
|
To disable the composite <code class="literal">HealthIndicator</code>, set <code class="literal">spring.cloud.discovery.client.composite-indicator.enabled=false</code>. |
|
A generic <code class="literal">HealthIndicator</code> based on <code class="literal">DiscoveryClient</code> is auto-configured (<code class="literal">DiscoveryClientHealthIndicator</code>). |
|
To disable it, set <code class="literal">spring.cloud.discovery.client.health-indicator.enabled=false</code>. |
|
To disable the description field of the <code class="literal">DiscoveryClientHealthIndicator</code>, set <code class="literal">spring.cloud.discovery.client.health-indicator.include-description=false</code>. |
|
Otherwise, it can bubble up as the <code class="literal">description</code> of the rolled up <code class="literal">HealthIndicator</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_ordering_discoveryclient_instances" href="#_ordering_discoveryclient_instances"></a>2.1.2 Ordering <code class="literal">DiscoveryClient</code> instances</h3></div></div></div><p><code class="literal">DiscoveryClient</code> interface extends <code class="literal">Ordered</code>. This is useful when using multiple discovery |
|
clients, as it allows you to define the order of the returned discovery clients, similar to |
|
how you can order the beans loaded by a Spring application. By default, the order of any <code class="literal">DiscoveryClient</code> is set to |
|
<code class="literal">0</code>. If you want to set a different order for your custom <code class="literal">DiscoveryClient</code> implementations, you just need to override |
|
the <code class="literal">getOrder()</code> method so that it returns the value that is suitable for your setup. Apart from this, you can use |
|
properties to set the order of the <code class="literal">DiscoveryClient</code> |
|
implementations provided by Spring Cloud, among others <code class="literal">ConsulDiscoveryClient</code>, <code class="literal">EurekaDiscoveryClient</code> and |
|
<code class="literal">ZookeeperDiscoveryClient</code>. In order to do it, you just need to set the |
|
<code class="literal">spring.cloud.{clientIdentifier}.discovery.order</code> (or <code class="literal">eureka.client.order</code> for Eureka) property to the desired value.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_serviceregistry" href="#_serviceregistry"></a>2.2 ServiceRegistry</h2></div></div></div><p>Commons now provides a <code class="literal">ServiceRegistry</code> interface that provides methods such as <code class="literal">register(Registration)</code> and <code class="literal">deregister(Registration)</code>, which let you provide custom registered services. |
|
<code class="literal">Registration</code> is a marker interface.</p><p>The following example shows the <code class="literal">ServiceRegistry</code> in use:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</span></em> |
|
<em><span class="hl-annotation" style="color: gray">@EnableDiscoveryClient(autoRegister=false)</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> MyConfiguration { |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> ServiceRegistry registry; |
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> MyConfiguration(ServiceRegistry registry) { |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.registry = registry; |
|
} |
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// called through some external process, such as an event or a custom actuator endpoint</span> |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> register() { |
|
Registration registration = constructRegistration(); |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.registry.register(registration); |
|
} |
|
}</pre><p>Each <code class="literal">ServiceRegistry</code> implementation has its own <code class="literal">Registry</code> implementation.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">ZookeeperRegistration</code> used with <code class="literal">ZookeeperServiceRegistry</code></li><li class="listitem"><code class="literal">EurekaRegistration</code> used with <code class="literal">EurekaServiceRegistry</code></li><li class="listitem"><code class="literal">ConsulRegistration</code> used with <code class="literal">ConsulServiceRegistry</code></li></ul></div><p>If you are using the <code class="literal">ServiceRegistry</code> interface, you are going to need to pass the |
|
correct <code class="literal">Registry</code> implementation for the <code class="literal">ServiceRegistry</code> implementation you |
|
are using.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_serviceregistry_auto_registration" href="#_serviceregistry_auto_registration"></a>2.2.1 ServiceRegistry Auto-Registration</h3></div></div></div><p>By default, the <code class="literal">ServiceRegistry</code> implementation auto-registers the running service. |
|
To disable that behavior, you can set: |
|
* <code class="literal">@EnableDiscoveryClient(autoRegister=false)</code> to permanently disable auto-registration. |
|
* <code class="literal">spring.cloud.service-registry.auto-registration.enabled=false</code> to disable the behavior through configuration.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_service_registry_actuator_endpoint" href="#_service_registry_actuator_endpoint"></a>2.2.2 Service Registry Actuator Endpoint</h3></div></div></div><p>Spring Cloud Commons provides a <code class="literal">/service-registry</code> actuator endpoint. |
|
This endpoint relies on a <code class="literal">Registration</code> bean in the Spring Application Context. |
|
Calling <code class="literal">/service-registry</code> with GET returns the status of the <code class="literal">Registration</code>. |
|
Using POST to the same endpoint with a JSON body changes the status of the current <code class="literal">Registration</code> to the new value. |
|
The JSON body has to include the <code class="literal">status</code> field with the preferred value. |
|
Please see the documentation of the <code class="literal">ServiceRegistry</code> implementation you use for the allowed values when updating the status and the values returned for the status. |
|
For instance, Eureka’s supported statuses are <code class="literal">UP</code>, <code class="literal">DOWN</code>, <code class="literal">OUT_OF_SERVICE</code>, and <code class="literal">UNKNOWN</code>.</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spring_resttemplate_as_a_load_balancer_client" href="#_spring_resttemplate_as_a_load_balancer_client"></a>2.3 Spring RestTemplate as a Load Balancer Client</h2></div></div></div><p><code class="literal">RestTemplate</code> can be automatically configured to use ribbon. |
|
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"><em><span class="hl-annotation" style="color: gray">@Configuration</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> MyConfiguration { |
|
|
|
<em><span class="hl-annotation" style="color: gray">@LoadBalanced</span></em> |
|
<em><span class="hl-annotation" style="color: gray">@Bean</span></em> |
|
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 { |
|
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> |
|
<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-core/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><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spring_webclient_as_a_load_balancer_client" href="#_spring_webclient_as_a_load_balancer_client"></a>2.4 Spring WebClient as a Load Balancer Client</h2></div></div></div><p><code class="literal">WebClient</code> can be automatically configured to use the <code class="literal">LoadBalancerClient</code>. |
|
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"><em><span class="hl-annotation" style="color: gray">@Configuration</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> MyConfiguration { |
|
|
|
<em><span class="hl-annotation" style="color: gray">@Bean</span></em> |
|
<em><span class="hl-annotation" style="color: gray">@LoadBalanced</span></em> |
|
<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 { |
|
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> WebClient.Builder webClientBuilder; |
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Mono<String> doOtherStuff() { |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> webClientBuilder.build().get().uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://stores/stores"</span>) |
|
.retrieve().bodyToMono(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>); |
|
} |
|
}</pre><p>The URI needs to use a virtual host name (that is, a service name, not a host name). |
|
The Ribbon client is used to create a full physical address.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_retrying_failed_requests" href="#_retrying_failed_requests"></a>2.4.1 Retrying Failed Requests</h3></div></div></div><p>A load-balanced <code class="literal">RestTemplate</code> can be configured to retry failed requests. |
|
By default, this logic is disabled. |
|
You can enable it by adding <a class="link" href="https://github.com/spring-projects/spring-retry" target="_top">Spring Retry</a> to your application’s classpath. |
|
The load-balanced <code class="literal">RestTemplate</code> honors some of the Ribbon configuration values related to retrying failed requests. |
|
You can use <code class="literal">client.ribbon.MaxAutoRetries</code>, <code class="literal">client.ribbon.MaxAutoRetriesNextServer</code>, and <code class="literal">client.ribbon.OkToRetryOnAllOperations</code> properties. |
|
If you would like to disable the retry logic with Spring Retry on the classpath, you can set <code class="literal">spring.cloud.loadbalancer.retry.enabled=false</code>. |
|
See the <a class="link" href="https://github.com/Netflix/ribbon/wiki/Getting-Started#the-properties-file-sample-clientproperties" target="_top">Ribbon documentation</a> for a description of what these properties do.</p><p>If you would like to implement a <code class="literal">BackOffPolicy</code> in your retries, you need to create a bean of type <code class="literal">LoadBalancedBackOffPolicyFactory</code> and return the <code class="literal">BackOffPolicy</code> you would like to use for a given service, as shown in the following example:</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">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyConfiguration { |
|
<em><span class="hl-annotation" style="color: gray">@Bean</span></em> |
|
LoadBalancedBackOffPolicyFactory backOffPolciyFactory() { |
|
<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> LoadBalancedBackOffPolicyFactory() { |
|
<em><span class="hl-annotation" style="color: gray">@Override</span></em> |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> BackOffPolicy createBackOffPolicy(String service) { |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ExponentialBackOffPolicy(); |
|
} |
|
}; |
|
} |
|
}</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p><code class="literal">client</code> in the preceding examples should be replaced with your Ribbon client’s name.</p></td></tr></table></div><p>If you want to add one or more <code class="literal">RetryListener</code> implementations to your retry functionality, you need to |
|
create a bean of type <code class="literal">LoadBalancedRetryListenerFactory</code> and return the <code class="literal">RetryListener</code> array |
|
you would like to use for a given service, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</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> MyConfiguration { |
|
<em><span class="hl-annotation" style="color: gray">@Bean</span></em> |
|
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() { |
|
<em><span class="hl-annotation" style="color: gray">@Override</span></em> |
|
<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() { |
|
<em><span class="hl-annotation" style="color: gray">@Override</span></em> |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <T, E <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> Throwable> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> open(RetryContext context, RetryCallback<T, E> callback) { |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//TODO Do you business...</span> |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> true; |
|
} |
|
|
|
<em><span class="hl-annotation" style="color: gray">@Override</span></em> |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <T, E <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> Throwable> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//TODO Do you business...</span> |
|
} |
|
|
|
<em><span class="hl-annotation" style="color: gray">@Override</span></em> |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <T, E <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> Throwable> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">//TODO Do you business...</span> |
|
} |
|
}}; |
|
} |
|
}; |
|
} |
|
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_multiple_resttemplate_objects" href="#_multiple_resttemplate_objects"></a>2.5 Multiple RestTemplate objects</h2></div></div></div><p>If you want a <code class="literal">RestTemplate</code> that is not load-balanced, create a <code class="literal">RestTemplate</code> bean and inject it. |
|
To access the load-balanced <code class="literal">RestTemplate</code>, use the <code class="literal">@LoadBalanced</code> qualifier when you create your <code class="literal">@Bean</code>, as shown in the following example:\</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</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> MyConfiguration { |
|
|
|
<em><span class="hl-annotation" style="color: gray">@LoadBalanced</span></em> |
|
<em><span class="hl-annotation" style="color: gray">@Bean</span></em> |
|
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(); |
|
} |
|
|
|
<em><span class="hl-annotation" style="color: gray">@Primary</span></em> |
|
<em><span class="hl-annotation" style="color: gray">@Bean</span></em> |
|
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 { |
|
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> RestTemplate restTemplate; |
|
|
|
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> |
|
<em><span class="hl-annotation" style="color: gray">@LoadBalanced</span></em> |
|
<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">"http://example.com"</span>, String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>); |
|
} |
|
}</pre><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Notice the use of the <code class="literal">@Primary</code> annotation on the plain <code class="literal">RestTemplate</code> declaration in the preceding example to disambiguate the unqualified <code class="literal">@Autowired</code> injection.</p></td></tr></table></div><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>If you see errors such as <code class="literal">java.lang.IllegalArgumentException: Can not set org.springframework.web.client.RestTemplate field com.my.app.Foo.restTemplate to com.sun.proxy.$Proxy89</code>, try injecting <code class="literal">RestOperations</code> or setting <code class="literal">spring.aop.proxyTargetClass=true</code>.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="loadbalanced-webclient" href="#loadbalanced-webclient"></a>2.6 Spring WebFlux WebClient as a Load Balancer Client</h2></div></div></div><p><code class="literal">WebClient</code> can be configured to use the <code class="literal">LoadBalancerClient</code>. <code class="literal">LoadBalancerExchangeFilterFunction</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 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 { |
|
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> LoadBalancerExchangeFilterFunction lbFunction; |
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Mono<String> doOtherStuff() { |
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> WebClient.builder().baseUrl(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://stores"</span>) |
|
.filter(lbFunction) |
|
.build() |
|
.get() |
|
.uri(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/stores"</span>) |
|
.retrieve() |
|
.bodyToMono(String.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>); |
|
} |
|
}</pre><p>The URI needs to use a virtual host name (that is, a service name, not a host name). |
|
The <code class="literal">LoadBalancerClient</code> is used to create a full physical address.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="ignore-network-interfaces" href="#ignore-network-interfaces"></a>2.7 Ignore Network Interfaces</h2></div></div></div><p>Sometimes, it is useful to ignore certain named network interfaces so that they can be excluded from Service Discovery registration (for example, when running in a Docker container). |
|
A list of regular expressions can be set to cause the desired network interfaces to be ignored. |
|
The following configuration ignores the <code class="literal">docker0</code> interface and all interfaces that start with <code class="literal">veth</code>:</p><p><b>application.yml. </b> |
|
</p><pre class="screen">spring: |
|
cloud: |
|
inetutils: |
|
ignoredInterfaces: |
|
- docker0 |
|
- veth.*</pre><p> |
|
</p><p>You can also force the use of only specified network addresses by using a list of regular expressions, as shown in the following example:</p><p><b>bootstrap.yml. </b> |
|
</p><pre class="screen">spring: |
|
cloud: |
|
inetutils: |
|
preferredNetworks: |
|
- 192.168 |
|
- 10.0</pre><p> |
|
</p><p>You can also force the use of only site-local addresses, as shown in the following example: |
|
.application.yml</p><pre class="screen">spring: |
|
cloud: |
|
inetutils: |
|
useOnlySiteLocalInterfaces: true</pre><p>See <a class="link" href="https://docs.oracle.com/javase/8/docs/api/java/net/Inet4Address.html#isSiteLocalAddress--" target="_top">Inet4Address.html.isSiteLocalAddress()</a> for more details about what constitutes a site-local address.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="http-clients" href="#http-clients"></a>2.8 HTTP Client Factories</h2></div></div></div><p>Spring Cloud Commons provides beans for creating both Apache HTTP clients (<code class="literal">ApacheHttpClientFactory</code>) and OK HTTP clients (<code class="literal">OkHttpClientFactory</code>). |
|
The <code class="literal">OkHttpClientFactory</code> bean is created only if the OK HTTP jar is on the classpath. |
|
In addition, Spring Cloud Commons provides beans for creating the connection managers used by both clients: <code class="literal">ApacheHttpClientConnectionManagerFactory</code> for the Apache HTTP client and <code class="literal">OkHttpClientConnectionPoolFactory</code> for the OK HTTP client. |
|
If you would like to customize how the HTTP clients are created in downstream projects, you can provide your own implementation of these beans. |
|
In addition, if you provide a bean of type <code class="literal">HttpClientBuilder</code> or <code class="literal">OkHttpClient.Builder</code>, the default factories use these builders as the basis for the builders returned to downstream projects. |
|
You can also disable the creation of these beans by setting <code class="literal">spring.cloud.httpclientfactories.apache.enabled</code> or <code class="literal">spring.cloud.httpclientfactories.ok.enabled</code> to <code class="literal">false</code>.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="enabled-features" href="#enabled-features"></a>2.9 Enabled Features</h2></div></div></div><p>Spring Cloud Commons provides a <code class="literal">/features</code> actuator endpoint. |
|
This endpoint returns features available on the classpath and whether they are enabled. |
|
The information returned includes the feature type, name, version, and vendor.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_feature_types" href="#_feature_types"></a>2.9.1 Feature types</h3></div></div></div><p>There are two types of 'features': abstract and named.</p><p>Abstract features are features where an interface or abstract class is defined and that an implementation the creates, such as <code class="literal">DiscoveryClient</code>, <code class="literal">LoadBalancerClient</code>, or <code class="literal">LockService</code>. |
|
The abstract class or interface is used to find a bean of that type in the context. |
|
The version displayed is <code class="literal">bean.getClass().getPackage().getImplementationVersion()</code>.</p><p>Named features are features that do not have a particular class they implement, such as "Circuit Breaker", "API Gateway", "Spring Cloud Bus", and others. These features require a name and a bean type.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_declaring_features" href="#_declaring_features"></a>2.9.2 Declaring features</h3></div></div></div><p>Any module can declare any number of <code class="literal">HasFeature</code> beans, as shown in the following examples:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em> |
|
<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>); |
|
} |
|
|
|
<em><span class="hl-annotation" style="color: gray">@Bean</span></em> |
|
<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>)); |
|
} |
|
|
|
<em><span class="hl-annotation" style="color: gray">@Bean</span></em> |
|
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></div></body></html> |