This is an automated email from the ASF dual-hosted git repository.
Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new e6523de8c5 fix: avoid copying unused request data in LoadbalancerUtils
(#6578) (#7431)
e6523de8c5 is described below
commit e6523de8c5e2daefac76337b8d1caee99ddf36cd
Author: wy471x <[email protected]>
AuthorDate: Thu Oct 8 14:46:54 2026 +0800
fix: avoid copying unused request data in LoadbalancerUtils (#6578) (#7431)
---
.../loadbalancer/entity/LoadBalanceData.java | 10 ++--
.../loadbalancer/entity/LoadBalanceDataTest.java | 68 ++++++++++++++++++++++
.../plugin/base/utils/LoadbalancerUtils.java | 36 +++---------
.../plugin/base/utils/LoadbalancerUtilsTest.java | 31 ++++++++--
4 files changed, 106 insertions(+), 39 deletions(-)
diff --git
a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/LoadBalanceData.java
b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/LoadBalanceData.java
index b06ba56813..9a37d9cf31 100644
---
a/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/LoadBalanceData.java
+++
b/shenyu-loadbalancer/src/main/java/org/apache/shenyu/loadbalancer/entity/LoadBalanceData.java
@@ -19,7 +19,7 @@ package org.apache.shenyu.loadbalancer.entity;
import java.net.URI;
import java.util.Collection;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.Map;
/**
@@ -33,13 +33,13 @@ public class LoadBalanceData {
private URI url;
- private Map<String, Collection<String>> headers = new HashMap<>();
+ private Map<String, Collection<String>> headers = Collections.emptyMap();
- private Map<String, String> cookies = new HashMap<>();
+ private Map<String, String> cookies = Collections.emptyMap();
- private Map<String, Object> attributes = new HashMap<>();
+ private Map<String, Object> attributes = Collections.emptyMap();
- private Map<String, Collection<String>> queryParams = new HashMap<>();
+ private Map<String, Collection<String>> queryParams =
Collections.emptyMap();
/**
* Instantiates a new Load balance data.
diff --git
a/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/entity/LoadBalanceDataTest.java
b/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/entity/LoadBalanceDataTest.java
new file mode 100644
index 0000000000..87f5743fc9
--- /dev/null
+++
b/shenyu-loadbalancer/src/test/java/org/apache/shenyu/loadbalancer/entity/LoadBalanceDataTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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.apache.shenyu.loadbalancer.entity;
+
+import org.junit.jupiter.api.Test;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Test cases for LoadBalanceData.
+ */
+class LoadBalanceDataTest {
+
+ @Test
+ void defaultInstanceUsesSharedEmptyCollections() {
+ LoadBalanceData data = new LoadBalanceData();
+ assertEquals("GET", data.getHttpMethod());
+ assertEquals("127.0.0.1", data.getIp());
+ assertTrue(data.getHeaders().isEmpty());
+ assertTrue(data.getCookies().isEmpty());
+ assertTrue(data.getAttributes().isEmpty());
+ assertTrue(data.getQueryParams().isEmpty());
+ LoadBalanceData another = new LoadBalanceData();
+ assertSame(data.getHeaders(), another.getHeaders());
+ assertSame(data.getCookies(), another.getCookies());
+ assertSame(data.getAttributes(), another.getAttributes());
+ assertSame(data.getQueryParams(), another.getQueryParams());
+ }
+
+ @Test
+ void fullConstructorKeepsProvidedValues() {
+ Map<String, Collection<String>> headers =
Collections.singletonMap("key", Collections.singletonList("value"));
+ Map<String, String> cookies = Collections.singletonMap("cookie",
"value");
+ Map<String, Object> attributes = Collections.singletonMap("attribute",
new Object());
+ Map<String, Collection<String>> queryParams =
Collections.singletonMap("param", Collections.singletonList("value"));
+ LoadBalanceData data = new LoadBalanceData("POST", "1.2.3.4",
URI.create("http://localhost"),
+ headers, cookies, attributes, queryParams);
+ assertEquals("POST", data.getHttpMethod());
+ assertEquals("1.2.3.4", data.getIp());
+ assertEquals(URI.create("http://localhost"), data.getUrl());
+ assertSame(headers, data.getHeaders());
+ assertSame(cookies, data.getCookies());
+ assertSame(attributes, data.getAttributes());
+ assertSame(queryParams, data.getQueryParams());
+ }
+}
diff --git
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/utils/LoadbalancerUtils.java
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/utils/LoadbalancerUtils.java
index 46acbba76c..cfcba20648 100644
---
a/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/utils/LoadbalancerUtils.java
+++
b/shenyu-plugin/shenyu-plugin-base/src/main/java/org/apache/shenyu/plugin/base/utils/LoadbalancerUtils.java
@@ -17,19 +17,14 @@
package org.apache.shenyu.plugin.base.utils;
-import org.apache.commons.collections4.MapUtils;
import org.apache.shenyu.loadbalancer.entity.LoadBalanceData;
import org.apache.shenyu.loadbalancer.entity.Upstream;
import org.apache.shenyu.loadbalancer.factory.LoadBalancerFactory;
-import org.springframework.http.HttpCookie;
-import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import java.net.URI;
-import java.util.Collection;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -73,31 +68,14 @@ public final class LoadbalancerUtils {
.map(address -> address.getHostAddress())
.orElse("127.0.0.1");
String httpMethod =
Optional.ofNullable(request.getMethod()).map(method ->
method.name()).orElse("GET");
- URI uri = exchange.getRequest().getURI();
- HttpHeaders headers = request.getHeaders();
- MultiValueMap<String, HttpCookie> cookies = request.getCookies();
+ URI uri = request.getURI();
Map<String, Object> attributes = exchange.getAttributes();
- MultiValueMap<String, String> queryParams = request.getQueryParams();
+ // Only the ip is read by a load balancer (hash); copying headers,
cookies and query
+ // params here would allocate maps per request without any consumer.
return new LoadBalanceData(httpMethod, ip, uri,
- buildMultiValueMap(headers),
- buildCookies(cookies),
+ Collections.emptyMap(),
+ Collections.emptyMap(),
attributes,
- buildMultiValueMap(queryParams));
- }
-
- private static Map<String, Collection<String>> buildMultiValueMap(final
MultiValueMap<String, String> queryParams) {
- Map<String, Collection<String>> resultMap = new HashMap<>();
- if (MapUtils.isNotEmpty(queryParams)) {
- resultMap.putAll(queryParams);
- }
- return resultMap;
- }
-
- private static Map<String, String> buildCookies(final
MultiValueMap<String, HttpCookie> cookies) {
- Map<String, String> resultMap = new HashMap<>();
- if (MapUtils.isNotEmpty(cookies)) {
- cookies.forEach((key, value) -> value.forEach((cookie) ->
resultMap.put(cookie.getName(), cookie.getValue())));
- }
- return resultMap;
+ Collections.emptyMap());
}
}
diff --git
a/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/utils/LoadbalancerUtilsTest.java
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/utils/LoadbalancerUtilsTest.java
index a2d8f27af1..1a35cc8971 100644
---
a/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/utils/LoadbalancerUtilsTest.java
+++
b/shenyu-plugin/shenyu-plugin-base/src/test/java/org/apache/shenyu/plugin/base/utils/LoadbalancerUtilsTest.java
@@ -20,17 +20,21 @@ package org.apache.shenyu.plugin.base.utils;
import org.apache.shenyu.common.enums.LoadBalanceEnum;
import org.apache.shenyu.loadbalancer.entity.Upstream;
import org.junit.jupiter.api.Test;
-import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.server.ServerWebExchange;
+import java.net.InetSocketAddress;
import java.net.URI;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@@ -42,9 +46,6 @@ public final class LoadbalancerUtilsTest {
public void testMissingRemoteAddressAndMethodUseDefaults() {
ServerHttpRequest request = mock(ServerHttpRequest.class);
when(request.getURI()).thenReturn(URI.create("http://localhost/test"));
- when(request.getHeaders()).thenReturn(HttpHeaders.EMPTY);
- when(request.getCookies()).thenReturn(new LinkedMultiValueMap<>());
- when(request.getQueryParams()).thenReturn(new LinkedMultiValueMap<>());
ServerWebExchange exchange = mock(ServerWebExchange.class);
when(exchange.getRequest()).thenReturn(request);
when(exchange.getAttributes()).thenReturn(new HashMap<>());
@@ -55,4 +56,24 @@ public final class LoadbalancerUtilsTest {
assertSame(upstream, selected);
}
+
+ @Test
+ public void testGetForExchangeDoesNotCopyUnusedRequestData() {
+ ServerHttpRequest request = mock(ServerHttpRequest.class);
+ when(request.getURI()).thenReturn(URI.create("http://localhost/test"));
+ when(request.getRemoteAddress()).thenReturn(new
InetSocketAddress("127.0.0.1", 8080));
+ ServerWebExchange exchange = mock(ServerWebExchange.class);
+ when(exchange.getRequest()).thenReturn(request);
+ when(exchange.getAttributes()).thenReturn(new HashMap<>());
+ List<Upstream> upstreamList = new ArrayList<>();
+ upstreamList.add(Upstream.builder().url("http://1.1.1.1/api").build());
+ upstreamList.add(Upstream.builder().url("http://2.2.2.2/api").build());
+
+ Upstream selected = LoadbalancerUtils.getForExchange(upstreamList,
LoadBalanceEnum.HASH.getName(), exchange);
+
+ assertNotNull(selected);
+ verify(request, never()).getHeaders();
+ verify(request, never()).getCookies();
+ verify(request, never()).getQueryParams();
+ }
}