Feign动态定义调用serverName与path

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;
    }
}
posted @ 2024-02-19 15:42  陨落的星尘  阅读(471)  评论(0编辑  收藏  举报