Feign动态定义调用serverName与path
方案一(DynamicProcessFeign)
1. 定义FeignClient工厂
@Component
public class DynamicProcessFeign<T> {
/**
* 缓存feignClient,提高客户端性能
*/
private static Map<String, Object> processMap = new HashMap<>();
private final FeignClientBuilder feignClientBuilder;
public DynamicProcessFeign(@Autowired ApplicationContext appContext) {
this.feignClientBuilder = new FeignClientBuilder(appContext);
}
public T getFeignClient(final Class<T> type, String serviceName, String path) {
String key = serviceName + path;
Object api = processMap.get(key);
if (api != null) {
return (T) api;
}
synchronized (DynamicProcessFeign.class) {
api = processMap.get(key);
if (api != null) {
return (T) api;
}
api = this.feignClientBuilder.forType(type, serviceName).path(path).build();
processMap.put(key, api);
}
return (T) api;
}
}
2. 定义测试接口
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
@PostMapping(value = "/test")
public AjaxResult test(@RequestBody JSONObject object) {
return AjaxResult.success(object);
}
}
3. 提供业务feignClient,并定义服务声明接口
@FeignClient(name = "TestClient", contextId = "TestClient")
public interface TestClient {
@PostMapping(value = "")
AjaxResult test01(@RequestBody JSONObject object);
}
4. 动态调用
@Slf4j
@RestController
@RequestMapping("/test")
public class TestFeignController {
@Autowired
private DynamicProcessFeign dynamicProcessFeign;
@PostMapping(value = "/test01")
public AjaxResult test01(@RequestBody JSONObject object) {
//微服务名称:shine-test-feign,请求路径/test/test
TestClient testClient = dynamicProcessFeign.getFeignClient(TestClient.class, "shine-test-feign", "/test/test");
AjaxResult result = testClient.test(object);
log.info("result:{}", result);
return result;
}
}
方案二(FeignInterceptorConfig)
1. 对feignClient中API的URL中定义一个特殊的变量标记
@FeignClient(name = "TestClient", contextId = "TestClient")
public interface TestClient {
@GetMapping("//$SERVER-NAME//test/test")
public String test();
}
2. 定义FeignInterceptorConfig
@Data
@Configuration
@ConfigurationProperties(prefix = "feign-interceptor-config")
public class FeignInterceptorConfig {
private Map<String, String> serverMap = new HashMap<>();
@Bean
public RequestInterceptor cloudContextInterceptor() {
return template -> {
replaceKey(template);
replaceSlash(template);
};
}
private void replaceKey(RequestTemplate template) {
String url = template.url();
for (Map.Entry<String, String> entry : serverMap.entrySet()) {
String key = entry.getKey();
if (url.contains(key)) {
url = url.replace(key, entry.getValue());
template.uri(url);
}
}
}
private void replaceSlash(RequestTemplate template) {
String url = template.url();
if (url.startsWith("//")) {
url = "http:" + url;
//去除地址后面的参数,防止下面重新设置target的时候出现参数重复
int index = url.indexOf("?");
if (index > 0) {
url = url.substring(0, index);
}
template.target(url);
template.uri("");
}
}
}
3. 配置文件配置动态映射替换
feign-interceptor-config:
server-map:
"[$SERVER-NAME]" : shine-test-feign
4. 动态调用
@Slf4j
@RestController
@RequestMapping("/test")
public class TestFeignController {
@PostMapping(value = "/test02")
public AjaxResult test02(@RequestBody JSONObject object) {
AjaxResult result = testClient.test02(object);
log.info("result:{}", result);
return result;
}
}
方案三(@PathVariable)
1. 在对feignClient中API定义
@FeignClient(name = "TestClient", contextId = "TestClient")
public interface TestClient {
@PostMapping(value = "//{serviceName}/{contextPath}")
AjaxResult test(@PathVariable(name = "serviceName") String serviceName, @PathVariable(name = "contextPath") String contextPath, @RequestBody JSONObject object);
}
2. 定义FeignInterceptorConfig
同方案二
3.动态调用
@Slf4j
@RestController
@RequestMapping("/test")
public class TestFeignController {
@PostMapping(value = "/test03")
public AjaxResult test03(@RequestBody JSONObject object) {
AjaxResult result = testClient.test03("shine-test-feign", "/test/test", object);
log.info("result:{}", result);
return result;
}
}