OpenFeign中动态URl、动态传递接口地址

文章介绍了在微服务架构中使用Feign进行接口开发时,如何动态获取第三方服务的URL和接口。通过三种方式展示了实现动态配置的策略,包括直接在FeignClient注解中设置URL、从配置文件读取以及在调用时动态传入URL。同时,文章提到了服务降级的实现,即在服务调用失败时的fallback方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:
在微服务盛行的今天,做接口开发请求第三方服务的接口,大概率会用feign做请求,而feign也是最常用的一种rpc框架;

这里主要是说明在进行feign请求的时候,第三方服务的url和接口如何动态获取。
若是该接口是作为基础服务可能会请求多个第三方使用(我们就是不同分支的代码作为独立项目部署,请求不同的客户接口),不同客户的接口地址可能不同,此时就需要做成动态方式;
若是不常改动,其实也没必要动态了;

常用方式

通常我们是这么请求第三方接口的:(用feign方式)

import com.zkaw.lxjtest.Dto.User;
import com.zkaw.lxjtest.remoteCall.feign.factory.RemoteFeignFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.List;

/**
 * @Author: Best_Liu
 * @Description:
 * @Date Create in 11:14 2022/7/1
 * @Modified By:
 */
@FeignClient(value = "mybatisPlus", url = "http://127.0.0.1:8090", fallbackFactory = RemoteFeignFactory.class)
public interface RemoteFeignClient {

    @PostMapping("/user/selectListNoPage")
    /*@Headers({"content-type:application/json"})*/
    List<User> test(@RequestBody User user);

}

说明:
请求客户的url是:http://127.0.0.1:8090,
调用客户的具体的目标方法是:/user/selectListNoPage 这个方法

第二种方式:配置文件传参

import com.zkaw.lxjtest.Dto.User;
import com.zkaw.lxjtest.remoteCall.feign.factory.RemoteFeignFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.List;

/**
 * @Author: Best_Liu
 * @Description:
 * @Date Create in 11:14 2022/7/1
 * @Modified By:
 */
@FeignClient(value = "mybatisPlus", url = "${feign.client.url.TestUrl}", fallbackFactory = RemoteFeignFactory.class)
public interface RemoteFeignClient {

    @PostMapping("/user/selectListNoPage")
    /*@Headers({"content-type:application/json"})*/
    List<User> test(@RequestBody User user);

}

然后添加配置文件,比如

在你的 application-dev.yml 文件中

feign:
  client:
    url:
      TestUrl: http://127.0.0.1:8088

第三种方式:调用feign时动态传入

实现了url和目标方法的动态传入

1、目标方法的动态传入

利用@PathVariable注解的特性;

用于接收请求路径中占位符的值

@PathVariable(“xxx”)
通过 @PathVariable 可以将URL中占位符参数{xxx}绑定到处理器类的方法形参中
如:
@RequestMapping(value=”user/{id}/{name}”)
请求路径:http://localhost:8080/hello/show/1/lisi

2、url动态实现

在创建feignclient时设置url地址

所以改造下我们的方法:

import com.zkaw.lxjtest.Dto.User;
import com.zkaw.lxjtest.remoteCall.feign.factory.RemoteFeignFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.List;

/**
 * @Author: Best_Liu
 * @Description:
 * @Date Create in 11:14 2022/7/1
 * @Modified By:
 */
@FeignClient(value = "mybatisPlus", fallbackFactory = RemoteFeignFactory.class)
public interface RemoteFeignClient {

    @PostMapping("{apiName}")
    /*@Headers({"content-type:application/json"})*/
    List<User> test(@PathVariable("apiName") String apiName, @RequestBody User user);

}

feign接口调用方式,createFeignClient是Feign核心部分

import com.zkaw.lxjtest.Dto.User;
import com.zkaw.lxjtest.remoteCall.feign.service.RemoteFeignClient;
import feign.Feign;
import feign.form.spring.SpringFormEncoder;
import feign.optionals.OptionalDecoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.cloud.openfeign.support.SpringMvcContract;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @Author: Best_Liu
 * @Description:
 * @Date Create in 11:20 2022/7/1
 * @Modified By:
 */
@RestController
@RequestMapping("/feign")
public class feignController {

    @Autowired
    ObjectFactory<HttpMessageConverters> messageConverters;

    private RemoteFeignClient createFeignClient(String url) {
        /*1、在创建Feign客户端的时候最核心的对象是decoder、encoder、contract
        通过跟踪源码与SpringBoot自动创建的Feign对象比较,设置decoder、encoder、
        contract为SpringBoot中自动创建对象相同,然后定义Feign接口的时候,
        各种参数的注解和方法的注解就可以和不动态修改url的相同了
        decoder解码器,对返回的结果进行解码*/
        OptionalDecoder decoder = new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(messageConverters)));
        //encoder编码器,对输入的数据进行编码
        SpringEncoder springEncoder = new SpringEncoder(messageConverters);
        SpringFormEncoder encoder = new SpringFormEncoder(springEncoder);
        //该对象是将接口进行解析,方便生成最后调用的网络对象HttpurlConnection
        SpringMvcContract contract = new SpringMvcContract();
        RemoteFeignClient feignClient = Feign.builder()
                .decoder(decoder)
                .encoder(encoder)
                .contract(contract)
                //这个地方的Url可以根据每次调用的时候进行改变
                .target(RemoteFeignClient.class, url);
        return feignClient;
    }

    @PostMapping("/selectListNoPage")
    public List<User> selectListNoPage(@RequestBody User user){
        String apiName = "user/selectListNoPage";
        String url = "http://127.0.0.1:8090";
        RemoteFeignClient remoteFeignClient = createFeignClient(url);
        List<User> users = remoteFeignClient.test(apiName,user);
        return users;
    }

}

结果示例

 fallback方式服务降级

import com.zkaw.lxjtest.Dto.User;
import com.zkaw.lxjtest.remoteCall.feign.service.RemoteFeignClient;
import feign.hystrix.FallbackFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: Best_Liu
 * @Description: 服务降级
 * @Date Create in 11:34 2022/7/1
 * @Modified By:
 */
@Component
public class RemoteFeignFactory implements FallbackFactory<RemoteFeignClient> {
    private static final Logger log = LoggerFactory.getLogger(RemoteFeignFactory.class);
    @Override
    public RemoteFeignClient create(Throwable throwable) {
        log.error("服务调用失败:{}", throwable.getMessage());
        return new RemoteFeignClient() {
            @Override
            public List<User> test(@PathVariable("apiName") String apiName, User user) {
                return new ArrayList<>();
            }
        };
    }
}

目前我想到的是这种方式,既可以把url动态配置,请求路径也可实现动态,
如果有其它方式还请留言多交流;

### OpenFeign动态远程调用实现方式 OpenFeign 是一种声明式的 HTTP 客户端工具,它允许开发者像调用本地方法一样调用远程服务[^1]。然而,默认情况下,OpenFeign接口定义是静态的,在开发阶段就已经固定下来。如果需要支持 **动态远程调用**,可以通过一些扩展机制来实现。 以下是通过 OpenFeign 实现动态远程调用的一种常见方案: #### 1. 使用 Feign.Builder 手动构建 Feign 客户端 `Feign.Builder` 提供了一种灵活的方式来创建动态Feign 客户端实例。这种方式不需要提前定义固定的接口,而是可以在运行时指定目标 URL 和请求参数。 ```java import feign.Feign; import feign.RequestLine; public class DynamicFeignExample { public static void main(String[] args) { String targetUrl = "http://example.com/api"; // 动态设置的目标URL MyDynamicInterface dynamicClient = Feign.builder() .target(MyDynamicInterface.class, targetUrl); // 调用远程方法 String response = dynamicClient.getSomeData(); System.out.println(response); } interface MyDynamicInterface { @RequestLine("GET /data") String getSomeData(); // 动态调用的方法 } } ``` 上述代码展示了如何使用 `Feign.Builder` 创建一个动态Feign 客户端,并将其指向不同的目标地址[^4]。 --- #### 2. 结合 Spring Cloud 自定义配置 Spring Cloud 中集成了 OpenFeign 支持,因此也可以利用其灵活性来自定义动态调用逻辑。具体来说,可以基于以下步骤完成: ##### (1) 配置动态目标地址 在实际应用中,可能需要根据业务需求动态调整目标服务地址。这可以通过自定义 Bean 来实现。 ```java import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; @FeignClient(name = "dynamic-client", url = "${dynamic.url}") // 动态url可以从配置文件或者环境变量读取 public interface DynamicFeignClient { @GetMapping("/api/data") String getData(); } ``` 在此示例中,`${dynamic.url}` 可以从配置文件或程序启动时传入的参数中获取,从而实现动态切换目标地址的功能[^5]。 --- ##### (2) 运行时修改目标地址 除了通过配置文件设定外,还可以在运行期间动态更改目标地址。例如,借助于 `Targeter` 或者手动替换 `LoadBalancerClient` 的行为。 ```java import org.springframework.beans.factory.ObjectFactory; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.support.SpringEncoder; import org.springframework.context.ApplicationContext; import feign.Contract; import feign.Feign; import feign.codec.Decoder; import feign.codec.Encoder; public class CustomFeignBuilder { public Object createDynamicClient(Class<?> type, String url) { Encoder encoder = new SpringEncoder(new HttpMessageConverters()); Decoder decoder = new ResponseEntityDecoder(new SpringDecoder((ObjectFactory<HttpMessageConverters>) () -> null)); return Feign.builder() .encoder(encoder) .decoder(decoder) .contract(new Contract.Default()) .target(type, url); // 动态传递目标URL } } ``` 此代码片段展示了一个通用的工厂类,用于按需生成针对不同 URLFeign 客户端实例[^3]。 --- #### 3. 利用反射技术增强动态能力 对于更加复杂的场景,比如完全未知的服务名和方法签名,可以考虑结合 Java 反射以及动态代理技术。不过需要注意的是,这种方法会增加一定的复杂度并可能导致性能下降。 --- ### 总结 以上介绍了几种常见的 OpenFeign 动态远程调用实现方式,包括但不限于使用 `Feign.Builder` 构建动态客户端、结合 Spring Cloud 自定义配置以及引入反射技术等手段[^2]。每种方法都有各自的适用范围和优缺点,应根据具体的业务需求选择合适的解决方案。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值