在项目开发中,会有调用第三方接口的场景。当开发或日常测试时,对方的服务挂了,我们就一直等着服务恢复,那么这就相当影响效率了。如果我们在开发时,就定义一个mock服务,在发起调用时,不直接调到第三方接口,而是调到我们自己的mock服务,这样就可以避免这些问题了。
外部接口
假如我们依赖外部一个的Fegin接口如下:
@FeignClient(value = "sample-service-web", primary = false)
public interface SampleServiceFeignApi {
// 外部的接口
@GetMapping("/info/{mid}")
BaseResponse queryInfo(@PathVariable(value = "mid") Long mid);
}
mock实现
定义一个实现类实现外部接口
@Primary
@Component
@ConditionalOnProperty(name = "feign.mock.sample", havingValue = "true")
public class SampleServiceFeignApiMock implements SampleServiceFeignApi{
// 外部的接口的Mock实现
@Override
public BaseResponse queryInfo(Long mid) {
return BaseResponse.result("Mock");
}
}
配置说明
-
外部接口(SampleServiceFeignApi)@FeignClient的primary要设置成false,mock实现类(SampleServiceFeignApiMock)需要加上@Primary
解释:@FeignClient的primary默认为true,因为这个接口Fegin会代理实现类,这个类就是做为这个接口的实现类做依赖注入,我们自己又mock实现了一个,所以将我们自己的mock实现的要添加上@Primary,这样在满足@ConditionalOnProperty的条件情况下,优先依赖注入的是我们自己mock的类
-
mock实现类(SampleServiceFeignApiMock)需要加上@ConditionalOnProperty,并且配置加载参数的配置
-
配置文件加上配置参数feign.mock.sample=true(Mock时配置,加载Mock类),feign.mock.sample=false(生产配置,不加载Mock类)
配置了fallback的情况
常用的fallback配置方式
@FeignClient(value = "sample-service-web", fallback = SampleServiceFeignFallback.class, primary = false)
public interface SampleServiceFeignApi {
// 外部的接口
@GetMapping("/info/{mid}")
BaseResponse queryInfo(@PathVariable(value = "mid") Long mid);
}
@Component
public class SampleServiceFeignFallback implements SampleServiceFeignApi {
@Override
public BaseResponse queryInfo(Long mid) {
return BaseResponse.error("服务熔断");
}
}
注意SampleServiceFeignFallback需要加@Component,被Spring去管理。正因如此,就不能使用以上方式实现mock,因为SampleServiceFeignApi设置了primary = false,在启用mock的时候SampleServiceFeignApiMock做为Primary,在不启用mock的时候,SampleServiceFeignFallback实现了SampleServiceFeignApi接口,加上Fegin自动生成的一个,SampleServiceFeignApi就有两个实现类并且都被Spring管理并且都没有设置Primary。
fallbackFactory配置方式
1、去掉SampleServiceFeignFallback的@Component,不让被Spring管理
public class SampleServiceFeignFallback implements SampleServiceFeignApi {
@Override
public BaseResponse queryInfo(Long mid) {
return BaseResponse.error("服务熔断");
}
}
2、配置Fegin接口的fallbackFactory
@FeignClient(value = "sample-service-web", fallbackFactory = SampleServiceFeignFallbackFactory.class, primary = false)
public interface SampleServiceFeignApi {
// 外部的接口
@GetMapping("/info/{mid}")
BaseResponse queryInfo(@PathVariable(value = "mid") Long mid);
}
3、开发FallbackFactory,可以输出Feign的错误原因。
@Component
@Slf4j
public class SampleServiceFeignFallbackFactory implements FallbackFactory<SampleServiceFeignApi> {
/**
* fallback对象是否创建完毕
*/
private AtomicBoolean fallbackObjectCreated = new AtomicBoolean(false);
// 自己创建,不由Spring去管理SampleServiceFeignApi
private SampleServiceFeignApi sampleServiceFeignApi = new SampleServiceFeignFallback();
@Override
public SampleServiceFeignApi create(Throwable throwable) {
if (fallbackObjectCreated.get()) {
// 打印fallback的原因, 方便定位问题
log.warn(String.format("fallback due to: %s", throwable.getMessage()), throwable);
} else {
fallbackObjectCreated.compareAndSet(false, true);
}
return sampleServiceFeignApi;
}
}
4、Mock的实现
@Primary
@Component
@ConditionalOnProperty(name = "feign.mock.sample", havingValue = "true")
public class SampleServiceFeignApiMock implements SampleServiceFeignApi{
// 外部的接口的Mock实现
@Override
public BaseResponse queryInfo(Long mid) {
return BaseResponse.result("Mock");
}
}
配置说明:
配置文件加上配置参数feign.mock.sample=true(Mock时配置,加载Mock类),feign.mock.sample=false(生产配置,不加载Mock类)
网友评论