概述
在微服务架构盛行的年代,我们将一个大型的系统,拆解成各个服务,要完成一个业务逻辑,就可能需要,调用不同服务。比如订单服务调用会员服务。当然我们可以使用JDK自带的URLConnection,或者Apache的Http Client来调用,但是最为优雅的使用feign。
Feign可以使我们调用远程服务跟调用本地方法一样,完全感知不到这是调用远程方法,更感知不到这个一个http请求。
Feign结合了Ribbon的负载均衡
Feign结合了Hystrix可以实现熔断,降级
Feign可以进行GZIP压缩。
Feign工作原理
程序启动的时候会自动FeignClients的注解的类,并注入spring ioc容器中,当定义的feign接口的方法被调用时,会使用JDK的动态代理,生成RequestTemplate,当生成代理时,会为每个接口方法建立一个RequestTemplate对象,这个对象封装了Http请求需要的信息,比如参数,请求方法等。
RequestTemplate生成request对象,将request交给client处理,这里的client默认是JDK原生的URLConnection、Apache的Http Client,当然可以是OKhttp,之后client会被封装成LoadBalanceClient,这个类结合ribbon提供负载均衡发起服务之间的调用。
Feign入门案例
1.引入依赖
代码语言:javascript复制<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.启动类通过注解开启
代码语言:javascript复制/**
* 會員服務
*
*/
@SpringBootApplication(scanBasePackages = { "com.ding" })
@EnableDiscoveryClient
@EnableFeignClients
public class MemberApplication {
public static void main(String[] args) {
SpringApplication.run(MemberApplication.class, args);
}
}
其中@EnableFeignClients注解表示当项目启动的时候,会自动扫描@FeignClient的类,进行处理
3.编写接口
代码语言:javascript复制package com.ding.member.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import com.ding.core.Result;
import com.ding.member.dto.MemberDto;
import com.ding.member.hystrix.MemberQueryFeignHystrix;
@FeignClient(value ="cloud-member",fallback=MemberQueryFeignHystrix.class)
public interface MemberQueryFeignApi {
@RequestMapping(value = "/memberQueryFeign/getMemberById",method=RequestMethod.GET)
Result<MemberDto> getMemberById(@RequestParam(value = "memberId")Long memberId);
}
feign超时
https://www.136.la/jingpin/show-210022.html
feign超时分为两种 1、ribbon超时 2、hystrix超时,高版本默认是关闭hystrix ribbon超时
hystrix超时
注意:Hystrix和Ribbon的超时时间,较小的值生效,Hystrix超时时间要设置比Ribbon大,不然熔断失效。 ribbon 总超时时间(conn_time read_time)(MaxAutoRetries 1) (MaxAutoRetriesServer 1)
Feign默认clinet的替换
feign默认使用JDK原生的URLConnection发送Http请求,没有连接池。但是对每个地址保持一个长连接。我们可以使用Apache的HttpClient来替换,通过设置连接池,超时时间等来优化
使用apache的httpclient来替换 1、引入依赖
2、修改配置文件
使用okhttp来替换
1、引入依赖
2、修改配置文件
使用post和get传递实体参数
在实际开发中我们经常将多个参数封装成一个POJO,用于参数的接受 ,在spring mvc中get请求是可以直接绑定POJO的,但是在feign中get请求是不能这样弄的。。post请求可以 addUser(User user) 解决方案 1.将参数拆成一个个独立的属性,放在方法参数列表中 addUser(Integer age,String name) 2.将参数变成一个Map进行传递和接收 3.使用get请求传递@RequestBody,但是这个方式违反了restful规范 addUser(@RequestBody User user) 4.使用feign的拦截器 通过实现feign的RequestInterceptor的apply方法,统一拦截使用get方法并且使用body传递参数
注意 这里一定要注意,再定义各参数绑定时,@RequestParam、@RequestHeader等可以指定参数名称的主角,它们的value千万不能少。在Spring MVC程序中,这些注解会根据参数名来作为默认值,但是在Feign中绑定参数必须通过value属性来指明具体的参数名,不然会抛出==IllegalStateException==异常,value属性不能为空。addUser(@RequestParam String name)会报错要addUser(@RequestParam(”name”) String name)或者addUser(@RequestParam(value=”name”) String name)
第一次请求失败
当feign结合了Ribbon和Hystrix之后,可能会出现首次调用超时失败。原因:hystrix默认超时时间为1秒,如果这个时间之内没有响应,就会进入fallback方法,进行熔断。。而spring的懒加载机制,bean的加载和装配都要再使用的使用才执行,所以feign首次请求会比较慢,从而出现这个问题。 方案:延长熔断时间
代码语言:javascript复制hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=
全局配置
全局配置的方法非常简单,我们可以直接使用ribbon.key=value的方式来设置ribbon的各项默认参数。如下:
代码语言:javascript复制#以下配置全局有效
ribbon.eureka.enabled=true
#建立连接超时时间,原1000
ribbon.ConnectTimeout=60000
#请求处理的超时时间,5分钟
ribbon.ReadTimeout=60000
#所有操作都重试
ribbon.OkToRetryOnAllOperations=true
#重试发生,更换节点数最大值
ribbon.MaxAutoRetriesNextServer=10
#单个节点重试最大值
ribbon.MaxAutoRetries=1
很多情况下,我们需要个性化设置,比如设置每个服务有不同的配置client.ribbon.key=value
代码语言:javascript复制#以下配置对服务cloud-member有效
cloud-member.ribbon.eureka.enabled=true
#建立连接超时时间,原1000
cloud-member.ribbon.ConnectTimeout=60000
#请求处理的超时时间,5分钟
cloud-member.ribbon.ReadTimeout=60000
#所有操作都重试
cloud-member.ribbon.OkToRetryOnAllOperations=true
#重试发生,更换节点数最大值
cloud-member.ribbon.MaxAutoRetriesNextServer=10
#单个节点重试最大值
cloud-member.ribbon.MaxAutoRetries=1
传递token
很多情况下,我们会发现当我们外部请求,经过网关—到达服务A(token可以取到)—到达服务B(token丢失)这样会导致我们token验证失败,我们可以使用拦截器来处理
开启feign调用日志
我们可以为每个feign client开启日志。 可以在application.properties文件中使用logging.level.FeignClient的参数配置格式来开启指定Feign客户端的DEBUG日志
代码语言:javascript复制@FeignClient(value ="cloud-member",fallback=MemberQueryFeignHystrix.class)
public interface MemberQueryFeignApi {
@RequestMapping(value = "/memberQueryFeign/getMemberById",method=RequestMethod.GET)
Result<MemberDto> getMemberById(@RequestParam(value = "memberId")Long memberId);
}
如上面 我们可以在配置文件
代码语言:javascript复制logging.level.com.ding.member.api.MemberQueryFeignApi=DEBUG
只是添加了如上配置,还无法实现对DEBUG日志的输出。这时由于Feign客户端默认对Logger.Level对象定义为NONE级别,该界别不会记录任何Feign调用过程中对信息,所以我们需要调整它对级别
代码语言:javascript复制@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
对于Feign的Logger级别主要有下面4类,可根据实际需要进行调整使用。
- NONE:不记录任何信息。
- BASIC:仅记录请求方法、URL以及响应状态码和执行时间。
- HEADERS:出了记录BASIC级别的信息之外,还会记录请求和响应的头信息。
- FULL:记录所有请求与响应的细节,包括头信息、请求体、元数据等。
参考 《重新定义spring cloud》 Spring Cloud Feign使用详解