当前位置:首页 > CN2资讯 > 正文内容

图解+源码讲解动态代理获取 FeignClient 代理对象feign动态代理实现

11小时前CN2资讯

图解+源码讲解 动态代理获取 FeignClient 代理对象


成功永远属于那些爱拼搏的人


相关文章
​图解+源码讲解 Feign 如何将客户端注入到容器中

从哪里开始分析

    我们在客户端进行注册的时候注册了一个客户端工厂类 FeignClientFactoryBean ,所以我们获取 FeignClient 指定是从这个工厂里面获取的了,所以我们就看看是怎么获取的这个FeignClient,一般用到了工厂的时候那么getObject方法就是获取实例的方法

@Override
public Object getObject() throws Exception {
// 获取目标实例
return getTarget();
}

getTarget()

// 返回一个 feign构造器客户端,通过 feingContext
<T> T getTarget() {
FeignContext context = this.applicationContext.getBean(FeignContext.class);
// 获取 feign 构造器
Feign.Builder builder = feign(context);

    这个构造器里面都构造了哪些东西呢,进入到构造器中

protected Feign.Builder feign(FeignContext context) {
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(this.type);

// @formatter:off
Feign.Builder builder = get(context, Feign.Builder.class)
// required values
.logger(logger)
.encoder(get(context, Encoder.class))
.decoder(get(context, Decoder.class))
.contract(get(context, Contract.class));
// @formatter:on

configureFeign(context, builder);
return builder;
}

    继续看 getTarget 方法的后面的流程,将 url 拼接成 http://GOODS-APPLICATION 这个地址

if (!StringUtils.hasText(this.url)) {
if (!this.name.startsWith("http")) {
// 进行url拼接
this.url = "http://" + this.name;
}
else {
this.url = this.name;
}
// http://GOODS-APPLICATION
this.url += cleanPath();
return (T) loadBalance(builder, context,
new HardCodedTarget<>(this.type, this.name, this.url));
}
}

    new HardCodedTarget 这个方法里面就是进行了赋值没有什么特殊的东西,直接看 loadBalance 这个方法

loadBalance() 方法

protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
HardCodedTarget<T> target) {
// 根据feignCotext 上下文获取客户端实例,获取的client是 LoadBalancerFeignClient
Client client = getOptional(context, Client.class);
// 如果客户端不为空
if (client != null) {
// 进行客户端创建
builder.client(client);
// 获取 Targeter 操作,这个Targeter 是 HystrixTargerer
Targeter targeter = get(context, Targeter.class);
// 调用 Targeter 的target方法
return targeter.target(this, builder, context, target);
}
}

getOptional 操作

    this.contextId 是 GOODS-APPLICATION,type 是 Client.class

protected <T> T getOptional(FeignContext context, Class<T> type) {
return context.getInstance(this.contextId, type);
}


    返回的 client 信息如下图所示,图中的 CachingSpringLoadBalancerFacory就是要用到的负载均衡那块

HystrixTargeter#target 方法

class HystrixTargeter implements Targeter {

@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
// 它两不是一种类型所以就是false 之后就是true,进入feign#target方法
if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
return feign.target(target);
}
......
}

Feign.Builder#target 方法

    build 方法里面其实就是创建了一个有关于feign的反射对象,之后又调用了 newInstance 方法

public <T> T target(Target<T> target) {
// 创建了一个 ReflectiveFeign 对象,之后调用 ReflectiveFeign#newInstance 方法
return build().newInstance(target);
}

    先进入build 方法,看看这个方法里面做了什么操作,其实里面主要是做了返回一个 ReflectiveFeign对象,其实一看就是和反射有关系,我们重点看一下ReflectiveFeign#newInstance方法

public Feign build() {
// 同步方法处理工厂,这里面构建了一些信息
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors,
logger, logLevel, decode404, closeAfterDecode, propagationPolicy);
// 解析一些信息
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
// 重要的方法new了一个 ReflectiveFeign
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}

【重点】反射创建代理实例 ReflectiveFeign#newInstance

@Override
public <T> T newInstance(Target<T> target) {
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);

    nameToHandler 处理完就是下图的样子,key是咱们定义的接口名字+#+方法名字,value是之前定义好的同步方法处理器

Map<Method, MethodHandler> methodToHandler =
new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers =
new LinkedList<DefaultMethodHandler>();
// 遍历 com.shangde.springcloud.service.GoodsClient 的所有方法,这里面就一个方法 goods
// method public abstract org.springframework.http.ResponseEntity
// com.shangde.springcloud.service.GoodsClient.goods()
for (Method method : target.type().getMethods()) {
if (method.getDeclaringClass() == Object.class) {
continue;
} else if (Util.isDefault(method)) {
DefaultMethodHandler handler = new DefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
} else {
// 因为它的声明不是类也不是默认工具方法所以直接走这里
// Feign.configKey(target.type(), method)) 是 GoodsClient#goods()
// 获取的 MethodHandler 就是 SynchronousMethodHandler
methodToHandler.put(method,
nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
// 创建动态代理,target 是HardCodeTarget,MethodHandler 就是 SynchronousMethodHandler
InvocationHandler handler = factory.create(target, methodToHandler);
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()}, handler);

for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}

    最后返回的proxy结果就是下图,里面有接口名字,访问的服务名字,以及url地址,其实就是返回了一个feign的代理对象 ReflectiveFeign

    你可能想看:

    扫描二维码推送至手机访问。

    版权声明:本文由皇冠云发布,如需转载请注明出处。

    本文链接:https://www.idchg.com/info/24483.html

    分享给朋友:

    “图解+源码讲解动态代理获取 FeignClient 代理对象feign动态代理实现” 的相关文章

    解锁高效跨境访问:BandwagonCN2让世界触手可及

    在全球化的今天,跨境访问已经成为许多人生活与工作的重要组成部分。无论是商务人士访问海外资源,还是留学生寻求教育资源,亦或是游戏玩家追求更流畅的体验,高效的网络连接都变得不可或缺。传统网络环境下,跨境访问常常面临延迟高、不稳定甚至完全无法访问的问题。在这背景下,BandwagonCN2应运而生,为用户...

    韩国服务器:提升企业在线表现的理想选择

    在当今数字化时代,韩国服务器以其独特的优势吸引了大量企业和开发者的关注。位于东亚的韩国,因其良好的地理位置,能够为用户提供低延迟和高速度的服务。无论是在线游戏、电子商务,还是移动应用,韩国服务器都能确保快速的响应和稳定的运行。 韩国服务器的特点令其在市场上独树一帜。首先,许多服务商提供高性能、稳定的...

    泰国VPS市场分析:高效、可靠的云服务器选择

    泰国VPS市场概述 近年来,泰国的VPS市场迎来了快速的发展。作为东南亚的一个重要互联网和商业枢纽,泰国吸引了越来越多的国内外服务商。这一切的变化让我感受到了市场的活力,尤其是在曼谷,一个充满竞争和机会的城市。在这片土地上,VPS服务逐渐成为了企业和个人用户实现数字化转型的重要工具。 在研究泰国VP...

    如何选择适合你的匿名服务器以保护隐私和数据安全

    在当今互联网时代,保护个人隐私和数据安全变得尤为重要。匿名服务器的概念应运而生,成为许多人实现在线安全和隐私的一种方式。简单来说,匿名服务器是一种特殊的服务器,能够隐藏用户的真实IP地址,从而在用户上网时保护其身份和活动。这对于那些希望自由浏览网络、避免被追踪的用户尤其重要。 匿名服务器通常与虚拟私...

    BBR脚本:提升Linux服务器网络性能的最佳选择

    BBR的基本概念 在近年来的网络技术发展中,BBR脚本不可不提。作为Google提出的拥塞控制算法,它带来了显著的性能提升。我常常会把BBR比作一位聪明的交通指挥官,它通过实时监测网络的瓶颈带宽和往返时间,像调节交通流量一样动态调整数据传输速率。这使得使用BBR的Linux服务器能够在面对不同网络条...

    AT&T VPS详解:稳定性与灵活性的完美选择

    在这篇文章中,我想和大家聊聊AT&T VPS,尤其是在更广泛的虚拟私有服务器市场中,AT&T VPS代表了什么。AT&T是一家美国知名的电信运营商,其提供的VPS服务在一定程度上依赖于它的网络基础设施。这种结合了高质量网络与虚拟服务器技术的服务,吸引了大量需要高稳定性和可扩展...