集成Feign简化调用方式

open-feign
DerekYRC 2 years ago
parent 2dd322f07f
commit c4cf557e30

@ -60,6 +60,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
</dependencies>
</project>

@ -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();
}
}

@ -1,7 +1,11 @@
package com.github.cloud.openfeign;
import com.github.cloud.openfeign.support.SpringMvcContract;
import feign.Client;
import feign.Contract;
import feign.Feign;
import feign.Target.HardCodedTarget;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
@ -23,9 +27,18 @@ public class FeignClientFactoryBean implements FactoryBean<Object>, ApplicationC
@Override
public Object getObject() throws Exception {
FeignContext feignContext = applicationContext.getBean(FeignContext.class);
Encoder encoder = feignContext.getInstance(contextId, Encoder.class);
Decoder decoder = feignContext.getInstance(contextId, Decoder.class);
Contract contract = feignContext.getInstance(contextId, Contract.class);
Client client = feignContext.getInstance(contextId, Client.class);
return Feign.builder()
.contract(new SpringMvcContract())
.target(type, "http://localhost:1234");
.encoder(encoder)
.decoder(decoder)
.contract(contract)
.client(client)
.target(new HardCodedTarget<>(type, contextId, "http://" + contextId));
}
@Override

@ -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;
/**
* feignAPI
*
* @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,16 @@
package com.github.cloud.openfeign;
import org.springframework.cloud.context.named.NamedContextFactory;
/**
* feign(ApplicationContext)feign
*
* @author derek()
* @date 2022/4/9
*/
public class FeignContext extends NamedContextFactory<FeignClientSpecification> {
public FeignContext() {
super(FeignClientsConfiguration.class, "feign", "feign.client.name");
}
}

@ -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…
Cancel
Save