Commit 3d7cc707 by Spencer Gibb

Merge branch 'feign-ribbon' of github.com:VanRoy/spring-cloud-netflix into vanroy-feign-ribbon

parents 70c3d9e7 943d1b9b
package org.springframework.cloud.netflix.feign;
import feign.Client;
import feign.Contract;
import feign.Feign;
import feign.Logger;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cloud.netflix.feign.ribbon.RibbonLoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration;
import com.netflix.loadbalancer.ILoadBalancer;
/**
* @author Spencer Gibb
*/
......@@ -36,4 +40,8 @@ public class FeignAutoConfiguration {
public Contract feignContract() {
return new SpringMvcContract();
}
@Bean
@ConditionalOnClass(ILoadBalancer.class)
public Client feignRibbonClient() { return new RibbonLoadBalancerClient(); }
}
package org.springframework.cloud.netflix.feign;
import feign.Client;
import feign.Contract;
import feign.Feign;
import feign.Logger;
......@@ -36,6 +37,9 @@ public class FeignConfigurer {
@Autowired
Contract contract;
@Autowired(required = false)
Client ribbonClient;
protected Feign.Builder feign() {
//ConfigurationManager.getConfigInstance().setProperty("exampleBackend.ribbon.listOfServers", "localhost:7080");
//exampleBackend.ribbon.NIWSServerListClassName=my.package.MyServerList
......@@ -53,7 +57,12 @@ public class FeignConfigurer {
protected <T> T loadBalance(Feign.Builder builder, Class<T> type, String schemeName) {
String name = URI.create(schemeName).getHost();
ribbonClientPreprocessor.preprocess(name);
return builder.target(LoadBalancingTarget.create(type, schemeName));
if(ribbonClient != null) {
return builder.client(ribbonClient).target(type, schemeName);
} else {
return builder.target(LoadBalancingTarget.create(type, schemeName));
}
}
}
package org.springframework.cloud.netflix.feign.ribbon;
import java.io.IOException;
import java.net.URI;
import java.util.Collection;
import java.util.Map;
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 feign.Client;
import feign.Request;
import feign.RequestTemplate;
import feign.Response;
public class RibbonLoadBalancer extends AbstractLoadBalancerAwareClient<RibbonLoadBalancer.RibbonRequest, RibbonLoadBalancer.RibbonResponse> {
private final Client delegate;
private final int connectTimeout;
private final int readTimeout;
private final IClientConfig clientConfig;
public RibbonLoadBalancer(Client delegate, ILoadBalancer lb, IClientConfig clientConfig) {
super(lb, clientConfig);
this.setRetryHandler(RetryHandler.DEFAULT);
this.clientConfig = clientConfig;
this.delegate = delegate;
connectTimeout = clientConfig.get(CommonClientConfigKey.ConnectTimeout);
readTimeout = clientConfig.get(CommonClientConfigKey.ReadTimeout);
}
@Override
public RibbonResponse execute(RibbonRequest request, IClientConfig configOverride) throws IOException {
Request.Options options;
if (configOverride != null) {
options = new Request.Options(configOverride.get(CommonClientConfigKey.ConnectTimeout, connectTimeout), (configOverride.get(CommonClientConfigKey.ReadTimeout, readTimeout)));
} else {
options = new Request.Options(connectTimeout, readTimeout);
}
Response response = delegate.execute(request.toRequest(), options);
return new RibbonResponse(request.getUri(), response);
}
@Override
public RequestSpecificRetryHandler getRequestSpecificRetryHandler(
RibbonRequest request, IClientConfig requestConfig) {
if (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);
}
}
static class RibbonRequest extends ClientRequest implements Cloneable {
private final Request request;
RibbonRequest(Request request, URI uri) {
this.request = request;
setUri(uri);
}
Request toRequest() {
return new RequestTemplate()
.method(request.method())
.append(getUri().toASCIIString())
.headers(request.headers())
.body(request.body(), request.charset())
.request();
}
public Object clone() {
return new RibbonRequest(request, getUri());
}
}
static class RibbonResponse implements IResponse {
private final URI uri;
private final Response response;
RibbonResponse(URI uri, Response response) {
this.uri = uri;
this.response = response;
}
@Override
public Object getPayload() throws ClientException {
return response.body();
}
@Override
public boolean hasPayload() {
return response.body() != null;
}
@Override
public boolean isSuccess() {
return response.status() == 200;
}
@Override
public URI getRequestedURI() {
return uri;
}
@Override
public Map<String, Collection<String>> getHeaders() {
return response.headers();
}
Response toResponse() {
return response;
}
@Override
public void close() throws IOException {
if (response != null && response.body() != null) {
response.body().close();
}
}
}
}
package org.springframework.cloud.netflix.feign.ribbon;
import java.io.IOException;
import java.net.URI;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.ribbon.RibbonClientPreprocessor;
import com.google.common.base.Throwables;
import com.netflix.client.ClientException;
import com.netflix.client.ClientFactory;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import dagger.Lazy;
import feign.Client;
import feign.Request;
import feign.Response;
/**
* @author: Julien Roy
*/
public class RibbonLoadBalancerClient implements Client {
private Client defaultClient = new Default(
new Lazy<SSLSocketFactory>() {
@Override
public SSLSocketFactory get() {
return (SSLSocketFactory) SSLSocketFactory.getDefault();
}
}, new Lazy<HostnameVerifier>() {
@Override
public HostnameVerifier get() {
return HttpsURLConnection.getDefaultHostnameVerifier();
}
});
@Override
public Response execute(Request request, Request.Options options) throws IOException {
try {
URI asUri = URI.create(request.url());
String clientName = asUri.getHost();
URI uriWithoutSchemeAndPort = URI.create(request.url().replace(asUri.getScheme() + "://" + asUri.getHost(), ""));
RibbonLoadBalancer.RibbonRequest ribbonRequest = new RibbonLoadBalancer.RibbonRequest(request, uriWithoutSchemeAndPort);
return lbClient(clientName).executeWithLoadBalancer(ribbonRequest).toResponse();
} catch (ClientException e) {
if (e.getCause() instanceof IOException) {
throw IOException.class.cast(e.getCause());
}
throw Throwables.propagate(e);
}
}
private RibbonLoadBalancer lbClient(String clientName) {
IClientConfig config = ClientFactory.getNamedConfig(clientName);
ILoadBalancer lb = ClientFactory.getNamedLoadBalancer(clientName);
return new RibbonLoadBalancer(defaultClient, lb, config);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment