聊聊spring-cloud的CachingSpringLoadBalancerFactory

12次阅读

共计 4510 个字符,预计需要花费 12 分钟才能阅读完成。

本文主要研究一下 spring cloud 的 CachingSpringLoadBalancerFactory

CachingSpringLoadBalancerFactory

spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/openfeign/ribbon/CachingSpringLoadBalancerFactory.java

public class CachingSpringLoadBalancerFactory {

    protected final SpringClientFactory factory;

    protected LoadBalancedRetryFactory loadBalancedRetryFactory = null;

    private volatile Map<String, FeignLoadBalancer> cache = new ConcurrentReferenceHashMap<>();

    public CachingSpringLoadBalancerFactory(SpringClientFactory factory) {this.factory = factory;}

    public CachingSpringLoadBalancerFactory(SpringClientFactory factory,
            LoadBalancedRetryFactory loadBalancedRetryPolicyFactory) {
        this.factory = factory;
        this.loadBalancedRetryFactory = loadBalancedRetryPolicyFactory;
    }

    public FeignLoadBalancer create(String clientName) {FeignLoadBalancer client = this.cache.get(clientName);
        if (client != null) {return client;}
        IClientConfig config = this.factory.getClientConfig(clientName);
        ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
        ServerIntrospector serverIntrospector = this.factory.getInstance(clientName,
                ServerIntrospector.class);
        client = this.loadBalancedRetryFactory != null
                ? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,
                        this.loadBalancedRetryFactory)
                : new FeignLoadBalancer(lb, config, serverIntrospector);
        this.cache.put(clientName, client);
        return client;
    }

}
  • CachingSpringLoadBalancerFactory 的构造器接收 SpringClientFactory、LoadBalancedRetryFactory;它提供了 create 方法用于创建 FeignLoadBalancer;其 create 方法使用 ConcurrentReferenceHashMap 来缓存每个 client 对应的 FeignLoadBalancer

LoadBalancerFeignClient

spring-cloud-openfeign-core-2.2.0.M1-sources.jar!/org/springframework/cloud/openfeign/ribbon/LoadBalancerFeignClient.java

public class LoadBalancerFeignClient implements Client {static final Request.Options DEFAULT_OPTIONS = new Request.Options();

    private final Client delegate;

    private CachingSpringLoadBalancerFactory lbClientFactory;

    private SpringClientFactory clientFactory;

    public LoadBalancerFeignClient(Client delegate,
            CachingSpringLoadBalancerFactory lbClientFactory,
            SpringClientFactory clientFactory) {
        this.delegate = delegate;
        this.lbClientFactory = lbClientFactory;
        this.clientFactory = clientFactory;
    }

    static URI cleanUrl(String originalUrl, String host) {
        String newUrl = originalUrl;
        if (originalUrl.startsWith("https://")) {newUrl = originalUrl.substring(0, 8)
                    + originalUrl.substring(8 + host.length());
        }
        else if (originalUrl.startsWith("http")) {newUrl = originalUrl.substring(0, 7)
                    + originalUrl.substring(7 + host.length());
        }
        StringBuffer buffer = new StringBuffer(newUrl);
        if ((newUrl.startsWith("https://") && newUrl.length() == 8)
                || (newUrl.startsWith("http://") && newUrl.length() == 7)) {buffer.append("/");
        }
        return URI.create(buffer.toString());
    }

    @Override
    public Response execute(Request request, Request.Options options) throws IOException {
        try {URI asUri = URI.create(request.url());
            String clientName = asUri.getHost();
            URI uriWithoutHost = cleanUrl(request.url(), clientName);
            FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(this.delegate, request, uriWithoutHost);

            IClientConfig requestConfig = getClientConfig(options, clientName);
            return lbClient(clientName)
                    .executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();}
        catch (ClientException e) {IOException io = findIOException(e);
            if (io != null) {throw io;}
            throw new RuntimeException(e);
        }
    }

    IClientConfig getClientConfig(Request.Options options, String clientName) {
        IClientConfig requestConfig;
        if (options == DEFAULT_OPTIONS) {requestConfig = this.clientFactory.getClientConfig(clientName);
        }
        else {requestConfig = new FeignOptionsClientConfig(options);
        }
        return requestConfig;
    }

    protected IOException findIOException(Throwable t) {if (t == null) {return null;}
        if (t instanceof IOException) {return (IOException) t;
        }
        return findIOException(t.getCause());
    }

    public Client getDelegate() {return this.delegate;}

    private FeignLoadBalancer lbClient(String clientName) {return this.lbClientFactory.create(clientName);
    }

    static class FeignOptionsClientConfig extends DefaultClientConfigImpl {FeignOptionsClientConfig(Request.Options options) {
            setProperty(CommonClientConfigKey.ConnectTimeout,
                    options.connectTimeoutMillis());
            setProperty(CommonClientConfigKey.ReadTimeout, options.readTimeoutMillis());
        }

        @Override
        public void loadProperties(String clientName) { }

        @Override
        public void loadDefaultValues() {}

    }

}
  • LoadBalancerFeignClient 的 lbClient 方法使用 CachingSpringLoadBalancerFactory 的 create 方法来创建 FeignLoadBalancer;而 execute 方法则调用了 lbClient 方法来获取 FeignLoadBalancer

小结

CachingSpringLoadBalancerFactory 的构造器接收 SpringClientFactory、LoadBalancedRetryFactory;它提供了 create 方法用于创建 FeignLoadBalancer;其 create 方法使用 ConcurrentReferenceHashMap 来缓存每个 client 对应的 FeignLoadBalancer

doc

  • CachingSpringLoadBalancerFactory
正文完
 0