公司内部有名字服务,在使用feign client的时候,也希望可以访问名字服务对应的IP和端口
名字服务
demo这里假设名字服务是从hashmap中得到的,使用前缀mao://
@Getter
@SuppressWarnings("UnstableApiUsage")
public class CustomLoadBalancer {
private static final Map<String, HostAndPort> HOST_AND_PORT_HASH_MAP = new HashMap<>();
static {
HOST_AND_PORT_HASH_MAP.put("baidu", HostAndPort.fromString("www.baidu.com:80"));
HOST_AND_PORT_HASH_MAP.put("netEasy", HostAndPort.fromString("www.163.com:80"));
}
private static final String PROTOCOL_PREFIX = "mao://";
private final String name;
private CustomLoadBalancer(String name) {
this.name = name;
}
/**
* 解析mao://{name}/hello/world
*/
public static CustomLoadBalancer parse(String url) {
Preconditions.checkArgument(CustomLoadBalancer.isAcceptable(url));
String urlBody = url.substring(PROTOCOL_PREFIX.length());
int index = urlBody.indexOf("/");
String name = index > 0 ? urlBody.substring(index) : urlBody;
if (!HOST_AND_PORT_HASH_MAP.containsKey(name)) {
throw new IllegalArgumentException("there is not host and port for " name);
}
return new CustomLoadBalancer(name);
}
public static boolean isAcceptable(String url) {
return url.startsWith(PROTOCOL_PREFIX);
}
public HostAndPort getHostAndPort() {
HostAndPort hostAndPort = HOST_AND_PORT_HASH_MAP.get(name);
if (hostAndPort == null) {
throw new IllegalArgumentException("there is not host and port for " name);
}
return hostAndPort;
}
}
feign clieng客户端
使用自定义客户端可以实现对名字服务的调用,来重建请求URL
代码语言:javascript复制@Slf4j
@SuppressWarnings("UnstableApiUsage")
public class TenmaoFeignClient extends LoadBalancerFeignClient {
public static final String BALANCER = "ribbon";
public TenmaoFeignClient(Client delegate, CachingSpringLoadBalancerFactory lbClientFactory, SpringClientFactory clientFactory) {
super(delegate, lbClientFactory, clientFactory);
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
log.info("feign client request:{} ", request);
URI orgUri = URI.create(request.url());
String listOfServers = ConfigurationManager.getConfigInstance()
.getString(Joiner.on(".").join(orgUri.getHost(), BALANCER, ListOfServers.key()));
if (CustomLoadBalancer.isAcceptable(listOfServers)) {
CustomLoadBalancer balancer = CustomLoadBalancer.parse(listOfServers);
HostAndPort hostAndPort = balancer.getHostAndPort();
//重建请求URL
String url = String.format("http://%s:%d%s?%s", hostAndPort.getHost(), hostAndPort.getPort(), orgUri.getRawPath(), orgUri.getRawQuery());
URI newUrl = URI.create(url);
Map<String, Collection<String>> headers = new LinkedHashMap(request.headers());
Request newRequest = Request.create(request.httpMethod(), newUrl.toASCIIString(), headers, request.requestBody());
return super.getDelegate().execute(newRequest, options);
}
return super.execute(request, options);
}
@Override
protected IOException findIOException(Throwable t) {
return super.findIOException(t);
}
@Override
public Client getDelegate() {
return super.getDelegate();
}
}
feign配置: 使用自定义feign client
代码语言:javascript复制@Slf4j
@Configuration
public class FeignClientConfiguration {
@ConditionalOnMissingBean(Client.class)
@Bean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory) {
return new TenmaoFeignClient(new Client.Default(null, null),
cachingFactory, clientFactory);
}
}
配置文件
代码语言:javascript复制eureka:
client:
enabled: false
home:
ribbon:
listOfServers: mao://baidu