当前位置: 首页 > news >正文

临沂网站建设选盛誉温州网站快速排名

临沂网站建设选盛誉,温州网站快速排名,沈阳发布紧急通知,网站为什么维护中文章目录 前言正文一、书接上回,从代理对象入手二、ReflectiveFeign.FeignInvocationHandler#invoke()三、SynchronousMethodHandler#invoke(...) 的实现原理3.1 invoke(...)源码3.2 executeAndDecode(...) 执行请求并解码 四、如何更换client 的实现 附录附1&#…

文章目录

  • 前言
  • 正文
    • 一、书接上回,从代理对象入手
    • 二、ReflectiveFeign.FeignInvocationHandler#invoke()
    • 三、SynchronousMethodHandler#invoke(...) 的实现原理
      • 3.1 invoke(...)源码
      • 3.2 executeAndDecode(...) 执行请求并解码
    • 四、如何更换client 的实现
  • 附录
    • 附1:本系列文章链接
    • 附2:比较HttpURLConnection、Apache HttpClient、OkHttp

前言

本篇是SpringCloud原理系列的 OpenFeign 模块的第四篇。

在我们启动完应用后,Spring容器也初始化好了很多我们用到的类。(什么,你不知道,烦请先看看第三篇)

那么我们下一步要做的就是,发出rest请求,然后调用FeignClient标注的接口方法。这篇文章,我们就来看看它的原理。

本文关键词:RequestTemplateSynchronousMethodHandler

使用java 17,spring cloud 4.0.4,springboot 3.1.4
使用项目是本系列第一篇中的项目

正文

一、书接上回,从代理对象入手

第三篇文章时,我们看到了SpringCloud将 OpenFeign的接口,映射为一个代理对象。
打个比方,使用如下接口:

@FeignClient(name = "helloFeignClient", url = "http://localhost:10080")
public interface HelloFeignClient {@PostMapping("/hello/post")HelloResponse postHello(@RequestBody HelloRequest helloRequest);
}

最终生成的代理对象是对 HelloFeignClient 接口的代理,并且绑定了handler。handler的类型是ReflectiveFeign.FeignInvocationHandler
在这里插入图片描述
换句话说,就是当我们调用接口HelloFeignClient 中的方法时,会触发调用ReflectiveFeign.FeignInvocationHandlerinvoke(...)方法。

二、ReflectiveFeign.FeignInvocationHandler#invoke()

在这里插入图片描述
查看源码可以知道,这里invoke方法,实际是先从 dispatch中找到对应方法的真正的处理器,然后进行调用。
从第三篇文章,我们能知道 dispatch 是对 method 的映射。

比如接口HelloFeignClient 会被映射为dispatch,一个方法对应为一对key、value值。dispatch的类型是:

private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;

也就是说Method 只是作为一个桥梁,连接起了HelloFeignClient 内的方法和真正执行的handler实例。这里的实例真正的实现是SynchronousMethodHandler。也就是说,当我们调用接口方法时,会执行SynchronousMethodHandler#invoke(...)

三、SynchronousMethodHandler#invoke(…) 的实现原理

3.1 invoke(…)源码

public Object invoke(Object[] argv) throws Throwable {// 创建请求模板,包装请求头、请求体,url等字段参数RequestTemplate template = this.buildTemplateFromArgs.create(argv);// 获取连接超时等参数Request.Options options = this.findOptions(argv);// 重试Retryer retryer = this.retryer.clone();while(true) {try {// 执行请求并解码return this.executeAndDecode(template, options);} catch (RetryableException var9) {RetryableException e = var9;try {retryer.continueOrPropagate(e);} catch (RetryableException var8) {Throwable cause = var8.getCause();if (this.propagationPolicy == ExceptionPropagationPolicy.UNWRAP && cause != null) {throw cause;}throw var8;}if (this.logLevel != Level.NONE) {this.logger.logRetry(this.metadata.configKey(), this.logLevel);}}}}

3.2 executeAndDecode(…) 执行请求并解码

Object executeAndDecode(RequestTemplate template, Request.Options options) throws Throwable {// 通过模版获取请求体,执行所有请求拦截器Request request = this.targetRequest(template);if (this.logLevel != Level.NONE) {this.logger.logRequest(this.metadata.configKey(), this.logLevel, request);}long start = System.nanoTime();Response response;try {// 使用客户端执行请求response = this.client.execute(request, options);// 使用响应建造器构造一个响应体,包含请求和请求模板response = response.toBuilder().request(request).requestTemplate(template).build();} catch (IOException var9) {if (this.logLevel != Level.NONE) {this.logger.logIOException(this.metadata.configKey(), this.logLevel, var9, this.elapsedTime(start));}throw FeignException.errorExecuting(request, var9);}long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);// 处理响应结果&记录日志&响应解码return this.responseHandler.handleResponse(this.metadata.configKey(), response, this.metadata.returnType(), elapsedTime);}

通过分析,发现是先创建了RequestTemplate 实例,然后调用了client实例进行远程调用。而client的实现有多个,我这边看到内部实现了一个默认的:

public static class Default implements Client {public Response execute(Request request, Request.Options options) throws IOException {HttpURLConnection connection = this.convertAndSend(request, options);return this.convertResponse(connection, request);}
}

也就是说,到了这一步,就涉及到远程连接了。

这里用的是比较原始的HttpURLConnection。每次都创建新的连接,去请求,然后断开连接。这样很多时间也就浪费在建立连接等操作上了。而且调用量一旦变大,很容易出错。

问题来了,有没有什么办法能优化下呢?

四、如何更换client 的实现

上文提到 HttpURLConnection 是默认的连接方式。那麽我们有什么优化方案吗?
可替代方案一般有两种,一种是带有连接池的Apache HttpClient ,另一种是协议上占有优势的 OkHttp

至于它们的更详细的优缺点,以及不同之处,请查看本文的附2。

另外,我的下一篇文打算单独将这块写一下 ===> SpringCloud实用-OpenFeign整合okHttp
戳附录中的【本系列文章链接】查看文章。

附录

附1:本系列文章链接

SpringCloud系列文章目录(总纲篇)

附2:比较HttpURLConnection、Apache HttpClient、OkHttp

参考:七大主流的HttpClient程序比较

Client优点缺点
HttpURLConnectionjdk自带、原始、简单缺乏连接池管理、域名机械控制等特性支持,性能&效率较低,一般不建议使用
Apache HttpClient (已经停止开发)
Apache HttpComponents HttpClient
1. 支持连接池、多线程
2. 易用,灵活
安卓社区不再使用它,替换为了okHttp
需要自己做一层封装
java.net.http.HttpClientjava11正式启用,替代原先的HttpURLConnection如果使用的版本是java11以下的,用不了它
okHttp性能方面与HttpClient基本一样
链接复用
Response 缓存和 Cookie
默认 GZIP
请求失败自动重连
DNS 扩展
Http2/SPDY/WebSocket 协议支持
默认情况下,OKHttp会自动处理常见的网络问题:像二次连接、SSL的握手问题。
从Android4.4开始HttpURLConnection的底层实现采用的是okHttp.

一般情况下,如果使用了SpringCloud,基本都会选择 OpenFeign+okHttp的组合。

http://www.yayakq.cn/news/619521/

相关文章:

  • 网站集群建设解决方案广州网站建设电话大全
  • 提升网站权重吗从WordPress源码恢复
  • 北京网站建设设计公司哪家好网站建设宗旨是什么
  • 简单大气网站陕西高速公路建设网站
  • 广东建网站工具类网站做排名
  • 公司做网站 微信平台活动营销
  • 取消网站的通知书网站优化策略分析
  • 交互 网站家装公司文案
  • 淘宝客网站域名备案吗乱码网站怎么办
  • 淘宝客户自己做网站怎么做室内设计平面图手绘
  • 网站建设实验总结报告网站不同颜色
  • 关于水果的网站开发在线培训系统平台
  • 嘉兴市住房和城乡建设局门户网站校园网站建设管理
  • 西安哪家做网站公司好太原seo排名优化软件
  • 如何编程写代码网站搜索引擎优化推广
  • 美工个人网站潜江资讯网找工作
  • 宿迁网站建设介绍公司淘客网站佣金建设
  • 专门做品牌折扣的网站有哪些经常开车的微信公众号
  • 北京服饰网站建设环保网站查询碾米是否做备案
  • 微信企业网站源码下载帝国网站模板建设
  • 个人网站可以做商业吗房价查询网
  • 怎么开发创建网站教程平面设计学徒
  • delphi10.2 网站开发客户关系管理软件免费
  • 手机网站开发学习视频麦当劳的网络营销方式
  • 北京网站建设 优化设计本推荐
  • 临沂高端网站建设上海千樱网站建设
  • 济南营销型网站建设贵吗合肥做网站的
  • 网站建设办什么手续企业网站建设指导规范
  • 网站建设首页模板南宁手机建站公司
  • 电子商务网站建设与管理课件最常用的网站推广方式