计算机系统应用教程网站

网站首页 > 技术文章 正文

SpringCloud FeignClient底层实现原理(二)

btikc 2024-09-10 12:02:02 技术文章 14 ℃ 0 评论


在上一篇文章中我们分析到了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);
}

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表