Ribbon改写请求uri的源码分析

进入RestTemplate的execute方法,其调用了自身的doExecute方法,在doExecute方法中通过createRequest方法创建了ClientHttpRequest对象,通过类名称,我们就可以知道这是一个发起http请求的封装类。那么在createRequest方法中RestTemplate做了哪些事情?

@Nullable
public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Object... uriVariables) throws RestClientException {
    URI expanded = this.getUriTemplateHandler().expand(url, uriVariables);
    return this.doExecute(expanded, method, requestCallback, responseExtractor);
}
@Nullable
protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
    Assert.notNull(url, "URI is required");
    Assert.notNull(method, "HttpMethod is required");
    ClientHttpResponse response = null;

    Object resource1;
    try {
         //创建发起http请求的封装对象
        ClientHttpRequest ex = this.createRequest(url, method);
        if(requestCallback != null) {
            requestCallback.doWithRequest(ex);
        }

        response = ex.execute();
        this.handleResponse(url, method, response);
        resource1 = responseExtractor != null?responseExtractor.extractData(response):null;
    } catch (IOException var12) {
        String resource = url.toString();
        String query = url.getRawQuery();
        resource = query != null?resource.substring(0, resource.indexOf(63)):resource;
        throw new ResourceAccessException("I/O error on " + method.name() + " request for \"" + resource + "\": " + var12.getMessage(), var12);
    } finally {
        if(response != null) {
            response.close();
        }

    }

    return resource1;
}

进入createRequest方法,它是RestTemplate顶级父类HttpAccessor中的方法,主要逻辑为获取RequestFactory后,通过url创建ClientHttpRequest,查看getRequestFactory方法,HttpAccessor中getRequestFactory只是直接返回了requestFactory成员变量,RestTemplate的父类InterceptingHttpAccessor重写了getRequestFactory方法,所以调用的实际是InterceptingHttpAccessor的getRequestFactory

protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
    ClientHttpRequest request = this.getRequestFactory().createRequest(url, method);
    this.initialize(request);
    if(this.logger.isDebugEnabled()) {
        this.logger.debug("HTTP " + method.name() + " " + url);
    }

    return request;
}
public ClientHttpRequestFactory getRequestFactory() {
    return this.requestFactory;
}

进入InterceptingHttpAccessor的getRequestFactory方法中,它会调用自己的getInterceptors方法(返回interceptors 成员变量,即拦截器列表),并添加interceptors到创建的InterceptingClientHttpRequestFactory对象中,拦截器列表默认为空列表,可以通过InterceptingHttpAccessor.setInterceptors方法添加拦截器,那么这个setInterceptors是在哪里调用的呢?

public ClientHttpRequestFactory getRequestFactory() {
    List interceptors = this.getInterceptors();
    if(!CollectionUtils.isEmpty(interceptors)) {
        Object factory = this.interceptingRequestFactory;
        if(factory == null) {
            factory = new InterceptingClientHttpRequestFactory(super.getRequestFactory(), interceptors);
            this.interceptingRequestFactory = (ClientHttpRequestFactory)factory;
        }

        return (ClientHttpRequestFactory)factory;
    } else {
        return super.getRequestFactory();
    }
}
public List<ClientHttpRequestInterceptor> getInterceptors() {
    return this.interceptors;
}
public void setInterceptors(List<ClientHttpRequestInterceptor> interceptors) {
    if(this.interceptors != interceptors) {
        this.interceptors.clear();
        this.interceptors.addAll(interceptors);
        AnnotationAwareOrderComparator.sort(this.interceptors);
    }

}

LoadBalancerAutoConfifiguration.LoadBalancerInterceptorConfig配置类中有一个restTemplateCustomizer方法,其调用了setInterceptors方法,并且添加了LoadBalancerInterceptor到restTemplate的拦截器列表中,我们先记住这里向RestTemplate中设置了LoadBalancerInterceptor拦截器。

@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(LoadBalancerInterceptor loadBalancerInterceptor) {
    return (restTemplate) -> {
        ArrayList list = new ArrayList(restTemplate.getInterceptors());
        list.add(loadBalancerInterceptor);
        restTemplate.setInterceptors(list);
    };
}

回到HttpAccessor的createRequest中,获取了RequestFactory(InterceptingClientHttpRequestFactory)后,调用了InterceptingClientHttpRequestFactory.createRequest方法,创建了InterceptingClientHttpRequest,它设置了interceptors成员变量。

protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
    ClientHttpRequest request = this.getRequestFactory().createRequest(url, method);
    this.initialize(request);
    if(this.logger.isDebugEnabled()) {
        this.logger.debug("HTTP " + method.name() + " " + url);
    }

    return request;
}
protected ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod, ClientHttpRequestFactory requestFactory) {
    return new InterceptingClientHttpRequest(requestFactory, this.interceptors, uri, httpMethod);
}

 

回到RestTemplate的doExecute方法中,会调用 ex.execute()方法,即InterceptingClientHttpRequest父类AbstractClientHttpRequestexecute方法,

public final ClientHttpResponse execute() throws IOException {
    this.assertNotExecuted();
    ClientHttpResponse result = this.executeInternal(this.headers);
    this.executed = true;
    return result;
}

最终会调用InterceptingClientHttpRequest的executeInternal方法

protected final ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
    InterceptingClientHttpRequest.InterceptingRequestExecution requestExecution = new InterceptingClientHttpRequest.InterceptingRequestExecution();
    return requestExecution.execute(this, bufferedOutput);
}
public InterceptingRequestExecution() { 
     this.iterator = InterceptingClientHttpRequest.this.interceptors.iterator(); 
}
public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
    if(this.iterator.hasNext()) {
        //这里拿到的就是拦截器列表的迭代器
        ClientHttpRequestInterceptor method1 = (ClientHttpRequestInterceptor)this.iterator.next();
        return method1.intercept(request, body, this);
    } else {
        HttpMethod method = request.getMethod();
        Assert.state(method != null, "No standard HTTP method");
        ClientHttpRequest delegate = InterceptingClientHttpRequest.this.requestFactory.createRequest(request.getURI(), method);
        request.getHeaders().forEach((key, value) -> {
            delegate.getHeaders().addAll(key, value);
        });
        if(body.length > 0) {
            if(delegate instanceof StreamingHttpOutputMessage) {
                StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage)delegate;
                streamingOutputMessage.setBody((outputStream) -> {
                    StreamUtils.copy(body, outputStream);
                });
            } else {
                StreamUtils.copy(body, delegate.getBody());
            }
        }

        return delegate.execute();
    }
}

 InterceptingClientHttpRequest.execute的主要逻辑为,如果存在ClientHttpRequestInterceptor 拦截器列表,依次调用拦截器的intercept方法(这里实现依次调用的方式后面分析),在上面的分析中已经提到,向InterceptingClientHttpRequest.this.interceptors中添加了LoadBalancerInterceptor,查看LoadBalancerInterceptor.intercept方法,主要逻辑为,获取请求的uri,通过uri获取请求的服务服务名名称,调用LoadBalancerClient的execute发起请求,获取请求的结果,那么这里的loadBalancer是具体是那个实现类,怎么注入的?

public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
    URI originalUri = request.getURI();//获得请求的URI 
    String serviceName = originalUri.getHost();//获得服务名称
    Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
    return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
}@Bean
public LoadBalancerInterceptor ribbonInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {
    return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}

 重新查看LoadBalancerAutoConfiguration.ribbonInterceptor方法,在创建LoadBalancerInterceptor的时候,通过构造函数传入了LoadBalancerClient ,在RibbonAutoConfiguration.loadBalancerClient方法中创建了RibbonLoadBalancerClient对象,所以LoadBalancerInterceptor.intercept最终调用了RibbonLoadBalancerClient的execute方法。

@Bean
@ConditionalOnMissingBean({LoadBalancerClient.class})
public LoadBalancerClient loadBalancerClient() {
    return new RibbonLoadBalancerClient(this.springClientFactory());
}

RibbonLoadBalancerClient.execute方法的主要逻辑为,根据serviceId获得一个ILoadBalancer,通过ILoadBalancer选择可用的服务器,ILoadBalancer是通过RibbonClientConfiguration.ribbonLoadBalancer方法创建的,默认为ZoneAwareLoadBalancer类型。

public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
    return this.execute(serviceId, (LoadBalancerRequest)request, (Object)null);
}

public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException {
    //根据serviceId获得一个ILoadBalancer
    ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
    //通过ILoadBalancer选择可用的服务器
    Server server = this.getServer(loadBalancer, hint);
    if(server == null) {
        throw new IllegalStateException("No instances available for " + serviceId);
    } else {
        RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
        return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
    }
}
protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
    return loadBalancer == null?null:loadBalancer.chooseServer(hint != null?hint:"default");
}
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config, ServerList<Server> serverList, ServerListFilter<Server> serverListFilter, IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
    return (ILoadBalancer)(this.propertiesFactory.isSet(ILoadBalancer.class, this.name)?(ILoadBalancer)this.propertiesFactory.get(ILoadBalancer.class, config, this.name):new ZoneAwareLoadBalancer(config, rule, ping, serverList, serverListFilter, serverListUpdater));
}
RibbonLoadBalancerClient.execute方法会调用另外一个execute重载方法,在这个方法中最终会调用LoadBalancerRequest.apply方法,而这个LoadBalancerRequest是在LoadBalancerInterceptor.intercept方法中调用LoadBalancerRequestFactory.createRequest方法
创建的

 

public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
    Server server = null;
    if(serviceInstance instanceof RibbonLoadBalancerClient.RibbonServer) {
        //
        server = ((RibbonLoadBalancerClient.RibbonServer)serviceInstance).getServer();
    }

    if(server == null) {
        throw new IllegalStateException("No instances available for " + serviceId);
    } else {
        RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId);
        RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);

        try {
            Object ex = request.apply(serviceInstance);
            statsRecorder.recordStats(ex);
            return ex;
        } catch (IOException var8) {
            statsRecorder.recordStats(var8);
            throw var8;
        } catch (Exception var9) {
            statsRecorder.recordStats(var9);
            ReflectionUtils.rethrowRuntimeException(var9);
            return null;
        }
    }
}
public LoadBalancerRequest<ClientHttpResponse> createRequest(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) {
    return (instance) -> {
        Object serviceRequest = new ServiceRequestWrapper(request, instance, this.loadBalancer);
        LoadBalancerRequestTransformer transformer;
        if(this.transformers != null) {
            for(Iterator var6 = this.transformers.iterator(); var6.hasNext(); serviceRequest = transformer.transformRequest((HttpRequest)serviceRequest, instance)) {
                transformer = (LoadBalancerRequestTransformer)var6.next();
            }
        }

        return execution.execute((HttpRequest)serviceRequest, body);
    };
}

查看LoadBalancerRequestFactory.createRequest方法,创建了一个ServiceRequestWrapper,对HttpRequest做了封装,ServiceRequestWrapper重写了getURI方法,所以LoadBalancerRequest.apply会调用ClientHttpRequestExecution.execute方法,即InterceptingClientHttpRequest.InterceptingRequestExecution.execute达到链式调用拦截器的目的,

public class ServiceRequestWrapper extends HttpRequestWrapper {
    private final ServiceInstance instance;
    private final LoadBalancerClient loadBalancer;

    public ServiceRequestWrapper(HttpRequest request, ServiceInstance instance, LoadBalancerClient loadBalancer) {
        super(request);
        this.instance = instance;
        this.loadBalancer = loadBalancer;
    }

    public URI getURI() {
        URI uri = this.loadBalancer.reconstructURI(this.instance, this.getRequest().getURI());
        return uri;
    }
}
ServiceRequestWrapper.getURI方法调用了RibbonLoadBalancerClient.reconstructURI即RibbonLoadBalancerClient.reconstructURI方法,
public URI reconstructURI(ServiceInstance instance, URI original) {
    Assert.notNull(instance, "instance can not be null");
    String serviceId = instance.getServiceId();
    RibbonLoadBalancerContext context = this.clientFactory.getLoadBalancerContext(serviceId);
    URI uri;
    Server server;
    if(instance instanceof RibbonLoadBalancerClient.RibbonServer) {
        RibbonLoadBalancerClient.RibbonServer clientConfig = (RibbonLoadBalancerClient.RibbonServer)instance;
        server = clientConfig.getServer();
        uri = RibbonUtils.updateToSecureConnectionIfNeeded(original, clientConfig);
    } else {
        server = new Server(instance.getScheme(), instance.getHost(), instance.getPort());
        IClientConfig clientConfig1 = this.clientFactory.getClientConfig(serviceId);
        ServerIntrospector serverIntrospector = this.serverIntrospector(serviceId);
        uri = RibbonUtils.updateToSecureConnectionIfNeeded(original, clientConfig1, serverIntrospector, server);
    }

    return context.reconstructURIWithServer(server, uri);
}

最终调用LoadBalancerContext.reconstructURIWithServer对URI进行改写,改写的主要逻辑就是拿到LoadBalancer选择的服务器的host、port,和原请求的path,拼接成新的uri,完成改写,这样当正式发起http请求,会使用改写后的uri,完成具体的调用

public URI reconstructURIWithServer(Server server, URI original) {
    String host = server.getHost();
    int port = server.getPort();
    String scheme = server.getScheme();
    if(host.equals(original.getHost()) && port == original.getPort() && scheme == original.getScheme()) {
        return original;
    } else {
        if(scheme == null) {
            scheme = original.getScheme();
        }

        if(scheme == null) {
            scheme = (String)this.deriveSchemeAndPortFromPartialUri(original).first();
        }

        try {
            StringBuilder e = new StringBuilder();
            e.append(scheme).append("://");
            if(!Strings.isNullOrEmpty(original.getRawUserInfo())) {
                e.append(original.getRawUserInfo()).append("@");
            }

            e.append(host);
            if(port >= 0) {
                e.append(":").append(port);
            }

            e.append(original.getRawPath());
            if(!Strings.isNullOrEmpty(original.getRawQuery())) {
                e.append("?").append(original.getRawQuery());
            }

            if(!Strings.isNullOrEmpty(original.getRawFragment())) {
                e.append("#").append(original.getRawFragment());
            }

            URI newURI = new URI(e.toString());
            return newURI;
        } catch (URISyntaxException var8) {
            throw new RuntimeException(var8);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值