- 前言
- 核心类
- Target接口
- Client
- FeignContext
- Feign
- Targeter
- 流程分析
- 1. 获取对象
- 2. 创建上下文、构建者
- 3. 创建Target
- 4. 生成代理对象
- 总结
在之前分析了@EnableFeignClients及@FeignClient 是如何进行扫描及读取Feign 接口信息的,最后注解上的信息是被加载为BeanDefinition放入了BeanDefinitionRegistry中,接下来就是加载为Bean 对象了,依据下图(来自于百度)Feign 基本原理,分析下Feign 动态代理机制。
Target接口封装了feign 客户端接口的一些信息,并提供了将RequestTemplate请求模板转化为实际请求的Request的方法。
public interface Target{ // 接口类型 Class type(); // 客户端名称 String name(); //访问URL String url(); // 将`RequestTemplate `请求模板转化为实际请求的`Request ` Request apply(RequestTemplate var1); }
Target接口有两个实现类,EmptyTarget和HardCodedTarget。
EmptyTarget意为空的目标,其没有URL属性。
HardCodedTarget意为硬编码目标,Feign 中采用的是这个。
ClientClient就是Feign 直接执行请求的接口,可以看到传入了Request请求对象,及一个Options对象(超时配置)。
public interface Client { // Response execute(Request var1, Options var2) throws IOException; }
该接口的默认实现类为Default,使用的是HttpURLConnection,性能较低。
如果使用了OkHttp,则会使用OkHttpClient,一般实际开发,应当替换掉Default。
FeignContext继承了NamedContextFactory,用于创建Spring 子容器,每个客户端都对应了唯一的一个FeignContext。
public class FeignContext extends NamedContextFactoryFeign{ // 只从子容器寻找bean,返回bean实例 @Nullable public T getInstanceWithoutAncestors(String name, Class type) { return BeanFactoryUtils.beanOfType(getContext(name), type); } // 只从子容器寻找bean,返回Map @Nullable public Map getInstancesWithoutAncestors(String name, Class type) { return getContext(name).getBeansOfType(type); } }
Feign是一个抽象类,提供了一个生成接口代理对象的核心方法。
public abstractT newInstance(Target var1);
还提供了一个构建者Builder,用于创建Feign 接口实例
public Feign build() { // Client 实例 Client client = (Client)Capability.enrich(this.client, this.capabilities); // 重试器 Retryer retryer = (Retryer)Capability.enrich(this.retryer, this.capabilities); // 拦截器 ListrequestInterceptors = (List)this.requestInterceptors.stream().map((ri) -> { return (RequestInterceptor)Capability.enrich(ri, this.capabilities); }).collect(Collectors.toList()); // 日志 Logger logger = (Logger)Capability.enrich(this.logger, this.capabilities); // 模板契约 Contract contract = (Contract)Capability.enrich(this.contract, this.capabilities); // 参数 Options options = (Options)Capability.enrich(this.options, this.capabilities); // 编码器 Encoder encoder = (Encoder)Capability.enrich(this.encoder, this.capabilities); // 解码器 Decoder decoder = (Decoder)Capability.enrich(this.decoder, this.capabilities); InvocationHandlerFactory invocationHandlerFactory = (InvocationHandlerFactory)Capability.enrich(this.invocationHandlerFactory, this.capabilities); QueryMapEncoder queryMapEncoder = (QueryMapEncoder)Capability.enrich(this.queryMapEncoder, this.capabilities); Factory synchronousMethodHandlerFactory = new Factory(client, retryer, requestInterceptors, logger, this.logLevel, this.decode404, this.closeAfterDecode, this.propagationPolicy, this.forceDecoding); ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder, this.errorDecoder, synchronousMethodHandlerFactory); // 返回示例 return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder); }
ReflectiveFeign实现了Feign 接口,重写了newInstance方法,实际生产的Feign 客户端对象就是这个类。
ParseHandlersByName 是ReflectiveFeign的静态内类,意思是通过名称解析处理器,它只有一个apply方法:
public MapTargeterapply(Target target) { // 方法元数据,Contract 会对传入的接口进行解析验证,看注解的使用是否符合规范,然后返回给我们接口上各种相应的元数据。 List metadata = this.contract.parseAndValidatemetadata(target.type()); // 将方法名称,方法处理器放入一个Map 中,,MethodHandler则是包含此方法执行需要的各种信息 Map result = new linkedHashMap(); Iterator var4 = metadata.iterator(); // 构建 while(var4.hasNext()) { Methodmetadata md = (Methodmetadata)var4.next(); Object buildTemplate; if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) { buildTemplate = new ReflectiveFeign.BuildFormEncodedTemplateFromArgs(md, this.encoder, this.queryMapEncoder, target); } else if (md.bodyIndex() != null) { buildTemplate = new ReflectiveFeign.BuildEncodedTemplateFromArgs(md, this.encoder, this.queryMapEncoder, target); } else { buildTemplate = new ReflectiveFeign.BuildTemplateByResolvingArgs(md, this.queryMapEncoder, target); } if (md.isIgnored()) { result.put(md.configKey(), (args) -> { throw new IllegalStateException(md.configKey() + " is not a method handled by feign"); }); } else { result.put(md.configKey(), this.factory.create(target, md, (Factory)buildTemplate, this.options, this.decoder, this.errorDecoder)); } } return result; } }
Targeter定义了target方法,它接收FeignClientFactoryBean、Feign.Builder、FeignContext、Target.HardCodedTarget类型的参数。
interface Targeter {T target(FeignClientFactoryBean factory, Builder feign, FeignContext context, HardCodedTarget target); }
最终生成的Bean 对象,是由该接口返回。
他有以下几个实现类:
DefaultTargeter是其默认实现类,直接调用了Builder中实际是Feign 子类实现的newInstance方法创建实例。
publicT target(FeignClientFactoryBean factory, Builder feign, FeignContext context, HardCodedTarget target) { return feign.target(target); }
还有一个HystrixTargeter,是可以创建基于Hystrix的目标对象,默认使用的是这个。
之前分析过,@FeignClient上的所有信息,都会注册为FeignClientFactoryBean类型的BeanDefinition,学过Spring 的应该知道,FactoryBean是一个工厂Bean,可以生成某一个类型Bean实例,其getObject()方法会返回创建的Bean实例。
在Spring 容器进行实例化的时候,就会进入到FeignClientFactoryBean的getObject()方法,其实际调用的是本身的getTarget()。首先可以看到FeignClientFactoryBean中的相关属性:
在getTarget()中,是根据是否配置了URL属性,创建不同的代理对象,没有URL,说明是需要从注册中心获取远程地址,使用的是loadBalance方法加载动态的负载均衡。
3. 创建TargetT getTarget() { // 获取FeignContext ,每个Feign 客户端都对应一个context FeignContext context = (FeignContext)this.applicationContext.getBean(FeignContext.class); // 获取Feign 构建者 Builder builder = this.feign(context); if (!StringUtils.hasText(this.url)) { if (!this.name.startsWith("http")) { this.url = "http://" + this.name; } else { this.url = this.name; } // 拼接URL -=》http://order-service this.url = this.url + this.cleanPath(); return this.loadBalance(builder, context, new HardCodedTarget(this.type, this.name, this.url)); } else { // 判断是否配置了url 属性,配置了则直接根据URL创建代理对象 if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) { this.url = "http://" + this.url; } String url = this.url + this.cleanPath(); Client client = (Client)this.getOptional(context, Client.class); // 省略..... return targeter.target(this, builder, context, new HardCodedTarget(this.type, this.name, url)); } }
在loadBalance方法中,首先会创建一个HardCodedTarget对象,其中封装了Feign 客户端接口的类型、请求url、名称。
4. 生成代理对象接着进入到loadBalance方法,生成代理对象。
protectedT loadBalance(Builder builder, FeignContext context, HardCodedTarget target) { // 创建客户端 Client client = (Client)this.getOptional(context, Client.class); if (client != null) { // builder.client(client); // 生成代理对象 Targeter targeter = (Targeter)this.get(context, Targeter.class); return targeter.target(this, builder, context, target); } else { throw new IllegalStateException("No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?"); } }
默认使用的是HystrixTargeter:
publicT target(FeignClientFactoryBean factory, Builder feign, FeignContext context, HardCodedTarget target) { // 没有使用hystric 直接创建Feign 的 if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) { return feign.target(target); } else { // 省略 // 使用的hystric 会设置fallback return fallbackFactory != Void.TYPE ? this.targetWithFallbackFactory(name, context, target, builder, fallbackFactory) : feign.target(target); } } }
直接调用的是构建者Builder 的newInstance方法为目标创建实例:
publicT target(Target target) { // 直接newInstance return this.build().newInstance(target); }
在newInstance方法中,会为当前接口下每个方法创建方法处理器,然后再使用Proxy创建动态代理对象。
publicT newInstance(Target target) { // 创建方法处理器,每个方法对应一个MethodHandler 实现类 Map nameToHandler = this.targetToHandlersByName.apply(target); Map methodToHandler = new linkedHashMap(); List defaultMethodHandlers = new linkedList(); Method[] var5 = target.type().getMethods(); int var6 = var5.length; // 循环方法Method 创建处理器 for(int var7 = 0; var7 < var6; ++var7) { Method method = var5[var7]; if (method.getDeclaringClass() != Object.class) { if (Util.isDefault(method)) { DefaultMethodHandler handler = new DefaultMethodHandler(method); defaultMethodHandlers.add(handler); methodToHandler.put(method, handler); } else { methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method))); } } } InvocationHandler handler = this.factory.create(target, methodToHandler); // 创建代理对象 T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler); Iterator var12 = defaultMethodHandlers.iterator(); while(var12.hasNext()) { DefaultMethodHandler defaultMethodHandler = (DefaultMethodHandler)var12.next(); defaultMethodHandler.bindTo(proxy); } return proxy; }
最终,该实例放入到了IOC中。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)