其他分享
首页 > 其他分享> > 记一次SpringCloud微服务项目中Feign客户端创建失败问题排查

记一次SpringCloud微服务项目中Feign客户端创建失败问题排查

作者:互联网

起因:

在工作中进行微服务开发过程中,为将接口及实现分离(便于提供API模块给其他微服务模块调用),将Feign客户端接口定义与Feign客户端实现分别写在API模块与服务模块中,由于以个人习惯定义包名,导致服务模块中创建Feign客户端失败,使用该客户端调用服务时,总会跳转到fallback定义(即服务降级)中。因为一开始没问题,修改了API模块及服务模块的包名之后,才出现问题,所以以这方面为思路去查找问题。

以下是代码复现(简约版) (注:本文后续代码仅展示关键部分)

feign客户端接口定义 -- 用户服务API模块
package com.personal.service.api.user.feign;

@FeignClient(
    value = "user-service",
    fallback = IUserClientFallback.class  # 启动后调用服务发现都往该实现类跳转了
)
public interface IUserClient {
}
feign客户端实现 -- 用户服务模块
package com.personal.service.user.feign;

@RestController
public class UserClient implements IUserClient {
}

 Application类定义 -- 用户服务模块

package com.personal.service.user

@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class UserApplication {
}

过程:

通过debug排查后,发现是Feign客户端创建失败。故而调用服务时,都会执行服务降级实现。

然后在同事的提醒下,参考之前的项目,将UserApplication类移到了包com.personal.service下之后,Feign客户端创建成功。

虽然问题解决,但是我不太明白问题的根本原因是什么,所以进行了一番探究学习。

发现与Application类的路径有关后,在Spring boot的官方文档中查找Spring boot关于Application类的规定及推荐。发现了这一句:

 意思是:@SpringBootApplication注解通常会被我们放在主类中,它隐含为项目定义了基本的搜索包。即,Spring boot项目通常会以这个注解所在的类的包路径为根去扫描bean定义(如果我们没有另外指定时)。

代码中,我的@SpringBootApplication注解在UserApplication中。

然后,通过对@EnableFeignClients的实现进行debug代码追踪:

该注解通过@Import注解引入了FeignClientsRegistrar类,并在其中完成Feign客户端bean的注册工作。

@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
}

进入到FeignClientsRegistrar类,其实现了ImportBeanDefinitionRegistrar接口,用于额外注册bean。找到注册bean定义的方法:

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        registerDefaultConfiguration(metadata, registry);
        registerFeignClients(metadata, registry);
}

找到注册Feign客户端的方法: registerFeignClients(metadata, registry);

 进入到 getBasePackages(metadata) 方法

所以会获取到UserApplication的包路径:com.personal.service.user,以该路径去扫描@FeignClient注解定义的Fegin客户端接口类。

但是我项目中的接口类路径为:com.personal.service.api.user.feign (文章一开始的代码复现中),故而找不到定义。Feign创建失败。至此,问题的根本原因找到。

结论:

使用Spring boot开发项目时,虽然提供给了我们很多便利,担其便捷的背后,也有着许多隐含的配置要求,所以我们要注意@SpringBootApplication注解定义的类的路径,在进行spring组件,即@Component、@Service等注解的bean时,如果我们未显式指定扫描包路径时,要注意定义的bean的包路径与Application类的包路径是否匹配。

标签:Feign,定义,service,SpringCloud,模块,注解,客户端
来源: https://www.cnblogs.com/chenwzdeboke/p/16449046.html