DefaultFeignLoadBalancedConfiguration解析及自定义ribbon负载均衡

132 阅读1分钟

代码的入口FeignClientFactoryBean 这是一个factoryBean 入口方法getObject() 里面调用的是getTarget()方法

 <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));
}

进入loadBalance代码

  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?");
	}

可以看到获取client的方法getOptional。 如果有自定义的负载均衡例如

public class LocalLoadBalancerFeignClient extends LoadBalancerFeignClient {
  
    public LocalLoadBalancerFeignClient(Client delegate, CachingSpringLoadBalancerFactory lbClientFactory, SpringClientFactory clientFactory) {
        super(delegate, lbClientFactory, clientFactory);
    }

    @Override
    public Response execute(Request request, Request.Options options) throws IOException {
        
        ......

        return getResponse(request, options, url.replaceFirst(clientName, configUrl).replace("http:",protocol));
    }

    private Response getResponse(Request request, Request.Options options, String newUrl) throws IOException {
        Request newRequest = Request.create(request.httpMethod(),
                newUrl, request.headers(), request.body(),
                request.charset());
        return defaultClient.execute(newRequest, options);
    }
}

如果能找到自定义的路由规则,优先走自定义的

    @Bean
    public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
                              SpringClientFactory clientFactory, @Autowired(required = false) DiscoveryClient discoveryClient) {
        return new LocalLoadBalancerFeignClient(new Client.Default(null, null),
                cachingFactory, clientFactory);
    }

当没有自定义的时候走default的ribbon的负载均衡,生成client。通过ConditionalOnMissingBean来实现,当没有发现本地的client实现的时候就用该默认的client。

@Configuration(proxyBeanMethods = false)
class DefaultFeignLoadBalancedConfiguration {

	@Bean
	@ConditionalOnMissingBean
	public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
			SpringClientFactory clientFactory) {
		return new LoadBalancerFeignClient(new Client.Default(null, null), cachingFactory,
				clientFactory);
	}

}