Spring Cloud Openfeign
OpenFeign 服务调用
概述
Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单。
它的使用方法是定义一个服务接口然后在上面添加注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡
特点:Feign是一个声明式的Web服务客户端,让编写Web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可
Feign和OpenFeign区别
Feign
Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端
Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。 Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务
依赖:spring-cloud-starter-feign
OpenFeign
OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等等。
OpenFeign的@Feignclient可以解析SpringMvc的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
依赖:spring-cloud-starter-openfeign
项目实例
1、引入依赖
<dependencies>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
2、Yaml配置
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
#设置feign客户端超时时间(OpenFeign默认支持ribbon),默认是1秒
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000
logging:
level:
# feign日志以什么级别监控哪个接口
com.atguigu.springcloud.service.PaymentFeignService: debug
3、启动类开启注解
@SpringBootApplication
@EnableFeignClients
public class OrderFeignMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderFeignMain80.class, args);
}
}
4、业务处理类
@Component
// 指定服务名
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService
{
// 调用 CLOUD-PAYMENT-SERVICE 服务提供的具体接口
@GetMapping("/payment/get/{id}")
public AjaxResult selectPaymentById(@PathVariable("id") Long id);
@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout();
}
5、客户端Controller
@RestController
@Slf4j
public class OrderFeignController
{
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping(value = "/consumer/payment/get/{id}")
public AjaxResult getPaymentById(@PathVariable("id") Long id)
{
return paymentFeignService.selectPaymentById(id);
}
@GetMapping(value = "/consumer/payment/feign/timeout")
public String paymentFeignTimeout()
{
// OpenFeign客户端一般默认等待1秒钟
return paymentFeignService.paymentFeignTimeout();
}
}
性能优化
超时控制
openFeign
默认的超时时间分别是连接超时时间10秒
、读超时时间60秒
,源码在feign.Request.Options#Options()
方法中,但是 openFeign
集成了Ribbon
,Ribbon
的默认超时连接时间、读超时时间都是是1秒
,源码在org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer#execute()
方法中。
所以,OpenFeign
客户端等待超过1秒未响应则报错
设置超时时间控制
1、设置Ribbon的超时时间(不推荐)
#设置feign客户端超时时间(OpenFeign默认支持ribbon),默认是1秒
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
ConnectTimeout: 5000
2、设置openFeign的超时时间(推荐)
feign:
client:
config:
## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
default:
connectTimeout: 5000
readTimeout: 5000
## 为 cloud-payment-service 这个服务单独配置超时时间:单个配置的超时时间将会覆盖全局配置。
cloud-payment-service:
connectTimeout: 30000
readTimeout: 30000
服务降级配置
hystrix版本
1、Yml配置开启
#开启hystrix服务降级
feign:
hystrix:
enabled: true
2、FeignClient接口服务
// FeignClient接口服务加入fallback或者fallbackFactory
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackServiceImpl.class)
// @FeignClient(fallbackFactory = RemoteUserFallbackFactory.class)
public interface PaymentHystrixService
{
....
}
3、添加接口实现类
/**
* 服务降级
* 接口的统一的fallback处理方法
* @author LiJunYi
* @date 2020/08/12
*/
@Component
public class PaymentFallbackServiceImpl implements PaymentHystrixService
{
@Override
public String paymentInfoOk(Integer id)
{
return "-----PaymentFallbackService fall back-paymentInfoOk";
}
@Override
public String paymentInfoTimeOut(Integer id)
{
return "-----PaymentFallbackService fall back-paymentInfo_TimeOut";
}
}
sentinel版本
1、依赖引入
<!--SpringCloud openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--SpringCloud ailibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--SpringCloud ailibaba sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2、Yaml配置
server:
port: 84
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: localhost:8080
#默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
port: 8719
# 激活Sentinel对Feign的支持
feign:
sentinel:
enabled: true
#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
service-url:
nacos-user-service: http://nacos-payment-provider
3、启动类开启注解
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class OrderNacosMain84
{
public static void main(String[] args) {
SpringApplication.run(OrderNacosMain84.class, args);
}
}
4、Feign接口业务类
/**
* 支付服务
*
* @author LiJunYi
* @date 2020/12/28
*/
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
public interface PaymentService
{
@GetMapping(value = "/paymentSQL/{id}")
AjaxResult paymentSQL(@PathVariable("id") Long id);
}
5、服务降级处理类
@Component
public class PaymentFallbackService implements PaymentService
{
@Override
public AjaxResult paymentSQL(Long id)
{
return AjaxResult.warn("服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial"));
}
}
日志打印功能
Feign 提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign 中 Http请求的细节。说白了就是对Feign接口的调用情况进行监控和输出
NONE:默认的,不显示任何日志;
BASIC:仅记录请求方法、URL、响应状态码及热行时间;
HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息;
FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。
配置日志
/**
* @ClassName: FeignConfig
* @Description: 日志控制
* @author: LiJunYi
*/
@Configuration
public class FeignConfig
{
@Bean
Logger.Level feignLoggerLevel()
{
return Logger.Level.FULL;
}
}
logging:
level:
# feign日志以什么级别监控哪个接口
com.atguigu.springcloud.service.PaymentFeignService: debug
请求拦截器
在微服务应用中,通过feign
的方式实现http
的调用,可以通过实现feign.RequestInterceptor
接口在feign
执行后进行拦截,对请求头等信息进行修改。
例如项目中利用feign
拦截器将本服务的userId
、userName
、authentication
传递给下游服务
/**
* feign 请求拦截器
*/
@Component
public class FeignRequestInterceptor implements RequestInterceptor
{
@Override
public void apply(RequestTemplate requestTemplate)
{
HttpServletRequest httpServletRequest = ServletUtils.getRequest();
if (StringUtils.isNotNull(httpServletRequest))
{
Map<String, String> headers = ServletUtils.getHeaders(httpServletRequest);
// 传递用户信息请求头,防止丢失
String userId = headers.get(CacheConstants.DETAILS_USER_ID);
if (StringUtils.isNotEmpty(userId))
{
requestTemplate.header(CacheConstants.DETAILS_USER_ID, userId);
}
String userName = headers.get(CacheConstants.DETAILS_USERNAME);
if (StringUtils.isNotEmpty(userName))
{
requestTemplate.header(CacheConstants.DETAILS_USERNAME, userName);
}
String authentication = headers.get(CacheConstants.AUTHORIZATION_HEADER);
if (StringUtils.isNotEmpty(authentication))
{
requestTemplate.header(CacheConstants.AUTHORIZATION_HEADER, authentication);
}
}
}
}
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackServiceImpl.class,configuration = {FeignRequestInterceptor.class})
public interface PaymentHystrixService
{
// ....
}
Gzip压缩
gzip
是一种数据格式,采用deflate
算法压缩数据。gzip
大约可以帮我们减少70%
以上的文件大小。
全局配置
server:
compression:
# 是否开启压缩
enabled: true
# 配置支持压缩的 MIME TYPE
mime-types: text/html,text/xml,text/plain,application/xml,application/json
局部配置
feign:
compression:
request:
# 开启请求压缩
enabled: true
# 配置压缩支持的 MIME TYPE
mime-types: text/xml,application/xml,application/json
# 配置压缩数据大小的下限
min-request-size: 2048
response:
# 开启响应压缩
enabled: true
Http连接池
两台服务器建立HTTP
连接的过程涉及到多个数据包的交换,很消耗时间。采用HTTP
连接池可以节约大量的时间提示吞吐量。
Feign
的HTTP
客户端支持3种框架:HttpURLConnection
、HttpClient
、OkHttp
。
默认是采用java.net.HttpURLConnection
,每次请求都会建立、关闭连接,为了性能考虑,可以引入httpclient
、okhttp
作为底层的通信框架。
例如将Feign
的HTTP
客户端工具修改为HttpClient
。
添加依赖
<!-- feign httpclient -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
全局配置
feign:
httpclient:
# 开启httpclient
enabled: true
测试验证
// RemoteUserService FeignClient
@GetMapping("/user/pojo")
public Object selectUser(SysUser user);
// 消费端
@Autowired
private RemoteUserService remoteUserService;
@GetMapping("/user/pojo")
public Object UserInfo(SysUser user)
{
return remoteUserService.selectUser(user);
}
// 服务端
@GetMapping("/pojo")
public R<SysUser> selectUser(@RequestBody SysUser user)
{
return R.ok(userService.selectUserByUserName(user.getUserName()));
}