1 概述
Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。SpringCloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
是一个声明式的web客户端,只需要创建一个接口,添加注解即可完成微服务之间的调用
2 Feign能干什么
Feign旨在使编写Java Http客户端变得更容易。 前面(ribbon的博客中)在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。
3 Feign 集成了Ribbon
Feign利用了Ribbon维护了服务列表信息,并且通过轮询的方式实现了客户端的负载均衡,而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,更加简单的实现了服务的调用
就是A要调用B,Feign就是在A中创建一个一模一样的B对外提供服务的的接口,我们调用这个接口,就可以服务到B
4 Feign和OpenFeign 区别
Feign | OpenFeign |
---|---|
Feign是Spring Cloud组件中一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用接口,就可以调用服务注册中心的服务。 | OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中. |
架包 spring-cloud-starter-feign | 架包 spring-cloud-starter-openfeign |
5 OpenFeign的使用
假如现在A服务调用BF服务
在A服务启动类添加注解@EnableFeignClients
@SpringBootApplication
@EnableFeignClients // 启动feign
public class CloudConsumerFeignOrder80Application {
public static void main(String[] args) {
SpringApplication.run(CloudConsumerFeignOrder80Application.class, args);
System.out.println("启动成功");
}
}
需要调用的其他服务的接口
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE") //指定调用那个服务
public interface PaymentFeignService {
@GetMapping(value = "/payment/get/{id}")
CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}
业务层面
@RestController
@RequestMapping("consumer")
@Slf4j
public class OrderFeignController {
@Resource
private PaymentFeignService paymentFeignService; //注入这个接口
@GetMapping(value = "/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
return paymentFeignService.getPaymentById(id);
}
}
启动之后就可以获取到B服务返回的业务数据
6 OpenFeign的超时机制
OpenFeign默认等待时间是1秒,超过1秒,直接报错
假如B服务接口返回数据的时间是3秒的话,这样A服务通过OpenFeign调用B服务的时候就出报 time out错误
设置超时时间,修改配置文件application.yml
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下, 两端连接所用的时间
ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000
7 OpenFeign日志
OpenFeign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解OpenFeign中Http请求的细节。即对OpenFeign远程接口调用的情况进行监控和日志输出。
OpenFeign日志级别有:
NONE:默认级别,不显示日志
BASIC:仅记录请求方法、URL、响应状态及执行时间
HEADERS:除了BASIC中定义的信息之外,还有请求和响应头信息
FULL:除了HEADERS中定义的信息之外,还有请求和响应正文及元数据信息
使用OpenFeign日志
@Configuration
public class FeignConfig {
/**
* NONE,
* BASIC,
* HEADERS,
* FULL;
* <p>
* 日志级别
*
* @return
*/
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
配置文件指定
logging:
level:
# feign日志以 debug 级别监控
com.atguigu.springcloud.service.PaymentFeignService: debug
8 OpenFeign请求添加Header
通过实现RequestInterceptor 添加Header
package com.demo.consumerorder.config;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
@Configuration
public class OpenFeignConfig implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
// 注意: RequestContextHolder依赖于 ThreadLocal, 所以在hystrix的隔离策略为THREAD、MQ的消费者、定时任务调用feignClient时,此处应为null
if (attributes == null) {
return;
}
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String value = request.getHeader(name);
if (name.toLowerCase().equals("content-length")) {
continue;
}
requestTemplate.header(name,value);
}
}
}
}
当OpenFeignConfig 通过@Configuration (或@Component或@Service )就可以将该配置注入spring容器中, 即可实现全局配置, 从而该项目中的所有FeignClient的feign接口都可以使用该配置.
如果想单独如果只想给指定FeignClient的feign接口使用该配置, 请勿将该类配置注入spring中.(去掉OpenFeignConfig 的@Configuration 注解,并且在@FeignClient 中指定改配置)
@FeignClient(value = "CLOUD-PAYMENT-SERVICE",configuration=OpenFeignConfig.class)
9 Spring @Configuration 和 @Component 区别
一句话概括就是 @Configuration 中所有带 @Bean 注解的方法都会被动态代理,因此调用该方法返回的都是同一个实例。