From 3bfc291d773f2624ba970446e1e03dee8b303393 Mon Sep 17 00:00:00 2001 From: Olga Maciaszek-Sharma Date: Wed, 20 Apr 2022 17:29:20 +0200 Subject: [PATCH] Add HttpRequestLoadBalancerRequest, DefaultLoadBalancerRequest and DefaultAsyncLoadBalancerRequest. --- .../AsyncLoadBalancerInterceptor.java | 7 +- .../DefaultAsyncLoadBalancerRequest.java | 66 ++++++++++++++++ .../DefaultLoadBalancerRequest.java | 76 +++++++++++++++++++ .../HttpRequestLoadBalancerRequest.java | 28 +++++++ .../LoadBalancerRequestFactory.java | 17 ++--- .../client/BlockingLoadBalancerClient.java | 20 ++++- 6 files changed, 196 insertions(+), 18 deletions(-) create mode 100644 spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/DefaultAsyncLoadBalancerRequest.java create mode 100644 spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/DefaultLoadBalancerRequest.java create mode 100644 spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/HttpRequestLoadBalancerRequest.java diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/AsyncLoadBalancerInterceptor.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/AsyncLoadBalancerInterceptor.java index 6d00965d..8d2391b9 100644 --- a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/AsyncLoadBalancerInterceptor.java +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/AsyncLoadBalancerInterceptor.java @@ -41,11 +41,8 @@ public class AsyncLoadBalancerInterceptor implements AsyncClientHttpRequestInter final AsyncClientHttpRequestExecution execution) throws IOException { final URI originalUri = request.getURI(); String serviceName = originalUri.getHost(); - return this.loadBalancer.execute(serviceName, instance -> { - HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, - AsyncLoadBalancerInterceptor.this.loadBalancer); - return execution.executeAsync(serviceRequest, body); - }); + return this.loadBalancer.execute(serviceName, new DefaultAsyncLoadBalancerRequest(loadBalancer, + new DefaultAsyncLoadBalancerRequest.ClientHttpRequestData(request, body, execution))); } } diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/DefaultAsyncLoadBalancerRequest.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/DefaultAsyncLoadBalancerRequest.java new file mode 100644 index 00000000..24a21f4d --- /dev/null +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/DefaultAsyncLoadBalancerRequest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.client.loadbalancer; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.AsyncClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.util.concurrent.ListenableFuture; + +/** + * @author Olga Maciaszek-Sharma + */ +class DefaultAsyncLoadBalancerRequest implements HttpRequestLoadBalancerRequest> { + + private final LoadBalancerClient loadBalancer; + + private final ClientHttpRequestData clientHttpRequestData; + + DefaultAsyncLoadBalancerRequest(LoadBalancerClient loadBalancer, ClientHttpRequestData clientHttpRequestData) { + this.loadBalancer = loadBalancer; + this.clientHttpRequestData = clientHttpRequestData; + } + + @Override + public ListenableFuture apply(ServiceInstance instance) throws Exception { + HttpRequest serviceRequest = new ServiceRequestWrapper(clientHttpRequestData.request, instance, loadBalancer); + return clientHttpRequestData.execution.executeAsync(serviceRequest, clientHttpRequestData.body); + } + + @Override + public HttpRequest getHttpRequest() { + return clientHttpRequestData.request; + } + + static class ClientHttpRequestData { + + private final HttpRequest request; + + private final byte[] body; + + private final AsyncClientHttpRequestExecution execution; + + ClientHttpRequestData(HttpRequest request, byte[] body, AsyncClientHttpRequestExecution execution) { + this.request = request; + this.body = body; + this.execution = execution; + } + + } + +} diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/DefaultLoadBalancerRequest.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/DefaultLoadBalancerRequest.java new file mode 100644 index 00000000..59433945 --- /dev/null +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/DefaultLoadBalancerRequest.java @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.client.loadbalancer; + +import java.util.List; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpResponse; + +/** + * @author Olga Maciaszek-Sharma + */ +class DefaultLoadBalancerRequest implements HttpRequestLoadBalancerRequest { + + private final LoadBalancerClient loadBalancer; + + private final List transformers; + + private final ClientHttpRequestData clientHttpRequestData; + + DefaultLoadBalancerRequest(LoadBalancerClient loadBalancer, List transformers, + ClientHttpRequestData clientHttpRequestData) { + this.loadBalancer = loadBalancer; + this.transformers = transformers; + this.clientHttpRequestData = clientHttpRequestData; + } + + @Override + public ClientHttpResponse apply(ServiceInstance instance) throws Exception { + HttpRequest serviceRequest = new ServiceRequestWrapper(clientHttpRequestData.request, instance, loadBalancer); + if (this.transformers != null) { + for (LoadBalancerRequestTransformer transformer : this.transformers) { + serviceRequest = transformer.transformRequest(serviceRequest, instance); + } + } + return clientHttpRequestData.execution.execute(serviceRequest, clientHttpRequestData.body); + } + + @Override + public HttpRequest getHttpRequest() { + return clientHttpRequestData.request; + } + + static class ClientHttpRequestData { + + private final HttpRequest request; + + private final byte[] body; + + private final ClientHttpRequestExecution execution; + + ClientHttpRequestData(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) { + this.request = request; + this.body = body; + this.execution = execution; + } + + } + +} diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/HttpRequestLoadBalancerRequest.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/HttpRequestLoadBalancerRequest.java new file mode 100644 index 00000000..2a821768 --- /dev/null +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/HttpRequestLoadBalancerRequest.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.client.loadbalancer; + +import org.springframework.http.HttpRequest; + +/** + * @author Olga Maciaszek-Sharma + */ +public interface HttpRequestLoadBalancerRequest extends LoadBalancerRequest { + + HttpRequest getHttpRequest(); + +} diff --git a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRequestFactory.java b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRequestFactory.java index 2e45bd63..5ec9bdc0 100644 --- a/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRequestFactory.java +++ b/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRequestFactory.java @@ -16,6 +16,7 @@ package org.springframework.cloud.client.loadbalancer; +import java.util.ArrayList; import java.util.List; import org.springframework.http.HttpRequest; @@ -32,9 +33,9 @@ import org.springframework.http.client.ClientHttpResponse; */ public class LoadBalancerRequestFactory { - private LoadBalancerClient loadBalancer; + private final LoadBalancerClient loadBalancer; - private List transformers; + private final List transformers; public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer, List transformers) { @@ -44,19 +45,13 @@ public class LoadBalancerRequestFactory { public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer) { this.loadBalancer = loadBalancer; + transformers = new ArrayList<>(); } public LoadBalancerRequest createRequest(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) { - return instance -> { - HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, this.loadBalancer); - if (this.transformers != null) { - for (LoadBalancerRequestTransformer transformer : this.transformers) { - serviceRequest = transformer.transformRequest(serviceRequest, instance); - } - } - return execution.execute(serviceRequest, body); - }; + return new DefaultLoadBalancerRequest(loadBalancer, transformers, + new DefaultLoadBalancerRequest.ClientHttpRequestData(request, body, execution)); } } diff --git a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/blocking/client/BlockingLoadBalancerClient.java b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/blocking/client/BlockingLoadBalancerClient.java index e689588b..0beb8177 100644 --- a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/blocking/client/BlockingLoadBalancerClient.java +++ b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/blocking/client/BlockingLoadBalancerClient.java @@ -28,6 +28,7 @@ import org.springframework.cloud.client.loadbalancer.DefaultRequest; import org.springframework.cloud.client.loadbalancer.DefaultRequestContext; import org.springframework.cloud.client.loadbalancer.DefaultResponse; import org.springframework.cloud.client.loadbalancer.EmptyResponse; +import org.springframework.cloud.client.loadbalancer.HttpRequestLoadBalancerRequest; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.client.loadbalancer.LoadBalancerLifecycle; import org.springframework.cloud.client.loadbalancer.LoadBalancerLifecycleValidator; @@ -36,10 +37,14 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest; import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestAdapter; import org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools; import org.springframework.cloud.client.loadbalancer.Request; +import org.springframework.cloud.client.loadbalancer.RequestData; +import org.springframework.cloud.client.loadbalancer.RequestDataContext; import org.springframework.cloud.client.loadbalancer.Response; import org.springframework.cloud.client.loadbalancer.ResponseData; +import org.springframework.cloud.client.loadbalancer.TimedRequestContext; import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer; import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory; +import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpResponse; import org.springframework.util.ReflectionUtils; @@ -68,8 +73,8 @@ public class BlockingLoadBalancerClient implements LoadBalancerClient { @Override public T execute(String serviceId, LoadBalancerRequest request) throws IOException { String hint = getHint(serviceId); - LoadBalancerRequestAdapter lbRequest = new LoadBalancerRequestAdapter<>(request, - new DefaultRequestContext(request, hint)); + LoadBalancerRequestAdapter lbRequest = new LoadBalancerRequestAdapter<>(request, + buildRequestContext(request, hint)); Set supportedLifecycleProcessors = getSupportedLifecycleProcessors(serviceId); supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest)); ServiceInstance serviceInstance = choose(serviceId, lbRequest); @@ -81,6 +86,17 @@ public class BlockingLoadBalancerClient implements LoadBalancerClient { return execute(serviceId, serviceInstance, lbRequest); } + private TimedRequestContext buildRequestContext(LoadBalancerRequest delegate, String hint) { + if (delegate instanceof HttpRequestLoadBalancerRequest) { + HttpRequest request = ((HttpRequestLoadBalancerRequest) delegate).getHttpRequest(); + if (request != null) { + RequestData requestData = new RequestData(request); + return new RequestDataContext(requestData, hint); + } + } + return new DefaultRequestContext(delegate, hint); + } + @Override public T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest request) throws IOException {