diff --git a/docs/pom.xml b/docs/pom.xml
index 750a0699..7225f151 100644
--- a/docs/pom.xml
+++ b/docs/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
spring-cloud-netflix-docs
pom
diff --git a/docs/src/main/asciidoc/spring-cloud-netflix.adoc b/docs/src/main/asciidoc/spring-cloud-netflix.adoc
index 53961116..bd65af99 100644
--- a/docs/src/main/asciidoc/spring-cloud-netflix.adoc
+++ b/docs/src/main/asciidoc/spring-cloud-netflix.adoc
@@ -1012,6 +1012,30 @@ static class HystrixClientFallback implements HystrixClient {
}
----
+If one needs access to the cause that made the fallback trigger, one can use the `fallbackFactory` attribute inside `@FeignClient`.
+
+[source,java,indent=0]
+----
+@FeignClient(name = "hello", fallbackFactory = HystrixClientFallbackFactory.class)
+protected interface HystrixClient {
+ @RequestMapping(method = RequestMethod.GET, value = "/hello")
+ Hello iFailSometimes();
+}
+
+@Component
+static class HystrixClientFallbackFactory implements FallbackFactory {
+ @Override
+ public HystrixClient create(Throwable cause) {
+ return new HystrixClientWithFallBackFactory() {
+ @Override
+ public Hello iFailSometimes() {
+ return new Hello("fallback; reason was: " + cause.getMessage());
+ }
+ };
+ }
+}
+----
+
WARNING: There is a limitation with the implementation of fallbacks in Feign and how Hystrix fallbacks work. Fallbacks are currently not supported for methods that return `com.netflix.hystrix.HystrixCommand` and `rx.Observable`.
[[spring-cloud-feign-inheritance]]
@@ -1363,7 +1387,7 @@ path rendering the `users` path unreachable.
=== Zuul Http Client
The default HTTP client used by zuul is now backed by the Apache HTTP Client instead of the
-deprecated Ribbon `RestClient. To use `RestClient` or to use the `okhttp3.OkHttpClient` set
+deprecated Ribbon `RestClient`. To use `RestClient` or to use the `okhttp3.OkHttpClient` set
`ribbon.restclient.enabled=true` or `ribbon.okhttp.enabled=true` respectively.
=== Cookies and Sensitive Headers
@@ -1734,6 +1758,18 @@ If Spring AOP is enabled and `org.aspectj:aspectjweaver` is present on your runt
3. URI, sanitized for Atlas
4. Client name
+WARNING: Avoid using hardcoded url parameters within `RestTemplate`. When targeting dynamic endpoints use URL variables. This will avoid potential "GC Overhead Limit Reached" issues where `ServoMonitorCache` treats each url as a unique key.
+
+[source,java,indent=0]
+----
+// recommended
+String orderid = "1";
+restTemplate.getForObject("http://testeurekabrixtonclient/orders/{orderid}", String.class, orderid)
+
+// avoid
+restTemplate.getForObject("http://testeurekabrixtonclient/orders/1", String.class)
+----
+
[[netflix-metrics-spectator]]
=== Metrics Collection: Spectator
diff --git a/pom.xml b/pom.xml
index b0994d49..ef239e18 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,14 +3,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
pom
Spring Cloud Netflix
Spring Cloud Netflix
org.springframework.cloud
spring-cloud-build
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
@@ -24,8 +24,8 @@
${basedir}
4.0.27.Final
2.7.3
- 1.1.4.BUILD-SNAPSHOT
- 1.2.1.BUILD-SNAPSHOT
+ 1.1.5.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
Brooklyn.BUILD-SNAPSHOT
diff --git a/spring-cloud-netflix-core/pom.xml b/spring-cloud-netflix-core/pom.xml
index 8f6985cc..3343772a 100644
--- a/spring-cloud-netflix-core/pom.xml
+++ b/spring-cloud-netflix-core/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-netflix-core
diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java
index 8c2e361f..1dc139a1 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java
@@ -90,6 +90,16 @@ public @interface FeignClient {
*/
Class> fallback() default void.class;
+ /**
+ * Define a fallback factory for the specified Feign client interface. The fallback
+ * factory must produce instances of fallback classes that implement the interface
+ * annotated by {@link FeignClient}. The fallback factory must be a valid spring
+ * bean.
+ *
+ * @see feign.hystrix.FallbackFactory for details.
+ */
+ Class> fallbackFactory() default void.class;
+
/**
* Path prefix to be used by all method-level mappings. Can be used with or without
* @RibbonClient.
diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientFactoryBean.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientFactoryBean.java
index fa345d88..e5fcffc7 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientFactoryBean.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientFactoryBean.java
@@ -51,9 +51,9 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = false)
class FeignClientFactoryBean implements FactoryBean, InitializingBean,
ApplicationContextAware {
-
- @Autowired
- private Targeter targeter;
+ /***********************************
+ * WARNING! Nothing in this class should be @Autowired. It causes NPEs because of some lifecycle race condition.
+ ***********************************/
private Class> type;
@@ -69,6 +69,8 @@ class FeignClientFactoryBean implements FactoryBean, InitializingBean,
private Class> fallback = void.class;
+ private Class> fallbackFactory = void.class;
+
@Override
public void afterPropertiesSet() throws Exception {
Assert.hasText(this.name, "Name must be set");
@@ -144,6 +146,7 @@ class FeignClientFactoryBean implements FactoryBean, InitializingBean,
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
+ Targeter targeter = get(context, Targeter.class);
return targeter.target(this, builder, context, target);
}
@@ -181,6 +184,7 @@ class FeignClientFactoryBean implements FactoryBean, InitializingBean,
}
builder.client(client);
}
+ Targeter targeter = get(context, Targeter.class);
return targeter.target(this, builder, context, new HardCodedTarget<>(
this.type, this.name, url));
}
diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsRegistrar.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsRegistrar.java
index 9020c6e7..53c34ef5 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsRegistrar.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsRegistrar.java
@@ -179,6 +179,7 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
+ definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
String alias = name + "FeignClient";
diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/HystrixTargeter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/HystrixTargeter.java
index 5b9ed8d8..66106c70 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/HystrixTargeter.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/HystrixTargeter.java
@@ -19,6 +19,9 @@ package org.springframework.cloud.netflix.feign;
import feign.Feign;
import feign.Target;
+import feign.hystrix.FallbackFactory;
+import feign.hystrix.HystrixFeign;
+import org.springframework.util.Assert;
/**
* @author Spencer Gibb
@@ -29,26 +32,67 @@ class HystrixTargeter implements Targeter {
@Override
public T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
Target.HardCodedTarget target) {
- if (factory.getFallback() == void.class
- || !(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
+ if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
return feign.target(target);
}
+ feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
+ Class> fallback = factory.getFallback();
+ if (fallback != void.class) {
+ return targetWithFallback(factory.getName(), context, target, builder, fallback);
+ }
+ Class> fallbackFactory = factory.getFallbackFactory();
+ if (fallbackFactory != void.class) {
+ return targetWithFallbackFactory(factory.getName(), context, target, builder, fallbackFactory);
+ }
- Object fallbackInstance = context.getInstance(factory.getName(), factory.getFallback());
+ return feign.target(target);
+ }
+
+ private T targetWithFallbackFactory(String feignClientName, FeignContext context,
+ Target.HardCodedTarget target,
+ HystrixFeign.Builder builder,
+ Class> fallbackFactoryClass) {
+ FallbackFactory extends T> fallbackFactory = (FallbackFactory extends T>)
+ getFromContext("fallbackFactory", feignClientName, context, fallbackFactoryClass, FallbackFactory.class);
+ /* We take a sample fallback from the fallback factory to check if it returns a fallback
+ that is compatible with the annotated feign interface. */
+ Object exampleFallback = fallbackFactory.create(new RuntimeException());
+ Assert.notNull(exampleFallback,
+ String.format(
+ "Incompatible fallbackFactory instance for feign client %s. Factory may not produce null!",
+ feignClientName));
+ if (!target.type().isAssignableFrom(exampleFallback.getClass())) {
+ throw new IllegalStateException(
+ String.format(
+ "Incompatible fallbackFactory instance for feign client %s. Factory produces instances of '%s', but should produce instances of '%s'",
+ feignClientName, exampleFallback.getClass(), target.type()));
+ }
+ return builder.target(target, fallbackFactory);
+ }
+
+
+ private T targetWithFallback(String feignClientName, FeignContext context,
+ Target.HardCodedTarget target,
+ HystrixFeign.Builder builder, Class> fallback) {
+ T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type());
+ return builder.target(target, fallbackInstance);
+ }
+
+ private T getFromContext(String fallbackMechanism, String feignClientName, FeignContext context,
+ Class> beanType, Class targetType) {
+ Object fallbackInstance = context.getInstance(feignClientName, beanType);
if (fallbackInstance == null) {
throw new IllegalStateException(String.format(
- "No fallback instance of type %s found for feign client %s",
- factory.getFallback(), factory.getName()));
+ "No " + fallbackMechanism + " instance of type %s found for feign client %s",
+ beanType, feignClientName));
}
- if (!target.type().isAssignableFrom(factory.getFallback())) {
+ if (!targetType.isAssignableFrom(beanType)) {
throw new IllegalStateException(
String.format(
- "Incompatible fallback instance. Fallback of type %s is not assignable to %s for feign client %s",
- factory.getFallback(), target.type(), factory.getName()));
+ "Incompatible " + fallbackMechanism + " instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s",
+ beanType, targetType, feignClientName));
}
-
- feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
- return builder.target(target, (T) fallbackInstance);
+ return (T) fallbackInstance;
}
}
diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancerClient.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancerClient.java
index 96ef9ae2..ca6ddfd8 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancerClient.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancerClient.java
@@ -52,11 +52,10 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient{
RibbonLoadBalancerContext context = this.clientFactory
.getLoadBalancerContext(serviceId);
Server server = new Server(instance.getHost(), instance.getPort());
- boolean secure = isSecure(server, serviceId);
- URI uri = original;
- if (secure) {
- uri = UriComponentsBuilder.fromUri(uri).scheme("https").build().toUri();
- }
+ IClientConfig clientConfig = clientFactory.getClientConfig(serviceId);
+ ServerIntrospector serverIntrospector = serverIntrospector(serviceId);
+ URI uri = RibbonUtils.updateToHttpsIfNeeded(original, clientConfig,
+ serverIntrospector, server);
return context.reconstructURIWithServer(server, uri);
}
diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulConfiguration.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulConfiguration.java
index cc5a5d0b..81f46576 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulConfiguration.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/ZuulConfiguration.java
@@ -24,8 +24,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration;
-import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.actuator.HasFeatures;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.cloud.client.discovery.event.HeartbeatMonitor;
diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java
index 0f99a99e..85bdb599 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelper.java
@@ -249,6 +249,12 @@ public class ProxyRequestHelper {
MultiValueMap headers) {
}
+ /**
+ * Get url encoded query string. Pay special attention to single parameters with no values
+ * and parameter names with colon (:) from use of UriTemplate.
+ * @param params Un-encoded request parameters
+ * @return
+ */
public String getQueryString(MultiValueMap params) {
if (params.isEmpty()) {
return "";
@@ -260,10 +266,21 @@ public class ProxyRequestHelper {
for (String value : params.get(param)) {
query.append("&");
query.append(param);
- if (!"".equals(value)) {
- singles.put(param + i, value);
+ if (!"".equals(value)) { // don't add =, if original is ?wsdl, output is not ?wsdl=
+ String key = param;
+ // if form feed is already part of param name double
+ // since form feed is used as the colon replacement below
+ if (key.contains("\f")) {
+ key = (key.replaceAll("\f", "\f\f"));
+ }
+ // colon is special to UriTemplate
+ if (key.contains(":")) {
+ key = key.replaceAll(":", "\f");
+ }
+ key = key + i;
+ singles.put(key, value);
query.append("={");
- query.append(param + i);
+ query.append(key);
query.append("}");
}
i++;
diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java
index b621f59d..59c37dab 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/ZuulProperties.java
@@ -103,7 +103,7 @@ public class ZuulProperties {
private Set ignoredHeaders = new LinkedHashSet<>();
/**
- * SECURITY_HEADERS are added to ignored headers if spring security is on the classpath and ignoreSecurityHeaders = true
+ * Flag to say that SECURITY_HEADERS are added to ignored headers if spring security is on the classpath.
* By setting ignoreSecurityHeaders to false we can switch off this default behaviour. This should be used together with
* disabling the default spring security headers
* see https://docs.spring.io/spring-security/site/docs/current/reference/html/headers.html#default-security-headers
diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java
index 22681762..500ee5a2 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java
@@ -22,16 +22,14 @@ import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.List;
-import java.util.Map.Entry;
import java.util.Set;
+import java.util.Map.Entry;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestWrapper;
import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.Part;
-import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
@@ -44,6 +42,7 @@ import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ReflectionUtils;
+import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;
import org.springframework.web.servlet.DispatcherServlet;
@@ -65,7 +64,7 @@ public class FormBodyWrapperFilter extends ZuulFilter {
this.requestField = ReflectionUtils.findField(HttpServletRequestWrapper.class,
"req", HttpServletRequest.class);
this.servletRequestField = ReflectionUtils.findField(ServletRequestWrapper.class,
- "request", ServletRequest.class);
+ "request", ServletRequest.class);
Assert.notNull(this.requestField,
"HttpServletRequestWrapper.req field not found");
Assert.notNull(this.servletRequestField,
@@ -121,7 +120,7 @@ public class FormBodyWrapperFilter extends ZuulFilter {
.getField(this.requestField, request);
wrapper = new FormBodyRequestWrapper(wrapped);
ReflectionUtils.setField(this.requestField, request, wrapper);
- if(request instanceof ServletRequestWrapper) {
+ if (request instanceof ServletRequestWrapper) {
ReflectionUtils.setField(this.servletRequestField, request, wrapper);
}
}
@@ -170,7 +169,7 @@ public class FormBodyWrapperFilter extends ZuulFilter {
}
return this.contentLength;
}
-
+
@Override
public long getContentLengthLong() {
return getContentLength();
@@ -233,7 +232,7 @@ public class FormBodyWrapperFilter extends ZuulFilter {
Set result = new HashSet<>();
String query = this.request.getQueryString();
if (query != null) {
- for (String value : StringUtils.split(query, "&")) {
+ for (String value : StringUtils.tokenizeToStringArray(query, "&")) {
if (value.contains("=")) {
value = value.substring(0, value.indexOf("="));
}
diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java
index cdefd022..a76a5dd5 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java
@@ -63,6 +63,7 @@ import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
+import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.protocol.HttpContext;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
@@ -271,34 +272,13 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
URL host = RequestContext.getCurrentContext().getRouteHost();
HttpHost httpHost = getHttpHost(host);
uri = StringUtils.cleanPath((host.getPath() + uri).replaceAll("/{2,}", "/"));
- HttpRequest httpRequest;
int contentLength = request.getContentLength();
InputStreamEntity entity = new InputStreamEntity(requestEntity, contentLength,
request.getContentType() != null
? ContentType.create(request.getContentType()) : null);
- switch (verb.toUpperCase()) {
- case "POST":
- HttpPost httpPost = new HttpPost(uri + this.helper.getQueryString(params));
- httpRequest = httpPost;
- httpPost.setEntity(entity);
- break;
- case "PUT":
- HttpPut httpPut = new HttpPut(uri + this.helper.getQueryString(params));
- httpRequest = httpPut;
- httpPut.setEntity(entity);
- break;
- case "PATCH":
- HttpPatch httpPatch = new HttpPatch(uri + this.helper.getQueryString(params));
- httpRequest = httpPatch;
- httpPatch.setEntity(entity);
- break;
- default:
- httpRequest = new BasicHttpRequest(verb,
- uri + this.helper.getQueryString(params));
- log.debug(uri + this.helper.getQueryString(params));
- }
+
+ HttpRequest httpRequest = buildHttpRequest(verb, uri, entity, headers, params);
try {
- httpRequest.setHeaders(convertHeaders(headers));
log.debug(httpHost.getHostName() + " " + httpHost.getPort() + " "
+ httpHost.getSchemeName());
HttpResponse zuulResponse = forwardRequest(httpclient, httpHost, httpRequest);
@@ -314,6 +294,43 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
}
}
+ protected HttpRequest buildHttpRequest (String verb, String uri, InputStreamEntity entity,
+ MultiValueMap headers, MultiValueMap params)
+ {
+ HttpRequest httpRequest;
+
+ switch (verb.toUpperCase()) {
+ case "POST":
+ HttpPost httpPost = new HttpPost(uri + this.helper.getQueryString(params));
+ httpRequest = httpPost;
+ httpPost.setEntity(entity);
+ break;
+ case "PUT":
+ HttpPut httpPut = new HttpPut(uri + this.helper.getQueryString(params));
+ httpRequest = httpPut;
+ httpPut.setEntity(entity);
+ break;
+ case "PATCH":
+ HttpPatch httpPatch = new HttpPatch(uri + this.helper.getQueryString(params));
+ httpRequest = httpPatch;
+ httpPatch.setEntity(entity);
+ break;
+ case "DELETE":
+ BasicHttpEntityEnclosingRequest entityRequest = new BasicHttpEntityEnclosingRequest(verb,
+ uri + this.helper.getQueryString(params));
+ httpRequest = entityRequest;
+ entityRequest.setEntity(entity);
+ break;
+ default:
+ httpRequest = new BasicHttpRequest(verb,
+ uri + this.helper.getQueryString(params));
+ log.debug(uri + this.helper.getQueryString(params));
+ }
+
+ httpRequest.setHeaders(convertHeaders(headers));
+ return httpRequest;
+ }
+
private MultiValueMap revertHeaders(Header[] headers) {
MultiValueMap map = new LinkedMultiValueMap();
for (Header header : headers) {
diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/invalid/FeignClientValidationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/invalid/FeignClientValidationTests.java
index 178fc643..bd7d235f 100644
--- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/invalid/FeignClientValidationTests.java
+++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/invalid/FeignClientValidationTests.java
@@ -16,6 +16,7 @@
package org.springframework.cloud.netflix.feign.invalid;
+import feign.hystrix.FallbackFactory;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -42,10 +43,7 @@ public class FeignClientValidationTests {
@Test
public void testNameAndValue() {
this.expected.expectMessage("only one is permitted");
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
- NameAndValueConfiguration.class);
- assertNotNull(context.getBean(NameAndValueConfiguration.Client.class));
- context.close();
+ new AnnotationConfigApplicationContext(NameAndValueConfiguration.class);
}
@Configuration
@@ -86,10 +84,7 @@ public class FeignClientValidationTests {
@Test
public void testNotLegalHostname() {
this.expected.expectMessage("not legal hostname (foo_bar)");
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
- BadHostnameConfiguration.class);
- assertNotNull(context.getBean(BadHostnameConfiguration.Client.class));
- context.close();
+ new AnnotationConfigApplicationContext(BadHostnameConfiguration.class);
}
@Configuration
@@ -107,11 +102,12 @@ public class FeignClientValidationTests {
@Test
public void testMissingFallback() {
- this.expected.expectMessage("No fallback instance of type");
+ try (
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
- MissingFallbackConfiguration.class);
- assertNotNull(context.getBean(MissingFallbackConfiguration.Client.class));
- context.close();
+ MissingFallbackConfiguration.class)) {
+ this.expected.expectMessage("No fallback instance of type");
+ assertNotNull(context.getBean(MissingFallbackConfiguration.Client.class));
+ }
}
@Configuration
@@ -136,11 +132,11 @@ public class FeignClientValidationTests {
@Test
public void testWrongFallbackType() {
- this.expected.expectMessage("Incompatible fallback instance");
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
- WrongFallbackTypeConfiguration.class);
- assertNotNull(context.getBean(WrongFallbackTypeConfiguration.Client.class));
- context.close();
+ try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
+ WrongFallbackTypeConfiguration.class)) {
+ this.expected.expectMessage("Incompatible fallback instance");
+ assertNotNull(context.getBean(WrongFallbackTypeConfiguration.Client.class));
+ }
}
@Configuration
@@ -163,4 +159,98 @@ public class FeignClientValidationTests {
}
}
+
+ @Test
+ public void testMissingFallbackFactory() {
+ try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
+ MissingFallbackFactoryConfiguration.class)) {
+ this.expected.expectMessage("No fallbackFactory instance of type");
+ assertNotNull(context.getBean(MissingFallbackFactoryConfiguration.Client.class));
+ }
+ }
+
+ @Configuration
+ @Import(FeignAutoConfiguration.class)
+ @EnableFeignClients(clients = MissingFallbackFactoryConfiguration.Client.class)
+ protected static class MissingFallbackFactoryConfiguration {
+
+ @FeignClient(name = "foobar", url = "http://localhost", fallbackFactory = ClientFallback.class)
+ interface Client {
+ @RequestMapping(method = RequestMethod.GET, value = "/")
+ String get();
+ }
+
+ class ClientFallback implements FallbackFactory {
+
+ @Override
+ public Client create(Throwable cause) {
+ return null;
+ }
+ }
+ }
+
+ @Test
+ public void testWrongFallbackFactoryType() {
+ try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
+ WrongFallbackFactoryTypeConfiguration.class)) {
+ this.expected.expectMessage("Incompatible fallbackFactory instance");
+ assertNotNull(context.getBean(WrongFallbackFactoryTypeConfiguration.Client.class));
+ }
+ }
+
+ @Configuration
+ @Import(FeignAutoConfiguration.class)
+ @EnableFeignClients(clients = WrongFallbackFactoryTypeConfiguration.Client.class)
+ protected static class WrongFallbackFactoryTypeConfiguration {
+
+ @FeignClient(name = "foobar", url = "http://localhost", fallbackFactory = Dummy.class)
+ interface Client {
+ @RequestMapping(method = RequestMethod.GET, value = "/")
+ String get();
+ }
+
+ @Bean
+ Dummy dummy() {
+ return new Dummy();
+ }
+
+ class Dummy {
+ }
+
+ }
+
+ @Test
+ public void testWrongFallbackFactoryGenericType() {
+ try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
+ WrongFallbackFactoryGenericTypeConfiguration.class)) {
+ this.expected.expectMessage("Incompatible fallbackFactory instance");
+ assertNotNull(context.getBean(WrongFallbackFactoryGenericTypeConfiguration.Client.class));
+ }
+ }
+
+ @Configuration
+ @Import(FeignAutoConfiguration.class)
+ @EnableFeignClients(clients = WrongFallbackFactoryGenericTypeConfiguration.Client.class)
+ protected static class WrongFallbackFactoryGenericTypeConfiguration {
+
+ @FeignClient(name = "foobar", url = "http://localhost", fallbackFactory = ClientFallback.class)
+ interface Client {
+ @RequestMapping(method = RequestMethod.GET, value = "/")
+ String get();
+ }
+
+ @Bean
+ ClientFallback dummy() {
+ return new ClientFallback();
+ }
+
+ class ClientFallback implements FallbackFactory {
+
+ @Override
+ public String create(Throwable cause) {
+ return "tryinToTrickYa";
+ }
+ }
+
+ }
}
diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignClientTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignClientTests.java
index 49f3b831..366e6454 100644
--- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignClientTests.java
+++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignClientTests.java
@@ -74,6 +74,7 @@ import feign.Client;
import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
+import feign.hystrix.FallbackFactory;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -115,6 +116,9 @@ public class FeignClientTests {
@Autowired
HystrixClient hystrixClient;
+ @Autowired
+ private HystrixClientWithFallBackFactory hystrixClientWithFallBackFactory;
+
@Autowired
@Qualifier("localapp3FeignClient")
HystrixClient namedHystrixClient;
@@ -237,6 +241,27 @@ public class FeignClientTests {
Future failFuture();
}
+ @FeignClient(name = "localapp4", fallbackFactory = HystrixClientFallbackFactory.class)
+ protected interface HystrixClientWithFallBackFactory {
+
+ @RequestMapping(method = RequestMethod.GET, path = "/fail")
+ Hello fail();
+ }
+
+ static class HystrixClientFallbackFactory implements FallbackFactory {
+
+ @Override
+ public HystrixClientWithFallBackFactory create(final Throwable cause) {
+ return new HystrixClientWithFallBackFactory() {
+ @Override
+ public Hello fail() {
+ assertNotNull("Cause was null", cause);
+ return new Hello("Hello from the fallback side: " + cause.getMessage());
+ }
+ };
+ }
+ }
+
static class HystrixClientFallback implements HystrixClient {
@Override
public Hello fail() {
@@ -268,13 +293,15 @@ public class FeignClientTests {
@EnableAutoConfiguration
@RestController
@EnableFeignClients(clients = { TestClientServiceId.class, TestClient.class,
- DecodingTestClient.class,
- HystrixClient.class }, defaultConfiguration = TestDefaultFeignConfig.class)
+ DecodingTestClient.class, HystrixClient.class, HystrixClientWithFallBackFactory.class },
+ defaultConfiguration = TestDefaultFeignConfig.class)
@RibbonClients({
@RibbonClient(name = "localapp", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp1", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp2", configuration = LocalRibbonClientConfiguration.class),
- @RibbonClient(name = "localapp3", configuration = LocalRibbonClientConfiguration.class), })
+ @RibbonClient(name = "localapp3", configuration = LocalRibbonClientConfiguration.class),
+ @RibbonClient(name = "localapp4", configuration = LocalRibbonClientConfiguration.class)
+ })
protected static class Application {
// needs to be in parent context to test multiple HystrixClient beans
@@ -283,6 +310,11 @@ public class FeignClientTests {
return new HystrixClientFallback();
}
+ @Bean
+ public HystrixClientFallbackFactory hystrixClientFallbackFactory() {
+ return new HystrixClientFallbackFactory();
+ }
+
@Bean
FeignFormatterRegistrar feignFormatterRegistrar() {
return new FeignFormatterRegistrar() {
@@ -584,6 +616,15 @@ public class FeignClientTests {
assertEquals("message was wrong", "fallbackfuture", hello.getMessage());
}
+ @Test
+ public void testHystrixClientWithFallBackFactory() throws Exception {
+ Hello hello = hystrixClientWithFallBackFactory.fail();
+ assertNotNull("hello was null", hello);
+ assertNotNull("hello#message was null", hello.getMessage());
+ assertTrue("hello#message did not contain the cause (status code) of the fallback invocation",
+ hello.getMessage().contains("500"));
+ }
+
@Test
public void namedFeignClientWorks() {
assertNotNull("namedHystrixClient was null", this.namedHystrixClient);
diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancerClientTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancerClientTests.java
index e224a134..905cc6ac 100644
--- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancerClientTests.java
+++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonLoadBalancerClientTests.java
@@ -29,6 +29,7 @@ import org.mockito.MockitoAnnotations;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.RibbonServer;
+import org.springframework.web.util.DefaultUriTemplateHandler;
import com.netflix.client.config.CommonClientConfigKey;
import com.netflix.client.config.IClientConfig;
@@ -107,6 +108,31 @@ public class RibbonLoadBalancerClientTests {
assertEquals(server.getPort(), uri.getPort());
}
+ @Test
+ public void testReconstructSecureUriWithSpecialCharsPath() {
+ testReconstructUriWithPath("https", "/foo=|");
+ }
+
+ @Test
+ public void testReconstructUnsecureUriWithSpecialCharsPath() {
+ testReconstructUriWithPath("http", "/foo=|");
+ }
+
+ private void testReconstructUriWithPath(String scheme, String path) {
+ RibbonServer server = getRibbonServer();
+ IClientConfig config = mock(IClientConfig.class);
+ when(config.get(CommonClientConfigKey.IsSecure)).thenReturn(true);
+ when(clientFactory.getClientConfig(server.getServiceId())).thenReturn(config);
+
+ RibbonLoadBalancerClient client = getRibbonLoadBalancerClient(server);
+ ServiceInstance serviceInstance = client.choose(server.getServiceId());
+
+ URI expanded = new DefaultUriTemplateHandler()
+ .expand(scheme + "://" + server.getServiceId() + path);
+ URI reconstructed = client.reconstructURI(serviceInstance, expanded);
+ assertEquals(expanded.getPath(), reconstructed.getPath());
+ }
+
@Test
@SneakyThrows
public void testReconstructUriWithSecureClientConfig() {
diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonUtilsTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonUtilsTests.java
index 53b1bd8d..92548e7f 100644
--- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonUtilsTests.java
+++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/ribbon/RibbonUtilsTests.java
@@ -17,9 +17,6 @@
package org.springframework.cloud.netflix.ribbon;
-import static org.hamcrest.Matchers.is;
-import static org.springframework.cloud.netflix.ribbon.RibbonUtils.*;
-
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
@@ -31,6 +28,10 @@ import com.netflix.client.config.CommonClientConfigKey;
import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.loadbalancer.Server;
+import static org.hamcrest.Matchers.is;
+import static org.springframework.cloud.netflix.ribbon.RibbonUtils.isSecure;
+import static org.springframework.cloud.netflix.ribbon.RibbonUtils.updateToHttpsIfNeeded;
+
/**
* @author Spencer Gibb
* @author Jacques-Etienne Beaudet
diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelperTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelperTests.java
index a3f6f6ab..4d211dc0 100644
--- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelperTests.java
+++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/ProxyRequestHelperTests.java
@@ -259,6 +259,28 @@ public class ProxyRequestHelperTests {
assertThat(queryString, is("?wsdl"));
}
+ @Test
+ public void getQueryStringEncoded() {
+ MultiValueMap params = new LinkedMultiValueMap<>();
+ params.add("foo", "weird#chars");
+
+ String queryString = new ProxyRequestHelper().getQueryString(params);
+
+ assertThat(queryString, is("?foo=weird%23chars"));
+ }
+
+ @Test
+ public void getQueryParamNameWithColon() {
+ MultiValueMap params = new LinkedMultiValueMap<>();
+ params.add("foo:bar", "baz");
+ params.add("foobar", "bam");
+ params.add("foo\fbar", "bat"); // form feed is the colon replacement char
+
+ String queryString = new ProxyRequestHelper().getQueryString(params);
+
+ assertThat(queryString, is("?foo:bar=baz&foobar=bam&foo%0Cbar=bat"));
+ }
+
@Test
public void buildZuulRequestURIWithUTF8() throws Exception {
String encodedURI = "/resource/esp%C3%A9cial-char";
diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilterTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilterTests.java
index 7275e36d..faf5871e 100644
--- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilterTests.java
+++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilterTests.java
@@ -16,6 +16,11 @@
package org.springframework.cloud.netflix.zuul.filters.route;
+import java.io.ByteArrayInputStream;
+
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpRequest;
+import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.junit.After;
import org.junit.Test;
@@ -26,6 +31,7 @@ import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.util.LinkedMultiValueMap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -80,6 +86,18 @@ public class SimpleHostRoutingFilterTests {
assertEquals(20, connMgr.getDefaultMaxPerRoute());
}
+ @Test
+ public void deleteRequestBuiltWithBody() {
+ setupContext();
+ InputStreamEntity inputStreamEntity = new InputStreamEntity(new ByteArrayInputStream(new byte[]{1}));
+ HttpRequest httpRequest = getFilter().buildHttpRequest("DELETE", "uri", inputStreamEntity,
+ new LinkedMultiValueMap(), new LinkedMultiValueMap());
+
+ assertTrue(httpRequest instanceof HttpEntityEnclosingRequest);
+ HttpEntityEnclosingRequest httpEntityEnclosingRequest = (HttpEntityEnclosingRequest) httpRequest;
+ assertTrue(httpEntityEnclosingRequest.getEntity() != null);
+ }
+
private void setupContext() {
this.context.register(PropertyPlaceholderAutoConfiguration.class,
TestConfiguration.class);
diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/restclient/RestClientRibbonCommandIntegrationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/restclient/RestClientRibbonCommandIntegrationTests.java
index 826a574b..7b1a4d8b 100644
--- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/restclient/RestClientRibbonCommandIntegrationTests.java
+++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/route/restclient/RestClientRibbonCommandIntegrationTests.java
@@ -186,6 +186,17 @@ public class RestClientRibbonCommandIntegrationTests extends ZuulProxyTestBase {
assertEquals("/query?foo=weird#chars", result.getBody());
}
+ @Test
+ public void simpleHostRouteWithColonParamNames() {
+ this.routes.addRoute("/self/**", "http://localhost:" + this.port + "/");
+ this.endpoint.reset();
+ ResponseEntity result = new TestRestTemplate().exchange(
+ "http://localhost:" + this.port + "/self/colonquery?foo:bar={foobar0}&foobar={foobar1}", HttpMethod.GET,
+ new HttpEntity<>((Void) null), String.class, "baz", "bam");
+ assertEquals(HttpStatus.OK, result.getStatusCode());
+ assertEquals("/colonquery?foo:bar=baz&foobar=bam", result.getBody());
+ }
+
@Test
public void simpleHostRouteWithContentType() {
this.routes.addRoute("/self/**", "http://localhost:" + this.port + "/");
@@ -295,10 +306,15 @@ public class RestClientRibbonCommandIntegrationTests extends ZuulProxyTestBase {
}
@RequestMapping("/query")
- public String addQuery(HttpServletRequest request, @RequestParam String foo) {
+ public String query(HttpServletRequest request, @RequestParam String foo) {
return request.getRequestURI() + "?foo=" + foo;
}
+ @RequestMapping("/colonquery")
+ public String colonQuery(HttpServletRequest request, @RequestParam(name = "foo:bar") String foobar0, @RequestParam(name = "foobar") String foobar1) {
+ return request.getRequestURI() + "?foo:bar=" + foobar0 + "&foobar=" + foobar1;
+ }
+
@RequestMapping("/matrix/{name}/{another}")
public String matrix(@PathVariable("name") String name,
@MatrixVariable(value = "p", pathVar = "name") int p,
diff --git a/spring-cloud-netflix-dependencies/pom.xml b/spring-cloud-netflix-dependencies/pom.xml
index 99e3cb2d..c40c98c6 100644
--- a/spring-cloud-netflix-dependencies/pom.xml
+++ b/spring-cloud-netflix-dependencies/pom.xml
@@ -5,11 +5,11 @@
spring-cloud-dependencies-parent
org.springframework.cloud
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
spring-cloud-netflix-dependencies
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
pom
spring-cloud-netflix-dependencies
Spring Cloud Netflix Dependencies
@@ -17,10 +17,10 @@
0.7.4
1.4.11
9.3.1
- 1.5.5
+ 1.5.6
2.2.0
0.10.1
- 1.2.2
+ 1.3.0
1.1.10
1.7
1.0.0
@@ -270,6 +270,10 @@
jackson-dataformat-xml
com.fasterxml.jackson.dataformat
+
+ *
+ com.amazonaws
+
diff --git a/spring-cloud-netflix-eureka-client/pom.xml b/spring-cloud-netflix-eureka-client/pom.xml
index 6d6bdcd9..a30f0e75 100644
--- a/spring-cloud-netflix-eureka-client/pom.xml
+++ b/spring-cloud-netflix-eureka-client/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-netflix-eureka-client
diff --git a/spring-cloud-netflix-eureka-server/pom.xml b/spring-cloud-netflix-eureka-server/pom.xml
index 74b41f12..4c1d4190 100644
--- a/spring-cloud-netflix-eureka-server/pom.xml
+++ b/spring-cloud-netflix-eureka-server/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-netflix-eureka-server
diff --git a/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/EurekaServerConfiguration.java b/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/EurekaServerConfiguration.java
index 0e2f81ed..e5fae161 100644
--- a/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/EurekaServerConfiguration.java
+++ b/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/EurekaServerConfiguration.java
@@ -71,7 +71,7 @@ import com.sun.jersey.spi.container.servlet.ServletContainer;
@Configuration
@Import(EurekaServerInitializerConfiguration.class)
@EnableDiscoveryClient
-@EnableConfigurationProperties(EurekaDashboardProperties.class)
+@EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class })
@PropertySource("classpath:/eureka/server.properties")
public class EurekaServerConfiguration extends WebMvcConfigurerAdapter {
/**
@@ -92,17 +92,9 @@ public class EurekaServerConfiguration extends WebMvcConfigurerAdapter {
@Autowired
private EurekaClient eurekaClient;
- /*
- * Setting expectedNumberOfRenewsPerMin to non-zero to ensure that even an isolated
- * server can adjust its eviction policy to the number of registrations (when it's
- * zero, even a successful registration won't reset the rate threshold in
- * InstanceRegistry.register()).
- */
- @Value("${eureka.server.expectedNumberOfRenewsPerMin:1}")
- private int expectedNumberOfRenewsPerMin;
+ @Autowired
+ private InstanceRegistryProperties instanceRegistryProperties;
- @Value("${eureka.server.defaultOpenForTrafficCount:1}")
- private int defaultOpenForTrafficCount;
public static final CloudJacksonJson JACKSON_JSON = new CloudJacksonJson();
@Bean
@@ -166,8 +158,9 @@ public class EurekaServerConfiguration extends WebMvcConfigurerAdapter {
ServerCodecs serverCodecs) {
this.eurekaClient.getApplications(); // force initialization
return new InstanceRegistry(this.eurekaServerConfig, this.eurekaClientConfig,
- serverCodecs, this.eurekaClient, this.expectedNumberOfRenewsPerMin,
- this.defaultOpenForTrafficCount);
+ serverCodecs, this.eurekaClient,
+ this.instanceRegistryProperties.getExpectedNumberOfRenewsPerMin(),
+ this.instanceRegistryProperties.getDefaultOpenForTrafficCount());
}
@Bean
diff --git a/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/InstanceRegistry.java b/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/InstanceRegistry.java
index 05c5676f..3faaef7e 100644
--- a/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/InstanceRegistry.java
+++ b/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/InstanceRegistry.java
@@ -18,6 +18,7 @@ package org.springframework.cloud.netflix.eureka.server;
import java.util.List;
+import com.netflix.eureka.lease.Lease;
import org.springframework.beans.BeansException;
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceCanceledEvent;
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRegisteredEvent;
@@ -35,6 +36,7 @@ import com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl;
import com.netflix.eureka.resources.ServerCodecs;
import lombok.extern.apachecommons.CommonsLog;
+import org.springframework.context.ApplicationEvent;
/**
* @author Spencer Gibb
@@ -64,8 +66,8 @@ public class InstanceRegistry extends PeerAwareInstanceRegistryImpl
/**
* If
* {@link PeerAwareInstanceRegistryImpl#openForTraffic(ApplicationInfoManager, int)}
- * is called with a zero * argument, it means that leases are not automatically *
- * cancelled if the instance * hasn't sent any renewals recently. This happens for a
+ * is called with a zero argument, it means that leases are not automatically
+ * cancelled if the instance hasn't sent any renewals recently. This happens for a
* standalone server. It seems like a bad default, so we set it to the smallest
* non-zero value we can, so that any instances that subsequently register can bump up
* the threshold.
@@ -78,37 +80,27 @@ public class InstanceRegistry extends PeerAwareInstanceRegistryImpl
@Override
public void register(InstanceInfo info, int leaseDuration, boolean isReplication) {
- if (log.isDebugEnabled()) {
- log.debug("register " + info.getAppName() + ", vip " + info.getVIPAddress()
- + ", leaseDuration " + leaseDuration + ", isReplication "
- + isReplication);
- }
- // TODO: what to publish from info (whole object?)
- this.ctxt.publishEvent(new EurekaInstanceRegisteredEvent(this, info,
- leaseDuration, isReplication));
-
+ handleRegistration(info, leaseDuration, isReplication);
super.register(info, leaseDuration, isReplication);
}
@Override
- public boolean cancel(String appName, String serverId, boolean isReplication) {
- if (log.isDebugEnabled()) {
- log.debug("cancel " + appName + " serverId " + serverId + ", isReplication {}"
- + isReplication);
- }
- this.ctxt.publishEvent(
- new EurekaInstanceCanceledEvent(this, appName, serverId, isReplication));
+ public void register(final InstanceInfo info, final boolean isReplication) {
+ handleRegistration(info, resolveInstanceLeaseDuration(info), isReplication);
+ super.register(info, isReplication);
+ }
+ @Override
+ public boolean cancel(String appName, String serverId, boolean isReplication) {
+ handleCancelation(appName, serverId, isReplication);
return super.cancel(appName, serverId, isReplication);
}
@Override
public boolean renew(final String appName, final String serverId,
boolean isReplication) {
- if (log.isDebugEnabled()) {
- log.debug("renew " + appName + " serverId " + serverId + ", isReplication {}"
- + isReplication);
- }
+ log("renew " + appName + " serverId " + serverId + ", isReplication {}"
+ + isReplication);
List applications = getSortedApplications();
for (Application input : applications) {
if (input.getName().equals(appName)) {
@@ -119,11 +111,49 @@ public class InstanceRegistry extends PeerAwareInstanceRegistryImpl
break;
}
}
- this.ctxt.publishEvent(new EurekaInstanceRenewedEvent(this, appName,
- serverId, instance, isReplication));
+ publishEvent(new EurekaInstanceRenewedEvent(this, appName, serverId,
+ instance, isReplication));
break;
}
}
return super.renew(appName, serverId, isReplication);
}
+
+ @Override
+ protected boolean internalCancel(String appName, String id, boolean isReplication) {
+ handleCancelation(appName, id, isReplication);
+ return super.internalCancel(appName, id, isReplication);
+ }
+
+ private void handleCancelation(String appName, String id, boolean isReplication) {
+ log("cancel " + appName + ", serverId " + id + ", isReplication " + isReplication);
+ publishEvent(new EurekaInstanceCanceledEvent(this, appName, id, isReplication));
+ }
+
+ private void handleRegistration(InstanceInfo info, int leaseDuration,
+ boolean isReplication) {
+ log("register " + info.getAppName() + ", vip " + info.getVIPAddress()
+ + ", leaseDuration " + leaseDuration + ", isReplication "
+ + isReplication);
+ publishEvent(new EurekaInstanceRegisteredEvent(this, info, leaseDuration,
+ isReplication));
+ }
+
+ private void log(String message) {
+ if (log.isDebugEnabled()) {
+ log.debug(message);
+ }
+ }
+
+ private void publishEvent(ApplicationEvent applicationEvent) {
+ this.ctxt.publishEvent(applicationEvent);
+ }
+
+ private int resolveInstanceLeaseDuration(final InstanceInfo info) {
+ int leaseDuration = Lease.DEFAULT_DURATION_IN_SECS;
+ if (info.getLeaseInfo() != null && info.getLeaseInfo().getDurationInSecs() > 0) {
+ leaseDuration = info.getLeaseInfo().getDurationInSecs();
+ }
+ return leaseDuration;
+ }
}
diff --git a/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/InstanceRegistryProperties.java b/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/InstanceRegistryProperties.java
new file mode 100644
index 00000000..87a0ebac
--- /dev/null
+++ b/spring-cloud-netflix-eureka-server/src/main/java/org/springframework/cloud/netflix/eureka/server/InstanceRegistryProperties.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2013-2016 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.springframework.cloud.netflix.eureka.server;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import static org.springframework.cloud.netflix.eureka.server.InstanceRegistryProperties.PREFIX;
+
+/**
+ * @author Spencer Gibb
+ */
+@ConfigurationProperties(PREFIX)
+public class InstanceRegistryProperties {
+
+ public static final String PREFIX = "eureka.instance.registry";
+
+
+ /* Default number of expected renews per minute, defaults to 1.
+ * Setting expectedNumberOfRenewsPerMin to non-zero to ensure that even an isolated
+ * server can adjust its eviction policy to the number of registrations (when it's
+ * zero, even a successful registration won't reset the rate threshold in
+ * InstanceRegistry.register()).
+ */
+ @Value("${eureka.server.expectedNumberOfRenewsPerMin:1}") // for backwards compatibility
+ private int expectedNumberOfRenewsPerMin = 1;
+
+ /** Value used in determining when leases are cancelled, default to 1 for standalone.
+ * Should be set to 0 for peer replicated eurekas */
+ @Value("${eureka.server.defaultOpenForTrafficCount:1}") // for backwards compatibility
+ private int defaultOpenForTrafficCount = 1;
+
+ public int getExpectedNumberOfRenewsPerMin() {
+ return expectedNumberOfRenewsPerMin;
+ }
+
+ public void setExpectedNumberOfRenewsPerMin(int expectedNumberOfRenewsPerMin) {
+ this.expectedNumberOfRenewsPerMin = expectedNumberOfRenewsPerMin;
+ }
+
+ public int getDefaultOpenForTrafficCount() {
+ return defaultOpenForTrafficCount;
+ }
+
+ public void setDefaultOpenForTrafficCount(int defaultOpenForTrafficCount) {
+ this.defaultOpenForTrafficCount = defaultOpenForTrafficCount;
+ }
+}
diff --git a/spring-cloud-netflix-eureka-server/src/test/java/org/springframework/cloud/netflix/eureka/server/InstanceRegistryTest.java b/spring-cloud-netflix-eureka-server/src/test/java/org/springframework/cloud/netflix/eureka/server/InstanceRegistryTest.java
new file mode 100644
index 00000000..9689e779
--- /dev/null
+++ b/spring-cloud-netflix-eureka-server/src/test/java/org/springframework/cloud/netflix/eureka/server/InstanceRegistryTest.java
@@ -0,0 +1,186 @@
+package org.springframework.cloud.netflix.eureka.server;
+
+import static org.junit.Assert.*;
+import static org.mockito.Matchers.isA;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.netflix.discovery.shared.Application;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.cloud.netflix.eureka.server.InstanceRegistryTest.TestApplication;
+import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceCanceledEvent;
+import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRegisteredEvent;
+import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRenewedEvent;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import com.netflix.appinfo.InstanceInfo;
+import com.netflix.appinfo.LeaseInfo;
+import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
+
+/**
+ * @author Bartlomiej Slota
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest(classes = TestApplication.class,
+ webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+ value = {"spring.application.name=eureka", "logging.level.org.springframework."
+ + "cloud.netflix.eureka.server.InstanceRegistry=DEBUG"})
+public class InstanceRegistryTest {
+
+ private final List applicationEvents = new LinkedList<>();
+ private static final String APP_NAME = "MY-APP-NAME";
+ private static final String HOST_NAME = "my-host-name";
+
+ @SpyBean(PeerAwareInstanceRegistry.class)
+ private InstanceRegistry instanceRegistry;
+
+ @MockBean
+ private ApplicationListener
+ instanceRegisteredEventListenerMock;
+
+ @MockBean
+ private ApplicationListener
+ instanceCanceledEventListenerMock;
+
+ @MockBean
+ private ApplicationListener instanceRenewedEventListener;
+
+ @Before
+ public void setup() {
+ applicationEvents.clear();
+ Answer applicationListenerAnswer = prepareListenerMockAnswer();
+ doAnswer(applicationListenerAnswer).when(instanceRegisteredEventListenerMock)
+ .onApplicationEvent(isA(EurekaInstanceRegisteredEvent.class));
+ doAnswer(applicationListenerAnswer).when(instanceCanceledEventListenerMock)
+ .onApplicationEvent(isA(EurekaInstanceCanceledEvent.class));
+ doAnswer(applicationListenerAnswer).when(instanceRenewedEventListener)
+ .onApplicationEvent(isA(EurekaInstanceRenewedEvent.class));
+ }
+
+
+ @Test
+ public void testRegister() throws Exception {
+ // creating instance info
+ final LeaseInfo leaseInfo = getLeaseInfo();
+ final InstanceInfo instanceInfo = getInstanceInfo(leaseInfo);
+ // calling tested method
+ instanceRegistry.register(instanceInfo, false);
+ // event of proper type is registered
+ assertEquals(1, applicationEvents.size());
+ assertTrue(applicationEvents.get(0) instanceof EurekaInstanceRegisteredEvent);
+ // event details are correct
+ final EurekaInstanceRegisteredEvent registeredEvent =
+ (EurekaInstanceRegisteredEvent) (applicationEvents.get(0));
+ assertEquals(instanceInfo, registeredEvent.getInstanceInfo());
+ assertEquals(leaseInfo.getDurationInSecs(), registeredEvent.getLeaseDuration());
+ assertEquals(instanceRegistry, registeredEvent.getSource());
+ assertFalse(registeredEvent.isReplication());
+ }
+
+ @Test
+ public void testDefaultLeaseDurationRegisterEvent() throws Exception {
+ // creating instance info
+ final InstanceInfo instanceInfo = getInstanceInfo(null);
+ // calling tested method
+ instanceRegistry.register(instanceInfo, false);
+ // instance info duration is set to default
+ final EurekaInstanceRegisteredEvent registeredEvent =
+ (EurekaInstanceRegisteredEvent) (applicationEvents.get(0));
+ assertEquals(LeaseInfo.DEFAULT_LEASE_DURATION,
+ registeredEvent.getLeaseDuration());
+ }
+
+ @Test
+ public void testInternalCancel() throws Exception {
+ // calling tested method
+ instanceRegistry.internalCancel(APP_NAME, HOST_NAME, false);
+ // event of proper type is registered
+ assertEquals(1, applicationEvents.size());
+ assertTrue(applicationEvents.get(0) instanceof EurekaInstanceCanceledEvent);
+ // event details are correct
+ final EurekaInstanceCanceledEvent registeredEvent =
+ (EurekaInstanceCanceledEvent) (applicationEvents.get(0));
+ assertEquals(APP_NAME, registeredEvent.getAppName());
+ assertEquals(HOST_NAME, registeredEvent.getServerId());
+ assertEquals(instanceRegistry, registeredEvent.getSource());
+ assertFalse(registeredEvent.isReplication());
+ }
+
+ @Test
+ public void testRenew() throws Exception {
+ // creating application list
+ final LeaseInfo leaseInfo = getLeaseInfo();
+ final InstanceInfo instanceInfo = getInstanceInfo(leaseInfo);
+ final List instances = new ArrayList<>();
+ instances.add(instanceInfo);
+ final Application application = new Application(APP_NAME, instances);
+ final List applications = new ArrayList<>();
+ applications.add(application);
+ // stubbing applications list
+ doReturn(applications).when(instanceRegistry).getSortedApplications();
+ // calling tested method
+ instanceRegistry.renew(APP_NAME, HOST_NAME, false);
+ // event of proper type is registered
+ assertEquals(1, applicationEvents.size());
+ assertTrue(applicationEvents.get(0) instanceof EurekaInstanceRenewedEvent);
+ // event details are correct
+ final EurekaInstanceRenewedEvent registeredEvent = (EurekaInstanceRenewedEvent)
+ (applicationEvents.get(0));
+ assertEquals(APP_NAME, registeredEvent.getAppName());
+ assertEquals(HOST_NAME, registeredEvent.getServerId());
+ assertEquals(instanceRegistry, registeredEvent.getSource());
+ assertEquals(instanceInfo, registeredEvent.getInstanceInfo());
+ assertFalse(registeredEvent.isReplication());
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ @EnableEurekaServer
+ protected static class TestApplication {
+ public static void main(String[] args) {
+ new SpringApplicationBuilder(TestApplication.class).run(args);
+ }
+ }
+
+ private LeaseInfo getLeaseInfo() {
+ LeaseInfo.Builder leaseBuilder = LeaseInfo.Builder.newBuilder();
+ leaseBuilder.setRenewalIntervalInSecs(10);
+ leaseBuilder.setDurationInSecs(15);
+ return leaseBuilder.build();
+ }
+
+ private InstanceInfo getInstanceInfo(LeaseInfo leaseInfo) {
+ InstanceInfo.Builder builder = InstanceInfo.Builder.newBuilder();
+ builder.setAppName(APP_NAME);
+ builder.setHostName(HOST_NAME);
+ builder.setPort(8008);
+ builder.setLeaseInfo(leaseInfo);
+ return builder.build();
+ }
+
+ private Answer prepareListenerMockAnswer() {
+ return new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ return applicationEvents
+ .add((ApplicationEvent) invocation.getArguments()[0]);
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-netflix-hystrix-amqp/pom.xml b/spring-cloud-netflix-hystrix-amqp/pom.xml
index b3dcd037..34442fc8 100644
--- a/spring-cloud-netflix-hystrix-amqp/pom.xml
+++ b/spring-cloud-netflix-hystrix-amqp/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-netflix-hystrix-amqp
diff --git a/spring-cloud-netflix-hystrix-dashboard/pom.xml b/spring-cloud-netflix-hystrix-dashboard/pom.xml
index 64d5f719..e0a0528b 100644
--- a/spring-cloud-netflix-hystrix-dashboard/pom.xml
+++ b/spring-cloud-netflix-hystrix-dashboard/pom.xml
@@ -8,7 +8,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
diff --git a/spring-cloud-netflix-hystrix-dashboard/src/main/java/org/springframework/cloud/netflix/hystrix/dashboard/HystrixDashboardConfiguration.java b/spring-cloud-netflix-hystrix-dashboard/src/main/java/org/springframework/cloud/netflix/hystrix/dashboard/HystrixDashboardConfiguration.java
index 38569b63..4d05b504 100644
--- a/spring-cloud-netflix-hystrix-dashboard/src/main/java/org/springframework/cloud/netflix/hystrix/dashboard/HystrixDashboardConfiguration.java
+++ b/spring-cloud-netflix-hystrix-dashboard/src/main/java/org/springframework/cloud/netflix/hystrix/dashboard/HystrixDashboardConfiguration.java
@@ -40,8 +40,8 @@ import org.apache.http.params.HttpParams;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration;
-import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.actuator.HasFeatures;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -53,7 +53,6 @@ import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
* @author Dave Syer
* @author Roy Clarkson
*/
-@SuppressWarnings("deprecation")
@Configuration
@EnableConfigurationProperties(HystrixDashboardProperties.class)
public class HystrixDashboardConfiguration {
@@ -263,6 +262,7 @@ public class HystrixDashboardConfiguration {
}
}
+ @SuppressWarnings("deprecation")
private static class ProxyConnectionManager {
private final static PoolingClientConnectionManager threadSafeConnectionManager = new PoolingClientConnectionManager();
diff --git a/spring-cloud-netflix-hystrix-stream/pom.xml b/spring-cloud-netflix-hystrix-stream/pom.xml
index dd4c8f51..1e5715a2 100644
--- a/spring-cloud-netflix-hystrix-stream/pom.xml
+++ b/spring-cloud-netflix-hystrix-stream/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-netflix-hystrix-stream
diff --git a/spring-cloud-netflix-sidecar/pom.xml b/spring-cloud-netflix-sidecar/pom.xml
index c39d4005..e919210c 100644
--- a/spring-cloud-netflix-sidecar/pom.xml
+++ b/spring-cloud-netflix-sidecar/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-netflix-sidecar
diff --git a/spring-cloud-netflix-spectator/pom.xml b/spring-cloud-netflix-spectator/pom.xml
index 55715ac6..2d193b84 100644
--- a/spring-cloud-netflix-spectator/pom.xml
+++ b/spring-cloud-netflix-spectator/pom.xml
@@ -6,7 +6,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-netflix-spectator
diff --git a/spring-cloud-netflix-turbine-stream/pom.xml b/spring-cloud-netflix-turbine-stream/pom.xml
index 7fdeef11..9328f905 100644
--- a/spring-cloud-netflix-turbine-stream/pom.xml
+++ b/spring-cloud-netflix-turbine-stream/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-netflix-turbine-stream
diff --git a/spring-cloud-netflix-turbine/pom.xml b/spring-cloud-netflix-turbine/pom.xml
index f4ba02b1..4af74b88 100644
--- a/spring-cloud-netflix-turbine/pom.xml
+++ b/spring-cloud-netflix-turbine/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-netflix-turbine
diff --git a/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/TurbineHttpConfiguration.java b/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/TurbineHttpConfiguration.java
index 0c58625c..8c23c86f 100644
--- a/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/TurbineHttpConfiguration.java
+++ b/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/TurbineHttpConfiguration.java
@@ -19,8 +19,8 @@ package org.springframework.cloud.netflix.turbine;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
-import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.actuator.HasFeatures;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
diff --git a/spring-cloud-starter-archaius/pom.xml b/spring-cloud-starter-archaius/pom.xml
index 29c05ed3..fa0b7fa9 100644
--- a/spring-cloud-starter-archaius/pom.xml
+++ b/spring-cloud-starter-archaius/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-starter-archaius
diff --git a/spring-cloud-starter-atlas/pom.xml b/spring-cloud-starter-atlas/pom.xml
index ef07240e..1add805c 100644
--- a/spring-cloud-starter-atlas/pom.xml
+++ b/spring-cloud-starter-atlas/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-starter-atlas
diff --git a/spring-cloud-starter-eureka-server/pom.xml b/spring-cloud-starter-eureka-server/pom.xml
index 281d6840..a7b34608 100644
--- a/spring-cloud-starter-eureka-server/pom.xml
+++ b/spring-cloud-starter-eureka-server/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-starter-eureka-server
diff --git a/spring-cloud-starter-eureka/pom.xml b/spring-cloud-starter-eureka/pom.xml
index 5db347ea..feb3560a 100644
--- a/spring-cloud-starter-eureka/pom.xml
+++ b/spring-cloud-starter-eureka/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-starter-eureka
diff --git a/spring-cloud-starter-feign/pom.xml b/spring-cloud-starter-feign/pom.xml
index cfced5bb..ba5bb310 100644
--- a/spring-cloud-starter-feign/pom.xml
+++ b/spring-cloud-starter-feign/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-starter-feign
diff --git a/spring-cloud-starter-hystrix-dashboard/pom.xml b/spring-cloud-starter-hystrix-dashboard/pom.xml
index ef126ed6..87069df1 100644
--- a/spring-cloud-starter-hystrix-dashboard/pom.xml
+++ b/spring-cloud-starter-hystrix-dashboard/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-starter-hystrix-dashboard
diff --git a/spring-cloud-starter-hystrix/pom.xml b/spring-cloud-starter-hystrix/pom.xml
index 220ad2e3..7c90a6f1 100644
--- a/spring-cloud-starter-hystrix/pom.xml
+++ b/spring-cloud-starter-hystrix/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-starter-hystrix
diff --git a/spring-cloud-starter-ribbon/pom.xml b/spring-cloud-starter-ribbon/pom.xml
index 533583c0..4a31be7c 100644
--- a/spring-cloud-starter-ribbon/pom.xml
+++ b/spring-cloud-starter-ribbon/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-starter-ribbon
diff --git a/spring-cloud-starter-spectator/pom.xml b/spring-cloud-starter-spectator/pom.xml
index ee66b0eb..5ed2f4ec 100644
--- a/spring-cloud-starter-spectator/pom.xml
+++ b/spring-cloud-starter-spectator/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-starter-spectator
diff --git a/spring-cloud-starter-turbine-amqp/pom.xml b/spring-cloud-starter-turbine-amqp/pom.xml
index 15e5a043..0820167f 100644
--- a/spring-cloud-starter-turbine-amqp/pom.xml
+++ b/spring-cloud-starter-turbine-amqp/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-starter-turbine-amqp
diff --git a/spring-cloud-starter-turbine-stream/pom.xml b/spring-cloud-starter-turbine-stream/pom.xml
index ef45f833..1a7edbcb 100644
--- a/spring-cloud-starter-turbine-stream/pom.xml
+++ b/spring-cloud-starter-turbine-stream/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-starter-turbine-stream
diff --git a/spring-cloud-starter-turbine/pom.xml b/spring-cloud-starter-turbine/pom.xml
index 3639be91..5f6ed33a 100644
--- a/spring-cloud-starter-turbine/pom.xml
+++ b/spring-cloud-starter-turbine/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-starter-turbine
diff --git a/spring-cloud-starter-zuul/pom.xml b/spring-cloud-starter-zuul/pom.xml
index 8b664ac8..fb397c1d 100644
--- a/spring-cloud-starter-zuul/pom.xml
+++ b/spring-cloud-starter-zuul/pom.xml
@@ -5,7 +5,7 @@
org.springframework.cloud
spring-cloud-netflix
- 1.2.1.BUILD-SNAPSHOT
+ 1.2.2.BUILD-SNAPSHOT
..
spring-cloud-starter-zuul