parent
2dd322f07f
commit
c4cf557e30
@ -0,0 +1,17 @@
|
||||
package com.github.cloud.openfeign;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author derek(易仁川)
|
||||
* @date 2022/4/9
|
||||
*/
|
||||
@Configuration
|
||||
public class FeignAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public FeignContext feignContext() {
|
||||
return new FeignContext();
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.github.cloud.openfeign;
|
||||
|
||||
import org.springframework.cloud.context.named.NamedContextFactory;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author derek(易仁川)
|
||||
* @date 2022/4/9
|
||||
*/
|
||||
public class FeignClientSpecification implements NamedContextFactory.Specification {
|
||||
|
||||
private String name;
|
||||
|
||||
private Class<?>[] configuration;
|
||||
|
||||
public FeignClientSpecification(String name, Class<?>[] configuration) {
|
||||
this.name = name;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?>[] getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public void setConfiguration(Class<?>[] configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
FeignClientSpecification that = (FeignClientSpecification) o;
|
||||
return name.equals(that.name) && Arrays.equals(configuration, that.configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(name);
|
||||
result = 31 * result + Arrays.hashCode(configuration);
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.github.cloud.openfeign;
|
||||
|
||||
import com.github.cloud.openfeign.ribbon.LoadBalancerFeignClient;
|
||||
import com.github.cloud.openfeign.support.SpringMvcContract;
|
||||
import feign.Client;
|
||||
import feign.Contract;
|
||||
import feign.codec.Decoder;
|
||||
import feign.codec.Encoder;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 配置feign的核心API
|
||||
*
|
||||
* @author derek(易仁川)
|
||||
* @date 2022/4/9
|
||||
*/
|
||||
@Configuration
|
||||
public class FeignClientsConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Encoder encoder() {
|
||||
return new Encoder.Default();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Decoder decoder() {
|
||||
return new Decoder.Default();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Contract contract() {
|
||||
return new SpringMvcContract();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Client client(LoadBalancerClient loadBalancerClient) {
|
||||
return new LoadBalancerFeignClient(loadBalancerClient, new Client.Default(null, null));
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
package com.github.cloud.openfeign.ribbon;
|
||||
|
||||
import com.netflix.client.ClientException;
|
||||
import com.netflix.client.ClientRequest;
|
||||
import com.netflix.client.IResponse;
|
||||
import feign.Client;
|
||||
import feign.Request;
|
||||
import feign.Response;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 具备负载均衡能力的feign client
|
||||
*
|
||||
* @author derek(易仁川)
|
||||
* @date 2022/4/9
|
||||
*/
|
||||
public class LoadBalancerFeignClient implements Client {
|
||||
|
||||
private LoadBalancerClient loadBalancerClient;
|
||||
|
||||
private Client delegate;
|
||||
|
||||
public LoadBalancerFeignClient(LoadBalancerClient loadBalancerClient, Client delegate) {
|
||||
this.loadBalancerClient = loadBalancerClient;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response execute(Request request, Request.Options options) throws IOException {
|
||||
//客户端负载均衡
|
||||
URI original = URI.create(request.url());
|
||||
String serviceId = original.getHost();
|
||||
//选择服务实例
|
||||
ServiceInstance serviceInstance = loadBalancerClient.choose(serviceId);
|
||||
//重建请求URI
|
||||
URI uri = loadBalancerClient.reconstructURI(serviceInstance, original);
|
||||
|
||||
Response response = delegate.execute(new RibbonRequest(request, uri).toRequest(), options);
|
||||
return new RibbonResponse(uri, response).getResponse();
|
||||
}
|
||||
|
||||
private static class RibbonRequest extends ClientRequest {
|
||||
|
||||
private Request request;
|
||||
|
||||
public RibbonRequest(Request request, URI uri) {
|
||||
this.request = request;
|
||||
setUri(uri);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private Request toRequest() {
|
||||
return Request.create(request.httpMethod(), getUri().toASCIIString(), new HashMap<>(),
|
||||
request.body(), StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
private static class RibbonResponse implements IResponse {
|
||||
|
||||
private final URI uri;
|
||||
|
||||
private final Response response;
|
||||
|
||||
protected 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, ?> getHeaders() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (response != null && response.body() != null) {
|
||||
response.body().close();
|
||||
}
|
||||
}
|
||||
|
||||
public Response getResponse() {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
com.github.cloud.openfeign.FeignAutoConfiguration
|
Loading…
Reference in new issue