OpenFeign
1.什么是OpenFeign
Feign是Spring Cloud提供的一个声明式的伪Http客户端, 它使得调用远程服务就像调用本地服务一样简单, 只需要创建一个接口并添加一个注解即可。
2. openfeign的使用
2.2 Nacos注册中心、Ribbon负载均衡、OpenFeign服务调用
Nacos很好的兼容了Feign, Feign负载均衡默认集成了 Ribbon, 所以在Nacos下使用Fegin默认就实现了负载均衡的效果。
- SpringCloudAlibaba中使用OpenFeign时,默认的负载均衡策略是轮询调用。
项目启动的时候,会用LoadBalancerFeignClient注册一个feign.Client到ioc容器中,
FeignClientFactoryBean会生成一个@FeignClient注解的对应的service实例。
3. 负载均衡
通俗的讲, 负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元(服务器,组件)上进行执行。
根据负载均衡发生位置的不同,一般分为服务端负载均衡和客户端负载均衡。
服务端负载均衡指的是发生在服务提供者一方,比如常见的nginx负载均衡
而客户端负载均衡指的是发生在服务请求的一方,也就是在发送请求之前已经选好了由哪个实例处理请求
我们在微服务调用关系中一般会选择客户端负载均衡,也就是在服务调用的一方来决定服务由哪个提供者执行.
4. 对比 Netflix Feign 和 OpenFeign
4.1 后来Netflix内部不在使用Feign并停止更新,为此Netflix把Feign提交给开源社区,命名为OpenFeign
5.openfeign设置超时 我有个问题 设置1秒,正常调用服务方,这个超时是因为服务方处理业务逻辑复杂或者调用第三方产生的时间大于1秒,这个时候 如何处理;
超时时间长一些 或者 查证交易
5.1 OpenFeign 实践之 FeignClient 超时设置
6.1 openfeign设置超时时间与日志增强 ribben控制无效
OpenFeign 客户端默认等待1秒钟,但是如果服务端业务超过1秒,则会报错。为了避免这样的情况,我们需要设置feign客户端的超时控制。
办法:由于OpenFeign 底层是ribbon 。所以超时控制由ribbon来控制。在yml文件中配置
feign: client: config: default: #建立连接所用的时间,适用于网络状况正常的情况下,两端连接所需要的时间, 连接超时 ConnectTimeOut: 5000 #指建立连接后从服务端读取到可用资源所用的时间,默认为1s,请求处理处理的超时时间 ReadTimeOut: 5000
----
#设置Feign客户端超时时间(openfeign默认支持ribbon)
ribbon:
ConnectTimeout: 5000
ReadTimeout: 5000
6.2 如果我们没有配置feign超时时间,上面的时间也会被ribbon覆盖?请求连接时间和超时时间,默认为1秒
16. openfeign调用 HttpServletRequest作为参数 报错.. 可以传递cookie 进行jwt验证 ,微服务之间调用 传递 httpServletRequest 对象
16.1 问题分析
- feign接口是不支持HttpServletRequest作为参数的
- feign和hystrix整合开启了feign对hystrix的熔断,导致feign的拦截器获取不到请
16.2 解决
问题1解决, 使用feign的拦截器,将请求拦截下
package top.bitqian.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; import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; /** * @author echo lovely * @date 2021/2/1 20:45 */ @Configuration public class FeignInterceptor implements RequestInterceptor { /** * 复写feign请求对象 * @param requestTemplate hhh */ @Override public void apply(RequestTemplate requestTemplate) { //获取请求头 Map<String,String> headers = getHeaders(Objects.requireNonNull(getHttpServletRequest())); for(String headerName : headers.keySet()){ requestTemplate.header(headerName, getHeaders(getHttpServletRequest()).get(headerName)); } } //获取请求对象 private HttpServletRequest getHttpServletRequest() { try { return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); } catch (Exception e) { e.printStackTrace(); return null; } } //拿到请求头信息 private Map<String, String> getHeaders(HttpServletRequest request) { Map<String, String> map = new LinkedHashMap<>(); Enumeration<String> enumeration = request.getHeaderNames(); while (enumeration.hasMoreElements()) { String key = enumeration.nextElement(); String value = request.getHeader(key); map.put(key, value); } return map; } }
这样feign接口中,就不用写HttpServletRequest 请求了,请求会通过feign发送到提供者。
问题二解决:造成原因,feing.hystrix.enabled=true, 开启了熔断
解决,将上面配置更换为:
hystrix: command: default: execution: isolation: strategy: SEMAPHORE
17.关于openfeign的参数传递 接口传参
18.openfeign 使用 httpclient的时候 pom文件 不要引入版本号 否则报错
java.lang.IllegalStateException: original request is required
19. 关于openfeign ;使用集成httpclient 使用其默认的连接池
由于 openfeign 使用Ribbon 进行负载均衡 默认轮询;
Ribbon默认也是用jdk自带的HttpURLConnection,需要给Ribbon也设置一个Http client
# ribbon 使用httpclient 替换默认 httpUrlConnection
ribbon:
http:
client:
enabled: true
20.开启hystrix 并且想要实现openFeign httpserveletRequest 传递怎么处理,首先使用feign的拦截器,将请求拦截下; 即开了hystrix 的熔断降级 也要实现httpServletRequest传递
hystrix: enabled: true command: default: execution: isolation: strategy: SEMAPHORE
20.1 创建一个自定义的hystrix 线程策略, 将servletRequestAttributes传入新线程中,并赋给RequestContextHolder:
public class MyHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy { @Override public <T> Callable<T> wrapCallable(Callable<T> callable){ ServletRequestAttributes servletRequestAttributes=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); return new Callable<T>() { @Override public T call() throws Exception { try { if (null != servletRequestAttributes) { RequestContextHolder.setRequestAttributes(servletRequestAttributes); } return callable.call(); }finally { RequestContextHolder.resetRequestAttributes(); } } }; } } @Configuration public class HystrixConfig { @PostConstruct public void init(){ HystrixPlugins.getInstance().registerConcurrencyStrategy( new MyHystrixConcurrencyStrategy() ); } }
22. Ribbon和OpenFeign
1.Ribbon侧重于做服务调用时的负载均衡,而OpenFeign侧重于面向接口进行服务调用。
2.OpenFeign自身集成Ribbon,所以默认开启轮询的负载均衡
3.我们不用过多去研究ribbon,它只是一个提供负载均衡的,大多时候只是更改负载均衡的算法。我们只需要编写好feign的接口以及其降级实现类, 所以引入依赖时,只用引入OpenFeign即可。