feign的设计思路:
1,Feign.builder()创建Builder
2,Builder.target()创建目标实例对象代对象---把普通的包装了接口类,请求地址,方法名的target,代理成可以发http的代理类(基于接口类生成代理,代理方法就是发送请求地址对应的http请求),中间有些包装request,response
interface GitHub {
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
}
GitHub github = Feign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");
public HardCodedTarget(Class<T> type, String name, String url) {
this.type = checkNotNull(type, "type");
this.name = checkNotNull(emptyToNull(name), "name");
this.url = checkNotNull(emptyToNull(url), "url");
}
T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler);
示例:
eign是简化Java HTTP客户端开发的工具(java-to-httpclient-binder),它的灵感来自于Retrofit、JAXRS-2.0和WebSocket。Feign的初衷是降低统一绑定Denominator到HTTP API的复杂度。
下来我们通过简单用例来分析工作核心原理以及流程
interface GitHub {
("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(("owner") String owner, ("repo") String repo);
}
static class Contributor {
String login;
int contributions;
}
public static void main(String... args) {
GitHub github = Feign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");
// 获取贡献者列表,并打印其登录名以及贡献次数
List<Contributor> contributors = github.contributors("netflix", "feign");
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
}
- ==通过上面样例我们看到首先定义了一个 GitHub接口,然后通过Feign.builder().target()创建了一个GitHub接口的实例。
那么Feign.builder().target()这里应该就是Feign的核心部分了,接下来我们跟踪源码,查看Feign都为我们做了什么事情==
- Feign.builder()创建Builder实例对象
//1.创建Builder实例对象
public static Feign.Builder builder() {
//调用创建Builder构建函数
return new Feign.Builder();
}
//2.Builder构建函数,初始化组件信息,当然我们也可以自定义组件
public Builder() {
//日志级别
this.logLevel = Level.NONE;
//注解解析组件
this.contract = new Default();
//http发送组件
this.client = new feign.Client.Default((SSLSocketFactory)null, (HostnameVerifier)null);
//重试机制组件
this.retryer = new feign.Retryer.Default();
//日志
this.logger = new NoOpLogger();
//编码解码器组件
this.encoder = new feign.codec.Encoder.Default();
this.decoder = new feign.codec.Decoder.Default();
this.errorDecoder = new feign.codec.ErrorDecoder.Default();
this.options = new Options();
//默认的反射InvocationHandlerFactory
// Feign 使用的jdk自带的动态代理
this.invocationHandlerFactory = new feign.InvocationHandlerFactory.Default();
}
- Builder.target()创建目标实例对象
//1. 调用target传入目标接口以及请求URL
public <T> T target(Class<T> apiType, String url) {
return this.target(new HardCodedTarget(apiType, url));
}
//2.根据Target包装对象创建目标接口的实例对象
public <T> T target(Target<T> target) {
//通过3构建一个Feign对象,然后通过newInstance方法获取目标实例对象
return this.build().newInstance(target);
}
// 3. 构建Feign对象
public Feign build() {
//创建方法代理类工厂
Factory synchronousMethodHandlerFactory = new Factory(this.client, this.retryer, this.requestInterceptors, this.logger, this.logLevel, this.decode404);
//
ParseHandlersByName handlersByName = new ParseHandlersByName(this.contract, this.options, this.encoder, this.decoder, this.errorDecoder, synchronousMethodHandlerFactory);
//这里返回真实的Feign对象
return new ReflectiveFeign(handlersByName, this.invocationHandlerFactory);
}
- Feign.newInstance()(通过2我们可以看出实际是通过ReflectiveFeign对象的newInstance方法创建)
//1. 这里是创建目录接口实例对象的真正地方
// 这里可以看到是使用了jdk自带的动态代理实现
//可以很清楚的看到返回的是目标接口的代理对象
public <T> T newInstance(Target<T> target) {
Map<String, MethodHandler> nameToHandler = this.targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList();
InvocationHandler handler = this.factory.create(target, methodToHandler);
//这里可以看到是使用了jdk自带的动态代理实现的
//那么我们知道jdk动态代理真正执行的是InvocationHandler接口中的invoke方法,我们再跟踪invoke,看下执行目标接口方法时具体逻辑。
T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler);
return proxy;
}
//2. 执行目标接口方法带来具体实现(FeignInvocationHandler)
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在此我们可以看出目标函数除了equals,hashCode,toString方法外都会调用this.dispatch.get(method)).invoke(args)
//dispatch是目标函数代理类集合,目标接口中每个函数都会对应有一个MethodHandler类,至于怎么得到的有兴趣可以查看源码
if(!"equals".equals(method.getName())) {
return "hashCode".equals(method.getName())?Integer.valueOf(this.hashCode()):("toString".equals(method.getName())?this.toString():((MethodHandler)this.dispatch.get(method)).invoke(args));
} else {
}
}
- 通过3我们看出了目录接口每个函数的执行其实是执行其MethodHandler类的invoke方法那么下来我们看下这里具体逻辑
MethodHandler默认实现SynchronousMethodHandler
//1. 接口方法执行都会调用其对应的invoke方法
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = this.buildTemplateFromArgs.create(argv);
//重试组件
Retryer retryer = this.retryer.clone();
while(true) {
try {
//执行请求并解码
return this.executeAndDecode(template);
} catch (RetryableException var5) {
retryer.continueOrPropagate(var5);
if(this.logLevel != Level.NONE) {
this.logger.logRetry(this.metadata.configKey(), this.logLevel);
}
}
}
}
//2 构建request请求并执行和解码
Object executeAndDecode(RequestTemplate template) throws Throwable {
//1. 获取request请求
Request request = this.targetRequest(template);
long start = System.nanoTime();
Response response;
try {
//通过http组件发送请求
response = this.client.execute(request, this.options);
response.toBuilder().request(request).build();
} catch (IOException var15) {
}
//解码操作调用解码组件进行解码
//这里省略
return var9;
}
//3组装request请求,这里同时完成了拦截器调用的逻辑
Request targetRequest(RequestTemplate template) {
//获取当前请求的所有拦截器
Iterator var2 = this.requestInterceptors.iterator();
while(var2.hasNext()) {
RequestInterceptor interceptor = (RequestInterceptor)var2.next();
//依次调用拦截器进行拦截操作
interceptor.apply(template);
}
//返回Request对象
return this.target.apply(new RequestTemplate(template));
}
通过上面四步我们可以清晰的看出我们通过定义目标接口是怎么一步一步的完成了http请求发送与接收。
在项目中我们使用Feign是简化我们的http操作,同时我们理解整个http请求响应是怎么通过Feign来完成的。这样后期不管是定制还是问题定位,我们都能快速有效的分析。
链接:https://www.jianshu.com/p/88c79c3aad2d
相关推荐
基于微服务架构实现的智能招聘系统 ( 可用于毕业设计 ) 部署方式 docker部署:mvn docker:build & java -jar 物理机部署:mvn install & java -jar 技术栈 Spring-Boot Spring-Cloud Spring-Cloud-Gateway Spring-...
**我们先从一个基本的 RPC 框架设计思路说起!** ### 一个基本的 RPC 框架设计思路 > **注意** :我们这里说的 RPC 框架指的是:可以让客户端直接调用服务端方法就像调用本地方法一样简单的框架,比如我前面介绍的...
- **核心类和接口**:了解Spring Cloud中的关键类和接口的设计思路。 - **依赖注入**:学习如何通过依赖注入管理组件和服务。 - **自动化配置**:理解Spring Cloud是如何通过注解和属性自动配置服务的。 - **集成...
《Nacos、Seata在分布式事务中的应用实践》 Nacos和Seata是两个在分布式系统中广泛应用的组件,...这种设计思路不仅提高了系统的可扩展性和稳定性,还降低了开发和运维的复杂度,是现代分布式系统中的一种典型实践。
本门课程围绕电商项目大觅网的业务场景,基于微服务原则设计电商项目,使用多种诸如Eureka、Feign、Hystrix、Ribbon、Zuul、Config等技术,另外基于虚拟化技术Docker+Jenkins实现程序自动发布、基于Mycat实现第三方...
- 论文文件:可能是一份详细的PDF文档,介绍了项目的背景、设计思路、技术选型、实现过程以及性能评估等。 通过研究这个项目,开发者可以学习到如何将Vue.js和Spring Cloud结合使用,创建一个完整的前后端分离的...
这意味着项目不仅包含源代码,还涵盖了系统设计思路和实现过程。可能包括服务拆分策略、数据库设计、API接口定义、服务间通信(如使用Ribbon、Feign等)以及部署和监控方案等内容。 4. **班车预约系统**: 这是一...
下面将详细阐述其设计思路、主要功能模块以及实现技术。 一、系统设计思想 1. 微服务架构:Spring Boot以其快速开发、自动配置的特点,成为微服务架构的理想选择。系统采用Spring Boot构建各个独立的服务,如用户...
微服务是一种设计思路,它将大型单体应用分解成一组小型、独立部署的服务,每个服务负责执行特定的业务功能。这种架构模式能够提高系统的可伸缩性和可维护性。 #### 服务注册与发现 在Spring Cloud中,服务注册与...
服务提供者(Provider)在启动时,作为Eureka Client向Eureka Server发送REST请求,将自己的元数据(如主机名、端口等)注册到...这种设计思路极大地简化了分布式系统中的服务治理,提高了系统的可扩展性和稳定性。
【描述】中提到的“同和君の毕业论文”可能是指该项目由一位名叫“同和君”的学生完成,并以毕业论文的形式呈现,意味着这份压缩包可能包含了一份详细的项目报告或论文,阐述了系统的设计思路、实施过程以及结果分析...
微服务架构是一种设计思路,它将单一应用程序开发为一组小型服务,每个服务独立运行在其自己的进程中,并通过轻量级通信机制(通常是HTTP资源API)相互交互。这样的架构具有以下几个显著特点: 1. **服务粒度小**:...
7. 演示PPT:这部分可能包含了项目介绍、功能模块、技术选型、系统架构图等内容,帮助理解项目的整体设计思路。 总结,"springcloud+vue实现电商系统"项目以SpringCloud为基础,结合Vue.js的前端技术,构建了一个...
#### 三、微服务架构的设计思路与实践 - **思维转变**: 从传统的单体应用向微服务转型,需要转变思维模式,重视DevOps理念的落实。 - **技术改进**: - 前后端分离: Web前端通过HTTP/HTTPS协议调用API网关,网关再...
论文部分则需要对系统的设计思路、实现方法、技术选型、性能优化等方面进行详细论述,包括系统架构的设计、数据库设计、微服务的划分、安全策略的设定等。此外,还需要对系统进行实际测试,分析其性能和稳定性,并...
《基于SpringCloud的饿了么O2O外卖系统后端详解》 饿了么O2O外卖系统是一款深受用户喜爱的在线订餐平台,其后端架构采用了微服务...这样的设计思路,对于大型互联网项目具有很高的参考价值,值得我们深入学习和借鉴。
在Spring Boot中实现分布式,通常会涉及服务注册与发现(如Eureka或Consul)、负载均衡(如Ribbon或Feign)、熔断机制(Hystrix)、配置中心(如Spring Cloud Config)等组件,这些都是微服务架构中的关键部分。...
学习这本“SpringCloud开发笔记”,你需要掌握如何集成和配置这些组件,以及如何在实际项目中应用微服务设计原则,例如服务的解耦、服务间通信、容错机制、分布式追踪等。同时,理解阿里巴巴内部的最佳实践,有助于...
学习这套源码,不仅可以深入了解SpringCloud和SpringCloud Alibaba的使用,还能掌握电商系统的设计思路和最佳实践,对于提升微服务架构的设计和实施能力大有裨益。通过深入研究,开发者可以更好地理解如何在实际项目...
基于微服务的新星购物电商系统可以解决传统电商平台存在的问题,提高系统的可扩展性和可靠性,为电商平台的发展提供了新的思路。 技术要点: 1. 微服务架构:将大型单体应用程序拆分为多个小型独立的服务,以提高...