0
点赞
收藏
分享

微信扫一扫

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

图解+源码讲解 动态代理获取 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);
}

图解+源码讲解动态代理获取 FeignClient 代理对象_Spring Cloud
    返回的 client 信息如下图所示,图中的 CachingSpringLoadBalancerFacory就是要用到的负载均衡那块
图解+源码讲解动态代理获取 FeignClient 代理对象_spring_02

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是之前定义好的同步方法处理器
图解+源码讲解动态代理获取 FeignClient 代理对象_后端_03
图解+源码讲解动态代理获取 FeignClient 代理对象_客户端_04

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
图解+源码讲解动态代理获取 FeignClient 代理对象_spring_05

举报

相关推荐

0 条评论