Feign是一个声明式的web服务客户端,让编写web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可。 GitHub:https://github.com/spring-cloud/spring-cloud-openfeign
Feign在消费端使用 依赖: 包含了ribbon
<!--openfeign--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>配置文件:
server: port: 80 eureka: client: register-with-eureka: false service-url: defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka主启动类:
@SpringBootApplication @EnableFeignClients public class OrderFeignMain80 { public static void main(String[] args) { SpringApplication.run(OrderFeignMain80.class,args); } }定义业务逻辑接口: 业务逻辑接口+@FeignClient配置调用provider服务
@Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping(value = "/payment/get/{id}") CommonResult<Payment> getPaymentById(@PathVariable("id") Long id); }控制层Controller:
@Slf4j @RestController public class OrderFeignController { @Autowired private PaymentFeignService paymentFeignService; @GetMapping(value = "/consumer/payment/get/{id}") CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) { return paymentFeignService.getPaymentById(id); } }测试: 先启动2个eureka集群7001/7002 再启动2个微服务8001/8002 启动服务消费者,OpenFeign启动。
http://localhost/consumer/payment/get/1Feign自带负载均衡配置项。
小总结:
注意:
feign的坑,在写sdk包的时候,@EnableFeignClients扫描不到feign接口,需要手动配置@EnableFeignClients(basePackages= "com.xxx.cloud.xxx.security.client"),但是如果新建一个项目配置feign,就不会出现这个问题,直接先@EnableFeignClients,就能扫描到feign接口FeignService里定义的接口,用到了@pathVariable,必须写上value,如:@pathVariabl("id")feign接口不支持HttpServletRequest,如果服务端的接口入参有这个,feignService里对应的接口就不写这个入参就行Feign发送Get请求时,采用POJO对象传递参数出现Request method ‘POST‘ not supported <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> </dependency> https://www.jb51.net/article/133767.htm 服务端接口返回值是mybatis-plus的IPage,feign接口直接调用会异常,feign接口用改为Page来接受就可以了feign接口@RequestParam的value属性要设置上,不然报异常如果多个feign接口的@FeignClient(value = "user")一样,会报错,bean名称重复,解决:@FeignClient(value ="user",contextId="userRemoteService"),使用contextId区别开来如果请求方式是Get方式,并且入参是对象,那么feign接口对应的入参加上@SpringQueryMap注解 例如:@GetMapping("/user/page") @ApiOperation(value = "分页查询用户") Result<RemotePage<UserVO>> page(@SpringQueryMap UserQO userQO);如果@SpringQueryMap标注的类,继承了父类,默认父类的属性不会被映射过来,要想父类的属性也被映射 1、解决办法,配置请求端的Fegin,加强SpringQueryMap解析。
@Configuration public class FeignConfiguration { @Bean public Feign.Builder feignBuilder() { return Feign.builder() .queryMapEncoder(new BeanQueryMapEncoder()) .retryer(Retryer.NEVER_RETRY); } }2、然后再使用Fegin加载该配置
@FeignClient(value = "test", configuration = FeignConfiguration.class)服务提供方8001,8002故意写暂停程序,模拟耗时长的业务:
@GetMapping(value = "/payment/feign/timeout") public String paymentFeignTimeout(){ try { TimeUnit.SECONDS.sleep(3); }catch (Exception e) {e.printStackTrace();} return serverPort; }服务消费方接口:
@Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping(value = "/payment/get/{id}") CommonResult<Payment> getPaymentById(@PathVariable("id") Long id); @GetMapping(value = "/payment/feign/timeout") String paymentFeignTimeout(); }服务消费方controller:
@GetMapping(value = "/consumer/payment/feign/timeout") public String paymentFeignTimeout(){ //openfeign-ribbon,客户端一般默认等待1秒钟 return paymentFeignService.paymentFeignTimeout(); }测试: 直接访问服务提供者:http://localhost:8001/payment/feign/timeout 等待3秒后出结果 访问服务消费者接口:http://localhost/consumer/payment/feign/timeout,直接报错了 OpenFeign默认等待一秒钟,超过后报错
配置文件:
#设置feign客户端超时时间(openfeign默认支持ribbon) ribbon: #建立连接后,读取到可用资源所用的时间 ReadTimeout: 5000 #建立连接所用的时间 ConnectTimeout: 5000配置日志bean:
@Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }配置文件: 服务消费方接口,打印debug日志
logging: level: com.lzh.springcloud.service.PaymentFeignService: debug测试: 重启服务消费者,访问接口