在上一篇文章中我们分析到了FeignClientFactoryBean的getTarget方法,该方法中我们先分析下loadBalance方法
<T> T getTarget() {
FeignContext context = this.applicationContext.getBean(FeignContext.class);
Feign.Builder builder = feign(context);
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));
}
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
this.url = "http://" + this.url;
}
String url = this.url + cleanPath();
Client client = getOptional(context, Client.class);
if (client != null) {
if (client instanceof LoadBalancerFeignClient) {
// not load balancing because we have a url,
// but ribbon is on the classpath, so unwrap
client = ((LoadBalancerFeignClient) client).getDelegate();
}
if (client instanceof FeignBlockingLoadBalancerClient) {
// not load balancing because we have a url,
// but Spring Cloud LoadBalancer is on the classpath, so unwrap
client = ((FeignBlockingLoadBalancerClient) client).getDelegate();
}
builder.client(client);
}
Targeter targeter = get(context, Targeter.class);
return (T) targeter.target(this, builder, context,new HardCodedTarget<>(this.type, this.name, url));
}
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,HardCodedTarget<T> target) {
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
Targeter targeter = get(context, Targeter.class);
return targeter.target(this, builder, context, target);
}
throw new IllegalStateException("No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?");
}
loadBalance此方中通过 client = getOptional(context, Client.class) 获取负载均衡类为LoadBalancerFeignClient,LoadBalancerFeignClient类是通过spring-cloud-openfeign-core jar包中WEB-INF下spring.factories文件中配置,如果对于自动装配的原理不理解可以看我之前的文章
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfiguration
在获取到负载均衡的client后将该client更新到Feign.Builder中,然后获取target代理类为HystrixTargeter如果不进行任何配置默认还是会调用feign中的默认方法,接下来进入到target方法中进行分析,该方法中主要有通过jdk动态代理的方式进行最终的http request调用,主要流程为FeignInvocationHandler 获取SynchronousMethodHandler并调用SynchronousMethodHandler的invoke方法最终执行http请求的方法为executeAndDecode 在此不再贴code进行分析,有兴趣的读者可以查阅源码
public <T> T target(Target<T> target) {
return this.build().newInstance(target);
}
public Feign build() {
Client client = (Client)Capability.enrich(this.client, this.capabilities);
Retryer retryer = (Retryer)Capability.enrich(this.retryer, this.capabilities);
List<RequestInterceptor> requestInterceptors = (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);
}
本文暂时没有评论,来添加一个吧(●'◡'●)