最近接手一個項目,各子工程之間通過feign調(diào)用;各服務(wù)部署在K8S上,通過nacos管理配置;由于服務(wù)部署的機器無法開放端口等原因,導(dǎo)致本機服務(wù)與測試環(huán)境網(wǎng)絡(luò)端口無法互通,故需要重寫feign的調(diào)用地址;個人總結(jié)的方法有以下幾種:
目錄
?第一種:feignclient配置URL
第二種:實現(xiàn)RequestInterceptor接口;
第三種:重寫feign的client的execute方法;
?第一種:feignclient配置URL
????????在feignclient里寫一個固定地址或者寫一個可配置的地址,這樣可以在配置文件里指定,這種方式在創(chuàng)建feign客戶端的時候就需要規(guī)劃好。
? ? ? ? 1.1 固定地址
@FeignClient(name = "feignCustomerService", url = "http://localhost:8080")
public interface FeignCustomerService {
/**
* 請求客戶的接口
*/
@RequestMapping(value = "order/update", method = RequestMethod.POST)
@Headers(value = "Content-Type: application/json")
OrderHttpResponse updateOrder(@RequestBody OrderUpdateDTO orderUpdateDTO);
}
1.2 可配置的地址
@FeignClient(name = "feignCustomerService", url = "${customer.url}")
public interface FeignCustomerService {
@RequestMapping(value = "test/list", method = RequestMethod.POST)
@Headers(value = "Content-Type: application/json")
OrderHttpResponse updateTest(@RequestBody OrderUpdateDTO orderUpdateDTO);
}
配置文件配置地址
customer.url=http://localhost:8080
第二種:實現(xiàn)RequestInterceptor接口;
????????這種方式具有局限性,在nacos上注冊的服務(wù)IP與本機IP不一致的時候(連接VPN)可能依舊調(diào)不通服務(wù),但是實現(xiàn)RequestInterceptor接口可以處理全局請求(header,身份認(rèn)證等)
@Component
public class Oauth2TokenRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
// 獲取請求中的消息頭
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String requestHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if (StringUtils.isNotBlank(requestHeader) && requestHeader.startsWith("Bearer ")) {
// 將消息頭塞入到請求模板中
requestTemplate.header(HttpHeaders.AUTHORIZATION, requestHeader);
}
//重寫URL,訪問指定服務(wù)
String url = target.url();
String newUrl = "http://localhost:8080";
template.target(newUrl );
}
}
第三種:重寫feign的client的execute方法;
????????這種方式可以自定義負(fù)載均衡的策略,也可以自定義訪問指定服務(wù)IP,這里以FeignBlockingLoadBalancerClient為例
配置類
package com.***.redirect;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import java.util.Map;
@Getter
@Setter
@RefreshScope
@ConfigurationProperties("localbalance")
@Component
public class LocalFeignPerpreties {
private Boolean enable;
private Map<String,String> rule;
}
配置文件配置內(nèi)容:
localbalance:
enable: true
rule:
aiflow-sys: http://IP:8888/SERVICE
aiflow-auth: http://IP:8888/SERVICE
重寫FeignBlockingLoadBalancerClient 的execute方法
package com.***.redirect;
import feign.Client;
import feign.Request;
import feign.RequestTemplate;
import feign.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
import org.springframework.context.annotation.Primary;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.*;
//@ConditionalOnBean
//@Primary
@Slf4j
public class LocalBlockingLoadBalancerClient extends FeignBlockingLoadBalancerClient {
private Client delegate;
private BlockingLoadBalancerClient loadBalancerClient;
@Autowired
private LocalFeignPerpreties localFeignPerpreties;
public LocalBlockingLoadBalancerClient(Client delegate,
BlockingLoadBalancerClient loadBalancerClient) {
super(delegate, loadBalancerClient);
this.delegate = delegate;
this.loadBalancerClient = loadBalancerClient;
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
try {
log.info("feign -> 配置化客戶端");
Boolean enable = localFeignPerpreties.getEnable();
if (enable) {
String url = request.url();
RequestTemplate requestTemplate = request.requestTemplate();
String name = requestTemplate.feignTarget().name();
Map<String, String> urlMap = localFeignPerpreties.getRule();
if (urlMap != null && urlMap.containsKey(name)) {
URI uri = URI.create(url);
StringBuffer strbuf = new StringBuffer();
strbuf.append(urlMap.get(name)).append(uri.getPath());
if (StringUtils.isNotBlank(uri.getQuery())) {
strbuf.append("?").append(uri.getQuery());
}
requestTemplate.target(urlMap.get(name));
Map<String, Collection<String>> headers = request.headers();
Map<String, Collection<String>> newheaders = new HashMap<>();
//處理請求頭
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest attributesRequest = attributes.getRequest();
Enumeration<String> headerNames = attributesRequest.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String element = headerNames.nextElement();
String elementVal = attributesRequest.getHeader(element);
newheaders.put(element, new ArrayList<String>() {{
add(elementVal);
}});
}
}
//構(gòu)建新的request
Request newRequest = buildRequest(request, strbuf.toString(), newheaders);
return super.getDelegate().execute(newRequest, options);
}
}
} catch (Exception e) {
e.printStackTrace();
}
log.info("feign -> 默認(rèn)客戶端");
return super.execute(request, options);
}
protected Request buildRequest(Request request,
String reconstructedUrl,
Map<String, Collection<String>> headers) {
return Request.create(request.httpMethod(), reconstructedUrl, headers,
request.body(), Charset.forName("UTF-8"), request.requestTemplate());
}
}
使配置類和重寫的client生效文章來源:http://www.zghlxwxcb.cn/news/detail-767313.html
package com.***.redirect;
import feign.Client;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//@ConditionalOnProperty(prefix = ReBalancerProperties.prefix,name = "enable",havingValue = "true")
@Configuration
@EnableConfigurationProperties(value = {LocalFeignPerpreties.class})
public class ReBalancerConfiguration {
@Bean
public Client feignReBalancer(BlockingLoadBalancerClient discoveryClient) {
return new LocalBlockingLoadBalancerClient(new Client.Default(null, null),
discoveryClient);
}
}
????????到這里基本上可以滿足重寫feign URL的需求了,這個前提條件是代碼在application啟動類的下一級,如果不在啟動類的同級或者下一級,是無法掃描到相關(guān)類的,這時我們可以注解完成掃描,需要在啟動類上加上相關(guān)注解文章來源地址http://www.zghlxwxcb.cn/news/detail-767313.html
package com.***.annotation;
import com.***.ReBalancerConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurationPackage;
import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import(ReBalancerConfiguration.class)
@AutoConfigurationPackage
public @interface EnableLocalFeignClient {
}
到了這里,關(guān)于feign自定義第三方接口;配置化Feign接口URL;調(diào)用指定IP的feign服務(wù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!