Compare commits

...
Author SHA1 Message Date
Dave Syer 4ee2055d5c Update to 1.2.5.RELEASE 2017-02-03 11:45:30 +00:00
Spencer Gibb 1fffc923e1 Remove mocks for application event listeners.
fixes gh-1616
2017-01-27 12:23:22 -07:00
Spencer Gibb b41027191e Make test forward compatible with boot 1.5 2017-01-27 10:51:08 -07:00
Spencer Gibb 0df5957f6b Make test forward compatible with boot 1.5 2017-01-27 10:13:23 -07:00
Spencer Gibb 234c4c65ae Handle content-type with charset.
A new version of httpclient introduced by boot changed the behaviour that previously allowed the charset. It now has to be parsed out and passed to the apache `ContentType` object explicitly.

fixes gh-1649
2017-01-27 08:44:40 -07:00
Marcin Grzejszczak c5117a8573 Making the prod code compile against boot 1.5.0 2017-01-23 12:38:26 +01:00
Bertrand Renuart f304ab7101 Use a fixed size buffer for the copy operation (#1538)
Set the default buffer size to 8192 to match Tomcat and Jetty defaults
Use a buffer per worker thread and use it for subsequent requests
2017-01-11 13:46:20 -05:00
Ryan Baxter f591136d80 Bumping versions for next release 2017-01-11 12:02:05 -05:00
Ryan Baxter 9170365b85 Revert "Version changes for 1.2.4.RELEASE"
This reverts commit f5c6920843.
2017-01-11 11:53:11 -05:00
Ryan Baxter f5c6920843 Version changes for 1.2.4.RELEASE 2017-01-11 10:50:35 -05:00
Ryan Baxter 470d6abf63 Merge pull request #1457 from ryanjbaxter/feign-retry
Use Spring Retry For Failed Requests Using Feign
2017-01-09 20:10:38 -05:00
Biju Kunjummen f3275c160b Fix null instanceinfo on EurekaInstanceRenewedEvent (#1574)
Fixes gh-1546
2017-01-09 11:26:22 -07:00
Ryan Baxter 5cd39df5e7 No longer use RetryTemplate bean since the retry policy being used is dependent on the request. We don’t want two Feign requests stomping on each other by switching out the retry policy for the template so each request now created a new template to use. 2016-12-22 11:15:29 -05:00
Ryan Baxter a91815aa43 Made Retryer a bean. 2016-12-08 19:51:44 -05:00
Ryan Baxter 0f7f88f89b Merge pull request #1519 from ryanjbaxter/config-value-changes-in-ribbon-1418
Use configuration from IConfigClient reference to always use the most up to date configuration
2016-12-01 20:26:53 -05:00
Ryan Baxter 2487ef2fad Fixed import ordering 2016-12-01 20:03:26 -05:00
Ryan Baxter b5195b7b86 Removed unnecessary null check and fixed imports 2016-12-01 20:00:55 -05:00
Ryan Baxter 845590e46c Uses configuration from IConfigClient reference to always use the most up to date configuration. Fixes #1481. 2016-12-01 14:24:23 -05:00
Spencer Gibb 7fdd86e69c Don't override values with defaults.
Defaults were set too late and were overriding values set in the environment.

Specifically, spring.application.name took precedence over eureka.instance.appname.

 fixes gh-1516
2016-11-30 11:36:32 -07:00
Spencer Gibb d1f8c03110 Fix Eureka Ribbon Auto Config conditions.
Specifically, add `@ConditionalOnBean(EurekaClient.class)`.

Fixes an issue where eureka and ribbon are on the classpath, eureka.client.enabled=false which would cause a bean not found exception.

fixes gh-1511
2016-11-29 14:29:40 -07:00
Ryan Baxter 728ef05bf3 Updated generated README 2016-11-23 17:12:42 -05:00
Ryan Baxter 27a2c31241 Bump version for next release 2016-11-23 17:12:28 -05:00
Ryan Baxter 3034c55b13 Revert "Version changes for 1.2.3 RELEASE"
This reverts commit cdaa97c006.
2016-11-23 17:03:25 -05:00
Ryan Baxter cdaa97c006 Version changes for 1.2.3 RELEASE 2016-11-23 15:33:42 -05:00
Ryan Baxter f563fcb4cd Upgrading Eureka to 1.4.12. Fixes #1429. 2016-11-22 19:49:16 -05:00
Ryan Baxter 14dd2d2359 -Addressed problem where choose server was being called multiple times per request
-Fixed imports
-Addressed other code review concerns
2016-11-11 12:15:53 -05:00
Ryan Baxter 8b4469db31 Removing commented out code 2016-11-10 10:00:00 -05:00
Ryan Baxter 658f29ed27 Merge remote-tracking branch 'Upstream/1.2.x' into feign-retry 2016-11-09 13:16:22 -05:00
Ryan Baxter 19556dc25d Merge pull request #1450 from ryanjbaxter/servlet-3.0.1-compat-1.2.x
Make Netflix Servlet 3.0.1 compatible
2016-11-09 11:56:06 -05:00
Ryan Baxter b31f6c5c4f Figure out whether servlet api 3.1 is available or not once 2016-11-09 11:09:26 -05:00
Ryan Baxter dfcc319ba7 Make Netflix Servlet 3.0.1 compatible. Fixes #1447 2016-11-07 16:11:41 -05:00
Ryan Baxter fad2c5d400 Merge remote-tracking branch 'Upstream/1.2.x' into feign-retry 2016-11-03 10:51:31 -04:00
Ryan Baxter 3201234ee1 Version changes for next release 2016-11-01 20:15:26 -04:00
Ryan Baxter 9b64d0da8f Revert "Version changes for 1.2.2 release"
This reverts commit be8eece91e.
2016-11-01 20:05:07 -04:00
Ryan Baxter be8eece91e Version changes for 1.2.2 release 2016-11-01 15:36:32 -04:00
Ryan Baxter 7c48814234 Switched media type to application/json 2016-10-27 15:46:42 -06:00
Ryan Baxter 72ccf2e649 Added route config 2016-10-27 15:46:36 -06:00
Ryan Baxter 3df42159fb Fixes #1429 2016-10-27 15:46:29 -06:00
Spencer Gibb 45e7a088bb Move initalizing appname, etc.. to afterPropertiesSet 2016-10-27 15:17:18 -06:00
Spencer Gibb 0f0c6b6204 Revert to deprecated boot APIs to support boot 1.3 2016-10-27 08:29:30 -06:00
Ryan Baxter 88a36b38e9 Initial commit for feign retry 2016-10-10 14:15:58 -04:00
63 changed files with 886 additions and 335 deletions
+2 -2
View File
@@ -85,11 +85,11 @@ a modified file in the correct place. Just commit it and push the change.
If you don't have an IDE preference we would recommend that you use
http://www.springsource.com/developer/sts[Spring Tools Suite] or
http://eclipse.org[Eclipse] when working with the code. We use the
http://eclipse.org/m2e/[m2eclipe] eclipse plugin for maven support. Other IDEs and tools
http://eclipse.org/m2e/[m2eclipse] eclipse plugin for maven support. Other IDEs and tools
should also work without issue as long as they use Maven 3.3.3 or better.
==== Importing into eclipse with m2eclipse
We recommend the http://eclipse.org/m2e/[m2eclipe] eclipse plugin when working with
We recommend the http://eclipse.org/m2e/[m2eclipse] eclipse plugin when working with
eclipse. If you don't already have m2eclipse installed it is available from the "eclipse
marketplace".
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
</parent>
<artifactId>spring-cloud-netflix-docs</artifactId>
<packaging>pom</packaging>
@@ -1236,7 +1236,8 @@ To enable it, annotate a Spring Boot main class with
service. By convention, a service with the ID "users", will
receive requests from the proxy located at `/users` (with the prefix
stripped). The proxy uses Ribbon to locate an instance to forward to
via discovery, and all requests are executed in a hystrix command, so
via discovery, and all requests are executed in a
<<hystrix-fallbacks-for-routes, hystrix command>>, so
failures will show up in Hystrix metrics, and once the circuit is open
the proxy will not try to contact the service.
@@ -1604,6 +1605,70 @@ possible filters that are enabled. If you want to disable one, simply set
`org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter` set
`zuul.SendResponseFilter.post.disable=true`.
[[hystrix-fallbacks-for-routes]]
=== Providing Hystrix Fallbacks For Routes
When a circuit for a given route in Zuul is tripped you can provide a fallback response
by creating a bean of type `ZuulFallbackProvider`. Within this bean you need to specify
the route ID the fallback is for and provide a `ClientHttpResponse` to return
as a fallback. Here is a very simple `ZuulFallbackProvider` implementation.
[source,java]
----
class MyFallbackProvider implements ZuulFallbackProvider {
@Override
public String getRoute() {
return "customers";
}
@Override
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
return 200;
}
@Override
public String getStatusText() throws IOException {
return "OK";
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("fallback".getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
----
And here is what the route configuration would look like.
[source,yaml]
----
zuul:
routes:
customers: /customers/**
----
=== Polyglot support with Sidecar
Do you have non-jvm languages you want to take advantage of Eureka, Ribbon and
+5 -5
View File
@@ -3,14 +3,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<packaging>pom</packaging>
<name>Spring Cloud Netflix</name>
<description>Spring Cloud Netflix</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.2.RELEASE</version>
<relativePath />
</parent>
<scm>
@@ -24,9 +24,9 @@
<main.basedir>${basedir}</main.basedir>
<netty.version>4.0.27.Final</netty.version>
<jackson.version>2.7.3</jackson.version>
<spring-cloud-commons.version>1.1.5.BUILD-SNAPSHOT</spring-cloud-commons.version>
<spring-cloud-config.version>1.2.2.BUILD-SNAPSHOT</spring-cloud-config.version>
<spring-cloud-stream.version>Brooklyn.BUILD-SNAPSHOT</spring-cloud-stream.version>
<spring-cloud-commons.version>1.1.7.RELEASE</spring-cloud-commons.version>
<spring-cloud-config.version>1.2.2.RELEASE</spring-cloud-config.version>
<spring-cloud-stream.version>Brooklyn.SR2</spring-cloud-stream.version>
<!-- Sonar -->
<surefire.plugin.version>2.19.1</surefire.plugin.version>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-netflix-core</artifactId>
@@ -16,9 +16,16 @@
package org.springframework.cloud.netflix.feign;
import feign.Contract;
import feign.Feign;
import feign.Logger;
import feign.Retryer;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.hystrix.HystrixFeign;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -35,16 +42,8 @@ import org.springframework.context.annotation.Scope;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.format.support.FormattingConversionService;
import com.netflix.hystrix.HystrixCommand;
import feign.Contract;
import feign.Feign;
import feign.Logger;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.hystrix.HystrixFeign;
/**
* @author Dave Syer
* @author Venil Noronha
@@ -103,11 +102,17 @@ public class FeignClientsConfiguration {
}
}
@Bean
@ConditionalOnMissingBean
public Retryer feignRetryer() {
return Retryer.NEVER_RETRY;
}
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public Feign.Builder feignBuilder() {
return Feign.builder();
public Feign.Builder feignBuilder(Retryer retryer) {
return Feign.builder().retryer(retryer);
}
@Bean
@@ -18,8 +18,11 @@ package org.springframework.cloud.netflix.feign.ribbon;
import java.util.Map;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicyFactory;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryPolicyFactory;
import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.ConcurrentReferenceHashMap;
import com.netflix.client.config.IClientConfig;
@@ -34,11 +37,19 @@ import com.netflix.loadbalancer.ILoadBalancer;
public class CachingSpringLoadBalancerFactory {
private final SpringClientFactory factory;
private final LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory;
private volatile Map<String, FeignLoadBalancer> cache = new ConcurrentReferenceHashMap<>();
public CachingSpringLoadBalancerFactory(SpringClientFactory factory) {
this.factory = factory;
this.loadBalancedRetryPolicyFactory = new RibbonLoadBalancedRetryPolicyFactory(factory);
}
public CachingSpringLoadBalancerFactory(SpringClientFactory factory,
LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory) {
this.factory = factory;
this.loadBalancedRetryPolicyFactory = loadBalancedRetryPolicyFactory;
}
public FeignLoadBalancer create(String clientName) {
@@ -48,7 +59,8 @@ public class CachingSpringLoadBalancerFactory {
IClientConfig config = this.factory.getClientConfig(clientName);
ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
ServerIntrospector serverIntrospector = this.factory.getInstance(clientName, ServerIntrospector.class);
FeignLoadBalancer client = new FeignLoadBalancer(lb, config, serverIntrospector);
FeignLoadBalancer client = new FeignLoadBalancer(lb, config, serverIntrospector,
loadBalancedRetryPolicyFactory);
this.cache.put(clientName, client);
return client;
}
@@ -16,44 +16,61 @@
package org.springframework.cloud.netflix.feign.ribbon;
import java.io.IOException;
import java.net.URI;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
import com.netflix.client.AbstractLoadBalancerAwareClient;
import com.netflix.client.ClientException;
import com.netflix.client.ClientRequest;
import com.netflix.client.IResponse;
import com.netflix.client.RequestSpecificRetryHandler;
import com.netflix.client.RetryHandler;
import com.netflix.client.config.CommonClientConfigKey;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import feign.Client;
import feign.Request;
import feign.Response;
import feign.Util;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicyFactory;
import org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.policy.NeverRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import com.netflix.client.AbstractLoadBalancerAwareClient;
import com.netflix.client.ClientException;
import com.netflix.client.ClientRequest;
import com.netflix.client.DefaultLoadBalancerRetryHandler;
import com.netflix.client.IResponse;
import com.netflix.client.RequestSpecificRetryHandler;
import com.netflix.client.config.CommonClientConfigKey;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import static org.springframework.cloud.netflix.ribbon.RibbonUtils.updateToHttpsIfNeeded;
public class FeignLoadBalancer extends
AbstractLoadBalancerAwareClient<FeignLoadBalancer.RibbonRequest, FeignLoadBalancer.RibbonResponse> {
AbstractLoadBalancerAwareClient<FeignLoadBalancer.RibbonRequest, FeignLoadBalancer.RibbonResponse> implements
ServiceInstanceChooser {
private final int connectTimeout;
private final int readTimeout;
private final IClientConfig clientConfig;
private final ServerIntrospector serverIntrospector;
private final LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory;
public FeignLoadBalancer(ILoadBalancer lb, IClientConfig clientConfig,
ServerIntrospector serverIntrospector) {
ServerIntrospector serverIntrospector, LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory) {
super(lb, clientConfig);
this.setRetryHandler(RetryHandler.DEFAULT);
this.loadBalancedRetryPolicyFactory = loadBalancedRetryPolicyFactory;
this.setRetryHandler(new DefaultLoadBalancerRetryHandler(clientConfig));
this.clientConfig = clientConfig;
this.connectTimeout = clientConfig.get(CommonClientConfigKey.ConnectTimeout);
this.readTimeout = clientConfig.get(CommonClientConfigKey.ReadTimeout);
@@ -61,9 +78,9 @@ public class FeignLoadBalancer extends
}
@Override
public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride)
public RibbonResponse execute(final RibbonRequest request, IClientConfig configOverride)
throws IOException {
Request.Options options;
final Request.Options options;
if (configOverride != null) {
options = new Request.Options(
configOverride.get(CommonClientConfigKey.ConnectTimeout,
@@ -74,26 +91,35 @@ public class FeignLoadBalancer extends
else {
options = new Request.Options(this.connectTimeout, this.readTimeout);
}
Response response = request.client().execute(request.toRequest(), options);
return new RibbonResponse(request.getUri(), response);
LoadBalancedRetryPolicy retryPolicy = loadBalancedRetryPolicyFactory.create(this.getClientName(), this);
RetryTemplate retryTemplate = new RetryTemplate();
retryTemplate.setRetryPolicy(retryPolicy == null ? new NeverRetryPolicy()
: new FeignRetryPolicy(request.toHttpRequest(), retryPolicy, this, this.getClientName()));
return retryTemplate.execute(new RetryCallback<RibbonResponse, IOException>() {
@Override
public RibbonResponse doWithRetry(RetryContext retryContext) throws IOException {
Request feignRequest = null;
//on retries the policy will choose the server and set it in the context
//extract the server and update the request being made
if(retryContext instanceof LoadBalancedRetryContext) {
ServiceInstance service = ((LoadBalancedRetryContext)retryContext).getServiceInstance();
if(service != null) {
feignRequest = ((RibbonRequest)request.replaceUri(reconstructURIWithServer(new Server(service.getHost(), service.getPort()), request.getUri()))).toRequest();
}
}
if(feignRequest == null) {
feignRequest = request.toRequest();
}
Response response = request.client().execute(feignRequest, options);
return new RibbonResponse(request.getUri(), response);
}
});
}
@Override
public RequestSpecificRetryHandler getRequestSpecificRetryHandler(
RibbonRequest request, IClientConfig requestConfig) {
if (this.clientConfig.get(CommonClientConfigKey.OkToRetryOnAllOperations,
false)) {
return new RequestSpecificRetryHandler(true, true, this.getRetryHandler(),
requestConfig);
}
if (!request.toRequest().method().equals("GET")) {
return new RequestSpecificRetryHandler(true, false, this.getRetryHandler(),
requestConfig);
}
else {
return new RequestSpecificRetryHandler(true, true, this.getRetryHandler(),
requestConfig);
}
return new RequestSpecificRetryHandler(false, false, this.getRetryHandler(), requestConfig);
}
@Override
@@ -102,6 +128,12 @@ public class FeignLoadBalancer extends
return super.reconstructURIWithServer(server, uri);
}
@Override
public ServiceInstance choose(String serviceId) {
return new RibbonLoadBalancerClient.RibbonServer(serviceId,
this.getLoadBalancer().chooseServer(serviceId));
}
static class RibbonRequest extends ClientRequest implements Cloneable {
private final Request request;
@@ -129,6 +161,33 @@ public class FeignLoadBalancer extends
return this.client;
}
HttpRequest toHttpRequest() {
return new HttpRequest() {
@Override
public HttpMethod getMethod() {
return HttpMethod.resolve(RibbonRequest.this.toRequest().method());
}
@Override
public URI getURI() {
return RibbonRequest.this.getUri();
}
@Override
public HttpHeaders getHeaders() {
Map<String, List<String>> headers = new HashMap<String, List<String>>();
Map<String, Collection<String>> feignHeaders = RibbonRequest.this.toRequest().headers();
for(String key : feignHeaders.keySet()) {
headers.put(key, new ArrayList<String>(feignHeaders.get(key)));
}
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.putAll(headers);
return httpHeaders;
}
};
}
@Override
public Object clone() {
return new RibbonRequest(this.client, this.request, getUri());
@@ -0,0 +1,119 @@
/*
*
* * 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.feign.ribbon;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.InterceptorRetryPolicy;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy;
import org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser;
import org.springframework.http.HttpRequest;
import org.springframework.retry.RetryContext;
/**
* @author Ryan Baxter
*/
public class FeignRetryPolicy extends InterceptorRetryPolicy {
private HttpRequest request;
private String serviceId;
public FeignRetryPolicy(HttpRequest request, LoadBalancedRetryPolicy policy, ServiceInstanceChooser serviceInstanceChooser, String serviceName) {
super(request, policy, serviceInstanceChooser, serviceName);
this.request = request;
this.serviceId = serviceName;
}
@Override
public boolean canRetry(RetryContext context) {
/*
* In InterceptorRetryPolicy.canRetry we ask the LoadBalancer to choose a server if one is not
* set in the retry context and then return true. RetryTemplat calls the canRetry method of
* the policy even on its first execution. So the fact that we didnt have a service instance set
* in the RetryContext signaled that it was the first execution and we should return true.
*
* In the Feign scenario, Feign as actually already queried the load balancer for a service instance
* and we set that service instance in the context when we call the open method of the policy. So in
* the Feign case we just return true if the retry count is 0 indicating we haven't yet made a failed
* request.
*/
if(context.getRetryCount() == 0) {
return true;
}
return super.canRetry(context);
}
@Override
public RetryContext open(RetryContext parent) {
/*
* With Feign (unlike Ribbon) the request already has the URI for the service instance
* we are going to make the request to, so extract that information and set the service
* instance in the context. In the Ribbon scenario the URI in the request object still has
* the service id so we choose and set the service instance later on.
*/
LoadBalancedRetryContext context = new LoadBalancedRetryContext(parent, this.request);
context.setServiceInstance(new FeignRetryPolicyServiceInstance(serviceId, request));
return context;
}
class FeignRetryPolicyServiceInstance implements ServiceInstance {
private String serviceId;
private HttpRequest request;
private Map<String, String> metadata;
FeignRetryPolicyServiceInstance(String serviceId, HttpRequest request) {
this.serviceId = serviceId;
this.request = request;
this.metadata = new HashMap<String, String>();
}
@Override
public String getServiceId() {
return serviceId;
}
@Override
public String getHost() {
return request.getURI().getHost();
}
@Override
public int getPort() {
return request.getURI().getPort();
}
@Override
public boolean isSecure() {
return "https".equals(request.getURI().getScheme());
}
@Override
public URI getUri() {
return request.getURI();
}
@Override
public Map<String, String> getMetadata() {
return metadata;
}
}
}
@@ -22,11 +22,13 @@ import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicyFactory;
import org.springframework.cloud.netflix.feign.FeignAutoConfiguration;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.retry.support.RetryTemplate;
import com.netflix.loadbalancer.ILoadBalancer;
@@ -50,8 +52,15 @@ public class FeignRibbonClientAutoConfiguration {
@Bean
@Primary
public CachingSpringLoadBalancerFactory cachingLBClientFactory(
SpringClientFactory factory) {
return new CachingSpringLoadBalancerFactory(factory);
SpringClientFactory factory, LoadBalancedRetryPolicyFactory retryPolicyFactory) {
return new CachingSpringLoadBalancerFactory(factory, retryPolicyFactory);
}
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate template = new RetryTemplate();
template.setThrowLastExceptionOnExhausted(true);
return template;
}
@Bean
@@ -141,17 +141,17 @@ public class RibbonLoadBalancerClient implements LoadBalancerClient {
return this.clientFactory.getLoadBalancer(serviceId);
}
protected static class RibbonServer implements ServiceInstance {
public static class RibbonServer implements ServiceInstance {
private final String serviceId;
private final Server server;
private final boolean secure;
private Map<String, String> metadata;
protected RibbonServer(String serviceId, Server server) {
public RibbonServer(String serviceId, Server server) {
this(serviceId, server, false, Collections.<String, String> emptyMap());
}
protected RibbonServer(String serviceId, Server server, boolean secure,
public RibbonServer(String serviceId, Server server, boolean secure,
Map<String, String> metadata) {
this.serviceId = serviceId;
this.server = server;
@@ -27,6 +27,8 @@ import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
import org.springframework.cloud.netflix.ribbon.support.AbstractLoadBalancingClient;
import org.springframework.web.util.UriComponentsBuilder;
import com.netflix.client.RequestSpecificRetryHandler;
import com.netflix.client.RetryHandler;
import com.netflix.client.config.CommonClientConfigKey;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
@@ -75,19 +77,13 @@ public class RibbonLoadBalancingHttpClient
public RibbonApacheHttpResponse execute(RibbonApacheHttpRequest request,
final IClientConfig configOverride) throws Exception {
final RequestConfig.Builder builder = RequestConfig.custom();
if (configOverride != null) {
builder.setConnectTimeout(configOverride.get(
CommonClientConfigKey.ConnectTimeout, this.connectTimeout));
builder.setSocketTimeout(configOverride.get(
CommonClientConfigKey.ReadTimeout, this.readTimeout));
builder.setRedirectsEnabled(configOverride.get(
CommonClientConfigKey.FollowRedirects, this.followRedirects));
}
else {
builder.setConnectTimeout(this.connectTimeout);
builder.setSocketTimeout(this.readTimeout);
builder.setRedirectsEnabled(this.followRedirects);
}
IClientConfig config = configOverride != null ? configOverride : this.config;
builder.setConnectTimeout(config.get(
CommonClientConfigKey.ConnectTimeout, this.connectTimeout));
builder.setSocketTimeout(config.get(
CommonClientConfigKey.ReadTimeout, this.readTimeout));
builder.setRedirectsEnabled(config.get(
CommonClientConfigKey.FollowRedirects, this.followRedirects));
final RequestConfig requestConfig = builder.build();
@@ -108,4 +104,9 @@ public class RibbonLoadBalancingHttpClient
return super.reconstructURIWithServer(server, uri);
}
@Override
public RequestSpecificRetryHandler getRequestSpecificRetryHandler(RibbonApacheHttpRequest request, IClientConfig requestConfig) {
return new RequestSpecificRetryHandler(false, false, RetryHandler.DEFAULT, null);
}
}
@@ -85,25 +85,16 @@ public class OkHttpLoadBalancingClient
OkHttpClient getOkHttpClient(IClientConfig configOverride, boolean secure) {
OkHttpClient.Builder builder = this.delegate.newBuilder();
if (configOverride != null) {
builder.connectTimeout(configOverride.get(
CommonClientConfigKey.ConnectTimeout, this.connectTimeout), TimeUnit.MILLISECONDS);
builder.readTimeout(configOverride.get(
CommonClientConfigKey.ReadTimeout, this.readTimeout), TimeUnit.MILLISECONDS);
builder.followRedirects(configOverride.get(
IClientConfig config = configOverride != null ? configOverride : this.config;
builder.connectTimeout(config.get(
CommonClientConfigKey.ConnectTimeout, this.connectTimeout), TimeUnit.MILLISECONDS);
builder.readTimeout(config.get(
CommonClientConfigKey.ReadTimeout, this.readTimeout), TimeUnit.MILLISECONDS);
builder.followRedirects(config.get(
CommonClientConfigKey.FollowRedirects, this.followRedirects));
if (secure) {
builder.followSslRedirects(configOverride.get(
CommonClientConfigKey.FollowRedirects, this.followRedirects));
if (secure) {
builder.followSslRedirects(configOverride.get(
CommonClientConfigKey.FollowRedirects, this.followRedirects));
}
}
else {
builder.connectTimeout(this.connectTimeout, TimeUnit.MILLISECONDS);
builder.readTimeout(this.readTimeout, TimeUnit.MILLISECONDS);
builder.followRedirects(this.followRedirects);
if (secure) {
builder.followSslRedirects(this.followRedirects);
}
}
return builder.build();
@@ -16,6 +16,10 @@
package org.springframework.cloud.netflix.zuul.filters;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -24,19 +28,12 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.PostConstruct;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import static com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE;
/**
@@ -16,17 +16,16 @@
package org.springframework.cloud.netflix.zuul.filters.post;
import lombok.extern.apachecommons.CommonsLog;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.GZIPInputStream;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.ReflectionUtils;
import com.netflix.config.DynamicBooleanProperty;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
@@ -37,8 +36,6 @@ import com.netflix.zuul.constants.ZuulHeaders;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.util.HTTPRequestUtils;
import lombok.extern.apachecommons.CommonsLog;
/**
* @author Spencer Gibb
*/
@@ -51,12 +48,30 @@ public class SendResponseFilter extends ZuulFilter {
private static DynamicIntProperty INITIAL_STREAM_BUFFER_SIZE = DynamicPropertyFactory
.getInstance()
.getIntProperty(ZuulConstants.ZUUL_INITIAL_STREAM_BUFFER_SIZE, 1024);
.getIntProperty(ZuulConstants.ZUUL_INITIAL_STREAM_BUFFER_SIZE, 8192);
private static DynamicBooleanProperty SET_CONTENT_LENGTH = DynamicPropertyFactory
.getInstance()
.getBooleanProperty(ZuulConstants.ZUUL_SET_CONTENT_LENGTH, false);
private boolean useServlet31 = true;
public SendResponseFilter() {
super();
// To support Servlet API 3.0.1 we need to check if setcontentLengthLong exists
try {
HttpServletResponse.class.getMethod("setContentLengthLong");
} catch(NoSuchMethodException e) {
useServlet31 = false;
}
}
private ThreadLocal<byte[]> buffers = new ThreadLocal<byte[]>() {
@Override
protected byte[] initialValue() {
return new byte[INITIAL_STREAM_BUFFER_SIZE.get()];
}
};
@Override
public String filterType() {
return "post";
@@ -167,21 +182,16 @@ public class SendResponseFilter extends ZuulFilter {
}
private void writeResponse(InputStream zin, OutputStream out) throws Exception {
byte[] bytes = new byte[INITIAL_STREAM_BUFFER_SIZE.get()];
int bytesRead = -1;
while ((bytesRead = zin.read(bytes)) != -1) {
try {
try {
byte[] bytes = buffers.get();
int bytesRead = -1;
while ((bytesRead = zin.read(bytes)) != -1) {
out.write(bytes, 0, bytesRead);
out.flush();
}
catch (IOException ex) {
// ignore
}
// doubles buffer size if previous read filled it
if (bytesRead == bytes.length) {
bytes = new byte[bytes.length * 2];
}
}
catch(IOException ioe) {
log.warn("Error while sending response to client: "+ioe.getMessage());
}
}
private void addResponseHeaders() {
@@ -210,10 +220,21 @@ public class SendResponseFilter extends ZuulFilter {
// Only inserts Content-Length if origin provides it and origin response is not
// gzipped
if (SET_CONTENT_LENGTH.get()) {
if (contentLength != null && !ctx.getResponseGZipped()) {
servletResponse.setContentLengthLong(contentLength);
if ( contentLength != null && !ctx.getResponseGZipped()) {
if(useServlet31) {
servletResponse.setContentLengthLong(contentLength);
} else {
//Try and set some kind of content length if we can safely convert the Long to an int
if (isLongSafe(contentLength)) {
servletResponse.setContentLength(contentLength.intValue());
}
}
}
}
}
private boolean isLongSafe(long value) {
return value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE;
}
}
@@ -170,7 +170,6 @@ public class FormBodyWrapperFilter extends ZuulFilter {
return this.contentLength;
}
@Override
public long getContentLengthLong() {
return getContentLength();
}
@@ -16,28 +16,25 @@
package org.springframework.cloud.netflix.zuul.filters.route;
import lombok.extern.apachecommons.CommonsLog;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.cloud.netflix.ribbon.support.RibbonRequestCustomizer;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.MultiValueMap;
import com.netflix.client.ClientException;
import com.netflix.hystrix.exception.HystrixRuntimeException;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.apachecommons.CommonsLog;
@CommonsLog
public class RibbonRoutingFilter extends ZuulFilter {
@@ -45,6 +42,7 @@ public class RibbonRoutingFilter extends ZuulFilter {
protected ProxyRequestHelper helper;
protected RibbonCommandFactory<?> ribbonCommandFactory;
protected List<RibbonRequestCustomizer> requestCustomizers;
private boolean useServlet31 = true;
public RibbonRoutingFilter(ProxyRequestHelper helper,
RibbonCommandFactory<?> ribbonCommandFactory,
@@ -52,6 +50,12 @@ public class RibbonRoutingFilter extends ZuulFilter {
this.helper = helper;
this.ribbonCommandFactory = ribbonCommandFactory;
this.requestCustomizers = requestCustomizers;
// To support Servlet API 3.0.1 we need to check if getcontentLengthLong exists
try {
HttpServletResponse.class.getMethod("getContentLengthLong");
} catch(NoSuchMethodException e) {
useServlet31 = false;
}
}
public RibbonRoutingFilter(RibbonCommandFactory<?> ribbonCommandFactory) {
@@ -119,8 +123,10 @@ public class RibbonRoutingFilter extends ZuulFilter {
// remove double slashes
uri = uri.replace("//", "/");
long contentLength = useServlet31 ? request.getContentLengthLong(): request.getContentLength();
return new RibbonCommandContext(serviceId, verb, uri, retryable, headers, params,
requestEntity, this.requestCustomizers, request.getContentLengthLong());
requestEntity, this.requestCustomizers, contentLength);
}
protected ClientHttpResponse forward(RibbonCommandContext context) throws Exception {
@@ -19,6 +19,7 @@ package org.springframework.cloud.netflix.zuul.filters.route;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
@@ -273,9 +274,21 @@ public class SimpleHostRoutingFilter extends ZuulFilter {
HttpHost httpHost = getHttpHost(host);
uri = StringUtils.cleanPath((host.getPath() + uri).replaceAll("/{2,}", "/"));
int contentLength = request.getContentLength();
InputStreamEntity entity = new InputStreamEntity(requestEntity, contentLength,
request.getContentType() != null
? ContentType.create(request.getContentType()) : null);
ContentType contentType = null;
if (request.getContentType() != null) {
String contentTypeString = request.getContentType();
Charset charset = null;
if (contentTypeString.contains(";charset=")) {
final String[] split = contentTypeString.split(";charset=");
contentTypeString = split[0];
charset = Charset.forName(split[1]);
}
contentType = ContentType.create(contentTypeString, charset);
}
InputStreamEntity entity = new InputStreamEntity(requestEntity, contentLength, contentType);
HttpRequest httpRequest = buildHttpRequest(verb, uri, entity, headers, params);
try {
@@ -108,7 +108,7 @@ public class FeignClientOverrideDefaultsTests {
@Test
public void overrideRetryer() {
assertNull(this.context.getInstance("foo", Retryer.class));
assertEquals(Retryer.NEVER_RETRY, this.context.getInstance("foo", Retryer.class));
Retryer.Default.class.cast(this.context.getInstance("bar", Retryer.class));
}
@@ -16,21 +16,23 @@
package org.springframework.cloud.netflix.feign.ribbon;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryPolicyFactory;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.retry.support.RetryTemplate;
import com.netflix.client.config.CommonClientConfigKey;
import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.client.config.IClientConfig;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* @author Spencer Gibb
*/
@@ -39,6 +41,9 @@ public class CachingSpringLoadBalancerFactoryTests {
@Mock
private SpringClientFactory delegate;
@Mock
private RibbonLoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory;
private CachingSpringLoadBalancerFactory factory;
@Before
@@ -52,7 +57,7 @@ public class CachingSpringLoadBalancerFactoryTests {
when(this.delegate.getClientConfig("client1")).thenReturn(config);
when(this.delegate.getClientConfig("client2")).thenReturn(config);
this.factory = new CachingSpringLoadBalancerFactory(this.delegate);
this.factory = new CachingSpringLoadBalancerFactory(this.delegate, loadBalancedRetryPolicyFactory);
}
@Test
@@ -1,5 +1,32 @@
package org.springframework.cloud.netflix.feign.ribbon;
import feign.Client;
import feign.Request;
import feign.Request.Options;
import feign.RequestTemplate;
import feign.Response;
import lombok.SneakyThrows;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.cloud.netflix.feign.ribbon.FeignLoadBalancer.RibbonRequest;
import org.springframework.cloud.netflix.feign.ribbon.FeignLoadBalancer.RibbonResponse;
import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryPolicyFactory;
import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
import org.springframework.retry.support.RetryTemplate;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import static com.netflix.client.config.CommonClientConfigKey.ConnectTimeout;
import static com.netflix.client.config.CommonClientConfigKey.IsSecure;
import static com.netflix.client.config.CommonClientConfigKey.MaxAutoRetries;
@@ -15,33 +42,6 @@ import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.cloud.netflix.feign.ribbon.FeignLoadBalancer.RibbonRequest;
import org.springframework.cloud.netflix.feign.ribbon.FeignLoadBalancer.RibbonResponse;
import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector;
import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import feign.Client;
import feign.Request;
import feign.Request.Options;
import feign.RequestTemplate;
import feign.Response;
import lombok.SneakyThrows;
public class FeignLoadBalancerTests {
@Mock
@@ -50,6 +50,8 @@ public class FeignLoadBalancerTests {
private ILoadBalancer lb;
@Mock
private IClientConfig config;
@Mock
private RibbonLoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory;
private FeignLoadBalancer feignLoadBalancer;
@@ -75,7 +77,7 @@ public class FeignLoadBalancerTests {
public void testUriInsecure() {
when(this.config.get(IsSecure)).thenReturn(false);
this.feignLoadBalancer = new FeignLoadBalancer(this.lb, this.config,
this.inspector);
this.inspector, loadBalancedRetryPolicyFactory);
Request request = new RequestTemplate().method("GET").append("http://foo/")
.request();
RibbonRequest ribbonRequest = new RibbonRequest(this.delegate, request,
@@ -96,7 +98,7 @@ public class FeignLoadBalancerTests {
public void testSecureUriFromClientConfig() {
when(this.config.get(IsSecure)).thenReturn(true);
this.feignLoadBalancer = new FeignLoadBalancer(this.lb, this.config,
this.inspector);
this.inspector, loadBalancedRetryPolicyFactory);
Server server = new Server("foo", 7777);
URI uri = this.feignLoadBalancer.reconstructURIWithServer(server,
new URI("http://foo/"));
@@ -118,7 +120,7 @@ public class FeignLoadBalancerTests {
public Map<String, String> getMetadata(Server server) {
return null;
}
});
}, loadBalancedRetryPolicyFactory);
Server server = new Server("foo", 7777);
URI uri = this.feignLoadBalancer.reconstructURIWithServer(server,
new URI("http://foo/"));
@@ -129,7 +131,7 @@ public class FeignLoadBalancerTests {
@SneakyThrows
public void testSecureUriFromClientConfigOverride() {
this.feignLoadBalancer = new FeignLoadBalancer(this.lb, this.config,
this.inspector);
this.inspector, loadBalancedRetryPolicyFactory);
Server server = Mockito.mock(Server.class);
when(server.getPort()).thenReturn(443);
when(server.getHost()).thenReturn("foo");
@@ -16,14 +16,13 @@
package org.springframework.cloud.netflix.feign.ribbon;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@@ -43,13 +42,12 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* Tests the Feign Retryer, not ribbon retry.
@@ -58,7 +56,8 @@ import lombok.NoArgsConstructor;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = FeignRibbonClientRetryTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = {
"spring.application.name=feignclientretrytest", "feign.okhttp.enabled=false",
"feign.httpclient.enabled=false", "feign.hystrix.enabled=false", })
"feign.httpclient.enabled=false", "feign.hystrix.enabled=false", "localapp.ribbon.MaxAutoRetries=2",
"localapp.ribbon.MaxAutoRetriesNextServer=3"})
@DirtiesContext
public class FeignRibbonClientRetryTests {
@@ -16,19 +16,19 @@
package org.springframework.cloud.netflix.feign.ribbon;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import feign.Client;
import feign.Request;
import feign.Request.Options;
import feign.RequestTemplate;
import org.hamcrest.CustomMatcher;
import org.junit.Before;
import org.junit.Test;
import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector;
import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancedRetryPolicyFactory;
import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.retry.support.RetryTemplate;
import com.netflix.client.config.CommonClientConfigKey;
import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.client.config.IClientConfig;
@@ -38,10 +38,11 @@ import com.netflix.loadbalancer.LoadBalancerStats;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerStats;
import feign.Client;
import feign.Request;
import feign.Request.Options;
import feign.RequestTemplate;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* @author Dave Syer
@@ -51,6 +52,7 @@ public class FeignRibbonClientTests {
private AbstractLoadBalancer loadBalancer = mock(AbstractLoadBalancer.class);
private Client delegate = mock(Client.class);
private RibbonLoadBalancedRetryPolicyFactory retryPolicyFactory = mock(RibbonLoadBalancedRetryPolicyFactory.class);
private SpringClientFactory factory = new SpringClientFactory() {
@Override
@@ -79,7 +81,8 @@ public class FeignRibbonClientTests {
// Even though we don't maintain FeignRibbonClient, keep these tests
// around to make sure the expected behaviour doesn't break
private Client client = new LoadBalancerFeignClient(this.delegate, new CachingSpringLoadBalancerFactory(this.factory), this.factory);
private Client client = new LoadBalancerFeignClient(this.delegate, new CachingSpringLoadBalancerFactory(this.factory,
retryPolicyFactory), this.factory);
@Before
public void init() {
@@ -17,6 +17,7 @@
package org.springframework.cloud.netflix.feign.valid;
import org.junit.Test;
import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.feign.FeignAutoConfiguration;
import org.springframework.cloud.netflix.feign.FeignClient;
@@ -82,6 +83,7 @@ public class FeignClientValidationTests {
@Test
public void validLoadBalanced() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
LoadBalancerAutoConfiguration.class,
RibbonAutoConfiguration.class,
FeignRibbonClientAutoConfiguration.class,
GoodServiceIdConfiguration.class);
@@ -114,6 +114,21 @@ public class RibbonLoadBalancingHttpClientTests {
assertThat(result.isRedirectsEnabled(), is(false));
}
@Test
public void testUpdatedTimeouts()
throws Exception {
SpringClientFactory factory = new SpringClientFactory();
RequestConfig result = getBuiltRequestConfig(Timeouts.class, null, factory);
assertThat(result.getConnectTimeout(), is(60000));
assertThat(result.getSocketTimeout(), is (50000));
IClientConfig config = factory.getClientConfig("service");
config.set(CommonClientConfigKey.ConnectTimeout, 60);
config.set(CommonClientConfigKey.ReadTimeout, 50);
result = getBuiltRequestConfig(Timeouts.class, null, factory);
assertThat(result.getConnectTimeout(), is(60));
assertThat(result.getSocketTimeout(), is (50));
}
@Configuration
protected static class UseDefaults {
@@ -164,8 +179,13 @@ public class RibbonLoadBalancingHttpClientTests {
private RequestConfig getBuiltRequestConfig(Class<?> defaultConfigurationClass,
IClientConfig configOverride) throws Exception {
return getBuiltRequestConfig(defaultConfigurationClass, configOverride, new SpringClientFactory());
}
private RequestConfig getBuiltRequestConfig(Class<?> defaultConfigurationClass,
IClientConfig configOverride, SpringClientFactory factory)
throws Exception {
SpringClientFactory factory = new SpringClientFactory();
factory.setApplicationContext(new AnnotationConfigApplicationContext(
RibbonAutoConfiguration.class, defaultConfigurationClass));
HttpClient delegate = mock(HttpClient.class);
@@ -84,9 +84,45 @@ public class OkHttpLoadBalancingClientTests {
assertThat(result.followRedirects(), is(false));
}
@Test
public void testTimeouts() throws Exception {
OkHttpClient result = getHttpClient(Timeouts.class, null);
assertThat(result.readTimeoutMillis(), is(50000));
assertThat(result.connectTimeoutMillis(), is(60000));
}
@Test
public void testTimeoutsOverride() throws Exception {
DefaultClientConfigImpl override = new DefaultClientConfigImpl();
override.set(CommonClientConfigKey.ConnectTimeout, 60);
override.set(CommonClientConfigKey.ReadTimeout, 50);
OkHttpClient result = getHttpClient(Timeouts.class, override);
assertThat(result.readTimeoutMillis(), is(50));
assertThat(result.connectTimeoutMillis(), is(60));
}
@Test
public void testUpdatedTimeouts() throws Exception {
SpringClientFactory factory = new SpringClientFactory();
OkHttpClient result = getHttpClient(Timeouts.class, null, factory);
assertThat(result.readTimeoutMillis(), is(50000));
assertThat(result.connectTimeoutMillis(), is(60000));
IClientConfig config = factory.getClientConfig("service");
config.set(CommonClientConfigKey.ConnectTimeout, 60);
config.set(CommonClientConfigKey.ReadTimeout, 50);
result = getHttpClient(Timeouts.class, null, factory);
assertThat(result.readTimeoutMillis(), is(50));
assertThat(result.connectTimeoutMillis(), is(60));
}
private OkHttpClient getHttpClient(Class<?> defaultConfigurationClass,
IClientConfig configOverride) throws Exception {
SpringClientFactory factory = new SpringClientFactory();
return getHttpClient(defaultConfigurationClass, configOverride, new SpringClientFactory());
}
private OkHttpClient getHttpClient(Class<?> defaultConfigurationClass,
IClientConfig configOverride,
SpringClientFactory factory) throws Exception {
factory.setApplicationContext(new AnnotationConfigApplicationContext(
RibbonAutoConfiguration.class, defaultConfigurationClass));
@@ -121,4 +157,15 @@ public class OkHttpLoadBalancingClientTests {
}
}
@Configuration
protected static class Timeouts {
@Bean
public IClientConfig clientConfig() {
DefaultClientConfigImpl config = new DefaultClientConfigImpl();
config.set(CommonClientConfigKey.ConnectTimeout, 60000);
config.set(CommonClientConfigKey.ReadTimeout, 50000);
return config;
}
}
}
+3 -3
View File
@@ -5,17 +5,17 @@
<parent>
<artifactId>spring-cloud-dependencies-parent</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.2.RELEASE</version>
<relativePath/>
</parent>
<artifactId>spring-cloud-netflix-dependencies</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<packaging>pom</packaging>
<name>spring-cloud-netflix-dependencies</name>
<description>Spring Cloud Netflix Dependencies</description>
<properties>
<archaius.version>0.7.4</archaius.version>
<eureka.version>1.4.11</eureka.version>
<eureka.version>1.4.12</eureka.version>
<feign.version>9.3.1</feign.version>
<hystrix.version>1.5.6</hystrix.version>
<ribbon.version>2.2.0</ribbon.version>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-netflix-eureka-client</artifactId>
@@ -107,21 +107,15 @@ public class EurekaClientAutoConfiguration {
@Bean
@ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT)
public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils) {
RelaxedPropertyResolver relaxedPropertyResolver = new RelaxedPropertyResolver(env, "eureka.instance.");
RelaxedPropertyResolver springPropertyResolver = new RelaxedPropertyResolver(env, "spring.application.");
String springAppName = springPropertyResolver.getProperty("name");
EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);
instance.setNonSecurePort(this.nonSecurePort);
instance.setInstanceId(getDefaultInstanceId(this.env));
if(StringUtils.hasText(springAppName)) {
instance.setAppname(springAppName);
instance.setVirtualHostName(springAppName);
instance.setSecureVirtualHostName(springAppName);
}
if (this.managementPort != this.nonSecurePort && this.managementPort != 0) {
if (StringUtils.hasText(this.hostname)) {
instance.setHostname(this.hostname);
}
RelaxedPropertyResolver relaxedPropertyResolver = new RelaxedPropertyResolver(env, "eureka.instance.");
String statusPageUrlPath = relaxedPropertyResolver.getProperty("statusPageUrlPath");
String healthCheckUrlPath = relaxedPropertyResolver.getProperty("healthCheckUrlPath");
if (StringUtils.hasText(statusPageUrlPath)) {
@@ -16,20 +16,26 @@
package org.springframework.cloud.netflix.eureka;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.commons.util.InetUtils.HostInfo;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import com.netflix.appinfo.DataCenterInfo;
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
import com.netflix.appinfo.MyDataCenterInfo;
import lombok.AccessLevel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.commons.util.InetUtils.HostInfo;
import com.netflix.appinfo.DataCenterInfo;
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
import com.netflix.appinfo.MyDataCenterInfo;
/**
* @author Dave Syer
* @author Spencer Gibb
@@ -37,7 +43,7 @@ import com.netflix.appinfo.MyDataCenterInfo;
*/
@Data
@ConfigurationProperties("eureka.instance")
public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig {
public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, EnvironmentAware {
private static final String UNKNOWN = "unknown";
@@ -272,6 +278,7 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig {
private InstanceStatus initialStatus = InstanceStatus.UP;
private String[] defaultAddressResolutionOrder = new String[0];
private Environment environment;
public String getHostname() {
return getHostName(false);
@@ -319,4 +326,17 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig {
}
return this.preferIpAddress ? this.ipAddress : this.hostname;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
// set some defaults from the environment, but allow the defaults to use relaxed binding
RelaxedPropertyResolver springPropertyResolver = new RelaxedPropertyResolver(this.environment, "spring.application.");
String springAppName = springPropertyResolver.getProperty("name");
if(StringUtils.hasText(springAppName)) {
setAppname(springAppName);
setVirtualHostName(springAppName);
setSecureVirtualHostName(springAppName);
}
}
}
@@ -16,7 +16,14 @@
package org.springframework.cloud.netflix.ribbon.eureka;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -24,8 +31,10 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import com.netflix.discovery.EurekaClient;
import com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList;
/**
@@ -33,11 +42,31 @@ import com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList;
*/
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass(DiscoveryEnabledNIWSServerList.class)
@ConditionalOnBean(SpringClientFactory.class)
@ConditionalOnProperty(value = "ribbon.eureka.enabled", matchIfMissing = true)
@RibbonEurekaAutoConfiguration.ConditionalOnRibbonAndEurekaEnabled
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = EurekaRibbonClientConfiguration.class)
public class RibbonEurekaAutoConfiguration {
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(OnRibbonAndEurekaEnabledCondition.class)
@interface ConditionalOnRibbonAndEurekaEnabled {
}
private static class OnRibbonAndEurekaEnabledCondition extends AllNestedConditions {
public OnRibbonAndEurekaEnabledCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnClass(DiscoveryEnabledNIWSServerList.class)
@ConditionalOnBean(SpringClientFactory.class)
@ConditionalOnProperty(value = "ribbon.eureka.enabled", matchIfMissing = true)
static class Defaults {}
@ConditionalOnBean(EurekaClient.class)
static class EurekaBeans {}
}
}
@@ -206,6 +206,23 @@ public class EurekaClientAutoConfigurationTests {
assertEquals("mytest", getInstanceConfig().getSecureVirtualHostName());
}
@Test
public void testAppNameUpper() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context, "SPRING_APPLICATION_NAME=mytestupper");
setupContext();
assertEquals("mytestupper", getInstanceConfig().getAppname());
assertEquals("mytestupper", getInstanceConfig().getVirtualHostName());
assertEquals("mytestupper", getInstanceConfig().getSecureVirtualHostName());
}
@Test
public void testInstanceNamePreferred() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context, "SPRING_APPLICATION_NAME=mytestspringappname",
"eureka.instance.appname=mytesteurekaappname");
setupContext();
assertEquals("mytesteurekaappname", getInstanceConfig().getAppname());
}
private void testNonSecurePort(String propName) {
addEnvironment(this.context, propName + ":8888");
setupContext();
@@ -16,11 +16,10 @@
package org.springframework.cloud.netflix.ribbon.eureka;
import static org.mockito.Mockito.mock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.commons.util.UtilAutoConfiguration;
@@ -30,9 +29,8 @@ import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import com.netflix.discovery.EurekaClient;
import com.netflix.loadbalancer.ConfigurationBasedServerList;
@@ -41,10 +39,12 @@ import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
import com.netflix.niws.loadbalancer.NIWSDiscoveryPing;
import static org.mockito.Mockito.mock;
/**
* @author Spencer Gibb
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(SpringRunner.class)
@SpringBootTest(classes = EurekaRibbonClientPropertyOverrideIntegrationTests.TestConfiguration.class)
@DirtiesContext
public class EurekaRibbonClientPropertyOverrideIntegrationTests {
@@ -72,7 +72,7 @@ public class EurekaRibbonClientPropertyOverrideIntegrationTests {
@Configuration
@RibbonClients
@Import({ UtilAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
@ImportAutoConfiguration({ UtilAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
ArchaiusAutoConfiguration.class, RibbonAutoConfiguration.class,
RibbonEurekaAutoConfiguration.class })
protected static class TestConfiguration {
@@ -16,12 +16,11 @@
package org.springframework.cloud.netflix.ribbon.eureka;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.commons.util.InetUtils;
@@ -35,7 +34,6 @@ import org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter;
import org.springframework.cloud.netflix.ribbon.eureka.RibbonClientPreprocessorIntegrationTests.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -44,6 +42,8 @@ import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ZoneAvoidanceRule;
import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
import static org.junit.Assert.assertEquals;
/**
* @author Dave Syer
*/
@@ -83,14 +83,14 @@ public class RibbonClientPreprocessorIntegrationTests {
@Configuration
@RibbonClient("foo")
@Import({ PropertyPlaceholderAutoConfiguration.class,
@ImportAutoConfiguration({ PropertyPlaceholderAutoConfiguration.class,
ArchaiusAutoConfiguration.class, RibbonAutoConfiguration.class })
protected static class PlainConfiguration {
}
@Configuration
@RibbonClient(name = "foo", configuration = FooConfiguration.class)
@Import({ PropertyPlaceholderAutoConfiguration.class,
@ImportAutoConfiguration({ PropertyPlaceholderAutoConfiguration.class,
ArchaiusAutoConfiguration.class, RibbonAutoConfiguration.class,
RibbonEurekaAutoConfiguration.class })
protected static class TestConfiguration {
@@ -0,0 +1,99 @@
/*
* 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.ribbon.eureka;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
/**
* @author Spencer Gibb
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = RibbonEurekaAutoConfigurationTests.EurekaClientDisabledApp.class,
properties = { "eureka.client.enabled=false", "spring.application.name=eurekadisabledtest" },
webEnvironment = RANDOM_PORT)
public class RibbonEurekaAutoConfigurationTests {
@Autowired
TestLoadbalancerClient testLoadbalancerClient;
@Test
public void contextLoads() {
assertThat(testLoadbalancerClient.instanceFound).isFalse();
}
@SpringBootConfiguration
@EnableAutoConfiguration
@EnableDiscoveryClient
public static class EurekaClientDisabledApp {
@Bean
public TestLoadbalancerClient testLoadbalanceClient(LoadBalancerClient loadBalancerClient) {
return new TestLoadbalancerClient(loadBalancerClient);
}
@Bean
public CommandLineRunner commandLineRunner(final TestLoadbalancerClient testLoadbalancerClient) {
return new CommandLineRunner() {
@Override
public void run(String... args) throws Exception {
testLoadbalancerClient.doStuff();
}
};
}
}
private static class TestLoadbalancerClient {
Log log = LogFactory.getLog(this.getClass());
private LoadBalancerClient loadBalancerClient;
private boolean instanceFound = false;
public TestLoadbalancerClient(LoadBalancerClient loadBalancerClient) {
this.loadBalancerClient = loadBalancerClient;
}
public void doStuff() {
ServiceInstance serviceInstance = loadBalancerClient.choose("http://host/doStuff");
if (serviceInstance != null) {
log.info("There is a service instance, because Eureka discovery is enabled and the service is registered");
instanceFound = true;
}
else {
log.warn("No instance found, because Eureka is disabled or there is no service matching.");
}
}
}
}
+6 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-netflix-eureka-server</artifactId>
@@ -37,6 +37,11 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-core</artifactId>
@@ -106,7 +106,7 @@ public class InstanceRegistry extends PeerAwareInstanceRegistryImpl
if (input.getName().equals(appName)) {
InstanceInfo instance = null;
for (InstanceInfo info : input.getInstances()) {
if (info.getHostName().equals(serverId)) {
if (info.getId().equals(serverId)) {
instance = info;
break;
}
@@ -42,7 +42,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = {
"spring.application.name=eureka", "server.contextPath=/context" })
"spring.application.name=eureka", "server.contextPath=/context",
"management.security.enabled=false" })
public class ApplicationContextTests {
@Value("${local.server.port}")
@@ -42,7 +42,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = {
"spring.application.name=eureka", "server.servletPath=/servlet" })
"spring.application.name=eureka", "server.servletPath=/servlet",
"management.security.enabled=false" })
public class ApplicationServletPathTests {
@Value("${local.server.port}")
@@ -52,7 +52,7 @@ import com.netflix.eureka.resources.ServerCodecs;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = {
"spring.jmx.enabled=true" })
"spring.jmx.enabled=true", "management.security.enabled=false" })
public class ApplicationTests {
@Value("${local.server.port}")
@@ -1,92 +1,77 @@
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.Arrays;
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.beans.factory.annotation.Autowired;
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.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.appinfo.LeaseInfo;
import com.netflix.discovery.shared.Application;
import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
/**
* @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"})
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<ApplicationEvent> applicationEvents = new LinkedList<>();
private static final String APP_NAME = "MY-APP-NAME";
private static final String HOST_NAME = "my-host-name";
private static final String INSTANCE_ID = "my-host-name:8008";
private static final int PORT = 8008;
@SpyBean(PeerAwareInstanceRegistry.class)
private InstanceRegistry instanceRegistry;
@MockBean
private ApplicationListener<EurekaInstanceRegisteredEvent>
instanceRegisteredEventListenerMock;
@MockBean
private ApplicationListener<EurekaInstanceCanceledEvent>
instanceCanceledEventListenerMock;
@MockBean
private ApplicationListener<EurekaInstanceRenewedEvent> 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));
this.testEvents.applicationEvents.clear();
}
@Autowired
private TestEvents testEvents;
@Test
public void testRegister() throws Exception {
// creating instance info
final LeaseInfo leaseInfo = getLeaseInfo();
final InstanceInfo instanceInfo = getInstanceInfo(leaseInfo);
final InstanceInfo instanceInfo = getInstanceInfo(APP_NAME, HOST_NAME, INSTANCE_ID, PORT, leaseInfo);
// calling tested method
instanceRegistry.register(instanceInfo, false);
// event of proper type is registered
assertEquals(1, applicationEvents.size());
assertTrue(applicationEvents.get(0) instanceof EurekaInstanceRegisteredEvent);
assertEquals(1, this.testEvents.applicationEvents.size());
assertTrue(this.testEvents.applicationEvents.get(0) instanceof EurekaInstanceRegisteredEvent);
// event details are correct
final EurekaInstanceRegisteredEvent registeredEvent =
(EurekaInstanceRegisteredEvent) (applicationEvents.get(0));
(EurekaInstanceRegisteredEvent) (this.testEvents.applicationEvents.get(0));
assertEquals(instanceInfo, registeredEvent.getInstanceInfo());
assertEquals(leaseInfo.getDurationInSecs(), registeredEvent.getLeaseDuration());
assertEquals(instanceRegistry, registeredEvent.getSource());
@@ -96,12 +81,12 @@ public class InstanceRegistryTest {
@Test
public void testDefaultLeaseDurationRegisterEvent() throws Exception {
// creating instance info
final InstanceInfo instanceInfo = getInstanceInfo(null);
final InstanceInfo instanceInfo = getInstanceInfo(APP_NAME, HOST_NAME, INSTANCE_ID, PORT, null);
// calling tested method
instanceRegistry.register(instanceInfo, false);
// instance info duration is set to default
final EurekaInstanceRegisteredEvent registeredEvent =
(EurekaInstanceRegisteredEvent) (applicationEvents.get(0));
(EurekaInstanceRegisteredEvent) (this.testEvents.applicationEvents.get(0));
assertEquals(LeaseInfo.DEFAULT_LEASE_DURATION,
registeredEvent.getLeaseDuration());
}
@@ -111,11 +96,11 @@ public class InstanceRegistryTest {
// 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);
assertEquals(1, this.testEvents.applicationEvents.size());
assertTrue(this.testEvents.applicationEvents.get(0) instanceof EurekaInstanceCanceledEvent);
// event details are correct
final EurekaInstanceCanceledEvent registeredEvent =
(EurekaInstanceCanceledEvent) (applicationEvents.get(0));
(EurekaInstanceCanceledEvent) (this.testEvents.applicationEvents.get(0));
assertEquals(APP_NAME, registeredEvent.getAppName());
assertEquals(HOST_NAME, registeredEvent.getServerId());
assertEquals(instanceRegistry, registeredEvent.getSource());
@@ -124,40 +109,70 @@ public class InstanceRegistryTest {
@Test
public void testRenew() throws Exception {
// creating application list
final LeaseInfo leaseInfo = getLeaseInfo();
final InstanceInfo instanceInfo = getInstanceInfo(leaseInfo);
final List<InstanceInfo> instances = new ArrayList<>();
instances.add(instanceInfo);
final Application application = new Application(APP_NAME, instances);
//Creating two instances of the app
final InstanceInfo instanceInfo1 = getInstanceInfo(APP_NAME, HOST_NAME, INSTANCE_ID, PORT, null);
final InstanceInfo instanceInfo2 = getInstanceInfo(APP_NAME, HOST_NAME, "my-host-name:8009", 8009, null);
// creating application list with an app having two instances
final Application application = new Application(APP_NAME, Arrays.asList(instanceInfo1, instanceInfo2));
final List<Application> applications = new ArrayList<>();
applications.add(application);
// stubbing applications list
doReturn(applications).when(instanceRegistry).getSortedApplications();
// calling tested method
instanceRegistry.renew(APP_NAME, HOST_NAME, false);
instanceRegistry.renew(APP_NAME, INSTANCE_ID, false);
instanceRegistry.renew(APP_NAME, "my-host-name:8009", false);
// event of proper type is registered
assertEquals(1, applicationEvents.size());
assertTrue(applicationEvents.get(0) instanceof EurekaInstanceRenewedEvent);
assertEquals(2, this.testEvents.applicationEvents.size());
assertTrue(this.testEvents.applicationEvents.get(0) instanceof EurekaInstanceRenewedEvent);
assertTrue(this.testEvents.applicationEvents.get(1) 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());
final EurekaInstanceRenewedEvent event1 = (EurekaInstanceRenewedEvent)
(this.testEvents.applicationEvents.get(0));
assertEquals(APP_NAME, event1.getAppName());
assertEquals(INSTANCE_ID, event1.getServerId());
assertEquals(instanceRegistry, event1.getSource());
assertEquals(instanceInfo1, event1.getInstanceInfo());
assertFalse(event1.isReplication());
final EurekaInstanceRenewedEvent event2 = (EurekaInstanceRenewedEvent)
(this.testEvents.applicationEvents.get(1));
assertEquals(instanceInfo2, event2.getInstanceInfo());
}
@Configuration
@EnableAutoConfiguration
@EnableEurekaServer
protected static class TestApplication {
@Bean
public TestEvents testEvents() {
return new TestEvents();
}
public static void main(String[] args) {
new SpringApplicationBuilder(TestApplication.class).run(args);
}
}
protected static class TestEvents {
public final List<ApplicationEvent> applicationEvents = new LinkedList<>();
@EventListener(EurekaInstanceRegisteredEvent.class)
public void onEvent(EurekaInstanceRegisteredEvent event) {
this.applicationEvents.add(event);
}
@EventListener(EurekaInstanceCanceledEvent.class)
public void onEvent(EurekaInstanceCanceledEvent event) {
this.applicationEvents.add(event);
}
@EventListener(EurekaInstanceRenewedEvent.class)
public void onEvent(EurekaInstanceRenewedEvent event) {
this.applicationEvents.add(event);
}
}
private LeaseInfo getLeaseInfo() {
LeaseInfo.Builder leaseBuilder = LeaseInfo.Builder.newBuilder();
leaseBuilder.setRenewalIntervalInSecs(10);
@@ -165,22 +180,14 @@ public class InstanceRegistryTest {
return leaseBuilder.build();
}
private InstanceInfo getInstanceInfo(LeaseInfo leaseInfo) {
private InstanceInfo getInstanceInfo(String appName, String hostName,
String instanceId, int port, LeaseInfo leaseInfo) {
InstanceInfo.Builder builder = InstanceInfo.Builder.newBuilder();
builder.setAppName(APP_NAME);
builder.setHostName(HOST_NAME);
builder.setPort(8008);
builder.setAppName(appName);
builder.setHostName(hostName);
builder.setInstanceId(instanceId);
builder.setPort(port);
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]);
}
};
}
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-netflix-hystrix-amqp</artifactId>
@@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<properties>
@@ -20,14 +20,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.apachecommons.CommonsLog;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
@@ -37,7 +34,6 @@ import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.HttpConnectionParams;
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.properties.EnableConfigurationProperties;
@@ -49,6 +45,8 @@ import org.springframework.http.HttpHeaders;
import org.springframework.ui.freemarker.SpringTemplateLoader;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import lombok.extern.apachecommons.CommonsLog;
/**
* @author Dave Syer
* @author Roy Clarkson
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-netflix-hystrix-stream</artifactId>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-netflix-sidecar</artifactId>
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-netflix-spectator</artifactId>
@@ -20,8 +20,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.test.ImportAutoConfiguration;
import org.springframework.cloud.netflix.metrics.MetricsHandlerInterceptor;
import org.springframework.cloud.netflix.metrics.servo.ServoMonitorCache;
import org.springframework.context.annotation.Bean;
@@ -160,4 +160,4 @@ class SpectatorMetricsTestController {
ModelAndView defaultErrorHandler(HttpServletRequest request, Exception e) {
return new ModelAndView("error");
}
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-netflix-turbine-stream</artifactId>
+6 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-netflix-turbine</artifactId>
@@ -61,6 +61,11 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-core</artifactId>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-archaius</artifactId>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-atlas</artifactId>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-eureka</artifactId>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-feign</artifactId>
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-hystrix</artifactId>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-ribbon</artifactId>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-spectator</artifactId>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-turbine-amqp</artifactId>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-turbine-stream</artifactId>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-turbine</artifactId>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix</artifactId>
<version>1.2.2.BUILD-SNAPSHOT</version>
<version>1.2.5.RELEASE</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-starter-zuul</artifactId>