feat: finish discovery ability in 2020.x

pull/12/head
chuntaojun 4 years ago
parent 085ae91f77
commit fa5d0eefb8

@ -14,6 +14,11 @@
<name>Polaris Discovery Callee Service</name>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
<groupId>com.tencent.cloud</groupId>

@ -18,6 +18,11 @@
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
<groupId>com.tencent.cloud</groupId>

@ -18,6 +18,8 @@
package com.tencent.cloud.polaris.discovery.service.caller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@ -37,6 +39,12 @@ public class DiscoveryCallerController {
@Autowired
private DiscoveryCalleeService discoveryCalleeService;
@Configuration
@LoadBalancerClient(value = "service-provider")
class DiscoveryCallerConfiguration {
}
/**
*
*

@ -1,10 +1,11 @@
server:
session-timeout: 1800
port: 48080
spring:
application:
name: DiscoveryCallerService
cloud:
loadbalancer:
configurations: default
polaris:
address: grpc://127.0.0.1:8091
consul:

@ -20,6 +20,7 @@
</modules>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

@ -23,11 +23,10 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
/**
* Wrap Spring Bean and decorating proxy for Feign Client.
@ -50,16 +49,14 @@ public class PolarisFeignBeanPostProcessor implements BeanPostProcessor, BeanFac
}
private Object wrapper(Object bean) {
if (isNeedWrap(bean)) {
if (bean instanceof LoadBalancerFeignClient) {
LoadBalancerFeignClient client = ((LoadBalancerFeignClient) bean);
return new PolarisLoadBalancerFeignClient(createPolarisFeignClient(client.getDelegate()), factory(),
clientFactory());
}
if (bean instanceof FeignBlockingLoadBalancerClient) {
FeignBlockingLoadBalancerClient client = (FeignBlockingLoadBalancerClient) bean;
return new PolarisFeignBlockingLoadBalancerClient(createPolarisFeignClient(client.getDelegate()),
factory.getBean(BlockingLoadBalancerClient.class));
factory.getBean(BlockingLoadBalancerClient.class),
factory.getBean(LoadBalancerProperties.class),
factory.getBean(LoadBalancerClientFactory.class));
}
return createPolarisFeignClient((Client) bean);
}
@ -68,8 +65,7 @@ public class PolarisFeignBeanPostProcessor implements BeanPostProcessor, BeanFac
private boolean isNeedWrap(Object bean) {
return bean instanceof Client && !(bean instanceof PolarisFeignClient)
&& !(bean instanceof PolarisFeignBlockingLoadBalancerClient)
&& !(bean instanceof PolarisLoadBalancerFeignClient);
&& !(bean instanceof PolarisFeignBlockingLoadBalancerClient);
}
private PolarisFeignClient createPolarisFeignClient(Client delegate) {
@ -80,12 +76,4 @@ public class PolarisFeignBeanPostProcessor implements BeanPostProcessor, BeanFac
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.factory = beanFactory;
}
CachingSpringLoadBalancerFactory factory() {
return this.factory.getBean(CachingSpringLoadBalancerFactory.class);
}
SpringClientFactory clientFactory() {
return this.factory.getBean(SpringClientFactory.class);
}
}

@ -18,7 +18,10 @@
package com.tencent.cloud.polaris.circuitbreaker.feign;
import feign.Client;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
/**
@ -28,9 +31,11 @@ import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalance
*/
public class PolarisFeignBlockingLoadBalancerClient extends FeignBlockingLoadBalancerClient {
public PolarisFeignBlockingLoadBalancerClient(Client delegate,
BlockingLoadBalancerClient loadBalancerClient) {
super(delegate, loadBalancerClient);
LoadBalancerClient loadBalancerClient,
LoadBalancerProperties properties,
LoadBalancerClientFactory loadBalancerClientFactory) {
super(delegate, loadBalancerClient, properties, loadBalancerClientFactory);
}
}

@ -1,37 +0,0 @@
/*
* 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.circuitbreaker.feign;
import feign.Client;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
/**
* Wrap for {@link LoadBalancerFeignClient}
*
* @author Haotian Zhang
*/
public class PolarisLoadBalancerFeignClient extends LoadBalancerFeignClient {
public PolarisLoadBalancerFeignClient(Client delegate,
CachingSpringLoadBalancerFactory lbClientFactory,
SpringClientFactory clientFactory) {
super(delegate, lbClientFactory, clientFactory);
}
}

@ -51,9 +51,6 @@ public class PolarisFeignClientTest {
if (client instanceof PolarisFeignClient) {
return;
}
if (client instanceof PolarisLoadBalancerFeignClient) {
return;
}
if (client instanceof PolarisFeignBlockingLoadBalancerClient) {
return;
}

@ -37,6 +37,11 @@
<artifactId>polaris-discovery-factory</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-router-factory</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-test-common</artifactId>
@ -91,11 +96,6 @@
<artifactId>powermock-api-mockito2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<version>3.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

@ -69,8 +69,8 @@ public class PolarisProperties {
/**
* 使spring cloud
*/
@Value("${server.port:}")
private int port;
@Value("${server.port:#{-1}}")
private int port = -1;
/**
*
@ -78,14 +78,12 @@ public class PolarisProperties {
@Value("${spring.cloud.polaris.discovery.loadbalancer.enabled:#{true}}")
private Boolean loadbalancerEnabled;
/**
* loadbalnce strategy
*/
@Value("${spring.cloud.polaris.discovery.loadbalancer.policy:#{'weightedRandom'}}")
private String policy;
/**
* loadbalnce strategy
*/

@ -17,8 +17,26 @@
package com.tencent.cloud.polaris.loadbalancer;
import com.tencent.cloud.constant.LoadbalancerConstant;
import com.tencent.cloud.polaris.PolarisProperties;
import com.tencent.polaris.router.api.core.RouterAPI;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
import org.springframework.cloud.client.ConditionalOnReactiveDiscoveryEnabled;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
/**
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
@ -27,4 +45,49 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnDiscoveryEnabled
public class PolarisLoadBalancerClientConfiguration {
@Bean
@ConditionalOnMissingBean
public ReactorLoadBalancer<ServiceInstance> nacosLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory,
PolarisProperties polarisProperties,
RouterAPI routerAPI) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new PolarisLoadbalancer(
name, loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
polarisProperties, routerAPI);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnReactiveDiscoveryEnabled
@Order(LoadbalancerConstant.DISCOVERY_SERVICE_INSTANCE_SUPPLIER_ORDER)
public static class ReactiveSupportConfiguration {
@Bean
@ConditionalOnBean(ReactiveDiscoveryClient.class)
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations", havingValue = "default", matchIfMissing = true)
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder().withDiscoveryClient()
.build(context);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBlockingDiscoveryEnabled
@Order(LoadbalancerConstant.DISCOVERY_SERVICE_INSTANCE_SUPPLIER_ORDER + 1)
public static class BlockingSupportConfiguration {
@Bean
@ConditionalOnBean(DiscoveryClient.class)
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations", havingValue = "default", matchIfMissing = true)
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient()
.build(context);
}
}
}

@ -18,8 +18,21 @@
package com.tencent.cloud.polaris.loadbalancer;
import com.tencent.cloud.metadata.context.MetadataContextHolder;
import com.tencent.cloud.polaris.PolarisProperties;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.tencent.cloud.polaris.pojo.PolarisServiceInstance;
import com.tencent.polaris.api.pojo.DefaultServiceInstances;
import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.api.pojo.ServiceInstances;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.api.rpc.Criteria;
import com.tencent.polaris.router.api.core.RouterAPI;
import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceRequest;
import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
@ -30,13 +43,14 @@ import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import reactor.core.publisher.Mono;
/**
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
public class PolarisLoadbalancer implements ReactorServiceInstanceLoadBalancer {
public class PolarisLoadbalancer extends RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private static final Logger log = LoggerFactory.getLogger(PolarisLoadbalancer.class);
@ -46,16 +60,23 @@ public class PolarisLoadbalancer implements ReactorServiceInstanceLoadBalancer {
private final PolarisProperties discoveryProperties;
private final RouterAPI routerAPI;
public PolarisLoadbalancer(String serviceId,
ObjectProvider<ServiceInstanceListSupplier> supplierObjectProvider,
PolarisProperties discoveryProperties) {
ObjectProvider<ServiceInstanceListSupplier> supplierObjectProvider,
PolarisProperties discoveryProperties, RouterAPI routerAPI) {
super(supplierObjectProvider, serviceId);
this.serviceId = serviceId;
this.supplierObjectProvider = supplierObjectProvider;
this.discoveryProperties = discoveryProperties;
this.routerAPI = routerAPI;
}
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
if (!discoveryProperties.getLoadbalancerEnabled()) {
return super.choose(request);
}
ServiceInstanceListSupplier supplier = supplierObjectProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get().next().map(this::getInstanceResponse);
}
@ -66,15 +87,28 @@ public class PolarisLoadbalancer implements ReactorServiceInstanceLoadBalancer {
return new EmptyResponse();
}
ProcessLoadBalanceRequest request = new ProcessLoadBalanceRequest();
request.setDstInstances(convertToPolarisServiceInstances(serviceInstances));
request.setLbPolicy(discoveryProperties.getPolicy());
request.setCriteria(new Criteria());
try {
ServiceInstance instance = NacosBalancer.getHostByRandomWeight3(serviceInstances);
return new DefaultResponse(instance);
ProcessLoadBalanceResponse response = routerAPI.processLoadBalance(request);
return new DefaultResponse(new PolarisServiceInstance(response.getTargetInstance()));
}
catch (Exception e) {
log.warn("NacosLoadBalancer error", e);
log.warn("PolarisLoadbalancer error", e);
return new EmptyResponse();
}
}
private static ServiceInstances convertToPolarisServiceInstances(List<ServiceInstance> serviceInstances) {
ServiceKey serviceKey = new ServiceKey(MetadataContextHolder.LOCAL_NAMESPACE, serviceInstances.get(0).getServiceId());
List<Instance> polarisInstances = serviceInstances
.stream()
.map(serviceInstance -> ((PolarisServiceInstance) serviceInstance).getPolarisInstance())
.collect(Collectors.toList());
return new DefaultServiceInstances(serviceKey, polarisInstances);
}
}

@ -23,6 +23,7 @@ import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegis
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@ -43,9 +44,10 @@ public class PolarisAutoServiceRegistration extends AbstractAutoServiceRegistrat
@Override
protected PolarisRegistration getRegistration() {
if (this.registration.getPort() <= 0) {
if (this.registration.getPort() < 0 && this.getPort().get() > 0) {
this.registration.setPort(this.getPort().get());
}
Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");
return this.registration;
}

@ -175,16 +175,13 @@ public class PolarisServiceRegistry implements ServiceRegistry<Registration> {
* @param heartbeatRequest
*/
public void heartbeat(InstanceHeartbeatRequest heartbeatRequest) {
heartbeatExecutor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
try {
polarisDiscoveryHandler.getProviderAPI().heartbeat(heartbeatRequest);
} catch (PolarisException e) {
log.error("polaris heartbeat[{}]", e.getCode(), e);
} catch (Exception e) {
log.error("polaris heartbeat runtime error", e);
}
heartbeatExecutor.scheduleWithFixedDelay(() -> {
try {
polarisDiscoveryHandler.getProviderAPI().heartbeat(heartbeatRequest);
} catch (PolarisException e) {
log.error("polaris heartbeat[{}]", e.getCode(), e);
} catch (Exception e) {
log.error("polaris heartbeat runtime error", e);
}
}, 0, ttl, TimeUnit.SECONDS);
}

@ -1,5 +1,4 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration,\
com.tencent.cloud.polaris.ribbon.PolarisDiscoveryRibbonAutoConfiguration,\
com.tencent.cloud.polaris.registry.PolarisServiceRegistryAutoConfiguration

@ -22,8 +22,6 @@ import static com.tencent.polaris.test.common.Consts.PORT;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.client.config.IClientConfig;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClientConfiguration;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler;
import org.junit.Test;
@ -40,7 +38,6 @@ public class PolarisRibbonServerListAutoConfigurationTest {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
PolarisRibbonClientTest.class,
PolarisDiscoveryClientConfiguration.class))
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT)
@ -48,36 +45,4 @@ public class PolarisRibbonServerListAutoConfigurationTest {
.withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST)
.withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx");
@Test
public void testProperties() {
this.contextRunner.run(context -> {
PolarisDiscoveryHandler discoveryHandler = context.getBean(PolarisDiscoveryHandler.class);
PolarisServerList serverList = new PolarisServerList(discoveryHandler);
IClientConfig iClientConfig = context.getBean(IClientConfig.class);
serverList.initWithNiwsConfig(iClientConfig);
assertThat(serverList.getServiceId()).isEqualTo(SERVICE_PROVIDER);
});
}
@Configuration
@EnableAutoConfiguration
@EnableDiscoveryClient
static class PolarisRibbonClientTest {
@Bean
IClientConfig iClientConfig() {
DefaultClientConfigImpl config = new DefaultClientConfigImpl();
config.setClientName(SERVICE_PROVIDER);
return config;
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
}

@ -24,13 +24,10 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.Server;
import com.tencent.cloud.polaris.context.PolarisContextConfiguration;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClientConfiguration;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler;
import java.util.List;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.test.mock.discovery.NamingServer;
@ -75,56 +72,6 @@ public class PolarisServerListTest {
}
}
/**
* Test {@link PolarisServerList#getInitialListOfServers()} with empty server list.
*/
@Test
@SuppressWarnings("unchecked")
public void test1(){
this.contextRunner.run(context -> {
// mock
IClientConfig iClientConfig = mock(IClientConfig.class);
when(iClientConfig.getClientName()).thenReturn(SERVICE_PROVIDER);
PolarisDiscoveryHandler polarisDiscoveryHandler = context.getBean(PolarisDiscoveryHandler.class);
PolarisServerList serverList = new PolarisServerList(polarisDiscoveryHandler);
serverList.initWithNiwsConfig(iClientConfig);
List<Server> servers = serverList.getInitialListOfServers();
assertThat(servers).isEmpty();
});
}
/**
* Test {@link PolarisServerList#getUpdatedListOfServers()} with server list of size 3.
*/
@Test
@SuppressWarnings("unchecked")
public void test2() throws Exception {
this.contextRunner.run(context -> {
// mock
IClientConfig iClientConfig = mock(IClientConfig.class);
when(iClientConfig.getClientName()).thenReturn(SERVICE_PROVIDER);
PolarisDiscoveryHandler polarisDiscoveryHandler = context.getBean(PolarisDiscoveryHandler.class);
PolarisServerList serverList = new PolarisServerList(polarisDiscoveryHandler);
serverList.initWithNiwsConfig(iClientConfig);
// add service with 3 instances
NamingService.InstanceParameter instanceParameter = new NamingService.InstanceParameter();
instanceParameter.setHealthy(true);
instanceParameter.setIsolated(false);
instanceParameter.setWeight(100);
ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER);
namingServer.getNamingService().batchAddInstances(serviceKey, PORT, 3, instanceParameter);
List<Server> servers = serverList.getUpdatedListOfServers();
assertThat(servers).hasSize(3);
assertThat(servers.get(0).getPort()).isEqualTo(PORT);
assertThat(servers.get(1).getPort()).isEqualTo(PORT + 1);
assertThat(servers.get(2).getPort()).isEqualTo(PORT + 2);
});
}
@Configuration
@EnableAutoConfiguration
@EnableDiscoveryClient

@ -34,7 +34,6 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<optional>true</optional>
</dependency>
<!-- Polaris dependencies start -->

@ -0,0 +1,112 @@
/*
* 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;
import com.tencent.cloud.constant.LoadbalancerConstant;
import com.tencent.cloud.polaris.router.PolarisRouterServiceInstanceListSupplier;
import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.client.api.SDKContext;
import com.tencent.polaris.factory.api.RouterAPIFactory;
import com.tencent.polaris.router.api.core.RouterAPI;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled;
import org.springframework.cloud.client.ConditionalOnReactiveDiscoveryEnabled;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
/**
* Auto-configuration Ribbon for Polaris.
*
* @author Haotian Zhang
*/
@Configuration()
@EnableConfigurationProperties
@ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.enabled", matchIfMissing = true)
public class PolarisRouterAutoConfiguration {
@Bean(name = "polarisRoute")
@ConditionalOnMissingBean
public RouterAPI polarisRouter(SDKContext polarisContext) throws PolarisException {
return RouterAPIFactory.createRouterAPIByContext(polarisContext);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnReactiveDiscoveryEnabled
@Order(LoadbalancerConstant.ROUTER_SERVICE_INSTANCE_SUPPLIER_ORDER - 1000)
public static class ReactiveSupportConfiguration {
// @Bean
// @ConditionalOnBean(ReactiveDiscoveryClient.class)
// @ConditionalOnMissingBean
// @ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations", havingValue = "default", matchIfMissing = true)
// public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(RouterAPI routerAPI,
// ConfigurableApplicationContext context) {
// return new PolarisRouterServiceInstanceListSupplier(ServiceInstanceListSupplier.builder().withDiscoveryClient()
// .build(context), routerAPI);
// }
@Bean
@ConditionalOnBean(ReactiveDiscoveryClient.class)
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations", havingValue = "zone-preference", matchIfMissing = true)
public ServiceInstanceListSupplier polarisRouterDiscoveryClientServiceInstanceListSupplier(RouterAPI routerAPI,
ConfigurableApplicationContext context) {
return new PolarisRouterServiceInstanceListSupplier(ServiceInstanceListSupplier.builder().withDiscoveryClient()
.withZonePreference()
.build(context), routerAPI);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBlockingDiscoveryEnabled
@Order(LoadbalancerConstant.ROUTER_SERVICE_INSTANCE_SUPPLIER_ORDER + 1 - 1000)
public static class BlockingSupportConfiguration {
// @Bean
// @ConditionalOnBean(DiscoveryClient.class)
// @ConditionalOnMissingBean
// @ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations", havingValue = "default", matchIfMissing = true)
// public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
// RouterAPI routerAPI,
// ConfigurableApplicationContext context) {
// return new PolarisRouterServiceInstanceListSupplier(ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient()
// .build(context), routerAPI);
// }
@Bean
@ConditionalOnBean(DiscoveryClient.class)
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations", havingValue = "zone-preference", matchIfMissing = true)
public ServiceInstanceListSupplier polarisRouterDiscoveryClientServiceInstanceListSupplier(RouterAPI routerAPI,
ConfigurableApplicationContext context) {
return new PolarisRouterServiceInstanceListSupplier(ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient()
.withZonePreference().build(context), routerAPI);
}
}
}

@ -34,19 +34,34 @@ import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.loadbalancer.core.DelegatingServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Flux;
/**
* @author Haotian Zhang
*/
public class PolarisRoutingLoadBalancer {
public class PolarisRouterServiceInstanceListSupplier extends DelegatingServiceInstanceListSupplier {
private final RouterAPI routerAPI;
public PolarisRoutingLoadBalancer(RouterAPI routerAPI) {
public PolarisRouterServiceInstanceListSupplier(ServiceInstanceListSupplier delegate, RouterAPI routerAPI) {
super(delegate);
this.routerAPI = routerAPI;
}
@Override
public Flux<List<ServiceInstance>> get() {
return getDelegate().get().map(this::chooseInstances);
}
@Override
public Flux<List<ServiceInstance>> get(Request request) {
return super.get(request);
}
public List<ServiceInstance> chooseInstances(List<ServiceInstance> allServers) {
if (CollectionUtils.isEmpty(allServers)) {
return allServers;
@ -93,5 +108,4 @@ public class PolarisRoutingLoadBalancer {
}
return filteredInstances;
}
}

@ -1,51 +0,0 @@
/*
* 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.config;
import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.client.api.SDKContext;
import com.tencent.polaris.factory.api.RouterAPIFactory;
import com.tencent.polaris.router.api.core.RouterAPI;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Auto-configuration Ribbon for Polaris.
*
* @author Haotian Zhang
*/
@Configuration()
@EnableConfigurationProperties
@ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.enabled", matchIfMissing = true)
public class PolarisRouterAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public PolarisRouterProperties polarisRibbonProperties() {
return new PolarisRouterProperties();
}
@Bean(name = "polarisRoute")
@ConditionalOnMissingBean
public RouterAPI polarisRouter(SDKContext polarisContext) throws PolarisException {
return RouterAPIFactory.createRouterAPIByContext(polarisContext);
}
}

@ -1,64 +0,0 @@
/*
* 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.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Haotian Zhang
*/
@ConfigurationProperties("spring.cloud.polaris.ribbon")
public class PolarisRouterProperties {
/**
*
*/
@Value("${spring.cloud.polaris.loadbalancer.enabled:#{true}}")
private Boolean loadbalancerEnabled;
/**
* loadbalnce strategy
*/
@Value("${spring.cloud.polaris.loadbalancer.strategy:#{'weightedRandom'}}")
private String policy;
public String getPolicy() {
return policy;
}
public void setPolicy(String policy) {
this.policy = policy;
}
public Boolean getLoadbalancerEnabled() {
return loadbalancerEnabled;
}
public void setLoadbalancerEnabled(Boolean loadbalancerEnabled) {
this.loadbalancerEnabled = loadbalancerEnabled;
}
@Override
public String toString() {
return "PolarisRibbonProperties{" +
"loadbalancerEnabled=" + loadbalancerEnabled +
", policy='" + policy + '\'' +
'}';
}
}

@ -1,53 +0,0 @@
/*
* 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.rule;
import java.util.Arrays;
/**
* @author Haotian Zhang
*/
public enum PolarisLoadBalanceRule {
/**
*
*/
WEIGHTED_RANDOM_RULE("weighted_random");
/**
*
*/
String policy;
PolarisLoadBalanceRule(String strategy) {
this.policy = strategy;
}
public static PolarisLoadBalanceRule fromStrategy(String strategy) {
return Arrays.stream(values()).filter(t -> t.getPolicy().equals(strategy)).findAny()
.orElse(WEIGHTED_RANDOM_RULE);
}
/**
* {@link #policy}getter
*/
public String getPolicy() {
return policy;
}
}

@ -1,2 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.router.config.PolarisRouterAutoConfiguration
com.tencent.cloud.polaris.router.PolarisRouterAutoConfiguration

@ -17,6 +17,7 @@
package com.tencent.cloud.polaris.router.config;
import com.tencent.cloud.polaris.router.PolarisRouterAutoConfiguration;
import com.tencent.polaris.router.api.core.RouterAPI;
import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
@ -41,14 +42,6 @@ public class PolarisRibbonAutoConfigurationTest {
.withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081");
@Test
public void testDefaultInitialization() {
this.contextRunner.run(context -> {
assertThat(context).hasSingleBean(RouterAPI.class);
assertThat(context).hasSingleBean(PolarisRouterProperties.class);
});
}
@Configuration
@EnableAutoConfiguration
static class PolarisRibbonTest {

@ -15,19 +15,20 @@
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.config;
import com.tencent.cloud.polaris.router.PolarisRoutingLoadBalancer;
import com.tencent.cloud.polaris.router.rule.PolarisLoadBalanceRule;
import com.tencent.polaris.router.api.core.RouterAPI;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
package com.tencent.cloud.constant;
/**
* @author Haotian Zhang
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
@Configuration
public class PolarisRouterClientConfiguration {
public final class LoadbalancerConstant {
private LoadbalancerConstant() {}
public static final int DISCOVERY_SERVICE_INSTANCE_SUPPLIER_ORDER = 193827465 - 1000000;
/**
* We need to ensure that the routing action is performed before the load balancing action can be performed
*/
public static final int ROUTER_SERVICE_INSTANCE_SUPPLIER_ORDER = DISCOVERY_SERVICE_INSTANCE_SUPPLIER_ORDER - 1000000;
}

@ -48,6 +48,10 @@ public class PolarisServiceInstance implements ServiceInstance {
}
}
public Instance getPolarisInstance() {
return instance;
}
@Override
public String getInstanceId() {
return ServiceInstance.super.getInstanceId();

@ -22,13 +22,16 @@ import feign.Contract;
import feign.Feign;
import feign.InvocationHandlerFactory;
import feign.Target;
import feign.hystrix.FallbackFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.cloud.openfeign.FeignClientFactoryBean;
import org.springframework.cloud.openfeign.FeignContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.StringUtils;
import java.lang.reflect.InvocationHandler;
@ -85,7 +88,10 @@ public class PluggableFeign {
super.invocationHandlerFactory(new InvocationHandlerFactory() {
@Override
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
Object feignClientFactoryBean = applicationContext.getBean("&" + target.type().getName());
GenericApplicationContext gctx = (GenericApplicationContext) Builder.this.applicationContext;
BeanDefinition def = gctx.getBeanDefinition(target.type().getName());
FeignClientFactoryBean feignClientFactoryBean = (FeignClientFactoryBean) def.getAttribute("feignClientsRegistrarFactoryBean");
Class fallback = (Class) ReflectionUtils.getFieldValue(feignClientFactoryBean, "fallback");
Class fallbackFactory = (Class) ReflectionUtils.getFieldValue(feignClientFactoryBean,
@ -104,8 +110,7 @@ public class PluggableFeign {
if (void.class != fallback) {
fallbackInstance = getFallbackInstanceFromContext(beanName, "fallback", fallback,
target.type());
return new PluggableFeignInvocationHandler(target, dispatch,
new FallbackFactory.Default<>(fallbackInstance), pluggableFeignPlugins);
return new PluggableFeignInvocationHandler(target, dispatch, (FallbackFactory) fallbackInstance, pluggableFeignPlugins);
}
if (void.class != fallbackFactory) {

@ -20,7 +20,7 @@ package com.tencent.cloud.feign;
import feign.FeignException;
import feign.InvocationHandlerFactory;
import feign.Target;
import feign.hystrix.FallbackFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import java.lang.reflect.Method;
import java.util.Map;
@ -36,7 +36,7 @@ public class PluggableFeignContext {
private Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;
private FallbackFactory fallbackFactory;
private FallbackFactory<?> fallbackFactory;
private Map<Method, Method> fallbackMethodMap;
@ -66,11 +66,11 @@ public class PluggableFeignContext {
this.dispatch = dispatch;
}
public FallbackFactory getFallbackFactory() {
public FallbackFactory<?> getFallbackFactory() {
return fallbackFactory;
}
public void setFallbackFactory(FallbackFactory fallbackFactory) {
public void setFallbackFactory(FallbackFactory<?> fallbackFactory) {
this.fallbackFactory = fallbackFactory;
}

@ -20,9 +20,9 @@ package com.tencent.cloud.feign;
import feign.FeignException;
import feign.InvocationHandlerFactory;
import feign.Target;
import feign.hystrix.FallbackFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.InvocationHandler;
@ -48,7 +48,7 @@ public class PluggableFeignInvocationHandler implements InvocationHandler {
private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;
private FallbackFactory fallbackFactory;
private FallbackFactory<?> fallbackFactory;
private Map<Method, Method> fallbackMethodMap;
@ -59,7 +59,7 @@ public class PluggableFeignInvocationHandler implements InvocationHandler {
private List<PluggableFeignPlugin> exceptionPluggableFeignPlugins;
PluggableFeignInvocationHandler(Target<?> target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch,
FallbackFactory fallbackFactory, List<PluggableFeignPlugin> pluggableFeignPlugins) {
FallbackFactory<?> fallbackFactory, List<PluggableFeignPlugin> pluggableFeignPlugins) {
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch");
this.fallbackFactory = fallbackFactory;
@ -110,7 +110,9 @@ public class PluggableFeignInvocationHandler implements InvocationHandler {
prePlugin.run(context);
}
result = this.dispatch.get(method).invoke(args);
InvocationHandlerFactory.MethodHandler handler = this.dispatch.get(method);
result = handler.invoke(args);
context.setResult(result);

@ -31,7 +31,7 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import static org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER;
import static org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER;
/**
* Scg filter used for writing metadata in HTTP request header.

Loading…
Cancel
Save