千家信息网

如何解决自定义feignClient的常见坑

发表于:2025-02-01 作者:千家信息网编辑
千家信息网最后更新 2025年02月01日,这篇文章主要讲解了"如何解决自定义feignClient的常见坑",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何解决自定义feignClient的常
千家信息网最后更新 2025年02月01日如何解决自定义feignClient的常见坑

这篇文章主要讲解了"如何解决自定义feignClient的常见坑",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何解决自定义feignClient的常见坑"吧!

目录
  • 自定义feignClient的常见坑

    • 一、从eureka上拉取相关服务的配置信息

    • 二、feignClient 发送请求到目标服务器

    • 三、一些坑

    • 四 、以下是现有全部的代码粘贴出来看一下

  • feignClient的使用

    • 服务提供端代码

    • 服务调用端

自定义feignClient的常见坑

自定义feignClient 踩过的坑,因为spring cloud 需要spring 4 以上的版本,所以对于低版本工程想要使用feign就需要自定义,在定义过程中遇到了很多问题,整理总结一下。(有需要的结合github请慢慢看,真的是手写的,但是有些东西不能全部粘贴出来抱歉了,全部的代码放在 第四点里面)

整体的过程分为两个部分:

  • 一、从eureka上拉取服务地址,

  • 二、feignClient 发送请求到目标服务器(其实feignClient 最终是使用httpClient 发送一个rest的请求,这就是官网给出httpclient和feign-okhttp的原因,这里使用okthhp 因为需要支持path请求)。

一、从eureka上拉取相关服务的配置信息

这里使用的是加载eureka的默认配置,初始化时使用单例。代码如下

1,2的目的是加载项目中的配置,常量定义如下

private static final String CLIENT_CONFIG_FILE_NAME = "eureka";private static final String CLIENT_RIBBON_CONFIG_FILE_NAME = "ribbon";

resource下定义两个文件:eureka.properties和ribbon.properties (名称可以需要改动),内容是声明服务必要的配置,具体配置如下:

ribbon.properties

aa.ribbon.DeploymentContextBasedVipAddresses=aa //aa 为feign中使用的服务名称aa.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList //服务调用策略,轮询等aa.ribbon.ServerListRefreshInterval=60000 //客户端请求eureka 刷新aa 服务节点列表时间ribbon.ConnectTimeout=50000000 //服务的超时时间ribbon.ReadTimeout=50000000eureka.propertieseureka.registration.enabled=false //服务是否注册到eureka上eureka.serviceUrl.default=http://discovery.ingageapp.com:9401/eureka //eureka地址#eureka.preferSameZone=true(其余可以百度下cans参数太多不一一列举#eureka.shouldUseDns=false

具体代码如下,看下代码的具体解释:

1,2两步分别shi是加载ribbon和eureka配置,

3 通过DiscoveryManager加载配置信息。

private XsyServiceLocator() {    try {        ConfigurationManager.loadCascadedPropertiesFromResources(CLIENT_RIBBON_CONFIG_FILE_NAME); //1        ConfigurationManager.loadCascadedPropertiesFromResources(CLIENT_CONFIG_FILE_NAME);   //2    } catch (IOException e) {        throw new IllegalStateException("Xsy client config load error! Please check your client.properties");    }    DiscoveryManager.getInstance().initComponent(new MyDataCenterInstanceConfig(), new DefaultEurekaClientConfig()); //3}

二、feignClient 发送请求到目标服务器

1,2两步是自定义了一个@FeignClient 注解,通过传经来的class拿去请求的服务名称即serviceId(如果你不会这个我也没办法了,略有尴尬)

3 Feign.builder() .client(new RibbonClient(new OkhttpClient())) (其实feign的负载均衡,发送请求都是通过ribbon完成的)

这里是初始化ribbonClient,最后的restclient 用的是okhttpclient。

4,5是用来编码和解码 (不要用goson的那个有坑)

6 是用来记录log的 关于log这个 ,feign默认打印的是debug级别的这个是因为他在代码里面写死的可以重写feign的Slf4jLogger类修改。

7 是设置log级别(具体哪些级别打印什么东西,自己搜下吧)

8 FeignInterceptor 是将一些请求header向下传递的(实现RequestInterceptor 接口重写即可)

9 拼接参数发送信息 拼接完 请求是 "http://aa(服务名称)/info (最后会根据eureka上的服务名称拼接成对应的ip+端口号,他自己底层实现的)

public  T lookup(Class clazz) {    FeignClient feignClient = clazz.getAnnotation(FeignClient.class);// 1    String serviceId = feignClient.value();//2    T service = Feign.builder()            .client(new RibbonClient(new OkhttpClient()))//3            .encoder(new JacksonEncoder)//4            .decoder(new JacksonDecoder)//5            .logger(logger)//6            .logLevel(Logger.Level.HEADERS)//7            .requestInterceptor(new FeignInterceptor())//8            .target(clazz, "http://" + serviceId);//9    return service;}

三、一些坑

1.源码的坑,实现过程中发现ribbon的配置并未生效,是因为feign-core源码问题,他总是会new一个 config 然后传进去,所以你得配置是无效的,这里重写(整个ribbonClient包copy下来改掉然后引用自己的)

2 这个类好像也是有问题的(忘记了)

四 、以下是现有全部的代码粘贴出来看一下

public class XsyServiceLocator {    private static final String CLIENT_CONFIG_FILE_NAME = "eureka";    private static final Object synRoot = new Object();    private static final String CLIENT_CONFIG_CUSTOM_FILED_NAME = "eureka.name";    private static final String CLIENT_RIBBON_CONFIG_FILE_NAME = "ribbon";    private static final JacksonEncoder jacksonEncoder = new JacksonEncoder();    private static final JacksonDecoder jacksonDecoder = new JacksonDecoder();    private static final RibbonClient ribbonClient = new RibbonClient(new OkHttpClient());    private static String ipAddress = null;    private static boolean isLoadEureka = true;//为true表示需要加载默认eureka 配置文件如 crm,false则加载自定义eureka配置文件如paas-aggregator-service    private static XsyFeignLogger logger = null;    private XsyServiceLocator() {        try {            ConfigurationManager.loadCascadedPropertiesFromResources(CLIENT_RIBBON_CONFIG_FILE_NAME);            ConfigurationManager.loadCascadedPropertiesFromResources(CLIENT_CONFIG_FILE_NAME);            Object eurekaName = ConfigurationManager.getConfigInstance().getProperty(CLIENT_CONFIG_CUSTOM_FILED_NAME);            if (eurekaName != null) {                isLoadEureka = false;            }        } catch (IOException e) {            throw new IllegalStateException("Xsy client config load error! Please check your client.properties");        }        while (isLoadEureka && ipAddress == null) {            DiscoveryManager.getInstance().initComponent(new MyDataCenterInstanceConfig(), new DefaultEurekaClientConfig());            ipAddress = DiscoveryManager.getInstance().getEurekaInstanceConfig().getIpAddress();        }    }
public  T lookup(Class clazz) {        if (isLoadEureka && ipAddress == null) {            DiscoveryManager.getInstance().initComponent(new MyDataCenterInstanceConfig(), new DefaultEurekaClientConfig());            ipAddress = DiscoveryManager.getInstance().getEurekaInstanceConfig().getIpAddress();        }        FeignClient feignClient = clazz.getAnnotation(FeignClient.class);        String serviceId = feignClient.value();        if(logger == null){            synchronized (synRoot){                if(logger == null){                    logger = new XsyFeignLogger(clazz);                }            }        }        T service = Feign.builder()                .client(ribbonClient)                .encoder(jacksonEncoder)                .decoder(jacksonDecoder)                .logger(logger)                .logLevel(Logger.Level.HEADERS)                .requestInterceptor(new FeignInterceptor())                .target(clazz, "http://" + serviceId);        return service;    }

feignClient的使用

服务提供端代码

@FeignClient(contextId = "remoteUserService", value = ServiceNameConstants.UPMS_SERVICE)public interface RemoteUserService { /**  * 通过用户名查询用户、角色信息  *  * @param username 用户名  * @param from     调用标志  * @return R  */ @GetMapping("/user/info/{username}") R info(@PathVariable("username") String username   , @RequestHeader(SecurityConstants.FROM) String from);}@GetMapping("/user/info/{username}") 是服务Controller包中的(@Inner注解代表内部方法,不用权限直接调用,不会被网管拦截) /**  * 获取指定用户全部信息  *  * @return 用户信息  */ @Inner @GetMapping("/info/{username}") public R info(@PathVariable String username) {  SysUser user = userService.getOne(Wrappers.query()    .lambda().eq(SysUser::getUsername, username));  if (user == null) {   return R.failed(null, String.format("用户信息为空 %s", username));  }  return R.ok(userService.findUserInfo(user)); }

服务调用端

(SecurityConstants.FROM_IN是系统内部服务调用的一个标识 值为IN)

@Slf4j@AllArgsConstructorpublic class HzUserDetailsServiceImpl implements HzUserDetailsService { private final RemoteUserService remoteUserService; private final CacheManager cacheManager;  /**  * 用户密码登录  *  * @param username 用户名  * @return  * @throws UsernameNotFoundException  */ @Override @SneakyThrows public UserDetails loadUserByUsername(String username) {  Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS);  if (cache != null && cache.get(username) != null) {   return (HzUser) cache.get(username).get();  }   R result = remoteUserService.info(username, SecurityConstants.FROM_IN);  UserDetails userDetails = getUserDetails(result);  cache.put(username, userDetails);  return userDetails; } }

感谢各位的阅读,以上就是"如何解决自定义feignClient的常见坑"的内容了,经过本文的学习后,相信大家对如何解决自定义feignClient的常见坑这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

服务 配置 代码 信息 用户 常见 名称 问题 内容 文件 服务器 用户名 目标 级别 过程 学习 东西 两个 参数 地址 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 sche注解在服务器上班错 广州越川网络技术有限公司 计算机网络安全基础知识 网络安全与数据安全法律法规 医疗数据库发展 网络安全系统恢复流程规定 油库设计软件开发 海尔工业互联网青岛科技大学 创新网络技术报价 家庭需要的网络安全服务 电网技术中心 网络安全项目 软件开发培训班真实收入 五大常用数据库的应用领域 互联网科技公司的部门 美国网络安全保险起源 松江区数据软件开发质量保障 石家庄软件开发培训吧 去泰国做软件开发危险么 我的世界服务器建筑插件 局域网的网络技术 共青团 网络安全宣传片 jsp访问数据库运行空白 数据库表存储过程的创建和执行 失控玩家最后破坏服务器 关于网络安全的博客英语作文句子 关于宣传网络安全的广告词 oracle数据库招聘 有名的网络安全质量服务 西宁网络技术哪家好 江西备案服务器云空间
0