FallbackFactory使用
概述
在FeignClient中,可以通过制定fallback,实现在服务不可用时自动调用fallback指定定的处理方法。
启动类
@EnableDiscoveryClient
@EnableFeignClients
@EnableFeignInterceptor
@SpringBootApplication
public class FileCenterApp {
public static void main(String[] args) {
SpringApplication.run(FileCenterApp.class, args);
}
}
接口类,绑定FallbackFactory类
@FeignClient(name = "file-center", fallbackFactory = FileServiceFallbackFactory.class, decode404 = true)
public interface FileService {
@GetMapping(value = "/files", params = "ids")
List<FileInfo> findFiles(@RequestParam("ids") List<String> ids);
}
只需要加入decode404 = true这一个参数,Feign对于2XX和404 ,都不会走Fallback。
排除404,已经基本上够用,如果想把409、400等status也加到例外中,可以重写一下Feign的errorDecoder。
@Slf4j
public class FileServiceFallbackFactory implements FallbackFactory<FileService> {
@Override
public FileService create(Throwable throwable) {
return new FileService() {
@Override
public List<FileInfo> findFiles(List<String> ids) {
log.error("获取文件信息异常:{}", ids, throwable);
return new ArrayList<>();
}
};
}
}
对应的contractor代码:
// 服务降级:若当前处理器方法发生异常,则执行fallbackMethod属性指定的方法
@HystrixCommand(fallbackMethod = "findFilesDefault")
@GetMapping("/files")
public List<FileInfo> findFiles(@RequestParam List<String> ids) {
return fileService.findList(ids);
}
/**
* 记得@PathVariable一定要设置括号里面的value,否则报错PathVariable annotation was empty on param 0.
*/
@GetMapping("/download/{fileName}")
String downloadFile(@PathVariable("fileName") String fileName);
public List<FileInfo> findFilesDefault(@RequestParam List<String> ids) {
return fileService.findList(ids);
}
上面配置两种服务降级形式,一种是类级别的FallbackFactory,一种是方法级别的FallbackMethod,FallbackFactory优先级高于FallbackMethod,即同时存在时不会走FallbackMethod。
fallback & fallbackFactory
/**
* Fallback class for the specified Feign client interface. The fallback class must implement the interface annotated by this annotation and be a valid spring bean.
*/
Class<?> fallback() default void.class;
/**
* Define a fallback factory for the specified Feign client interface. The fallback factory must produce instances of fallback classes that implement the interface annotated by {@link FeignClient}. The fallback factory must be a valid spring bean.
* @see feign.hystrix.FallbackFactory for details.
*/
Class<?> fallbackFactory() default void.class;
使用示例:
@FeignClient(value = "merchant-provider", fallback = RemoteMerchantServiceFallbackImpl.class,
fallbackFactory = RemoteMerchantServiceFallbackFactory.class)
public interface RemoteMerchantService {
@RequestMapping(value = {"/merchant/app/findByAppKey"}, method = {RequestMethod.POST})
Response<GetMerchantAppVO> findByAppKey(GetMerchantAppInfoDTO merchantAppInfoDTO);
}
@Slf4j
@Component
public class RemoteMerchantServiceFallbackImpl implements RemoteMerchantService {
@Override
public Response<GetMerchantAppVO> findByAppKey(GetMerchantAppInfoDTO merchantAppInfoDTO) {
log.info("Fallback findByAppKey...");
return Response.error();
}
}
import feign.hystrix.FallbackFactory;
@Component
public class RemoteMerchantServiceFallbackFactory implements FallbackFactory<RemoteMerchantService> {
@Override
public RemoteMerchantService create(Throwable throwable) {
log.error("异常原因: ", throwable);
return new RemoteMerchantService() {
@Override
public Response<GetMerchantAppVO> findByAppKey(GetMerchantAppInfoDTO merchantAppInfoDTO) {
log.info("Fallback findByAppKey...");
return Response.error();
}
};
}
}
两者有何区别呢?参考:https://arnoldgalovics.com/feign-fallback/
What’s the difference between this and the regular fallback? With the regular fallback, you can’t access the underlying exception that triggered the fallback however with the fallback factory, you can.
大致意思:
- fallbackFactory:可以捕获异常信息即Throwable并打印,可返回默认降级结果。类似于断容器
- fallback:不能捕获异常打印堆栈信息,不利于问题排查,可返回默认降级结果
TODO:不能同时使用?