习琴 發表於 2026-1-9 16:43:17

Java skill动态指定feign的访问地址方式

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>场景</li><li>编码</li><ul class="second_class_ul"><li>新增feign传参类</li><li>新增调用内部服务的feign接口</li><li>feign配置类逻辑修改</li></ul><li>大坑</li><ul class="second_class_ul"></ul><li>总结</li><ul class="second_class_ul"></ul></ul></div><p class="maodian"></p><h2>场景</h2>
<p>在有下沉节点项目的前提下,使用feign调用内部服务的时候,在redis查询需要调用的内部服务的elb地址并调用</p>
<p class="maodian"></p><h2>编码</h2>
<p class="maodian"></p><h3>新增feign传参类</h3>
<div class="jb51code"><pre class="brush:java;">@Data
public class TestDto {
    private String id;
}
</pre></div>
<p class="maodian"></p><h3>新增调用内部服务的feign接口</h3>
<div class="jb51code"><pre class="brush:java;">@FeignClient(name = "test", url = "http://localhost:1234", configuration = FeignConfig.class)
public interface TestClient {
    @PostMapping(value = "/v1/test/get_name")
    Object getNameById(@RequestParam("id") String id, @RequestBody TestDto body);
}
</pre></div>
<p class="maodian"></p><h3>feign配置类逻辑修改</h3>
<div class="jb51code"><pre class="brush:java;">@Configuration
public class FeignConfig {

    @Bean
    public RequestInterceptor headerInterceptor() {
      return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate requestTemplate) {
                    // 只有请求url的前缀是【/v1/test/】才需要指定地址
                if(requestTemplate.url().startsWith("/v1/test/")){
                        // 初始化地址信息
                        String url = "";
                        // 获取@RequestBody 中的参数
                  Object parse = JSONObject.parse(new String(requestTemplate.body()));
                  Map&lt;String,String&gt; info = (Map&lt;String, String&gt;) parse;
                  String id= info.get("id");
                  if(StringUtils.isBlank(id)){
                        // 如果body中没有id,去@RequestParam 查询
                        Map&lt;String, Collection&lt;String&gt;&gt; queries = requestTemplate.queries();
                        //================ 业务逻辑 begin
                                             .
                                             .
                                             .
                                             .
                        //================ 业务逻辑 end
                        // 拿到要访问的地址之后,配置RequestTemplate.target,这样就可以实现feign指定地址调用了
                        requestTemplate.target(url);
                  }
                }

            }
      };
    }
}
</pre></div>
<p class="maodian"></p><h2>大坑</h2>
<p>1、如果feign接口中@FeignClient注解的name值是nacos注册的服务名,那要实现动态指定访问地址的话,分以下两种情况:</p>
<ul><li>指定的地址在nacos的服务名中不存在,url参数一定要赋初始值,否则,就会发现requestTemplate.target 就失效了,实质是在<code>debug日志级别</code>会打印负载均衡失败的日志。</li><li>指定的地址在nacos的服务名中存在,url参数没有硬性要求。</li><li>还是建议大家,动态指定feign的访问地址,<code>url参数最好赋一个初始值</code></li></ul>
<p>2、<code>requestTemplate.target(url)</code>中的参数url内容一定是完整的地址<code>(如:http://127.0.0.1:8080)</code></p>
<p>3、不要在这个apply()方法中使用<code>ThreadLocal</code>这种获取当前线程中的相关信息的类,因为feign是线程池管理的,主线程进入到feign之后,就进入到了一个子线程,在feign中的所有操作都是在一个子线程中的操作,所以使用ThreadLocal这种类时会出问题。</p>
<p>如果必须要在feign中获取到此次请求中的一个全局参数的话,可以考虑一下使用<code>MDC</code>(log4j和logback等日志框架提供的一种机制),ThreadLocal是面向单个线程的,MDC是面向单个请求的(跨线程),使用MDC就不用考虑多个线程的问题了,但一定要注意&nbsp;<strong>请求结束之后要清除</strong>。</p>
<p class="maodian"></p><h2>总结</h2>
<p>以上为个人经验,希望能给大家一个参考,也希望大家多多支持琼殿技术社区。</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>Java中 springcloud.openfeign应用案例解析</li><li>Java微服务之Feign远程调用方式</li><li>解决Spring调用Feign报错:java.io.IOException:Incomplete&nbsp;output&nbsp;stream问题</li><li>Java中的Feign深入分析</li><li>java解决Feign异步情况丢失上下文问题</li><li>java异步调用Feign接口空指针问题解决</li><li>Java微服务间接口调用&nbsp;feign</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: Java skill动态指定feign的访问地址方式