feat:zuul supports polaris router. (#502)

pull/507/head
jarvisxiong 2 years ago committed by GitHub
parent a6061e6b05
commit 8b9a104f69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -6,3 +6,4 @@
- [Feature: delete implement ServiceInstance](https://github.com/Tencent/spring-cloud-tencent/pull/481) - [Feature: delete implement ServiceInstance](https://github.com/Tencent/spring-cloud-tencent/pull/481)
- [Upgrade owasp esapi's configuration](https://github.com/Tencent/spring-cloud-tencent/pull/492) - [Upgrade owasp esapi's configuration](https://github.com/Tencent/spring-cloud-tencent/pull/492)
- [Bugfix: update byte-buddy scope test to compile](https://github.com/Tencent/spring-cloud-tencent/pull/495) - [Bugfix: update byte-buddy scope test to compile](https://github.com/Tencent/spring-cloud-tencent/pull/495)
- [Feature: zuul supports polaris router](https://github.com/Tencent/spring-cloud-tencent/pull/502)

@ -62,6 +62,18 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-zuul</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.netflix.zuul</groupId>
<artifactId>zuul-core</artifactId>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId> <artifactId>spring-boot-actuator</artifactId>
@ -92,6 +104,12 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>net.bytebuddy</groupId> <groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId> <artifactId>byte-buddy</artifactId>

@ -18,6 +18,9 @@
package com.tencent.cloud.polaris.router.config; package com.tencent.cloud.polaris.router.config;
import java.util.List;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.polaris.context.ServiceRuleManager; import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.beanprocessor.LoadBalancerClientFilterBeanPostProcessor; import com.tencent.cloud.polaris.router.beanprocessor.LoadBalancerClientFilterBeanPostProcessor;
@ -28,10 +31,14 @@ import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouter
import com.tencent.cloud.polaris.router.interceptor.MetadataRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.MetadataRouterRequestInterceptor;
import com.tencent.cloud.polaris.router.interceptor.NearbyRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.NearbyRouterRequestInterceptor;
import com.tencent.cloud.polaris.router.interceptor.RuleBasedRouterRequestInterceptor; import com.tencent.cloud.polaris.router.interceptor.RuleBasedRouterRequestInterceptor;
import com.tencent.cloud.polaris.router.spi.ServletRouterLabelResolver;
import com.tencent.cloud.polaris.router.zuul.PolarisRibbonRoutingFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.netflix.ribbon.RibbonClients; import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
@ -85,4 +92,15 @@ public class RouterAutoConfiguration {
public RuleBasedRouterRequestInterceptor ruleBasedRouterRequestInterceptor(PolarisRuleBasedRouterProperties polarisRuleBasedRouterProperties) { public RuleBasedRouterRequestInterceptor ruleBasedRouterRequestInterceptor(PolarisRuleBasedRouterProperties polarisRuleBasedRouterProperties) {
return new RuleBasedRouterRequestInterceptor(polarisRuleBasedRouterProperties); return new RuleBasedRouterRequestInterceptor(polarisRuleBasedRouterProperties);
} }
@Bean(initMethod = "init")
@ConditionalOnClass(name = "org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter")
public PolarisRibbonRoutingFilter ribbonRoutingFilter(ProxyRequestHelper helper,
RibbonCommandFactory<?> ribbonCommandFactory,
MetadataLocalProperties metadataLocalProperties,
RouterRuleLabelResolver routerRuleLabelResolver,
List<ServletRouterLabelResolver> routerLabelResolvers) {
return new PolarisRibbonRoutingFilter(helper, ribbonCommandFactory, metadataLocalProperties,
routerRuleLabelResolver, routerLabelResolvers);
}
} }

@ -0,0 +1,45 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.cloud.polaris.router.spi;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.springframework.core.Ordered;
/**
* Router label resolver for spring web http request.
*
* @author jarvisxiong 2022-08-04
*/
public interface ServletRouterLabelResolver extends Ordered {
/**
* resolve labels from servlet http request. User can customize expression parser to extract labels.
*
* @param request the servlet http request.
* @param expressionLabelKeys the expression labels which are configured in router rule.
* @return resolved labels
*/
default Map<String, String> resolve(HttpServletRequest request, Set<String> expressionLabelKeys) {
return Collections.emptyMap();
}
}

@ -0,0 +1,195 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.cloud.polaris.router.zuul;
import java.io.InputStream;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import com.netflix.zuul.context.RequestContext;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.util.BeanFactoryUtils;
import com.tencent.cloud.common.util.expresstion.ServletExpressionLabelUtils;
import com.tencent.cloud.polaris.router.PolarisRouterContext;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.spi.ServletRouterLabelResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.cloud.netflix.ribbon.support.RibbonCommandContext;
import org.springframework.cloud.netflix.ribbon.support.RibbonRequestCustomizer;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter;
import org.springframework.core.Ordered;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.LOAD_BALANCER_KEY;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.RETRYABLE_KEY;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVICE_ID_KEY;
/**
* Replaces the default RibbonRoutingFilter implementation.
*
* @author jarvisxiong 2022-08-04
*/
public class PolarisRibbonRoutingFilter extends RibbonRoutingFilter implements BeanFactoryAware {
private static final Logger LOGGER = LoggerFactory.getLogger(PolarisRibbonRoutingFilter.class);
private BeanFactory factory;
private final MetadataLocalProperties metadataLocalProperties;
private final RouterRuleLabelResolver routerRuleLabelResolver;
private final List<ServletRouterLabelResolver> routerLabelResolvers;
private boolean useServlet31 = true;
public PolarisRibbonRoutingFilter(ProxyRequestHelper helper,
RibbonCommandFactory<?> ribbonCommandFactory,
MetadataLocalProperties metadataLocalProperties,
RouterRuleLabelResolver routerRuleLabelResolver,
List<ServletRouterLabelResolver> routerLabelResolvers) {
super(helper, ribbonCommandFactory, Collections.emptyList());
this.metadataLocalProperties = metadataLocalProperties;
this.routerRuleLabelResolver = routerRuleLabelResolver;
if (!CollectionUtils.isEmpty(routerLabelResolvers)) {
routerLabelResolvers.sort(Comparator.comparingInt(Ordered::getOrder));
this.routerLabelResolvers = routerLabelResolvers;
}
else {
this.routerLabelResolvers = null;
}
// To support Servlet API 3.1 we need to check if getContentLengthLong exists
// Spring 5 minimum support is 3.0, so this stays
try {
HttpServletRequest.class.getMethod("getContentLengthLong");
}
catch (NoSuchMethodException e) {
useServlet31 = false;
}
}
@Override
protected RibbonCommandContext buildCommandContext(RequestContext context) {
HttpServletRequest request = context.getRequest();
MultiValueMap<String, String> headers = this.helper
.buildZuulRequestHeaders(request);
MultiValueMap<String, String> params = this.helper
.buildZuulRequestQueryParams(request);
String verb = getVerb(request);
InputStream requestEntity = getRequestBody(request);
if (request.getContentLength() < 0 && !verb.equalsIgnoreCase("GET")) {
context.setChunkedRequestBody();
}
String serviceId = (String) context.get(SERVICE_ID_KEY);
Boolean retryable = (Boolean) context.get(RETRYABLE_KEY);
Object loadBalancerKey = context.get(LOAD_BALANCER_KEY);
if (loadBalancerKey == null) {
// By default, use the routerContext as loadBalancerKey
loadBalancerKey = genRouterContext(request, serviceId);
}
String uri = this.helper.buildZuulRequestURI(request);
// remove double slashes
uri = uri.replace("//", "/");
long contentLength = useServlet31 ? request.getContentLengthLong()
: request.getContentLength();
return new RibbonCommandContext(serviceId, verb, uri, retryable, headers, params,
requestEntity, this.requestCustomizers, contentLength, loadBalancerKey);
}
PolarisRouterContext genRouterContext(HttpServletRequest request, String serviceId) {
// local service labels
Map<String, String> labels = new HashMap<>(metadataLocalProperties.getContent());
// labels from rule expression
Set<String> expressionLabelKeys = routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE,
MetadataContext.LOCAL_SERVICE, serviceId);
Map<String, String> ruleExpressionLabels = getExpressionLabels(request, expressionLabelKeys);
if (!CollectionUtils.isEmpty(ruleExpressionLabels)) {
labels.putAll(ruleExpressionLabels);
}
// labels from request
if (!CollectionUtils.isEmpty(routerLabelResolvers)) {
routerLabelResolvers.forEach(resolver -> {
try {
Map<String, String> customResolvedLabels = resolver.resolve(request, expressionLabelKeys);
if (!CollectionUtils.isEmpty(customResolvedLabels)) {
labels.putAll(customResolvedLabels);
}
}
catch (Throwable t) {
LOGGER.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t);
}
});
}
// labels from downstream
Map<String, String> transitiveLabels = MetadataContextHolder.get()
.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE);
labels.putAll(transitiveLabels);
PolarisRouterContext routerContext = new PolarisRouterContext();
routerContext.putLabels(PolarisRouterContext.ROUTER_LABELS, labels);
routerContext.putLabels(PolarisRouterContext.TRANSITIVE_LABELS, transitiveLabels);
return routerContext;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.factory = beanFactory;
}
private Map<String, String> getExpressionLabels(HttpServletRequest request, Set<String> labelKeys) {
if (CollectionUtils.isEmpty(labelKeys)) {
return Collections.emptyMap();
}
return ServletExpressionLabelUtils.resolve(request, labelKeys);
}
private void init() {
this.requestCustomizers = BeanFactoryUtils.getBeans(factory, RibbonRequestCustomizer.class);
}
}

@ -0,0 +1,373 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* 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 com.tencent.cloud.polaris.router.zuul;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.netflix.client.config.CommonClientConfigKey;
import com.netflix.client.config.IClientConfig;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.niws.client.http.RestClient;
import com.netflix.zuul.context.RequestContext;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.polaris.loadbalancer.PolarisLoadBalancer;
import com.tencent.cloud.polaris.router.PolarisRouterContext;
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
import com.tencent.cloud.polaris.router.spi.ServletRouterLabelResolver;
import okhttp3.OkHttpClient;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.cloud.netflix.ribbon.apache.RibbonLoadBalancingHttpClient;
import org.springframework.cloud.netflix.ribbon.okhttp.OkHttpLoadBalancingClient;
import org.springframework.cloud.netflix.ribbon.support.RibbonCommandContext;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.cloud.netflix.zuul.filters.route.RestClientRibbonCommand;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory;
import org.springframework.cloud.netflix.zuul.filters.route.apache.HttpClientRibbonCommand;
import org.springframework.cloud.netflix.zuul.filters.route.okhttp.OkHttpRibbonCommand;
import org.springframework.mock.web.MockHttpServletRequest;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.LOAD_BALANCER_KEY;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.RETRYABLE_KEY;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVICE_ID_KEY;
/**
* test for {@link PolarisRibbonRoutingFilter}.
*
* @author jarvisxiong 2022-08-09
*/
@RunWith(MockitoJUnitRunner.class)
public class PolarisRibbonRoutingFilterTest {
private static final String callerService = "callerService";
private static final String calleeService = "calleeService";
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
private static MockedStatic<MetadataContextHolder> mockedMetadataContextHolder;
@Mock
private MetadataLocalProperties metadataLocalProperties;
@Mock
private RouterRuleLabelResolver routerRuleLabelResolver;
@Mock
private ServletRouterLabelResolver routerLabelResolver;
@Mock
private ProxyRequestHelper proxyRequestHelper;
@Mock
private RibbonCommandFactory<?> ribbonCommandFactory;
@Mock
private FallbackProvider fallbackProvider;
@Mock
private PolarisLoadBalancer polarisLoadBalancer;
@BeforeClass
public static void beforeClass() {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn(callerService);
MetadataContext metadataContext = Mockito.mock(MetadataContext.class);
// mock transitive metadata
Map<String, String> transitiveLabels = new HashMap<>();
transitiveLabels.put("t1", "v1");
transitiveLabels.put("t2", "v2");
when(metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE)).thenReturn(transitiveLabels);
mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class);
mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext);
}
@AfterClass
public static void afterClass() {
mockedApplicationContextAwareUtils.close();
mockedMetadataContextHolder.close();
}
@Test
public void testGenRouterContext() {
PolarisRibbonRoutingFilter polarisRibbonRoutingFilter = new PolarisRibbonRoutingFilter(proxyRequestHelper,
ribbonCommandFactory, metadataLocalProperties, routerRuleLabelResolver,
Lists.newArrayList(routerLabelResolver));
Map<String, String> localMetadata = new HashMap<>();
localMetadata.put("env", "blue");
when(metadataLocalProperties.getContent()).thenReturn(localMetadata);
Set<String> expressionLabelKeys = Sets.newHashSet("${http.header.k1}", "${http.query.userid}");
when(routerRuleLabelResolver.getExpressionLabelKeys(anyString(), anyString(), anyString()))
.thenReturn(expressionLabelKeys);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("/" + calleeService + "/users");
request.addHeader("k1", "v1");
request.setQueryString("userid=zhangsan");
Map<String, String> customMetadata = new HashMap<>();
customMetadata.put("k2", "v2");
when(routerLabelResolver.resolve(request, expressionLabelKeys)).thenReturn(customMetadata);
PolarisRouterContext routerContext = polarisRibbonRoutingFilter.genRouterContext(request, calleeService);
Map<String, String> routerLabels = routerContext.getLabels(PolarisRouterContext.ROUTER_LABELS);
Assert.assertEquals("v1", routerLabels.get("${http.header.k1}"));
Assert.assertEquals("zhangsan", routerLabels.get("${http.query.userid}"));
Assert.assertEquals("blue", routerLabels.get("env"));
Assert.assertEquals("v1", routerLabels.get("t1"));
Assert.assertEquals("v2", routerLabels.get("t2"));
}
@Test
public void testHttpCallWithoutRouter() {
ZuulProperties zuulProperties = new ZuulProperties();
zuulProperties.setRibbonIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);
zuulProperties.setThreadPool(new ZuulProperties.HystrixThreadPool());
PolarisRibbonRoutingFilter polarisRibbonRoutingFilter = new PolarisRibbonRoutingFilter(
new ProxyRequestHelper(zuulProperties), ribbonCommandFactory, metadataLocalProperties,
routerRuleLabelResolver, Lists.newArrayList(routerLabelResolver));
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("http://" + calleeService + "/users");
request.addHeader("k1", "v1");
request.setQueryString("userid=zhangsan");
RequestContext context = new RequestContext();
context.setRequest(request);
context.set(SERVICE_ID_KEY, calleeService);
context.set(RETRYABLE_KEY, Boolean.FALSE);
context.set(LOAD_BALANCER_KEY, calleeService);
RequestContext.testSetCurrentContext(context);
RibbonCommandContext commandContext = polarisRibbonRoutingFilter.buildCommandContext(context);
IClientConfig clientConfig = IClientConfig.Builder.newBuilder().build();
RibbonLoadBalancingHttpClient client = new RibbonLoadBalancingHttpClient(clientConfig, null);
client.setLoadBalancer(polarisLoadBalancer);
HttpClientRibbonCommand command = new HttpClientRibbonCommand(calleeService, client, commandContext,
zuulProperties, fallbackProvider, clientConfig);
command.execute();
verify(polarisLoadBalancer).chooseServer(calleeService);
verify(metadataLocalProperties, times(0)).getContent();
}
@Test
public void testRestCallWithoutRouter() {
ZuulProperties zuulProperties = new ZuulProperties();
zuulProperties.setRibbonIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);
zuulProperties.setThreadPool(new ZuulProperties.HystrixThreadPool());
PolarisRibbonRoutingFilter polarisRibbonRoutingFilter = new PolarisRibbonRoutingFilter(
new ProxyRequestHelper(zuulProperties), ribbonCommandFactory, metadataLocalProperties,
routerRuleLabelResolver, Lists.newArrayList(routerLabelResolver));
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("http://" + calleeService + "/users");
request.addHeader("k1", "v1");
request.setQueryString("userid=zhangsan");
request.setMethod("GET");
RequestContext context = new RequestContext();
context.setRequest(request);
context.set(SERVICE_ID_KEY, calleeService);
context.set(RETRYABLE_KEY, Boolean.FALSE);
context.set(LOAD_BALANCER_KEY, calleeService);
RequestContext.testSetCurrentContext(context);
RibbonCommandContext commandContext = polarisRibbonRoutingFilter.buildCommandContext(context);
IClientConfig clientConfig = IClientConfig.Builder.newBuilder().build();
RestClient restClient = new RestClient(polarisLoadBalancer);
RestClientRibbonCommand command = new RestClientRibbonCommand(calleeService, restClient, commandContext,
zuulProperties, fallbackProvider, clientConfig);
command.execute();
// RestClient not use loadBalancerKey
verify(polarisLoadBalancer).chooseServer(null);
verify(metadataLocalProperties, times(0)).getContent();
}
@Test
public void testOkHttpCallWithoutRouter() {
ZuulProperties zuulProperties = new ZuulProperties();
zuulProperties.setRibbonIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);
zuulProperties.setThreadPool(new ZuulProperties.HystrixThreadPool());
PolarisRibbonRoutingFilter polarisRibbonRoutingFilter = new PolarisRibbonRoutingFilter(
new ProxyRequestHelper(zuulProperties), ribbonCommandFactory, metadataLocalProperties,
routerRuleLabelResolver, Lists.newArrayList(routerLabelResolver));
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("http://" + calleeService + "/users");
request.addHeader("k1", "v1");
request.setQueryString("userid=zhangsan");
RequestContext context = new RequestContext();
context.setRequest(request);
context.set(SERVICE_ID_KEY, calleeService);
context.set(RETRYABLE_KEY, Boolean.FALSE);
context.set(LOAD_BALANCER_KEY, calleeService);
RequestContext.testSetCurrentContext(context);
RibbonCommandContext commandContext = polarisRibbonRoutingFilter.buildCommandContext(context);
IClientConfig clientConfig = IClientConfig.Builder.newBuilder().build();
OkHttpLoadBalancingClient client = new OkHttpLoadBalancingClient(new OkHttpClient(), clientConfig, null);
client.setLoadBalancer(polarisLoadBalancer);
OkHttpRibbonCommand command = new OkHttpRibbonCommand(calleeService, client, commandContext, zuulProperties,
fallbackProvider, clientConfig);
command.execute();
verify(polarisLoadBalancer).chooseServer(calleeService);
verify(metadataLocalProperties, times(0)).getContent();
}
@Test
public void testHttpCallWithRouter() {
ZuulProperties zuulProperties = new ZuulProperties();
zuulProperties.setRibbonIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);
zuulProperties.setThreadPool(new ZuulProperties.HystrixThreadPool());
PolarisRibbonRoutingFilter polarisRibbonRoutingFilter = new PolarisRibbonRoutingFilter(
new ProxyRequestHelper(zuulProperties), ribbonCommandFactory, metadataLocalProperties,
routerRuleLabelResolver, Lists.newArrayList(routerLabelResolver));
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("http://" + calleeService + "/users");
request.addHeader("k1", "v1");
request.setQueryString("userid=zhangsan");
RequestContext context = new RequestContext();
context.setRequest(request);
context.set(SERVICE_ID_KEY, calleeService);
context.set(RETRYABLE_KEY, Boolean.FALSE);
PolarisRouterContext routerContext = polarisRibbonRoutingFilter.genRouterContext(request, calleeService);
context.set(LOAD_BALANCER_KEY, routerContext);
RequestContext.testSetCurrentContext(context);
RibbonCommandContext commandContext = polarisRibbonRoutingFilter.buildCommandContext(context);
IClientConfig clientConfig = IClientConfig.Builder.newBuilder().build();
RibbonLoadBalancingHttpClient client = new RibbonLoadBalancingHttpClient(clientConfig, null);
client.setLoadBalancer(polarisLoadBalancer);
HttpClientRibbonCommand command = new HttpClientRibbonCommand(calleeService, client, commandContext,
zuulProperties, fallbackProvider, clientConfig);
command.execute();
verify(polarisLoadBalancer).chooseServer(routerContext);
verify(metadataLocalProperties, times(1)).getContent();
}
@Test
public void testRestCallWithRouter() {
ZuulProperties zuulProperties = new ZuulProperties();
zuulProperties.setRibbonIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);
zuulProperties.setThreadPool(new ZuulProperties.HystrixThreadPool());
PolarisRibbonRoutingFilter polarisRibbonRoutingFilter = new PolarisRibbonRoutingFilter(
new ProxyRequestHelper(zuulProperties), ribbonCommandFactory, metadataLocalProperties,
routerRuleLabelResolver, Lists.newArrayList(routerLabelResolver));
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("http://" + calleeService + "/users");
request.addHeader("k1", "v1");
request.setQueryString("userid=zhangsan");
request.setMethod("GET");
RequestContext context = new RequestContext();
context.setRequest(request);
context.set(SERVICE_ID_KEY, calleeService);
context.set(RETRYABLE_KEY, Boolean.FALSE);
PolarisRouterContext routerContext = polarisRibbonRoutingFilter.genRouterContext(request, calleeService);
context.set(LOAD_BALANCER_KEY, routerContext);
RequestContext.testSetCurrentContext(context);
RibbonCommandContext commandContext = polarisRibbonRoutingFilter.buildCommandContext(context);
IClientConfig clientConfig = IClientConfig.Builder.newBuilder().build();
RestClient restClient = new RestClient(polarisLoadBalancer);
RestClientRibbonCommand command = new RestClientRibbonCommand(calleeService, restClient, commandContext,
zuulProperties, fallbackProvider, clientConfig);
command.execute();
// RestClient not use loadBalancerKey
verify(polarisLoadBalancer).chooseServer(null);
verify(metadataLocalProperties, times(1)).getContent();
}
@Test
public void testOkHttpCallWithRouter() {
ZuulProperties zuulProperties = new ZuulProperties();
zuulProperties.setRibbonIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);
zuulProperties.setThreadPool(new ZuulProperties.HystrixThreadPool());
PolarisRibbonRoutingFilter polarisRibbonRoutingFilter = new PolarisRibbonRoutingFilter(
new ProxyRequestHelper(zuulProperties), ribbonCommandFactory, metadataLocalProperties,
routerRuleLabelResolver, Lists.newArrayList(routerLabelResolver));
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestURI("http://" + calleeService + "/users");
request.addHeader("k1", "v1");
request.setQueryString("userid=zhangsan");
request.setMethod("GET");
RequestContext context = new RequestContext();
context.setRequest(request);
context.set(SERVICE_ID_KEY, calleeService);
context.set(RETRYABLE_KEY, Boolean.FALSE);
PolarisRouterContext routerContext = polarisRibbonRoutingFilter.genRouterContext(request, calleeService);
context.set(LOAD_BALANCER_KEY, routerContext);
RequestContext.testSetCurrentContext(context);
RibbonCommandContext commandContext = polarisRibbonRoutingFilter.buildCommandContext(context);
IClientConfig clientConfig = IClientConfig.Builder.newBuilder().build();
// Retry once by default, so close retry
clientConfig.set(CommonClientConfigKey.MaxAutoRetriesNextServer, 0);
OkHttpLoadBalancingClient client = new OkHttpLoadBalancingClient(new OkHttpClient(), clientConfig, null);
client.setLoadBalancer(polarisLoadBalancer);
OkHttpRibbonCommand command = new OkHttpRibbonCommand(calleeService, client, commandContext, zuulProperties,
fallbackProvider, clientConfig);
command.execute();
verify(polarisLoadBalancer).chooseServer(routerContext);
verify(metadataLocalProperties, times(1)).getContent();
}
}

@ -15,6 +15,11 @@ spring:
router: router:
feature-env: feature-env:
enabled: true enabled: true
metadata:
content:
a: 1
transitive:
- a
polaris: polaris:
address: grpc://183.47.111.80:8091 address: grpc://183.47.111.80:8091
namespace: default namespace: default

@ -24,6 +24,11 @@
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
</dependency> </dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-metadata-transfer</artifactId> <artifactId>spring-cloud-starter-tencent-metadata-transfer</artifactId>

Loading…
Cancel
Save