什么是OpenFeign
OpenFeign是Spring Cloud提供的一个声明式的伪Http客户端, 它使得调用远程服务就像调用本地服务一样 简单, 只需要创建一个接口并添加一个注解即可。 Nacos很好的兼容了OpenFeign, OpenFeign默认集成了 Ribbon, 所以在Nacos下使用OpenFegin默认就实现了负载均 衡的效果。
Feign与OpenFeign的区别
Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端。Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
OpenFeign是Spring Cloud 在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
OpenFeign 常见API
- @FeignClient
1、name:指定该类的容器名称,类似于@Service(容器名称) 2、url: url一般用于调试,可以手动指定@FeignClient调用的地址 3、decode404:当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException 4、configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract 5、fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口 6、fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码 7、path: 定义当前FeignClient的统一前缀,当我们项目中配置了server.context-path,server.servlet-path时使用 示例:
@FeignClient(value = ServiceConst.SAMPLES_NACOS_PROVIDER, fallbackFactory = SamplesFallbackFactory.class)
public interface FeignTestService {
}
-
@EnableFeignClients
-
@SpringQueryMap注解
spring cloud项目使用feign的时候都会发现一个问题,就是get方式无法解析对象参数。其实feign是支持对象传递的,但是得是Map形式,而且不能为空,与spring在机制上不兼容,因此无法使用。spring cloud在2.1.x版本中提供了@SpringQueryMap注解,可以传递对象参数,框架自动解析。
SpringMVC 常用注解
- @GetMapping
- @PostMapping
日志配置
全局请求日志配置
feign:
client:
config:
# 默认配置 如果不单独配置每个服务会走默认配置
default:
loggerLevel: FULL # 日志级别 NONE:不打印 BASIC:打印简单信息 HEADERS:打印头信息 FULL:打印全部信息 (默认 NONE)
单个请求的配置
feign:
client:
config:
# 配置单独FeignClient
# @FeignClient(value = "kerwin-user",contextId = "userInfoClient")
# 如果FeignClient注解设置了contextId这里就使用userInfoClient如果没有设置contextId就直接使用服务名称kerwin-user
userInfoClient:
loggerLevel: FULL # 日志级别 NONE:默认不打印 BASIC:打印简单信息 HEADERS:打印头信息 FULL:打印全部信息(默认 NONE)
OpenFeign使用
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
启动注解
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients//开启Fegin
代码
常量配置
public interface RequestMappingConst {
String SAMPLES_INTERFACE = "/samples/interface";
String SAMPLES_INTERFACE_TWO = "/samples/interface/two";
String SAMPLES_INTERFACE_SEARCH_LOGS = "/samples/interface/search/logs";
}
feign接口
@FeignClient(value = ServiceConst.SAMPLES_NACOS_PROVIDER, fallbackFactory = SamplesFallbackFactory.class)
public interface SamplesInterface {
@RequestMapping(RequestMappingConst.SAMPLES_INTERFACE)
SamplesModel samplesInterface(@RequestParam("name") String name);
@RequestMapping(RequestMappingConst.SAMPLES_INTERFACE_TWO)
SamplesModel samplesInterfaceTwo(@RequestParam("name") String name);
@RequestMapping(RequestMappingConst.SAMPLES_INTERFACE_SEARCH_LOGS)
SamplesModel samplesInterfaceSearchLogs();
}
熔断配置
@Component
public class SamplesFallbackFactory implements FallbackFactory {
@Override
public Object create(Throwable cause) {
return new SamplesInterface() {
@Override
public SamplesModel samplesInterface(String name) {
return new SamplesModel("当前服务不可用");
}
@Override
public SamplesModel samplesInterfaceTwo(String name) {
return new SamplesModel("当前服务不可用");
}
@Override
public SamplesModel samplesInterfaceSearchLogs() {
return null;
}
};
}
}
控制层
@RestController
@RequestMapping("/samples")
public class SamplesController {
@Autowired
private SamplesInterface samplesInterface;
/**
* 对外接口URL需要与当前Controller URL一致
*
* @param name
* @return
*/
@HystrixCommand(fallbackMethod = "samplesInterfaceTimeOutHandler", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})
@RequestMapping("/interface")
public SamplesModel samplesInterface(String name) {
return samplesInterface.samplesInterface(name);
}
/**
* @param name
* @return
* @HystrixCommand Debug 或sleep 测试熔断器
*/
@HystrixCommand(fallbackMethod = "samplesInterfaceTimeOutHandler", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})
@RequestMapping("/interface/two")
public SamplesModel samplesInterfaceTwo(String name) {
return samplesInterface.samplesInterfaceTwo(name);
}
private SamplesModel samplesInterfaceTimeOutHandler(String name) {
return new SamplesModel("赵六");
}
}