基于代理模式构建Feign.Builder
FeignClientFactoryBean
上一篇文章中,我们完成了Feign相关包以及组件扫描相关源码的阅读,这一节开始进行FeignClient相关组件的初始化,即通过代理模式生成相关的Bean.入口类为FeignClientFactoryBean,本篇主要讲解如下内容
目录
- 完成Feign.Builder的构建
- 构建动态代理与LoadBalancerFeignClient
1.动态代理构建Feign.Builder
FeignClientFactoryBean
1.1.核心入口方法
和阅读其他源码的套路一样,我们先看@Override相关的方法,找到如下
@Overridepublic Object getObject() throws Exception {return getTarget();}
下面我们来看这个核心方法的实现,代码片段如下
<T> T getTarget() {FeignContext context = this.applicationContext.getBean(FeignContext.class);Feign.Builder builder = feign(context);//因为没有在@FeignClient中指定url,因此会走下面的逻辑if (!StringUtils.hasText(this.url)) {if (!this.name.startsWith("http")) {this.url = "http://" + this.name;}else {this.url = this.name;}this.url += cleanPath();return (T) loadBalance(builder, context,new HardCodedTarget<>(this.type, this.name, this.url));}.....}
FeignContext
在
FeignAutoConfiguration中找到了FeignContext的初始化
@Beanpublic FeignContext feignContext() {FeignContext context = new FeignContext();context.setConfigurations(this.configurations);return context;}
FeignContext内部维护了一个map,key为服务名,value是对应的spring容器
初始化的时候分别将decoder,encoder,logger等组件全部放到该map中
1.2.构建Feign.Builder
feign(context);
protected Feign.Builder feign(FeignContext context) {FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);Logger logger = loggerFactory.create(this.type);//创建Slf4jLogger// @formatter:offFeign.Builder builder = get(context, Feign.Builder.class)// required values.logger(logger).encoder(get(context, Encoder.class))//从FeignContext中获取ResponseEntityDecoder.decoder(get(context, Decoder.class)).contract(get(context, Contract.class));// @formatter:on//加载配置文件configureFeign(context, builder);return builder;}
- 从
FeignContext中获取到Feign.Builder对应的组件- logger:Slf4jLogger,通过Factory创建
- Encoder:SpringEncoder
- Decoder
- Contract
- 读取配置文件,优先级从低到高
- 自定义配置类,若有,低
- default配置,中
- 指定服务的配置: 高

2.基于Feign.Builder构建FeignClient
这里创建的是
LoadBalancerFeignClient
HardCodedTarget
public static class HardCodedTarget<T> implements Target<T> {private final Class<T> type;private final String name;private final String url;}
在我们这里的HardCodedTarget的属性分别是
- type: OrderClient,即对于的FeignClient
- name:
SERVICE-ORDER - url:
http://SERVICE-ORDER
Client client = getOptional(context, Client.class);
protected <T> T getOptional(FeignContext context, Class<T> type) {
return context.getInstance(this.contextId, type);
}
从FeignContext中获取到LoadBalancerFeignClient,之后将该client设置到builder中

这一步我们完成了图中最下面这部分逻辑,即将服务名,URL,对应的client类型构建一个Client->LoadBalancerFeignClient,绑定到Feign.Builder上
2.创建动态代理对象的细节
HystrixTargeter.target()
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
return feign.target(target);
}
}
这里的Builder是Feign.Builder,因此会走上面的逻辑.最终通过feign.target(target)走如下流程
public <T> T newInstance(Target<T> target) {
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
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 {
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
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;
}
2.1.基于SpringMVCContract解析方法的定义
第一行代码 Map
nameToHandler = targetToHandlersByName.apply(target); 该方法主要是将FeignClient中对应的多个请求接口转化为 MethodHandler
public Map<String, MethodHandler> apply(Target target) {
List<MethodMetadata> metadata = contract.parseAndValidateMetadata(target.type());
Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
for (MethodMetadata md : metadata) {
BuildTemplateByResolvingArgs buildTemplate;
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
buildTemplate =
new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
} else if (md.bodyIndex() != null) {
buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
} else {
buildTemplate = new BuildTemplateByResolvingArgs(md, 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(),
factory.create(target, md, buildTemplate, options, decoder, errorDecoder));
}
}
return result;
}
}


其中MethodHandler中包含的内容如上,
- key即为对应FeignClient中的请求接口,
- Client是和Ribbon整合的一个接口调用组件,即
LoadBalancerFeignClient - 这里创建处理的
MethodHandler是SynchronousMethodHandler

