背景
Springboot项目集成Feign,Ribbon(由于项目部署在K8S集群中,所以未使用Eureka),因此FeignClient使用url来调用其他服务,配置如下:
@FeignClient(name = "user", url = "${user.url}", configuration = {FeignExceptionDecoder.class})
此时url是的值是占位符,读取的配置文件,项目运行没有问题
问题
1. 执行单元测试时,BaseTest报错
无法初始化feignClient,因为占位符
http://${user.url}
替换不了
第一反应是配置文件读取失败,要不然占位符已经被成功替换了,而不是拼上http://
,于是去检查配置,配置没有问题
很奇怪,于是去看EnableFeignClients
注解,点到FeignClientsRegistrar.Class
,搜索url发现了getUrl()
方法(如下),看到里面用的是#{}
而不是${}
去判断,于是突发奇想,把所有的FeignClient里的url都使用#{}
,执行单元测试,不报这个错了
static String getUrl(String url) {
if (StringUtils.hasText(url) && (!url.startsWith("#{") || !url.contains("}"))) {
if (!url.contains("://")) {
url = "http://" + url;
}
try {
new URL(url);
} catch (MalformedURLException var2) {
throw new IllegalArgumentException(url + " is malformed", var2);
}
}
return url;
}
2. 继续执行单元测试,抛出异常NoSuchBeanDefinitionException
如果在此时运行项目,会发现FeignClient的bean都无法注入了,但是当时博主已被自己的机智迷昏了头脑,没发现这个问题
这时候,网上各种搜索这个报错,发现看下来有以下几个解决方法:
- BaseTest启动类加上注解
@EnableFeignClients
但是博主已经加了的,所以这个对博主无用
- BaseTest启动类加上注解
@ImportAutoConfiguration({RibbonAutoConfiguration.class, FeignRibbonClientAutoConfiguration.class, FeignAutoConfiguration.class})
加上试了无用,还是一样的报错
- BaseTest启动类加上注解
@EnableFeignClients(basePackages = "com.xxx")
刚试完加上单元测试还是报错,突然发现项目跑不起来了,而且代码是push过的(因为让另一个同事帮忙一起看下),此时博主开始慌了,赶紧把FeignClient里url的占位符#再改回$,项目跑起来了,谢天谢地。
这时候博主突然奇想,会不会是因为配置的basePackages范围太大了(博主的项目是多模块分层的,所有的FeignClient都放在Service模块的第x层包下,而此时就只配到第2层而已),所以修改basePackages,配置到FeignClient所在的包目录
惊奇的发现!单元测试跑起来了!依赖注入也都有值
总结
其实最开始的占位符http://${user.url}
替换不了,以及后面的NoSuchBeanDefinitionException
,都应该想到,是因为springboot扫包没扫到引起的,贴上博主可行的配置
@RunWith(SpringRunner.class)
@SpringBootTest
@EnableFeignClients(basePackages = "com.xxxx.xxxx.xxxx.xxxx")
public class BaseTest extends AbstractTransactionalTestNGSpringContextTests {
}
收工!