refactor:refactor rpc enhancement.

pull/1080/head
Haotian Zhang 2 years ago
parent 0673da7818
commit 28a0a9fc63

@ -5,3 +5,4 @@
- feature: Enhance default configuration to support `application*.yaml` and `bootstrap*.yaml`. - feature: Enhance default configuration to support `application*.yaml` and `bootstrap*.yaml`.
- feat:adapt for nacos instance. - feat:adapt for nacos instance.
- Refactoring: Refactor Circuitbreaker ut. - Refactoring: Refactor Circuitbreaker ut.
- refactor:refactor rpc enhancement.

@ -89,7 +89,7 @@
<properties> <properties>
<!-- Project revision --> <!-- Project revision -->
<revision>1.12.0-Hoxton.SR12</revision> <revision>1.12.0-Hoxton.SR12-SNAPSHOT</revision>
<!-- Spring Framework --> <!-- Spring Framework -->
<spring.framework.version>5.2.22.RELEASE</spring.framework.version> <spring.framework.version>5.2.22.RELEASE</spring.framework.version>

@ -94,15 +94,15 @@ public class PolarisCircuitBreakerAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(SuccessCircuitBreakerReporter.class) @ConditionalOnMissingBean(SuccessCircuitBreakerReporter.class)
public SuccessCircuitBreakerReporter successCircuitBreakerReporter(RpcEnhancementReporterProperties properties, public SuccessCircuitBreakerReporter successCircuitBreakerReporter(RpcEnhancementReporterProperties properties,
SDKContext polarisContext, CircuitBreakAPI circuitBreakAPI) { CircuitBreakAPI circuitBreakAPI) {
return new SuccessCircuitBreakerReporter(properties, polarisContext, circuitBreakAPI); return new SuccessCircuitBreakerReporter(properties, circuitBreakAPI);
} }
@Bean @Bean
@ConditionalOnMissingBean(ExceptionCircuitBreakerReporter.class) @ConditionalOnMissingBean(ExceptionCircuitBreakerReporter.class)
public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhancementReporterProperties properties, public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhancementReporterProperties properties,
SDKContext polarisContext, CircuitBreakAPI circuitBreakAPI) { CircuitBreakAPI circuitBreakAPI) {
return new ExceptionCircuitBreakerReporter(properties, polarisContext, circuitBreakAPI); return new ExceptionCircuitBreakerReporter(properties, circuitBreakAPI);
} }
@Bean @Bean

@ -64,15 +64,15 @@ public class ReactivePolarisCircuitBreakerAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean(SuccessCircuitBreakerReporter.class) @ConditionalOnMissingBean(SuccessCircuitBreakerReporter.class)
public SuccessCircuitBreakerReporter successCircuitBreakerReporter(RpcEnhancementReporterProperties properties, public SuccessCircuitBreakerReporter successCircuitBreakerReporter(RpcEnhancementReporterProperties properties,
SDKContext polarisContext, CircuitBreakAPI circuitBreakAPI) { CircuitBreakAPI circuitBreakAPI) {
return new SuccessCircuitBreakerReporter(properties, polarisContext, circuitBreakAPI); return new SuccessCircuitBreakerReporter(properties, circuitBreakAPI);
} }
@Bean @Bean
@ConditionalOnMissingBean(ExceptionCircuitBreakerReporter.class) @ConditionalOnMissingBean(ExceptionCircuitBreakerReporter.class)
public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhancementReporterProperties properties, public ExceptionCircuitBreakerReporter exceptionCircuitBreakerReporter(RpcEnhancementReporterProperties properties,
SDKContext polarisContext, CircuitBreakAPI circuitBreakAPI) { CircuitBreakAPI circuitBreakAPI) {
return new ExceptionCircuitBreakerReporter(properties, polarisContext, circuitBreakAPI); return new ExceptionCircuitBreakerReporter(properties, circuitBreakAPI);
} }
@Bean @Bean

@ -19,15 +19,14 @@ package com.tencent.cloud.polaris.circuitbreaker.reporter;
import java.util.Optional; import java.util.Optional;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.PolarisEnhancedPluginUtils;
import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat; import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -36,16 +35,22 @@ import org.springframework.cloud.client.ServiceInstance;
import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.ClientPluginOrder.CIRCUIT_BREAKER_REPORTER_PLUGIN_ORDER; import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.ClientPluginOrder.CIRCUIT_BREAKER_REPORTER_PLUGIN_ORDER;
public class ExceptionCircuitBreakerReporter extends AbstractPolarisReporterAdapter implements EnhancedPlugin { /**
* ExceptionCircuitBreakerReporter.
*
* @author sean yu
*/
public class ExceptionCircuitBreakerReporter implements EnhancedPlugin {
private static final Logger LOG = LoggerFactory.getLogger(ExceptionCircuitBreakerReporter.class); private static final Logger LOG = LoggerFactory.getLogger(ExceptionCircuitBreakerReporter.class);
private final CircuitBreakAPI circuitBreakAPI; private final CircuitBreakAPI circuitBreakAPI;
private final RpcEnhancementReporterProperties reportProperties;
public ExceptionCircuitBreakerReporter(RpcEnhancementReporterProperties reportProperties, public ExceptionCircuitBreakerReporter(RpcEnhancementReporterProperties reportProperties,
SDKContext context,
CircuitBreakAPI circuitBreakAPI) { CircuitBreakAPI circuitBreakAPI) {
super(reportProperties, context); this.reportProperties = reportProperties;
this.circuitBreakAPI = circuitBreakAPI; this.circuitBreakAPI = circuitBreakAPI;
} }
@ -56,20 +61,20 @@ public class ExceptionCircuitBreakerReporter extends AbstractPolarisReporterAdap
@Override @Override
public EnhancedPluginType getType() { public EnhancedPluginType getType() {
return EnhancedPluginType.EXCEPTION; return EnhancedPluginType.Client.EXCEPTION;
} }
@Override @Override
public void run(EnhancedPluginContext context) throws Throwable { public void run(EnhancedPluginContext context) throws Throwable {
if (!super.reportProperties.isEnabled()) { if (!this.reportProperties.isEnabled()) {
return; return;
} }
EnhancedRequestContext request = context.getRequest(); EnhancedRequestContext request = context.getRequest();
ServiceInstance serviceInstance = Optional.ofNullable(context.getServiceInstance()) ServiceInstance serviceInstance = Optional.ofNullable(context.getTargetServiceInstance())
.orElse(new DefaultServiceInstance()); .orElse(new DefaultServiceInstance());
ResourceStat resourceStat = createInstanceResourceStat( ResourceStat resourceStat = PolarisEnhancedPluginUtils.createInstanceResourceStat(
serviceInstance.getServiceId(), serviceInstance.getServiceId(),
serviceInstance.getHost(), serviceInstance.getHost(),
serviceInstance.getPort(), serviceInstance.getPort(),

@ -19,17 +19,16 @@ package com.tencent.cloud.polaris.circuitbreaker.reporter;
import java.util.Optional; import java.util.Optional;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.cloud.rpc.enhancement.plugin.PolarisEnhancedPluginUtils;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter; import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter;
import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat; import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat;
import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI; import com.tencent.polaris.circuitbreak.api.CircuitBreakAPI;
import com.tencent.polaris.client.api.SDKContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -38,17 +37,22 @@ import org.springframework.cloud.client.ServiceInstance;
import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.ClientPluginOrder.CIRCUIT_BREAKER_REPORTER_PLUGIN_ORDER; import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.ClientPluginOrder.CIRCUIT_BREAKER_REPORTER_PLUGIN_ORDER;
/**
public class SuccessCircuitBreakerReporter extends AbstractPolarisReporterAdapter implements EnhancedPlugin { * SuccessCircuitBreakerReporter.
*
* @author sean yu
*/
public class SuccessCircuitBreakerReporter implements EnhancedPlugin {
private static final Logger LOG = LoggerFactory.getLogger(SuccessPolarisReporter.class); private static final Logger LOG = LoggerFactory.getLogger(SuccessPolarisReporter.class);
private final CircuitBreakAPI circuitBreakAPI; private final CircuitBreakAPI circuitBreakAPI;
private final RpcEnhancementReporterProperties reportProperties;
public SuccessCircuitBreakerReporter(RpcEnhancementReporterProperties reportProperties, public SuccessCircuitBreakerReporter(RpcEnhancementReporterProperties reportProperties,
SDKContext context,
CircuitBreakAPI circuitBreakAPI) { CircuitBreakAPI circuitBreakAPI) {
super(reportProperties, context); this.reportProperties = reportProperties;
this.circuitBreakAPI = circuitBreakAPI; this.circuitBreakAPI = circuitBreakAPI;
} }
@ -59,20 +63,20 @@ public class SuccessCircuitBreakerReporter extends AbstractPolarisReporterAdapte
@Override @Override
public EnhancedPluginType getType() { public EnhancedPluginType getType() {
return EnhancedPluginType.POST; return EnhancedPluginType.Client.POST;
} }
@Override @Override
public void run(EnhancedPluginContext context) throws Throwable { public void run(EnhancedPluginContext context) throws Throwable {
if (!super.reportProperties.isEnabled()) { if (!this.reportProperties.isEnabled()) {
return; return;
} }
EnhancedRequestContext request = context.getRequest(); EnhancedRequestContext request = context.getRequest();
EnhancedResponseContext response = context.getResponse(); EnhancedResponseContext response = context.getResponse();
ServiceInstance serviceInstance = Optional.ofNullable(context.getServiceInstance()) ServiceInstance serviceInstance = Optional.ofNullable(context.getTargetServiceInstance())
.orElse(new DefaultServiceInstance()); .orElse(new DefaultServiceInstance());
ResourceStat resourceStat = createInstanceResourceStat( ResourceStat resourceStat = PolarisEnhancedPluginUtils.createInstanceResourceStat(
serviceInstance.getServiceId(), serviceInstance.getServiceId(),
serviceInstance.getHost(), serviceInstance.getHost(),
serviceInstance.getPort(), serviceInstance.getPort(),

@ -95,7 +95,7 @@ public class ExceptionCircuitBreakerReporterTest {
@Test @Test
public void testType() { public void testType() {
assertThat(exceptionCircuitBreakerReporter.getType()).isEqualTo(EnhancedPluginType.EXCEPTION); assertThat(exceptionCircuitBreakerReporter.getType()).isEqualTo(EnhancedPluginType.Client.EXCEPTION);
} }
@Test @Test
@ -121,7 +121,7 @@ public class ExceptionCircuitBreakerReporterTest {
pluginContext.setRequest(request); pluginContext.setRequest(request);
pluginContext.setResponse(response); pluginContext.setResponse(response);
pluginContext.setServiceInstance(serviceInstance); pluginContext.setTargetServiceInstance(serviceInstance);
pluginContext.setThrowable(new RuntimeException()); pluginContext.setThrowable(new RuntimeException());
exceptionCircuitBreakerReporter.run(pluginContext); exceptionCircuitBreakerReporter.run(pluginContext);

@ -40,6 +40,7 @@ import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
@ -74,6 +75,12 @@ public class SuccessCircuitBreakerReporterTest {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test"); .thenReturn("unit-test");
ApplicationContext applicationContext = mock(ApplicationContext.class);
RpcEnhancementReporterProperties reporterProperties = mock(RpcEnhancementReporterProperties.class);
doReturn(reporterProperties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
} }
@AfterAll @AfterAll
@ -94,7 +101,7 @@ public class SuccessCircuitBreakerReporterTest {
@Test @Test
public void testType() { public void testType() {
assertThat(successCircuitBreakerReporter.getType()).isEqualTo(EnhancedPluginType.POST); assertThat(successCircuitBreakerReporter.getType()).isEqualTo(EnhancedPluginType.Client.POST);
} }
@Test @Test
@ -120,7 +127,7 @@ public class SuccessCircuitBreakerReporterTest {
pluginContext.setRequest(request); pluginContext.setRequest(request);
pluginContext.setResponse(response); pluginContext.setResponse(response);
pluginContext.setServiceInstance(serviceInstance); pluginContext.setTargetServiceInstance(serviceInstance);
successCircuitBreakerReporter.run(pluginContext); successCircuitBreakerReporter.run(pluginContext);
successCircuitBreakerReporter.getOrder(); successCircuitBreakerReporter.getOrder();

@ -45,6 +45,11 @@ public class PolarisDiscoveryProperties {
@Value("${spring.cloud.polaris.discovery.service:${spring.cloud.polaris.service:${spring.application.name:}}}") @Value("${spring.cloud.polaris.discovery.service:${spring.cloud.polaris.service:${spring.application.name:}}}")
private String service; private String service;
/**
* Service instance id.
*/
private String instanceId;
/** /**
* The polaris authentication token. * The polaris authentication token.
*/ */
@ -96,6 +101,14 @@ public class PolarisDiscoveryProperties {
*/ */
private Long serviceListRefreshInterval = 60000L; private Long serviceListRefreshInterval = 60000L;
public String getInstanceId() {
return instanceId;
}
public void setInstanceId(String instanceId) {
this.instanceId = instanceId;
}
public String getNamespace() { public String getNamespace() {
return namespace; return namespace;
} }
@ -204,6 +217,7 @@ public class PolarisDiscoveryProperties {
return "PolarisDiscoveryProperties{" + return "PolarisDiscoveryProperties{" +
"namespace='" + namespace + '\'' + "namespace='" + namespace + '\'' +
", service='" + service + '\'' + ", service='" + service + '\'' +
", instanceId='" + instanceId + '\'' +
", token='" + token + '\'' + ", token='" + token + '\'' +
", weight=" + weight + ", weight=" + weight +
", version='" + version + '\'' + ", version='" + version + '\'' +

@ -17,6 +17,9 @@
package com.tencent.cloud.polaris.registry; package com.tencent.cloud.polaris.registry;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -32,15 +35,21 @@ import org.springframework.util.StringUtils;
*/ */
public class PolarisAutoServiceRegistration extends AbstractAutoServiceRegistration<PolarisRegistration> { public class PolarisAutoServiceRegistration extends AbstractAutoServiceRegistration<PolarisRegistration> {
private static final Logger LOG = LoggerFactory.getLogger(PolarisAutoServiceRegistration.class); private static final Logger log = LoggerFactory.getLogger(PolarisAutoServiceRegistration.class);
private final PolarisRegistration registration; private final PolarisRegistration registration;
public PolarisAutoServiceRegistration(ServiceRegistry<PolarisRegistration> serviceRegistry, private final AssemblyAPI assemblyAPI;
public PolarisAutoServiceRegistration(
ServiceRegistry<PolarisRegistration> serviceRegistry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties, AutoServiceRegistrationProperties autoServiceRegistrationProperties,
PolarisRegistration registration) { PolarisRegistration registration,
AssemblyAPI assemblyAPI
) {
super(serviceRegistry, autoServiceRegistrationProperties); super(serviceRegistry, autoServiceRegistrationProperties);
this.registration = registration; this.registration = registration;
this.assemblyAPI = assemblyAPI;
} }
@Override @Override
@ -56,9 +65,12 @@ public class PolarisAutoServiceRegistration extends AbstractAutoServiceRegistrat
@Override @Override
protected void register() { protected void register() {
if (!this.registration.isRegisterEnabled()) { if (!this.registration.isRegisterEnabled()) {
LOG.debug("Registration disabled."); log.debug("Registration disabled.");
return; return;
} }
if (assemblyAPI != null) {
assemblyAPI.initService(new ServiceKey(MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE));
}
super.register(); super.register();
} }

@ -113,6 +113,7 @@ public class PolarisServiceRegistry implements ServiceRegistry<PolarisRegistrati
instanceRegisterRequest.setMetadata(registration.getMetadata()); instanceRegisterRequest.setMetadata(registration.getMetadata());
instanceRegisterRequest.setProtocol(polarisDiscoveryProperties.getProtocol()); instanceRegisterRequest.setProtocol(polarisDiscoveryProperties.getProtocol());
instanceRegisterRequest.setVersion(polarisDiscoveryProperties.getVersion()); instanceRegisterRequest.setVersion(polarisDiscoveryProperties.getVersion());
instanceRegisterRequest.setInstanceId(polarisDiscoveryProperties.getInstanceId());
try { try {
ProviderAPI providerClient = polarisDiscoveryHandler.getProviderAPI(); ProviderAPI providerClient = polarisDiscoveryHandler.getProviderAPI();
InstanceRegisterResponse instanceRegisterResponse; InstanceRegisterResponse instanceRegisterResponse;

@ -26,6 +26,7 @@ import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler;
import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties; import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties;
import com.tencent.cloud.polaris.extend.nacos.NacosContextProperties; import com.tencent.cloud.polaris.extend.nacos.NacosContextProperties;
import com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties; import com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatProperties;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import com.tencent.polaris.client.api.SDKContext; import com.tencent.polaris.client.api.SDKContext;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -50,8 +51,7 @@ import org.springframework.context.annotation.Configuration;
@EnableConfigurationProperties @EnableConfigurationProperties
@ConditionalOnPolarisRegisterEnabled @ConditionalOnPolarisRegisterEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true) @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@AutoConfigureAfter({AutoServiceRegistrationConfiguration.class, @AutoConfigureAfter({AutoServiceRegistrationConfiguration.class, AutoServiceRegistrationAutoConfiguration.class,
AutoServiceRegistrationAutoConfiguration.class,
PolarisDiscoveryAutoConfiguration.class}) PolarisDiscoveryAutoConfiguration.class})
public class PolarisServiceRegistryAutoConfiguration { public class PolarisServiceRegistryAutoConfiguration {
@ -82,8 +82,10 @@ public class PolarisServiceRegistryAutoConfiguration {
public PolarisAutoServiceRegistration polarisAutoServiceRegistration( public PolarisAutoServiceRegistration polarisAutoServiceRegistration(
PolarisServiceRegistry registry, PolarisServiceRegistry registry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties, AutoServiceRegistrationProperties autoServiceRegistrationProperties,
PolarisRegistration registration) { PolarisRegistration registration,
return new PolarisAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration); @Autowired(required = false) AssemblyAPI assemblyAPI
) {
return new PolarisAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration, assemblyAPI);
} }
@Bean @Bean

@ -85,10 +85,15 @@ public class PolarisDiscoveryPropertiesTest {
polarisDiscoveryProperties.setServiceListRefreshInterval(1000L); polarisDiscoveryProperties.setServiceListRefreshInterval(1000L);
assertThat(polarisDiscoveryProperties.getServiceListRefreshInterval()).isEqualTo(1000L); assertThat(polarisDiscoveryProperties.getServiceListRefreshInterval()).isEqualTo(1000L);
// InstanceId
polarisDiscoveryProperties.setInstanceId("test-ins-id");
assertThat(polarisDiscoveryProperties.getInstanceId()).isEqualTo("test-ins-id");
assertThat(polarisDiscoveryProperties.toString()) assertThat(polarisDiscoveryProperties.toString())
.isEqualTo("PolarisDiscoveryProperties{" .isEqualTo("PolarisDiscoveryProperties{"
+ "namespace='Test'" + "namespace='Test'"
+ ", service='java_provider_test'" + ", service='java_provider_test'"
+ ", instanceId='test-ins-id'"
+ ", token='19485a7674294e3c88dba293373c1534'" + ", token='19485a7674294e3c88dba293373c1534'"
+ ", weight=10, version='1.0.0'" + ", weight=10, version='1.0.0'"
+ ", protocol='HTTP'" + ", protocol='HTTP'"

@ -75,7 +75,7 @@ public class PolarisAutoServiceRegistrationTest {
doNothing().when(serviceRegistry).register(nullable(PolarisRegistration.class)); doNothing().when(serviceRegistry).register(nullable(PolarisRegistration.class));
polarisAutoServiceRegistration = polarisAutoServiceRegistration =
new PolarisAutoServiceRegistration(serviceRegistry, autoServiceRegistrationProperties, registration); new PolarisAutoServiceRegistration(serviceRegistry, autoServiceRegistrationProperties, registration, null);
doReturn(environment).when(applicationContext).getEnvironment(); doReturn(environment).when(applicationContext).getEnvironment();
polarisAutoServiceRegistration.setApplicationContext(applicationContext); polarisAutoServiceRegistration.setApplicationContext(applicationContext);

@ -48,11 +48,6 @@ public class MetadataContext {
*/ */
public static final String FRAGMENT_DISPOSABLE = "disposable"; public static final String FRAGMENT_DISPOSABLE = "disposable";
/**
* load balancer context.
*/
public static final String FRAGMENT_LOAD_BALANCER = "loadbalancer";
/** /**
* upstream disposable Context. * upstream disposable Context.
*/ */
@ -115,8 +110,12 @@ public class MetadataContext {
private final Map<String, Map<String, String>> fragmentContexts; private final Map<String, Map<String, String>> fragmentContexts;
private final Map<String, Object> loadbalancerMetadata;
public MetadataContext() { public MetadataContext() {
this.fragmentContexts = new ConcurrentHashMap<>(); this.fragmentContexts = new ConcurrentHashMap<>();
this.loadbalancerMetadata = new ConcurrentHashMap<>();
} }
public Map<String, String> getDisposableMetadata() { public Map<String, String> getDisposableMetadata() {
@ -148,8 +147,8 @@ public class MetadataContext {
return this.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV); return this.getFragmentContext(MetadataContext.FRAGMENT_RAW_TRANSHEADERS_KV);
} }
public Map<String, String> getLoadbalancerMetadata() { public Map<String, Object> getLoadbalancerMetadata() {
return this.getFragmentContext(FRAGMENT_LOAD_BALANCER); return this.loadbalancerMetadata;
} }
public void setTransitiveMetadata(Map<String, String> transitiveMetadata) { public void setTransitiveMetadata(Map<String, String> transitiveMetadata) {
@ -172,8 +171,8 @@ public class MetadataContext {
this.putContext(FRAGMENT_RAW_TRANSHEADERS, key, value); this.putContext(FRAGMENT_RAW_TRANSHEADERS, key, value);
} }
public void setLoadbalancer(String key, String value) { public void setLoadbalancer(String key, Object value) {
this.putContext(FRAGMENT_LOAD_BALANCER, key, value); this.loadbalancerMetadata.put(key, value);
} }
public Map<String, String> getFragmentContext(String fragment) { public Map<String, String> getFragmentContext(String fragment) {

@ -70,7 +70,7 @@
</developers> </developers>
<properties> <properties>
<revision>1.12.0-Hoxton.SR12</revision> <revision>1.12.0-Hoxton.SR12-SNAPSHOT</revision>
<!-- Dependencies --> <!-- Dependencies -->
<polaris.version>1.13.0</polaris.version> <polaris.version>1.13.0</polaris.version>

@ -110,6 +110,11 @@
<groupId>com.tencent.polaris</groupId> <groupId>com.tencent.polaris</groupId>
<artifactId>loadbalancer-ringhash</artifactId> <artifactId>loadbalancer-ringhash</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-assembly-factory</artifactId>
</dependency>
<!-- Polaris dependencies end --> <!-- Polaris dependencies end -->
<dependency> <dependency>

@ -27,6 +27,8 @@ import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.api.core.ProviderAPI; import com.tencent.polaris.api.core.ProviderAPI;
import com.tencent.polaris.api.exception.PolarisException; import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.assembly.api.AssemblyAPI;
import com.tencent.polaris.assembly.factory.AssemblyAPIFactory;
import com.tencent.polaris.client.api.SDKContext; import com.tencent.polaris.client.api.SDKContext;
import com.tencent.polaris.factory.api.DiscoveryAPIFactory; import com.tencent.polaris.factory.api.DiscoveryAPIFactory;
import com.tencent.polaris.factory.api.RouterAPIFactory; import com.tencent.polaris.factory.api.RouterAPIFactory;
@ -73,6 +75,11 @@ public class PolarisContextAutoConfiguration {
return RouterAPIFactory.createRouterAPIByContext(polarisContext); return RouterAPIFactory.createRouterAPIByContext(polarisContext);
} }
@Bean
public AssemblyAPI assemblyAPI(SDKContext polarisContext) throws PolarisException {
return AssemblyAPIFactory.createAssemblyAPIByContext(polarisContext);
}
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ModifyAddress polarisConfigModifier(PolarisContextProperties properties) { public ModifyAddress polarisConfigModifier(PolarisContextProperties properties) {

@ -17,7 +17,7 @@
<!-- Spring Cloud Tencent dependencies start --> <!-- Spring Cloud Tencent dependencies start -->
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-polaris-context</artifactId> <artifactId>spring-cloud-tencent-rpc-enhancement</artifactId>
</dependency> </dependency>
<!-- Spring Cloud Tencent dependencies end --> <!-- Spring Cloud Tencent dependencies end -->

@ -36,7 +36,7 @@ public final class PolarisLoadBalancerRingHashKeyProvider {
} }
static String getHashKey() { static String getHashKey() {
return MetadataContextHolder.get().getLoadbalancerMetadata().get(LOAD_BALANCER_HASH_KEY); return (String) MetadataContextHolder.get().getLoadbalancerMetadata().get(LOAD_BALANCER_HASH_KEY);
} }
} }

@ -17,15 +17,24 @@
package com.tencent.cloud.polaris.loadbalancer.config; package com.tencent.cloud.polaris.loadbalancer.config;
import java.util.ArrayList;
import java.util.List;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
import org.springframework.cloud.netflix.ribbon.RibbonClients; import org.springframework.cloud.netflix.ribbon.RibbonClients;
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.http.client.ClientHttpRequestInterceptor;
/** /**
* Auto-configuration Ribbon for Polaris. * Auto-configuration Ribbon for Polaris.
@ -44,4 +53,24 @@ public class PolarisLoadBalancerAutoConfiguration {
public PolarisLoadBalancerProperties polarisLoadBalancerProperties() { public PolarisLoadBalancerProperties polarisLoadBalancerProperties() {
return new PolarisLoadBalancerProperties(); return new PolarisLoadBalancerProperties();
} }
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(@Autowired(required = false) LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors());
// LoadBalancerInterceptor must invoke before EnhancedRestTemplateInterceptor
if (loadBalancerInterceptor != null) {
int addIndex = list.size();
for (int i = 0; i < list.size(); i++) {
if (list.get(i) instanceof EnhancedRestTemplateInterceptor) {
addIndex = i;
}
}
list.add(addIndex, loadBalancerInterceptor);
}
restTemplate.setInterceptors(list);
};
}
} }

@ -24,20 +24,22 @@ import com.netflix.zuul.ZuulFilter;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.rpc.enhancement.feign.EnhancedFeignBeanPostProcessor; import com.tencent.cloud.rpc.enhancement.feign.EnhancedFeignBeanPostProcessor;
import com.tencent.cloud.rpc.enhancement.filter.EnhancedReactiveFilter;
import com.tencent.cloud.rpc.enhancement.filter.EnhancedServletFilter;
import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner; import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.ExceptionPolarisReporter; import com.tencent.cloud.rpc.enhancement.plugin.reporter.ExceptionPolarisReporter;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter; import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter;
import com.tencent.cloud.rpc.enhancement.resttemplate.BlockingLoadBalancerClientAspect;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor; import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor;
import com.tencent.cloud.rpc.enhancement.resttemplate.RibbonLoadBalancerClientAspect; import com.tencent.cloud.rpc.enhancement.resttemplate.PolarisLoadBalancerRequestTransformer;
import com.tencent.cloud.rpc.enhancement.scg.EnhancedGatewayGlobalFilter; import com.tencent.cloud.rpc.enhancement.scg.EnhancedGatewayGlobalFilter;
import com.tencent.cloud.rpc.enhancement.webclient.EnhancedWebClientReporter; import com.tencent.cloud.rpc.enhancement.webclient.EnhancedWebClientExchangeFilterFunction;
import com.tencent.cloud.rpc.enhancement.webclient.PolarisLoadBalancerClientRequestTransformer; import com.tencent.cloud.rpc.enhancement.webclient.PolarisLoadBalancerClientRequestTransformer;
import com.tencent.cloud.rpc.enhancement.webclient.RibbonLoadBalancerClientAspect;
import com.tencent.cloud.rpc.enhancement.zuul.EnhancedErrorZuulFilter; import com.tencent.cloud.rpc.enhancement.zuul.EnhancedErrorZuulFilter;
import com.tencent.cloud.rpc.enhancement.zuul.EnhancedPostZuulFilter; import com.tencent.cloud.rpc.enhancement.zuul.EnhancedPostZuulFilter;
import com.tencent.cloud.rpc.enhancement.zuul.EnhancedPreZuulFilter; import com.tencent.cloud.rpc.enhancement.zuul.EnhancedRouteZuulFilter;
import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.client.api.SDKContext; import com.tencent.polaris.client.api.SDKContext;
@ -49,16 +51,26 @@ import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.client.serviceregistry.Registration;
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.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Role; import org.springframework.context.annotation.Role;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
import static javax.servlet.DispatcherType.ASYNC;
import static javax.servlet.DispatcherType.ERROR;
import static javax.servlet.DispatcherType.FORWARD;
import static javax.servlet.DispatcherType.INCLUDE;
import static javax.servlet.DispatcherType.REQUEST;
/** /**
* Auto Configuration for Polaris {@link feign.Feign} OR {@link RestTemplate} which can automatically bring in the call * Auto Configuration for Polaris {@link feign.Feign} OR {@link RestTemplate} which can automatically bring in the call
* results for reporting. * results for reporting.
@ -73,23 +85,55 @@ import org.springframework.web.reactive.function.client.WebClient;
public class RpcEnhancementAutoConfiguration { public class RpcEnhancementAutoConfiguration {
@Bean @Bean
@Lazy
public EnhancedPluginRunner enhancedFeignPluginRunner( public EnhancedPluginRunner enhancedFeignPluginRunner(
@Autowired(required = false) List<EnhancedPlugin> enhancedPlugins) { @Autowired(required = false) List<EnhancedPlugin> enhancedPlugins,
return new DefaultEnhancedPluginRunner(enhancedPlugins); @Autowired(required = false) Registration registration,
SDKContext sdkContext) {
return new DefaultEnhancedPluginRunner(enhancedPlugins, registration, sdkContext);
} }
@Bean @Bean
public SuccessPolarisReporter successPolarisReporter(RpcEnhancementReporterProperties properties, public SuccessPolarisReporter successPolarisReporter(RpcEnhancementReporterProperties properties,
SDKContext context,
ConsumerAPI consumerAPI) { ConsumerAPI consumerAPI) {
return new SuccessPolarisReporter(properties, context, consumerAPI); return new SuccessPolarisReporter(properties, consumerAPI);
} }
@Bean @Bean
public ExceptionPolarisReporter exceptionPolarisReporter(RpcEnhancementReporterProperties properties, public ExceptionPolarisReporter exceptionPolarisReporter(RpcEnhancementReporterProperties properties,
SDKContext context,
ConsumerAPI consumerAPI) { ConsumerAPI consumerAPI) {
return new ExceptionPolarisReporter(properties, context, consumerAPI); return new ExceptionPolarisReporter(properties, consumerAPI);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
protected static class RpcEnhancementServletFilterConfig {
@Bean
public FilterRegistrationBean<EnhancedServletFilter> enhancedServletFilterRegistrationBean(
EnhancedServletFilter enhancedServletFilter) {
FilterRegistrationBean<EnhancedServletFilter> filterRegistrationBean =
new FilterRegistrationBean<>(enhancedServletFilter);
filterRegistrationBean.setDispatcherTypes(ASYNC, ERROR, FORWARD, INCLUDE, REQUEST);
filterRegistrationBean.setOrder(enhancedServletFilter.getClass().getAnnotation(Order.class).value());
return filterRegistrationBean;
}
@Bean
public EnhancedServletFilter enhancedServletFilter(@Lazy EnhancedPluginRunner pluginRunner) {
return new EnhancedServletFilter(pluginRunner);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
protected static class RpcEnhancementReactiveFilterConfig {
@Bean
public EnhancedReactiveFilter enhancedReactiveFilter(@Lazy EnhancedPluginRunner pluginRunner) {
return new EnhancedReactiveFilter(pluginRunner);
}
} }
/** /**
@ -141,16 +185,9 @@ public class RpcEnhancementAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
@ConditionalOnClass(name = {"org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient"}) @ConditionalOnClass(name = {"org.springframework.cloud.client.loadbalancer.LoadBalancerRequestTransformer"})
public BlockingLoadBalancerClientAspect blockingLoadBalancerClientAspect() { public PolarisLoadBalancerRequestTransformer polarisLoadBalancerRequestTransformer() {
return new BlockingLoadBalancerClientAspect(); return new PolarisLoadBalancerRequestTransformer();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(name = {"org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient"})
public RibbonLoadBalancerClientAspect ribbonLoadBalancerClientAspect() {
return new RibbonLoadBalancerClientAspect();
} }
} }
@ -166,12 +203,12 @@ public class RpcEnhancementAutoConfiguration {
private List<WebClient.Builder> webClientBuilder = Collections.emptyList(); private List<WebClient.Builder> webClientBuilder = Collections.emptyList();
@Bean @Bean
public EnhancedWebClientReporter exchangeFilterFunction(@Lazy EnhancedPluginRunner pluginRunner) { public EnhancedWebClientExchangeFilterFunction exchangeFilterFunction(@Lazy EnhancedPluginRunner pluginRunner) {
return new EnhancedWebClientReporter(pluginRunner); return new EnhancedWebClientExchangeFilterFunction(pluginRunner);
} }
@Bean @Bean
public SmartInitializingSingleton addEnhancedWebClientReporterForWebClient(EnhancedWebClientReporter reporter) { public SmartInitializingSingleton addEnhancedWebClientReporterForWebClient(EnhancedWebClientExchangeFilterFunction reporter) {
return () -> webClientBuilder.forEach(webClient -> { return () -> webClientBuilder.forEach(webClient -> {
webClient.filter(reporter); webClient.filter(reporter);
}); });
@ -184,6 +221,12 @@ public class RpcEnhancementAutoConfiguration {
return new PolarisLoadBalancerClientRequestTransformer(); return new PolarisLoadBalancerClientRequestTransformer();
} }
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(name = {"org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient"})
public RibbonLoadBalancerClientAspect ribbonLoadBalancerClientAspect() {
return new RibbonLoadBalancerClientAspect();
}
} }
/** /**
@ -211,8 +254,8 @@ public class RpcEnhancementAutoConfiguration {
@ConditionalOnClass(name = "com.netflix.zuul.http.ZuulServlet") @ConditionalOnClass(name = "com.netflix.zuul.http.ZuulServlet")
protected static class PolarisCircuitBreakerZuulFilterConfig { protected static class PolarisCircuitBreakerZuulFilterConfig {
@Bean @Bean
public EnhancedPreZuulFilter enhancedZuulPreFilter(@Lazy EnhancedPluginRunner pluginRunner, Environment environment) { public EnhancedRouteZuulFilter enhancedZuulRouteFilter(@Lazy EnhancedPluginRunner pluginRunner, Environment environment) {
return new EnhancedPreZuulFilter(pluginRunner, environment); return new EnhancedRouteZuulFilter(pluginRunner, environment);
} }
@Bean @Bean

@ -23,6 +23,7 @@ import java.util.ArrayList;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import feign.Client; import feign.Client;
@ -34,10 +35,6 @@ import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.EXCEPTION;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.FINALLY;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.POST;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.PRE;
import static feign.Util.checkNotNull; import static feign.Util.checkNotNull;
/** /**
@ -66,13 +63,19 @@ public class EnhancedFeignClient implements Client {
EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder() EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpHeaders(requestHeaders) .httpHeaders(requestHeaders)
.httpMethod(HttpMethod.resolve(request.httpMethod().name())) .httpMethod(HttpMethod.valueOf(request.httpMethod().name()))
.url(url) .url(url)
.build(); .build();
enhancedPluginContext.setRequest(enhancedRequestContext); enhancedPluginContext.setRequest(enhancedRequestContext);
enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance());
DefaultServiceInstance serviceInstance = new DefaultServiceInstance(request.requestTemplate().feignTarget()
.name(), url.getHost(), url.getPort(), url.getScheme().equals("https"));
enhancedPluginContext.setTargetServiceInstance(serviceInstance);
// Run pre enhanced plugins. // Run pre enhanced plugins.
pluginRunner.run(PRE, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.PRE, enhancedPluginContext);
long startMillis = System.currentTimeMillis(); long startMillis = System.currentTimeMillis();
try { try {
Response response = delegate.execute(request, options); Response response = delegate.execute(request, options);
@ -87,24 +90,20 @@ public class EnhancedFeignClient implements Client {
.build(); .build();
enhancedPluginContext.setResponse(enhancedResponseContext); enhancedPluginContext.setResponse(enhancedResponseContext);
DefaultServiceInstance serviceInstance = new DefaultServiceInstance(request.requestTemplate().feignTarget()
.name(), url.getHost(), url.getPort(), url.getScheme().equals("https"));
enhancedPluginContext.setServiceInstance(serviceInstance);
// Run post enhanced plugins. // Run post enhanced plugins.
pluginRunner.run(POST, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.POST, enhancedPluginContext);
return response; return response;
} }
catch (IOException origin) { catch (IOException origin) {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis); enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
enhancedPluginContext.setThrowable(origin); enhancedPluginContext.setThrowable(origin);
// Run exception enhanced feign plugins. // Run exception enhanced feign plugins.
pluginRunner.run(EXCEPTION, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.EXCEPTION, enhancedPluginContext);
throw origin; throw origin;
} }
finally { finally {
// Run finally enhanced plugins. // Run finally enhanced plugins.
pluginRunner.run(FINALLY, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.FINALLY, enhancedPluginContext);
} }
} }
} }

@ -0,0 +1,93 @@
/*
* 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.rpc.enhancement.filter;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import reactor.core.publisher.Mono;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
/**
* EnhancedReactiveFilter.
*
* @author sean yu
*/
public class EnhancedReactiveFilter implements WebFilter, Ordered {
private final EnhancedPluginRunner pluginRunner;
public EnhancedReactiveFilter(EnhancedPluginRunner pluginRunner) {
this.pluginRunner = pluginRunner;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpHeaders(exchange.getRequest().getHeaders())
.httpMethod(exchange.getRequest().getMethod())
.url(exchange.getRequest().getURI())
.build();
enhancedPluginContext.setRequest(enhancedRequestContext);
enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance());
// Run pre enhanced plugins.
pluginRunner.run(EnhancedPluginType.Server.PRE, enhancedPluginContext);
long startMillis = System.currentTimeMillis();
return chain.filter(exchange)
.doOnSuccess(v -> {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
EnhancedResponseContext enhancedResponseContext = EnhancedResponseContext.builder()
.httpStatus(exchange.getResponse().getRawStatusCode())
.httpHeaders(exchange.getResponse().getHeaders())
.build();
enhancedPluginContext.setResponse(enhancedResponseContext);
// Run post enhanced plugins.
pluginRunner.run(EnhancedPluginType.Server.POST, enhancedPluginContext);
})
.doOnError(e -> {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
enhancedPluginContext.setThrowable(e);
// Run exception enhanced plugins.
pluginRunner.run(EnhancedPluginType.Server.EXCEPTION, enhancedPluginContext);
})
.doFinally(v -> {
// Run finally enhanced plugins.
pluginRunner.run(EnhancedPluginType.Server.FINALLY, enhancedPluginContext);
});
}
@Override
public int getOrder() {
return MetadataConstant.OrderConstant.WEB_FILTER_ORDER + 1;
}
}

@ -0,0 +1,116 @@
/*
* 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.rpc.enhancement.filter;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* EnhancedServletFilter.
*
* @author sean yu
*/
@Order(MetadataConstant.OrderConstant.WEB_FILTER_ORDER + 1)
public class EnhancedServletFilter extends OncePerRequestFilter {
private final EnhancedPluginRunner pluginRunner;
public EnhancedServletFilter(EnhancedPluginRunner pluginRunner) {
this.pluginRunner = pluginRunner;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
HttpHeaders requestHeaders = new HttpHeaders();
Enumeration<String> requestHeaderNames = request.getHeaderNames();
if (requestHeaderNames != null) {
while (requestHeaderNames.hasMoreElements()) {
String requestHeaderName = requestHeaderNames.nextElement();
requestHeaders.addAll(requestHeaderName, Collections.list(request.getHeaders(requestHeaderName)));
}
}
EnhancedRequestContext enhancedRequestContext = EnhancedRequestContext.builder()
.httpHeaders(requestHeaders)
.httpMethod(HttpMethod.valueOf(request.getMethod()))
.url(URI.create(request.getRequestURL().toString()))
.build();
enhancedPluginContext.setRequest(enhancedRequestContext);
enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance());
// Run pre enhanced plugins.
pluginRunner.run(EnhancedPluginType.Server.PRE, enhancedPluginContext);
long startMillis = System.currentTimeMillis();
try {
filterChain.doFilter(request, response);
enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
HttpHeaders responseHeaders = new HttpHeaders();
Collection<String> responseHeaderNames = response.getHeaderNames();
if (responseHeaderNames != null) {
for (String responseHeaderName : responseHeaderNames) {
responseHeaders.addAll(responseHeaderName, new ArrayList<>(response.getHeaders(responseHeaderName)));
}
}
EnhancedResponseContext enhancedResponseContext = EnhancedResponseContext.builder()
.httpStatus(response.getStatus())
.httpHeaders(responseHeaders)
.build();
enhancedPluginContext.setResponse(enhancedResponseContext);
// Run post enhanced plugins.
pluginRunner.run(EnhancedPluginType.Server.POST, enhancedPluginContext);
}
catch (ServletException | IOException e) {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
enhancedPluginContext.setThrowable(e);
// Run exception enhanced plugins.
pluginRunner.run(EnhancedPluginType.Server.EXCEPTION, enhancedPluginContext);
throw e;
}
finally {
// Run finally enhanced plugins.
pluginRunner.run(EnhancedPluginType.Server.FINALLY, enhancedPluginContext);
}
}
}

@ -23,7 +23,12 @@ import java.util.List;
import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.polaris.client.api.SDKContext;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
/** /**
@ -33,13 +38,28 @@ import org.springframework.util.CollectionUtils;
*/ */
public class DefaultEnhancedPluginRunner implements EnhancedPluginRunner { public class DefaultEnhancedPluginRunner implements EnhancedPluginRunner {
private final Multimap<String, EnhancedPlugin> pluginMap = ArrayListMultimap.create(); private final Multimap<EnhancedPluginType, EnhancedPlugin> pluginMap = ArrayListMultimap.create();
public DefaultEnhancedPluginRunner(List<EnhancedPlugin> enhancedPlugins) { private final ServiceInstance localServiceInstance;
public DefaultEnhancedPluginRunner(
List<EnhancedPlugin> enhancedPlugins,
Registration registration,
SDKContext sdkContext
) {
if (!CollectionUtils.isEmpty(enhancedPlugins)) { if (!CollectionUtils.isEmpty(enhancedPlugins)) {
enhancedPlugins.stream() enhancedPlugins.stream()
.sorted(Comparator.comparing(EnhancedPlugin::getOrder)) .sorted(Comparator.comparing(EnhancedPlugin::getOrder))
.forEach(plugin -> pluginMap.put(plugin.getType().name(), plugin)); .forEach(plugin -> pluginMap.put(plugin.getType(), plugin));
}
if (registration != null) {
localServiceInstance = registration;
}
else {
DefaultServiceInstance defaultServiceInstance = new DefaultServiceInstance();
defaultServiceInstance.setServiceId(MetadataContext.LOCAL_SERVICE);
defaultServiceInstance.setHost(sdkContext.getConfig().getGlobal().getAPI().getBindIP());
localServiceInstance = defaultServiceInstance;
} }
} }
@ -51,7 +71,7 @@ public class DefaultEnhancedPluginRunner implements EnhancedPluginRunner {
*/ */
@Override @Override
public void run(EnhancedPluginType pluginType, EnhancedPluginContext context) { public void run(EnhancedPluginType pluginType, EnhancedPluginContext context) {
for (EnhancedPlugin plugin : pluginMap.get(pluginType.name())) { for (EnhancedPlugin plugin : pluginMap.get(pluginType)) {
try { try {
plugin.run(context); plugin.run(context);
} }
@ -60,4 +80,10 @@ public class DefaultEnhancedPluginRunner implements EnhancedPluginRunner {
} }
} }
} }
@Override
public ServiceInstance getLocalServiceInstance() {
return this.localServiceInstance;
}
} }

@ -35,7 +35,12 @@ public class EnhancedPluginContext {
private long delay; private long delay;
private ServiceInstance serviceInstance; private ServiceInstance localServiceInstance;
/**
* targetServiceInstance only exist in a client runner type.
*/
private ServiceInstance targetServiceInstance;
public EnhancedRequestContext getRequest() { public EnhancedRequestContext getRequest() {
return request; return request;
@ -69,12 +74,20 @@ public class EnhancedPluginContext {
this.delay = delay; this.delay = delay;
} }
public ServiceInstance getServiceInstance() { public ServiceInstance getLocalServiceInstance() {
return serviceInstance; return localServiceInstance;
}
public void setLocalServiceInstance(ServiceInstance localServiceInstance) {
this.localServiceInstance = localServiceInstance;
} }
public void setServiceInstance(ServiceInstance serviceInstance) { public ServiceInstance getTargetServiceInstance() {
this.serviceInstance = serviceInstance; return targetServiceInstance;
}
public void setTargetServiceInstance(ServiceInstance targetServiceInstance) {
this.targetServiceInstance = targetServiceInstance;
} }
@Override @Override
@ -84,7 +97,9 @@ public class EnhancedPluginContext {
", response=" + response + ", response=" + response +
", throwable=" + throwable + ", throwable=" + throwable +
", delay=" + delay + ", delay=" + delay +
", serviceInstance=" + serviceInstance + ", localServiceInstance=" + localServiceInstance +
", targetServiceInstance=" + targetServiceInstance +
'}'; '}';
} }
} }

@ -18,6 +18,8 @@
package com.tencent.cloud.rpc.enhancement.plugin; package com.tencent.cloud.rpc.enhancement.plugin;
import org.springframework.cloud.client.ServiceInstance;
/** /**
* Plugin runner. * Plugin runner.
* *
@ -32,4 +34,7 @@ public interface EnhancedPluginRunner {
* @param context context in enhanced feign client. * @param context context in enhanced feign client.
*/ */
void run(EnhancedPluginType pluginType, EnhancedPluginContext context); void run(EnhancedPluginType pluginType, EnhancedPluginContext context);
ServiceInstance getLocalServiceInstance();
} }

@ -22,25 +22,52 @@ package com.tencent.cloud.rpc.enhancement.plugin;
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
public enum EnhancedPluginType { public interface EnhancedPluginType {
/** enum Client implements EnhancedPluginType {
* Pre feign plugin. /**
*/ * Pre Client plugin.
PRE, */
PRE,
/**
* Post feign plugin. /**
*/ * Post Client plugin.
POST, */
POST,
/**
* Exception feign plugin. /**
*/ * Exception Client plugin.
EXCEPTION, */
EXCEPTION,
/**
* Finally feign plugin. /**
*/ * Finally Client plugin.
FINALLY */
FINALLY
}
enum Server implements EnhancedPluginType {
/**
* Pre Server plugin.
*/
PRE,
/**
* Post Server plugin.
*/
POST,
/**
* Exception Server plugin.
*/
EXCEPTION,
/**
* Finally Server plugin.
*/
FINALLY
}
} }

@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License. * specific language governing permissions and limitations under the License.
*/ */
package com.tencent.cloud.rpc.enhancement; package com.tencent.cloud.rpc.enhancement.plugin;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
@ -24,12 +24,18 @@ import java.net.URLDecoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tencent.cloud.common.constant.HeaderConstant; import com.tencent.cloud.common.constant.HeaderConstant;
import com.tencent.cloud.common.constant.RouterConstant; import com.tencent.cloud.common.constant.RouterConstant;
import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.common.util.RequestLabelUtils; import com.tencent.cloud.common.util.RequestLabelUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat; import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat;
@ -39,11 +45,11 @@ import com.tencent.polaris.api.pojo.RetStatus;
import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.api.rpc.ServiceCallResult; import com.tencent.polaris.api.rpc.ServiceCallResult;
import com.tencent.polaris.api.utils.CollectionUtils; import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.client.api.SDKContext;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@ -63,30 +69,21 @@ import static org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE;
import static org.springframework.http.HttpStatus.VARIANT_ALSO_NEGOTIATES; import static org.springframework.http.HttpStatus.VARIANT_ALSO_NEGOTIATES;
/** /**
* Abstract Polaris Reporter Adapter . * Abstract Polaris Plugin Adapter .
* *
* @author <a href="mailto:iskp.me@gmail.com">Elve.Xu</a> 2022-07-11 * @author <a href="mailto:iskp.me@gmail.com">Elve.Xu</a> 2022-07-11
*/ */
public abstract class AbstractPolarisReporterAdapter { public final class PolarisEnhancedPluginUtils {
private static final Logger LOG = LoggerFactory.getLogger(AbstractPolarisReporterAdapter.class);
private static final List<HttpStatus> HTTP_STATUSES = toList(NOT_IMPLEMENTED, BAD_GATEWAY,
SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT, HTTP_VERSION_NOT_SUPPORTED, VARIANT_ALSO_NEGOTIATES,
INSUFFICIENT_STORAGE, LOOP_DETECTED, BANDWIDTH_LIMIT_EXCEEDED, NOT_EXTENDED, NETWORK_AUTHENTICATION_REQUIRED);
protected final RpcEnhancementReporterProperties reportProperties; private PolarisEnhancedPluginUtils() {
protected final SDKContext context;
/**
* Constructor With {@link RpcEnhancementReporterProperties} .
*
* @param reportProperties instance of {@link RpcEnhancementReporterProperties}.
*/
protected AbstractPolarisReporterAdapter(RpcEnhancementReporterProperties reportProperties, SDKContext context) {
this.reportProperties = reportProperties;
this.context = context;
} }
private static final Logger LOG = LoggerFactory.getLogger(PolarisEnhancedPluginUtils.class);
private static final List<HttpStatus> HTTP_STATUSES = toList(NOT_IMPLEMENTED, BAD_GATEWAY,
SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT, HTTP_VERSION_NOT_SUPPORTED, VARIANT_ALSO_NEGOTIATES,
INSUFFICIENT_STORAGE, LOOP_DETECTED, BANDWIDTH_LIMIT_EXCEEDED, NOT_EXTENDED, NETWORK_AUTHENTICATION_REQUIRED);
/** /**
* createServiceCallResult. * createServiceCallResult.
* @param calleeServiceName will pick up url host when null * @param calleeServiceName will pick up url host when null
@ -100,7 +97,7 @@ public abstract class AbstractPolarisReporterAdapter {
* @param exception exception * @param exception exception
* @return ServiceCallResult * @return ServiceCallResult
*/ */
public ServiceCallResult createServiceCallResult( public static ServiceCallResult createServiceCallResult(String callerHost,
@Nullable String calleeServiceName, @Nullable String calleeHost, @Nullable Integer calleePort, @Nullable String calleeServiceName, @Nullable String calleeHost, @Nullable Integer calleePort,
URI uri, HttpHeaders requestHeaders, @Nullable HttpHeaders responseHeaders, URI uri, HttpHeaders requestHeaders, @Nullable HttpHeaders responseHeaders,
@Nullable Integer statusCode, long delay, @Nullable Throwable exception) { @Nullable Integer statusCode, long delay, @Nullable Throwable exception) {
@ -112,11 +109,11 @@ public abstract class AbstractPolarisReporterAdapter {
resultRequest.setRetCode(statusCode == null ? -1 : statusCode); resultRequest.setRetCode(statusCode == null ? -1 : statusCode);
resultRequest.setDelay(delay); resultRequest.setDelay(delay);
resultRequest.setCallerService(new ServiceKey(MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE)); resultRequest.setCallerService(new ServiceKey(MetadataContext.LOCAL_NAMESPACE, MetadataContext.LOCAL_SERVICE));
resultRequest.setCallerIp(this.context.getConfig().getGlobal().getAPI().getBindIP()); resultRequest.setCallerIp(callerHost);
resultRequest.setHost(StringUtils.isBlank(calleeHost) ? uri.getHost() : calleeHost); resultRequest.setHost(StringUtils.isBlank(calleeHost) ? uri.getHost() : calleeHost);
resultRequest.setPort(calleePort == null ? getPort(uri) : calleePort); resultRequest.setPort(calleePort == null ? getPort(uri) : calleePort);
resultRequest.setLabels(getLabels(requestHeaders)); resultRequest.setLabels(getLabels(requestHeaders));
resultRequest.setRetStatus(getRetStatusFromRequest(responseHeaders, getDefaultRetStatus(statusCode, exception))); resultRequest.setRetStatus(getRetStatusFromRequest(responseHeaders, statusCode, exception));
resultRequest.setRuleName(getActiveRuleNameFromRequest(responseHeaders)); resultRequest.setRuleName(getActiveRuleNameFromRequest(responseHeaders));
return resultRequest; return resultRequest;
} }
@ -132,7 +129,7 @@ public abstract class AbstractPolarisReporterAdapter {
* @param exception exception * @param exception exception
* @return ResourceStat * @return ResourceStat
*/ */
public ResourceStat createInstanceResourceStat( public static ResourceStat createInstanceResourceStat(
@Nullable String calleeServiceName, @Nullable String calleeHost, @Nullable Integer calleePort, @Nullable String calleeServiceName, @Nullable String calleeHost, @Nullable Integer calleePort,
URI uri, @Nullable Integer statusCode, long delay, @Nullable Throwable exception) { URI uri, @Nullable Integer statusCode, long delay, @Nullable Throwable exception) {
ServiceKey calleeServiceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, StringUtils.isBlank(calleeServiceName) ? uri.getHost() : calleeServiceName); ServiceKey calleeServiceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, StringUtils.isBlank(calleeServiceName) ? uri.getHost() : calleeServiceName);
@ -165,42 +162,40 @@ public abstract class AbstractPolarisReporterAdapter {
* @param httpStatus request http status code * @param httpStatus request http status code
* @return true , otherwise return false . * @return true , otherwise return false .
*/ */
protected boolean apply(@Nullable HttpStatus httpStatus) { static boolean apply(@Nullable HttpStatus httpStatus) {
if (Objects.isNull(httpStatus)) { if (Objects.isNull(httpStatus)) {
return false; return false;
} }
else { RpcEnhancementReporterProperties reportProperties;
// statuses > series try {
List<HttpStatus> status = reportProperties.getStatuses(); reportProperties = ApplicationContextAwareUtils.getApplicationContext().getBean(RpcEnhancementReporterProperties.class);
}
if (status.isEmpty()) { catch (BeansException e) {
List<HttpStatus.Series> series = reportProperties.getSeries(); LOG.error("get RpcEnhancementReporterProperties bean err", e);
// Check INTERNAL_SERVER_ERROR (500) status. reportProperties = new RpcEnhancementReporterProperties();
if (reportProperties.isIgnoreInternalServerError() && Objects.equals(httpStatus, INTERNAL_SERVER_ERROR)) { }
return false; // statuses > series
} List<HttpStatus> status = reportProperties.getStatuses();
if (series.isEmpty()) { if (status.isEmpty()) {
return HTTP_STATUSES.contains(httpStatus); List<HttpStatus.Series> series = reportProperties.getSeries();
} // Check INTERNAL_SERVER_ERROR (500) status.
else { if (reportProperties.isIgnoreInternalServerError() && Objects.equals(httpStatus, INTERNAL_SERVER_ERROR)) {
try { return false;
return series.contains(HttpStatus.Series.valueOf(httpStatus));
}
catch (Exception e) {
LOG.warn("Decode http status failed.", e);
}
}
} }
else { if (series.isEmpty()) {
// Use the user-specified fuse status code. return HTTP_STATUSES.contains(httpStatus);
return status.contains(httpStatus);
} }
return series.contains(httpStatus.series());
} }
// DEFAULT RETURN FALSE. // Use the user-specified fuse status code.
return false; return status.contains(httpStatus);
}
public static RetStatus getRetStatusFromRequest(HttpHeaders headers, Integer statusCode, Throwable exception) {
return getRetStatusFromRequest(headers, getDefaultRetStatus(statusCode, exception));
} }
protected RetStatus getRetStatusFromRequest(HttpHeaders headers, RetStatus defaultVal) { static RetStatus getRetStatusFromRequest(HttpHeaders headers, RetStatus defaultVal) {
if (headers != null && headers.containsKey(HeaderConstant.INTERNAL_CALLEE_RET_STATUS)) { if (headers != null && headers.containsKey(HeaderConstant.INTERNAL_CALLEE_RET_STATUS)) {
List<String> values = headers.get(HeaderConstant.INTERNAL_CALLEE_RET_STATUS); List<String> values = headers.get(HeaderConstant.INTERNAL_CALLEE_RET_STATUS);
if (CollectionUtils.isNotEmpty(values)) { if (CollectionUtils.isNotEmpty(values)) {
@ -216,7 +211,7 @@ public abstract class AbstractPolarisReporterAdapter {
return defaultVal; return defaultVal;
} }
protected String getActiveRuleNameFromRequest(HttpHeaders headers) { static String getActiveRuleNameFromRequest(HttpHeaders headers) {
if (headers != null && headers.containsKey(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME)) { if (headers != null && headers.containsKey(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME)) {
Collection<String> values = headers.get(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME); Collection<String> values = headers.get(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME);
if (CollectionUtils.isNotEmpty(values)) { if (CollectionUtils.isNotEmpty(values)) {
@ -226,7 +221,7 @@ public abstract class AbstractPolarisReporterAdapter {
return ""; return "";
} }
private RetStatus getDefaultRetStatus(Integer statusCode, Throwable exception) { private static RetStatus getDefaultRetStatus(Integer statusCode, Throwable exception) {
RetStatus retStatus = RetStatus.RetSuccess; RetStatus retStatus = RetStatus.RetSuccess;
if (exception != null) { if (exception != null) {
retStatus = RetStatus.RetFail; retStatus = RetStatus.RetFail;
@ -240,12 +235,12 @@ public abstract class AbstractPolarisReporterAdapter {
return retStatus; return retStatus;
} }
private int getPort(URI uri) { private static int getPort(URI uri) {
// -1 means access directly by url, and use http default port number 80 // -1 means access directly by url, and use http default port number 80
return uri.getPort() == -1 ? 80 : uri.getPort(); return uri.getPort() == -1 ? 80 : uri.getPort();
} }
private String getLabels(HttpHeaders headers) { private static String getLabels(HttpHeaders headers) {
if (headers != null) { if (headers != null) {
Collection<String> labels = headers.get(RouterConstant.ROUTER_LABEL_HEADER); Collection<String> labels = headers.get(RouterConstant.ROUTER_LABEL_HEADER);
if (CollectionUtils.isNotEmpty(labels) && labels.iterator().hasNext()) { if (CollectionUtils.isNotEmpty(labels) && labels.iterator().hasNext()) {
@ -262,5 +257,27 @@ public abstract class AbstractPolarisReporterAdapter {
return null; return null;
} }
public static Map<String, String> getLabelMap(HttpHeaders headers) {
if (headers != null) {
Collection<String> labels = headers.get(RouterConstant.ROUTER_LABEL_HEADER);
if (CollectionUtils.isNotEmpty(labels) && labels.iterator().hasNext()) {
String label = labels.iterator().next();
try {
label = URLDecoder.decode(label, UTF_8);
}
catch (UnsupportedEncodingException e) {
LOG.error("unsupported charset exception " + UTF_8, e);
}
try {
return new ObjectMapper().readValue(label, new TypeReference<HashMap<String, String>>() { });
}
catch (JsonProcessingException e) {
LOG.error("parse label map exception", e);
}
}
}
return null;
}
} }

@ -20,15 +20,14 @@ package com.tencent.cloud.rpc.enhancement.plugin.reporter;
import java.util.Optional; import java.util.Optional;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.PolarisEnhancedPluginUtils;
import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.api.rpc.ServiceCallResult; import com.tencent.polaris.api.rpc.ServiceCallResult;
import com.tencent.polaris.client.api.SDKContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -42,16 +41,17 @@ import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.Clien
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
public class ExceptionPolarisReporter extends AbstractPolarisReporterAdapter implements EnhancedPlugin { public class ExceptionPolarisReporter implements EnhancedPlugin {
private static final Logger LOG = LoggerFactory.getLogger(ExceptionPolarisReporter.class); private static final Logger LOG = LoggerFactory.getLogger(ExceptionPolarisReporter.class);
private final ConsumerAPI consumerAPI; private final ConsumerAPI consumerAPI;
public ExceptionPolarisReporter(RpcEnhancementReporterProperties reporterProperties, private final RpcEnhancementReporterProperties reportProperties;
SDKContext context,
public ExceptionPolarisReporter(RpcEnhancementReporterProperties reportProperties,
ConsumerAPI consumerAPI) { ConsumerAPI consumerAPI) {
super(reporterProperties, context); this.reportProperties = reportProperties;
this.consumerAPI = consumerAPI; this.consumerAPI = consumerAPI;
} }
@ -62,23 +62,24 @@ public class ExceptionPolarisReporter extends AbstractPolarisReporterAdapter imp
@Override @Override
public EnhancedPluginType getType() { public EnhancedPluginType getType() {
return EnhancedPluginType.EXCEPTION; return EnhancedPluginType.Client.EXCEPTION;
} }
@Override @Override
public void run(EnhancedPluginContext context) { public void run(EnhancedPluginContext context) {
if (!super.reportProperties.isEnabled()) { if (!this.reportProperties.isEnabled()) {
return; return;
} }
EnhancedRequestContext request = context.getRequest(); EnhancedRequestContext request = context.getRequest();
ServiceInstance serviceInstance = Optional.ofNullable(context.getServiceInstance()) ServiceInstance callerServiceInstance = Optional.ofNullable(context.getLocalServiceInstance()).orElse(new DefaultServiceInstance());
.orElse(new DefaultServiceInstance()); ServiceInstance calleeServiceInstance = Optional.ofNullable(context.getTargetServiceInstance()).orElse(new DefaultServiceInstance());
ServiceCallResult resultRequest = createServiceCallResult( ServiceCallResult resultRequest = PolarisEnhancedPluginUtils.createServiceCallResult(
serviceInstance.getServiceId(), callerServiceInstance.getHost(),
serviceInstance.getHost(), calleeServiceInstance.getServiceId(),
serviceInstance.getPort(), calleeServiceInstance.getHost(),
calleeServiceInstance.getPort(),
request.getUrl(), request.getUrl(),
request.getHttpHeaders(), request.getHttpHeaders(),
null, null,
@ -88,8 +89,7 @@ public class ExceptionPolarisReporter extends AbstractPolarisReporterAdapter imp
); );
LOG.debug("Will report ServiceCallResult of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.", LOG.debug("Will report ServiceCallResult of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.",
resultRequest.getRetStatus().name(), request.getHttpMethod().name(), request.getUrl() resultRequest.getRetStatus().name(), request.getHttpMethod().name(), request.getUrl().getPath(), context.getThrowable().getMessage(), context.getDelay());
.getPath(), context.getThrowable().getMessage(), context.getDelay());
consumerAPI.updateServiceCallResult(resultRequest); consumerAPI.updateServiceCallResult(resultRequest);

@ -19,16 +19,15 @@ package com.tencent.cloud.rpc.enhancement.plugin.reporter;
import java.util.Optional; import java.util.Optional;
import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.cloud.rpc.enhancement.plugin.PolarisEnhancedPluginUtils;
import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.api.rpc.ServiceCallResult; import com.tencent.polaris.api.rpc.ServiceCallResult;
import com.tencent.polaris.client.api.SDKContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -42,16 +41,17 @@ import static com.tencent.cloud.rpc.enhancement.plugin.PluginOrderConstant.Clien
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
public class SuccessPolarisReporter extends AbstractPolarisReporterAdapter implements EnhancedPlugin { public class SuccessPolarisReporter implements EnhancedPlugin {
private static final Logger LOG = LoggerFactory.getLogger(SuccessPolarisReporter.class); private static final Logger LOG = LoggerFactory.getLogger(SuccessPolarisReporter.class);
private final ConsumerAPI consumerAPI; private final ConsumerAPI consumerAPI;
public SuccessPolarisReporter(RpcEnhancementReporterProperties properties, private final RpcEnhancementReporterProperties reportProperties;
SDKContext context,
public SuccessPolarisReporter(RpcEnhancementReporterProperties reportProperties,
ConsumerAPI consumerAPI) { ConsumerAPI consumerAPI) {
super(properties, context); this.reportProperties = reportProperties;
this.consumerAPI = consumerAPI; this.consumerAPI = consumerAPI;
} }
@ -62,24 +62,25 @@ public class SuccessPolarisReporter extends AbstractPolarisReporterAdapter imple
@Override @Override
public EnhancedPluginType getType() { public EnhancedPluginType getType() {
return EnhancedPluginType.POST; return EnhancedPluginType.Client.POST;
} }
@Override @Override
public void run(EnhancedPluginContext context) { public void run(EnhancedPluginContext context) {
if (!super.reportProperties.isEnabled()) { if (!this.reportProperties.isEnabled()) {
return; return;
} }
EnhancedRequestContext request = context.getRequest(); EnhancedRequestContext request = context.getRequest();
EnhancedResponseContext response = context.getResponse(); EnhancedResponseContext response = context.getResponse();
ServiceInstance serviceInstance = Optional.ofNullable(context.getServiceInstance()) ServiceInstance callerServiceInstance = Optional.ofNullable(context.getLocalServiceInstance()).orElse(new DefaultServiceInstance());
.orElse(new DefaultServiceInstance()); ServiceInstance calleeServiceInstance = Optional.ofNullable(context.getTargetServiceInstance()).orElse(new DefaultServiceInstance());
ServiceCallResult resultRequest = createServiceCallResult( ServiceCallResult resultRequest = PolarisEnhancedPluginUtils.createServiceCallResult(
serviceInstance.getServiceId(), callerServiceInstance.getHost(),
serviceInstance.getHost(), calleeServiceInstance.getServiceId(),
serviceInstance.getPort(), calleeServiceInstance.getHost(),
calleeServiceInstance.getPort(),
request.getUrl(), request.getUrl(),
request.getHttpHeaders(), request.getHttpHeaders(),
response.getHttpHeaders(), response.getHttpHeaders(),
@ -89,8 +90,7 @@ public class SuccessPolarisReporter extends AbstractPolarisReporterAdapter imple
); );
LOG.debug("Will report ServiceCallResult of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.", LOG.debug("Will report ServiceCallResult of {}. Request=[{} {}]. Response=[{}]. Delay=[{}]ms.",
resultRequest.getRetStatus().name(), request.getHttpMethod().name(), request.getUrl() resultRequest.getRetStatus().name(), request.getHttpMethod().name(), request.getUrl().getPath(), response.getHttpStatus(), context.getDelay());
.getPath(), response.getHttpStatus(), context.getDelay());
consumerAPI.updateServiceCallResult(resultRequest); consumerAPI.updateServiceCallResult(resultRequest);

@ -1,43 +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.rpc.enhancement.resttemplate;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
/**
* Intercept for BlockingLoadBalancerClient, put host and port to thread local.
*
* @author lepdou 2022-09-05
*/
@Aspect
public class BlockingLoadBalancerClientAspect {
@Pointcut("execution(public * org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient.reconstructURI(..)) ")
public void pointcut() {
}
@Around("pointcut()")
public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {
LoadBalancerClientAspectUtils.extractLoadBalancerResult(joinPoint);
return joinPoint.proceed();
}
}

@ -18,25 +18,21 @@
package com.tencent.cloud.rpc.enhancement.resttemplate; package com.tencent.cloud.rpc.enhancement.resttemplate;
import java.io.IOException; import java.io.IOException;
import java.util.Map;
import com.tencent.cloud.common.constant.HeaderConstant;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.ServiceInstance;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.EXCEPTION; import static com.tencent.cloud.rpc.enhancement.resttemplate.PolarisLoadBalancerRequestTransformer.LOAD_BALANCER_SERVICE_INSTANCE;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.FINALLY;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.POST;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.PRE;
/** /**
* EnhancedRestTemplateInterceptor. * EnhancedRestTemplateInterceptor.
@ -63,8 +59,13 @@ public class EnhancedRestTemplateInterceptor implements ClientHttpRequestInterce
.build(); .build();
enhancedPluginContext.setRequest(enhancedRequestContext); enhancedPluginContext.setRequest(enhancedRequestContext);
enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance());
enhancedPluginContext.setTargetServiceInstance(
(ServiceInstance) MetadataContextHolder.get().getLoadbalancerMetadata().get(LOAD_BALANCER_SERVICE_INSTANCE));
// Run pre enhanced plugins. // Run pre enhanced plugins.
pluginRunner.run(PRE, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.PRE, enhancedPluginContext);
long startMillis = System.currentTimeMillis(); long startMillis = System.currentTimeMillis();
try { try {
ClientHttpResponse response = execution.execute(request, body); ClientHttpResponse response = execution.execute(request, body);
@ -76,29 +77,20 @@ public class EnhancedRestTemplateInterceptor implements ClientHttpRequestInterce
.build(); .build();
enhancedPluginContext.setResponse(enhancedResponseContext); enhancedPluginContext.setResponse(enhancedResponseContext);
Map<String, String> loadBalancerContext = MetadataContextHolder.get().getLoadbalancerMetadata();
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
serviceInstance.setServiceId(request.getURI().getHost());
serviceInstance.setHost(loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_INSTANCE_HOST));
if (loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_INSTANCE_PORT) != null) {
serviceInstance.setPort(Integer.parseInt(loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_INSTANCE_PORT)));
}
enhancedPluginContext.setServiceInstance(serviceInstance);
// Run post enhanced plugins. // Run post enhanced plugins.
pluginRunner.run(POST, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.POST, enhancedPluginContext);
return response; return response;
} }
catch (IOException e) { catch (IOException e) {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis); enhancedPluginContext.setDelay(System.currentTimeMillis() - startMillis);
enhancedPluginContext.setThrowable(e); enhancedPluginContext.setThrowable(e);
// Run exception enhanced plugins. // Run exception enhanced plugins.
pluginRunner.run(EXCEPTION, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.EXCEPTION, enhancedPluginContext);
throw e; throw e;
} }
finally { finally {
// Run finally enhanced plugins. // Run finally enhanced plugins.
pluginRunner.run(FINALLY, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.FINALLY, enhancedPluginContext);
} }
} }

@ -17,28 +17,36 @@
package com.tencent.cloud.rpc.enhancement.resttemplate; package com.tencent.cloud.rpc.enhancement.resttemplate;
import com.tencent.cloud.common.constant.HeaderConstant;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestTransformer;
import org.springframework.http.HttpRequest;
/** /**
* Extract load balancer result from {@link LoadBalancerClient} and put to MetadataContext. * PolarisLoadBalancerRequestTransformer.
* @author lepdou 2022-09-06 *
* @author sean yu
*/ */
public final class LoadBalancerClientAspectUtils { public class PolarisLoadBalancerRequestTransformer implements LoadBalancerRequestTransformer {
private LoadBalancerClientAspectUtils() { /**
} * LOAD_BALANCER_SERVICE_INSTANCE MetadataContext key.
*/
public static final String LOAD_BALANCER_SERVICE_INSTANCE = "LOAD_BALANCER_SERVICE_INSTANCE";
public static void extractLoadBalancerResult(ProceedingJoinPoint joinPoint) { /**
Object server = joinPoint.getArgs()[0]; * Transform Request, add Loadbalancer ServiceInstance to MetadataContext.
if (server instanceof ServiceInstance) { * @param request request
ServiceInstance instance = (ServiceInstance) server; * @param instance instance
MetadataContextHolder.get().setLoadbalancer(HeaderConstant.INTERNAL_CALLEE_INSTANCE_HOST, instance.getHost()); * @return HttpRequest
MetadataContextHolder.get().setLoadbalancer(HeaderConstant.INTERNAL_CALLEE_INSTANCE_PORT, String.valueOf(instance.getPort())); */
@Override
public HttpRequest transformRequest(HttpRequest request, ServiceInstance instance) {
if (instance != null) {
MetadataContextHolder.get().setLoadbalancer(LOAD_BALANCER_SERVICE_INSTANCE, instance);
} }
return request;
} }
} }

@ -21,6 +21,7 @@ import java.net.URI;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@ -33,10 +34,6 @@ import org.springframework.cloud.gateway.route.Route;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.EXCEPTION;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.FINALLY;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.POST;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.PRE;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;
@ -64,8 +61,15 @@ public class EnhancedGatewayGlobalFilter implements GlobalFilter, Ordered {
.build(); .build();
enhancedPluginContext.setRequest(enhancedRequestContext); enhancedPluginContext.setRequest(enhancedRequestContext);
// enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance());
// Response<ServiceInstance> serviceInstanceResponse = exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR);
// if (serviceInstanceResponse != null && serviceInstanceResponse.hasServer()) {
// ServiceInstance instance = serviceInstanceResponse.getServer();
// enhancedPluginContext.setTargetServiceInstance(instance);
// }
// Run pre enhanced plugins. // Run pre enhanced plugins.
pluginRunner.run(PRE, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.PRE, enhancedPluginContext);
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
return chain.filter(exchange) return chain.filter(exchange)
@ -80,7 +84,7 @@ public class EnhancedGatewayGlobalFilter implements GlobalFilter, Ordered {
serviceInstance.setHost(uri.getHost()); serviceInstance.setHost(uri.getHost());
serviceInstance.setPort(uri.getPort()); serviceInstance.setPort(uri.getPort());
} }
enhancedPluginContext.setServiceInstance(serviceInstance); enhancedPluginContext.setTargetServiceInstance(serviceInstance);
}) })
.doOnSuccess(v -> { .doOnSuccess(v -> {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startTime); enhancedPluginContext.setDelay(System.currentTimeMillis() - startTime);
@ -91,18 +95,18 @@ public class EnhancedGatewayGlobalFilter implements GlobalFilter, Ordered {
enhancedPluginContext.setResponse(enhancedResponseContext); enhancedPluginContext.setResponse(enhancedResponseContext);
// Run post enhanced plugins. // Run post enhanced plugins.
pluginRunner.run(POST, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.POST, enhancedPluginContext);
}) })
.doOnError(t -> { .doOnError(t -> {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startTime); enhancedPluginContext.setDelay(System.currentTimeMillis() - startTime);
enhancedPluginContext.setThrowable(t); enhancedPluginContext.setThrowable(t);
// Run exception enhanced plugins. // Run exception enhanced plugins.
pluginRunner.run(EXCEPTION, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.EXCEPTION, enhancedPluginContext);
}) })
.doFinally(v -> { .doFinally(v -> {
// Run finally enhanced plugins. // Run finally enhanced plugins.
pluginRunner.run(FINALLY, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.FINALLY, enhancedPluginContext);
}); });
} }

@ -17,35 +17,31 @@
package com.tencent.cloud.rpc.enhancement.webclient; package com.tencent.cloud.rpc.enhancement.webclient;
import java.util.Map;
import com.tencent.cloud.common.constant.HeaderConstant;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.ServiceInstance;
import org.springframework.web.reactive.function.client.ClientRequest; import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction; import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.ExchangeFunction; import org.springframework.web.reactive.function.client.ExchangeFunction;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.EXCEPTION; import static com.tencent.cloud.rpc.enhancement.resttemplate.PolarisLoadBalancerRequestTransformer.LOAD_BALANCER_SERVICE_INSTANCE;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.FINALLY;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.POST;
/** /**
* EnhancedWebClientReporter. * EnhancedWebClientExchangeFilterFunction.
* *
* @author sean yu * @author sean yu
*/ */
public class EnhancedWebClientReporter implements ExchangeFilterFunction { public class EnhancedWebClientExchangeFilterFunction implements ExchangeFilterFunction {
private final EnhancedPluginRunner pluginRunner; private final EnhancedPluginRunner pluginRunner;
public EnhancedWebClientReporter(EnhancedPluginRunner pluginRunner) { public EnhancedWebClientExchangeFilterFunction(EnhancedPluginRunner pluginRunner) {
this.pluginRunner = pluginRunner; this.pluginRunner = pluginRunner;
} }
@ -60,38 +56,37 @@ public class EnhancedWebClientReporter implements ExchangeFilterFunction {
.build(); .build();
enhancedPluginContext.setRequest(enhancedRequestContext); enhancedPluginContext.setRequest(enhancedRequestContext);
enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance());
enhancedPluginContext.setTargetServiceInstance(
(ServiceInstance) MetadataContextHolder.get().getLoadbalancerMetadata().get(LOAD_BALANCER_SERVICE_INSTANCE));
// Run post enhanced plugins.
pluginRunner.run(EnhancedPluginType.Client.PRE, enhancedPluginContext);
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
return next.exchange(request) return next.exchange(request)
.doOnSubscribe(subscription -> {
Map<String, String> loadBalancerContext = MetadataContextHolder.get().getLoadbalancerMetadata();
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
serviceInstance.setServiceId(loadBalancerContext.get(HeaderConstant.INTERNAL_CALLEE_SERVICE_ID));
serviceInstance.setHost(request.url().getHost());
serviceInstance.setPort(request.url().getPort());
enhancedPluginContext.setServiceInstance(serviceInstance);
})
.doOnSuccess(response -> { .doOnSuccess(response -> {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startTime); enhancedPluginContext.setDelay(System.currentTimeMillis() - startTime);
EnhancedResponseContext enhancedResponseContext = EnhancedResponseContext.builder() EnhancedResponseContext enhancedResponseContext = EnhancedResponseContext.builder()
.httpStatus(response.rawStatusCode()) .httpStatus(response.statusCode().value())
.httpHeaders(response.headers().asHttpHeaders()) .httpHeaders(response.headers().asHttpHeaders())
.build(); .build();
enhancedPluginContext.setResponse(enhancedResponseContext); enhancedPluginContext.setResponse(enhancedResponseContext);
// Run post enhanced plugins. // Run post enhanced plugins.
pluginRunner.run(POST, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.POST, enhancedPluginContext);
}) })
.doOnError(t -> { .doOnError(t -> {
enhancedPluginContext.setDelay(System.currentTimeMillis() - startTime); enhancedPluginContext.setDelay(System.currentTimeMillis() - startTime);
enhancedPluginContext.setThrowable(t); enhancedPluginContext.setThrowable(t);
// Run exception enhanced plugins. // Run exception enhanced plugins.
pluginRunner.run(EXCEPTION, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.EXCEPTION, enhancedPluginContext);
}) })
.doFinally(v -> { .doFinally(v -> {
// Run finally enhanced plugins. // Run finally enhanced plugins.
pluginRunner.run(FINALLY, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.FINALLY, enhancedPluginContext);
}); });
} }
} }

@ -17,13 +17,14 @@
package com.tencent.cloud.rpc.enhancement.webclient; package com.tencent.cloud.rpc.enhancement.webclient;
import com.tencent.cloud.common.constant.HeaderConstant;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerClientRequestTransformer; import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerClientRequestTransformer;
import org.springframework.web.reactive.function.client.ClientRequest; import org.springframework.web.reactive.function.client.ClientRequest;
import static com.tencent.cloud.rpc.enhancement.resttemplate.PolarisLoadBalancerRequestTransformer.LOAD_BALANCER_SERVICE_INSTANCE;
/** /**
* PolarisLoadBalancerClientRequestTransformer. * PolarisLoadBalancerClientRequestTransformer.
* *
@ -31,10 +32,16 @@ import org.springframework.web.reactive.function.client.ClientRequest;
*/ */
public class PolarisLoadBalancerClientRequestTransformer implements LoadBalancerClientRequestTransformer { public class PolarisLoadBalancerClientRequestTransformer implements LoadBalancerClientRequestTransformer {
/**
* Transform Request, add Loadbalancer ServiceInstance to MetadataContext.
* @param request request
* @param instance instance
* @return HttpRequest
*/
@Override @Override
public ClientRequest transformRequest(ClientRequest request, ServiceInstance instance) { public ClientRequest transformRequest(ClientRequest request, ServiceInstance instance) {
if (instance != null) { if (instance != null) {
MetadataContextHolder.get().setLoadbalancer(HeaderConstant.INTERNAL_CALLEE_SERVICE_ID, instance.getServiceId()); MetadataContextHolder.get().setLoadbalancer(LOAD_BALANCER_SERVICE_INSTANCE, instance);
} }
return request; return request;
} }

@ -15,13 +15,16 @@
* specific language governing permissions and limitations under the License. * specific language governing permissions and limitations under the License.
*/ */
package com.tencent.cloud.rpc.enhancement.resttemplate; package com.tencent.cloud.rpc.enhancement.webclient;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.annotation.Pointcut;
import static com.tencent.cloud.rpc.enhancement.resttemplate.PolarisLoadBalancerRequestTransformer.LOAD_BALANCER_SERVICE_INSTANCE;
/** /**
* Intercept for RibbonLoadBalancerClient, put host and port to thread local. * Intercept for RibbonLoadBalancerClient, put host and port to thread local.
* *
@ -30,14 +33,17 @@ import org.aspectj.lang.annotation.Pointcut;
@Aspect @Aspect
public class RibbonLoadBalancerClientAspect { public class RibbonLoadBalancerClientAspect {
@Pointcut("execution(public * org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.reconstructURI(..))") @Pointcut("execution(public * org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.choose(..))")
public void pointcut() { public void pointcut() {
} }
@Around("pointcut()") @Around("pointcut()")
public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable { public Object invoke(ProceedingJoinPoint joinPoint) throws Throwable {
LoadBalancerClientAspectUtils.extractLoadBalancerResult(joinPoint); Object result = joinPoint.proceed();
return joinPoint.proceed(); if (result != null) {
MetadataContextHolder.get().setLoadbalancer(LOAD_BALANCER_SERVICE_INSTANCE, result);
}
return result;
} }
} }

@ -24,22 +24,18 @@ import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException; import com.netflix.zuul.exception.ZuulException;
import com.tencent.cloud.common.constant.ContextConstant; import com.tencent.cloud.common.constant.ContextConstant;
import com.tencent.cloud.common.util.ZuulFilterUtils;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.netflix.ribbon.apache.RibbonApacheHttpResponse;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static com.tencent.cloud.common.constant.ContextConstant.Zuul.POLARIS_PRE_ROUTE_TIME; import static com.tencent.cloud.common.constant.ContextConstant.Zuul.POLARIS_PRE_ROUTE_TIME;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.EXCEPTION;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.FINALLY;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ERROR_TYPE; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ERROR_TYPE;
/** /**
@ -90,13 +86,9 @@ public class EnhancedErrorZuulFilter extends ZuulFilter {
enhancedPluginContext = (EnhancedPluginContext) enhancedPluginContextObj; enhancedPluginContext = (EnhancedPluginContext) enhancedPluginContextObj;
} }
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
Object ribbonResponseObj = context.get("ribbonResponse");
Object startTimeMilliObject = context.get(POLARIS_PRE_ROUTE_TIME); Object startTimeMilliObject = context.get(POLARIS_PRE_ROUTE_TIME);
Throwable throwable = context.getThrowable(); Throwable throwable = context.getThrowable();
RibbonApacheHttpResponse ribbonResponse; if (throwable != null && startTimeMilliObject != null && startTimeMilliObject instanceof Long) {
if (throwable != null && ribbonResponseObj != null && ribbonResponseObj instanceof RibbonApacheHttpResponse
&& startTimeMilliObject != null && startTimeMilliObject instanceof Long) {
HttpHeaders responseHeaders = new HttpHeaders(); HttpHeaders responseHeaders = new HttpHeaders();
Collection<String> names = context.getResponse().getHeaderNames(); Collection<String> names = context.getResponse().getHeaderNames();
for (String name : names) { for (String name : names) {
@ -110,17 +102,12 @@ public class EnhancedErrorZuulFilter extends ZuulFilter {
Long startTimeMilli = (Long) startTimeMilliObject; Long startTimeMilli = (Long) startTimeMilliObject;
enhancedPluginContext.setDelay(System.currentTimeMillis() - startTimeMilli); enhancedPluginContext.setDelay(System.currentTimeMillis() - startTimeMilli);
enhancedPluginContext.setThrowable(throwable); enhancedPluginContext.setThrowable(throwable);
ribbonResponse = (RibbonApacheHttpResponse) ribbonResponseObj;
serviceInstance.setServiceId(ZuulFilterUtils.getServiceId(context));
serviceInstance.setHost(ribbonResponse.getRequestedURI().getHost());
serviceInstance.setPort(ribbonResponse.getRequestedURI().getPort());
enhancedPluginContext.setServiceInstance(serviceInstance);
// Run post enhanced plugins. // Run post enhanced plugins.
pluginRunner.run(EXCEPTION, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.EXCEPTION, enhancedPluginContext);
// Run finally enhanced plugins. // Run finally enhanced plugins.
pluginRunner.run(FINALLY, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.FINALLY, enhancedPluginContext);
} }
return null; return null;
} }

@ -24,22 +24,18 @@ import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException; import com.netflix.zuul.exception.ZuulException;
import com.tencent.cloud.common.constant.ContextConstant; import com.tencent.cloud.common.constant.ContextConstant;
import com.tencent.cloud.common.util.ZuulFilterUtils;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.netflix.ribbon.apache.RibbonApacheHttpResponse;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static com.tencent.cloud.common.constant.ContextConstant.Zuul.POLARIS_PRE_ROUTE_TIME; import static com.tencent.cloud.common.constant.ContextConstant.Zuul.POLARIS_PRE_ROUTE_TIME;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.FINALLY;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.POST;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.POST_TYPE; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.POST_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_RESPONSE_FILTER_ORDER; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_RESPONSE_FILTER_ORDER;
@ -89,12 +85,8 @@ public class EnhancedPostZuulFilter extends ZuulFilter {
enhancedPluginContext = (EnhancedPluginContext) enhancedPluginContextObj; enhancedPluginContext = (EnhancedPluginContext) enhancedPluginContextObj;
} }
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
Object ribbonResponseObj = context.get("ribbonResponse");
Object startTimeMilliObject = context.get(POLARIS_PRE_ROUTE_TIME); Object startTimeMilliObject = context.get(POLARIS_PRE_ROUTE_TIME);
RibbonApacheHttpResponse ribbonResponse; if (startTimeMilliObject instanceof Long) {
if (ribbonResponseObj != null && ribbonResponseObj instanceof RibbonApacheHttpResponse
&& startTimeMilliObject != null && startTimeMilliObject instanceof Long) {
HttpHeaders responseHeaders = new HttpHeaders(); HttpHeaders responseHeaders = new HttpHeaders();
Collection<String> names = context.getResponse().getHeaderNames(); Collection<String> names = context.getResponse().getHeaderNames();
for (String name : names) { for (String name : names) {
@ -107,17 +99,12 @@ public class EnhancedPostZuulFilter extends ZuulFilter {
enhancedPluginContext.setResponse(enhancedResponseContext); enhancedPluginContext.setResponse(enhancedResponseContext);
Long startTimeMilli = (Long) startTimeMilliObject; Long startTimeMilli = (Long) startTimeMilliObject;
enhancedPluginContext.setDelay(System.currentTimeMillis() - startTimeMilli); enhancedPluginContext.setDelay(System.currentTimeMillis() - startTimeMilli);
ribbonResponse = (RibbonApacheHttpResponse) ribbonResponseObj;
serviceInstance.setServiceId(ZuulFilterUtils.getServiceId(context));
serviceInstance.setHost(ribbonResponse.getRequestedURI().getHost());
serviceInstance.setPort(ribbonResponse.getRequestedURI().getPort());
enhancedPluginContext.setServiceInstance(serviceInstance);
// Run post enhanced plugins. // Run post enhanced plugins.
pluginRunner.run(POST, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.POST, enhancedPluginContext);
// Run finally enhanced plugins. // Run finally enhanced plugins.
pluginRunner.run(FINALLY, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.FINALLY, enhancedPluginContext);
} }
return null; return null;
} }

@ -29,46 +29,48 @@ import com.tencent.cloud.common.constant.ContextConstant;
import com.tencent.cloud.common.util.ZuulFilterUtils; import com.tencent.cloud.common.util.ZuulFilterUtils;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.netflix.ribbon.apache.RibbonApacheHttpResponse;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static com.tencent.cloud.common.constant.ContextConstant.Zuul.POLARIS_PRE_ROUTE_TIME; import static com.tencent.cloud.common.constant.ContextConstant.Zuul.POLARIS_PRE_ROUTE_TIME;
import static com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType.PRE; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.RIBBON_ROUTING_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER; import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ROUTE_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
/** /**
* Polaris circuit breaker implement in Zuul. * Polaris circuit breaker implement in Zuul.
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
public class EnhancedPreZuulFilter extends ZuulFilter { public class EnhancedRouteZuulFilter extends ZuulFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(EnhancedPreZuulFilter.class); private static final Logger LOGGER = LoggerFactory.getLogger(EnhancedRouteZuulFilter.class);
private final EnhancedPluginRunner pluginRunner; private final EnhancedPluginRunner pluginRunner;
private final Environment environment; private final Environment environment;
public EnhancedPreZuulFilter(EnhancedPluginRunner pluginRunner, Environment environment) { public EnhancedRouteZuulFilter(EnhancedPluginRunner pluginRunner, Environment environment) {
this.pluginRunner = pluginRunner; this.pluginRunner = pluginRunner;
this.environment = environment; this.environment = environment;
} }
@Override @Override
public String filterType() { public String filterType() {
return PRE_TYPE; return ROUTE_TYPE;
} }
@Override @Override
public int filterOrder() { public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER + 1; return RIBBON_ROUTING_FILTER_ORDER + 1;
} }
@Override @Override
@ -100,9 +102,21 @@ public class EnhancedPreZuulFilter extends ZuulFilter {
.build(); .build();
enhancedPluginContext.setRequest(enhancedRequestContext); enhancedPluginContext.setRequest(enhancedRequestContext);
enhancedPluginContext.setLocalServiceInstance(pluginRunner.getLocalServiceInstance());
Object ribbonResponseObj = context.get("ribbonResponse");
RibbonApacheHttpResponse ribbonResponse;
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
if (ribbonResponseObj != null && ribbonResponseObj instanceof RibbonApacheHttpResponse) {
ribbonResponse = (RibbonApacheHttpResponse) ribbonResponseObj;
serviceInstance.setServiceId(ZuulFilterUtils.getServiceId(context));
serviceInstance.setHost(ribbonResponse.getRequestedURI().getHost());
serviceInstance.setPort(ribbonResponse.getRequestedURI().getPort());
enhancedPluginContext.setTargetServiceInstance(serviceInstance);
}
// Run pre enhanced plugins. // Run pre enhanced plugins.
pluginRunner.run(PRE, enhancedPluginContext); pluginRunner.run(EnhancedPluginType.Client.PRE, enhancedPluginContext);
Object startTimeMilliObject = context.get(POLARIS_PRE_ROUTE_TIME); Object startTimeMilliObject = context.get(POLARIS_PRE_ROUTE_TIME);
if (startTimeMilliObject == null || !(startTimeMilliObject instanceof Long)) { if (startTimeMilliObject == null || !(startTimeMilliObject instanceof Long)) {

@ -26,6 +26,7 @@ import com.tencent.cloud.rpc.enhancement.plugin.DefaultEnhancedPluginRunner;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPlugin;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType; import com.tencent.cloud.rpc.enhancement.plugin.EnhancedPluginType;
import com.tencent.polaris.client.api.SDKContext;
import feign.Client; import feign.Client;
import feign.Request; import feign.Request;
import feign.RequestTemplate; import feign.RequestTemplate;
@ -34,6 +35,7 @@ import feign.Target;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.context.junit.jupiter.SpringExtension;
@ -55,6 +57,9 @@ import static org.mockito.Mockito.mock;
properties = {"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp", "spring.cloud.gateway.enabled=false"}) properties = {"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp", "spring.cloud.gateway.enabled=false"})
public class EnhancedFeignClientTest { public class EnhancedFeignClientTest {
@Autowired
private SDKContext sdkContext;
@Test @Test
public void testConstructor() { public void testConstructor() {
try { try {
@ -75,7 +80,7 @@ public class EnhancedFeignClientTest {
List<EnhancedPlugin> enhancedPlugins = getMockEnhancedFeignPlugins(); List<EnhancedPlugin> enhancedPlugins = getMockEnhancedFeignPlugins();
try { try {
new EnhancedFeignClient(mock(Client.class), new DefaultEnhancedPluginRunner(enhancedPlugins)); new EnhancedFeignClient(mock(Client.class), new DefaultEnhancedPluginRunner(enhancedPlugins, null, sdkContext));
} }
catch (Throwable e) { catch (Throwable e) {
fail("Exception encountered.", e); fail("Exception encountered.", e);
@ -104,7 +109,7 @@ public class EnhancedFeignClientTest {
RequestTemplate requestTemplate = new RequestTemplate(); RequestTemplate requestTemplate = new RequestTemplate();
requestTemplate.feignTarget(target); requestTemplate.feignTarget(target);
EnhancedFeignClient polarisFeignClient = new EnhancedFeignClient(delegate, new DefaultEnhancedPluginRunner(getMockEnhancedFeignPlugins())); EnhancedFeignClient polarisFeignClient = new EnhancedFeignClient(delegate, new DefaultEnhancedPluginRunner(getMockEnhancedFeignPlugins(), null, sdkContext));
// 200 // 200
Response response = polarisFeignClient.execute(Request.create(Request.HttpMethod.GET, "http://localhost:8080/test", Response response = polarisFeignClient.execute(Request.create(Request.HttpMethod.GET, "http://localhost:8080/test",
@ -134,7 +139,7 @@ public class EnhancedFeignClientTest {
enhancedPlugins.add(new EnhancedPlugin() { enhancedPlugins.add(new EnhancedPlugin() {
@Override @Override
public EnhancedPluginType getType() { public EnhancedPluginType getType() {
return EnhancedPluginType.PRE; return EnhancedPluginType.Client.PRE;
} }
@Override @Override
@ -156,7 +161,7 @@ public class EnhancedFeignClientTest {
enhancedPlugins.add(new EnhancedPlugin() { enhancedPlugins.add(new EnhancedPlugin() {
@Override @Override
public EnhancedPluginType getType() { public EnhancedPluginType getType() {
return EnhancedPluginType.POST; return EnhancedPluginType.Client.POST;
} }
@Override @Override
@ -178,7 +183,7 @@ public class EnhancedFeignClientTest {
enhancedPlugins.add(new EnhancedPlugin() { enhancedPlugins.add(new EnhancedPlugin() {
@Override @Override
public EnhancedPluginType getType() { public EnhancedPluginType getType() {
return EnhancedPluginType.EXCEPTION; return EnhancedPluginType.Client.EXCEPTION;
} }
@Override @Override
@ -200,7 +205,7 @@ public class EnhancedFeignClientTest {
enhancedPlugins.add(new EnhancedPlugin() { enhancedPlugins.add(new EnhancedPlugin() {
@Override @Override
public EnhancedPluginType getType() { public EnhancedPluginType getType() {
return EnhancedPluginType.FINALLY; return EnhancedPluginType.Client.FINALLY;
} }
@Override @Override

@ -25,6 +25,9 @@ import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.ExceptionPolarisReporter; import com.tencent.cloud.rpc.enhancement.plugin.reporter.ExceptionPolarisReporter;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter; import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter;
import com.tencent.polaris.api.config.Configuration;
import com.tencent.polaris.api.config.global.APIConfig;
import com.tencent.polaris.api.config.global.GlobalConfig;
import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.client.api.SDKContext; import com.tencent.polaris.client.api.SDKContext;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
@ -38,6 +41,7 @@ import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
@ -65,6 +69,8 @@ public class EnhancedPluginContextTest {
private SDKContext sdkContext; private SDKContext sdkContext;
@Mock @Mock
private ConsumerAPI consumerAPI; private ConsumerAPI consumerAPI;
@Mock
private Registration registration;
@BeforeAll @BeforeAll
static void beforeAll() { static void beforeAll() {
@ -111,24 +117,38 @@ public class EnhancedPluginContextTest {
EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext(); EnhancedPluginContext enhancedPluginContext = new EnhancedPluginContext();
enhancedPluginContext.setRequest(requestContext); enhancedPluginContext.setRequest(requestContext);
enhancedPluginContext.setResponse(responseContext); enhancedPluginContext.setResponse(responseContext);
enhancedPluginContext.setServiceInstance(new DefaultServiceInstance()); enhancedPluginContext.setTargetServiceInstance(new DefaultServiceInstance());
enhancedPluginContext.setThrowable(mock(Exception.class)); enhancedPluginContext.setThrowable(mock(Exception.class));
enhancedPluginContext.setDelay(0); enhancedPluginContext.setDelay(0);
assertThat(enhancedPluginContext.getRequest()).isNotNull(); assertThat(enhancedPluginContext.getRequest()).isNotNull();
assertThat(enhancedPluginContext.getResponse()).isNotNull(); assertThat(enhancedPluginContext.getResponse()).isNotNull();
assertThat(enhancedPluginContext.getServiceInstance()).isNotNull(); assertThat(enhancedPluginContext.getTargetServiceInstance()).isNotNull();
assertThat(enhancedPluginContext.getThrowable()).isNotNull(); assertThat(enhancedPluginContext.getThrowable()).isNotNull();
assertThat(enhancedPluginContext.getDelay()).isNotNull(); assertThat(enhancedPluginContext.getDelay()).isNotNull();
EnhancedPlugin enhancedPlugin = new SuccessPolarisReporter(reporterProperties, sdkContext, consumerAPI); EnhancedPlugin enhancedPlugin = new SuccessPolarisReporter(reporterProperties, consumerAPI);
EnhancedPlugin enhancedPlugin1 = new ExceptionPolarisReporter(reporterProperties, sdkContext, consumerAPI); EnhancedPlugin enhancedPlugin1 = new ExceptionPolarisReporter(reporterProperties, consumerAPI);
EnhancedPluginRunner enhancedPluginRunner = new DefaultEnhancedPluginRunner(Arrays.asList(enhancedPlugin, enhancedPlugin1)); EnhancedPluginRunner enhancedPluginRunner = new DefaultEnhancedPluginRunner(Arrays.asList(enhancedPlugin, enhancedPlugin1), registration, sdkContext);
enhancedPluginRunner.run(EnhancedPluginType.POST, enhancedPluginContext); enhancedPluginRunner.run(EnhancedPluginType.Client.POST, enhancedPluginContext);
assertThat(enhancedPluginRunner.getLocalServiceInstance()).isEqualTo(registration);
EnhancedPlugin enhancedPlugin2 = mock(EnhancedPlugin.class); EnhancedPlugin enhancedPlugin2 = mock(EnhancedPlugin.class);
doThrow(new RuntimeException()).when(enhancedPlugin2).run(any()); doThrow(new RuntimeException()).when(enhancedPlugin2).run(any());
doReturn(EnhancedPluginType.POST).when(enhancedPlugin2).getType(); doReturn(EnhancedPluginType.Client.POST).when(enhancedPlugin2).getType();
enhancedPluginRunner = new DefaultEnhancedPluginRunner(Arrays.asList(enhancedPlugin2));
enhancedPluginRunner.run(EnhancedPluginType.POST, enhancedPluginContext); APIConfig apiConfig = mock(APIConfig.class);
doReturn("0.0.0.0").when(apiConfig).getBindIP();
GlobalConfig globalConfig = mock(GlobalConfig.class);
doReturn(apiConfig).when(globalConfig).getAPI();
Configuration configuration = mock(Configuration.class);
doReturn(globalConfig).when(configuration).getGlobal();
doReturn(configuration).when(sdkContext).getConfig();
enhancedPluginRunner = new DefaultEnhancedPluginRunner(Arrays.asList(enhancedPlugin2), null, sdkContext);
enhancedPluginRunner.run(EnhancedPluginType.Client.POST, enhancedPluginContext);
} }
} }

@ -23,11 +23,7 @@ import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.ExceptionPolarisReporter; import com.tencent.cloud.rpc.enhancement.plugin.reporter.ExceptionPolarisReporter;
import com.tencent.polaris.api.config.Configuration;
import com.tencent.polaris.api.config.global.APIConfig;
import com.tencent.polaris.api.config.global.GlobalConfig;
import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.client.api.SDKContext;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -40,6 +36,7 @@ import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
@ -63,8 +60,6 @@ public class ExceptionPolarisReporterTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils; private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@Mock @Mock
private RpcEnhancementReporterProperties reporterProperties; private RpcEnhancementReporterProperties reporterProperties;
@Mock
private SDKContext sdkContext;
@InjectMocks @InjectMocks
private ExceptionPolarisReporter exceptionPolarisReporter; private ExceptionPolarisReporter exceptionPolarisReporter;
@Mock @Mock
@ -75,6 +70,12 @@ public class ExceptionPolarisReporterTest {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test"); .thenReturn("unit-test");
ApplicationContext applicationContext = mock(ApplicationContext.class);
RpcEnhancementReporterProperties reporterProperties = mock(RpcEnhancementReporterProperties.class);
doReturn(reporterProperties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
} }
@AfterAll @AfterAll
@ -95,7 +96,7 @@ public class ExceptionPolarisReporterTest {
@Test @Test
public void testType() { public void testType() {
assertThat(exceptionPolarisReporter.getType()).isEqualTo(EnhancedPluginType.EXCEPTION); assertThat(exceptionPolarisReporter.getType()).isEqualTo(EnhancedPluginType.Client.EXCEPTION);
} }
@Test @Test
@ -107,32 +108,23 @@ public class ExceptionPolarisReporterTest {
doReturn(true).when(reporterProperties).isEnabled(); doReturn(true).when(reporterProperties).isEnabled();
APIConfig apiConfig = mock(APIConfig.class);
doReturn("0.0.0.0").when(apiConfig).getBindIP();
GlobalConfig globalConfig = mock(GlobalConfig.class);
doReturn(apiConfig).when(globalConfig).getAPI();
Configuration configuration = mock(Configuration.class);
doReturn(globalConfig).when(configuration).getGlobal();
doReturn(configuration).when(sdkContext).getConfig();
EnhancedPluginContext pluginContext = new EnhancedPluginContext(); EnhancedPluginContext pluginContext = new EnhancedPluginContext();
EnhancedRequestContext request = EnhancedRequestContext.builder() EnhancedRequestContext request = EnhancedRequestContext.builder()
.httpMethod(HttpMethod.GET) .httpMethod(HttpMethod.GET)
.url(URI.create("http://0.0.0.0/")) .url(URI.create("http://0.0.0.0/"))
.httpHeaders(new HttpHeaders()) .httpHeaders(new HttpHeaders())
.build(); .build();
request.toString();
EnhancedResponseContext response = EnhancedResponseContext.builder() EnhancedResponseContext response = EnhancedResponseContext.builder()
.httpStatus(200) .httpStatus(200)
.build(); .build();
response.toString();
DefaultServiceInstance serviceInstance = new DefaultServiceInstance(); DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
serviceInstance.setServiceId(SERVICE_PROVIDER); serviceInstance.setServiceId(SERVICE_PROVIDER);
pluginContext.setRequest(request); pluginContext.setRequest(request);
pluginContext.setResponse(response); pluginContext.setResponse(response);
pluginContext.setServiceInstance(serviceInstance); pluginContext.setTargetServiceInstance(serviceInstance);
pluginContext.setThrowable(new RuntimeException()); pluginContext.setThrowable(new RuntimeException());
exceptionPolarisReporter.run(pluginContext); exceptionPolarisReporter.run(pluginContext);

@ -15,20 +15,19 @@
* specific language governing permissions and limitations under the License. * specific language governing permissions and limitations under the License.
*/ */
package com.tencent.cloud.rpc.enhancement; package com.tencent.cloud.rpc.enhancement.plugin;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import com.tencent.cloud.common.constant.HeaderConstant; import com.tencent.cloud.common.constant.HeaderConstant;
import com.tencent.cloud.common.constant.RouterConstant; import com.tencent.cloud.common.constant.RouterConstant;
import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.polaris.api.config.Configuration;
import com.tencent.polaris.api.config.global.APIConfig;
import com.tencent.polaris.api.config.global.GlobalConfig;
import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat; import com.tencent.polaris.api.plugin.circuitbreaker.ResourceStat;
import com.tencent.polaris.api.pojo.RetStatus; import com.tencent.polaris.api.pojo.RetStatus;
import com.tencent.polaris.api.rpc.ServiceCallResult; import com.tencent.polaris.api.rpc.ServiceCallResult;
@ -43,6 +42,7 @@ import org.mockito.MockedStatic;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -54,12 +54,12 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
/** /**
* Test For {@link AbstractPolarisReporterAdapter}. * Test For {@link PolarisEnhancedPluginUtils}.
* *
* @author <a href="mailto:iskp.me@gmail.com">Elve.Xu</a> 2022/7/11 * @author <a href="mailto:iskp.me@gmail.com">Elve.Xu</a> 2022/7/11
*/ */
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
public class AbstractPolarisReporterAdapterTest { public class PolarisEnhancedPluginUtilsTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils; private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
private final RpcEnhancementReporterProperties reporterProperties = new RpcEnhancementReporterProperties(); private final RpcEnhancementReporterProperties reporterProperties = new RpcEnhancementReporterProperties();
@ -71,6 +71,12 @@ public class AbstractPolarisReporterAdapterTest {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test"); .thenReturn("unit-test");
ApplicationContext applicationContext = mock(ApplicationContext.class);
RpcEnhancementReporterProperties reporterProperties = mock(RpcEnhancementReporterProperties.class);
doReturn(reporterProperties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
} }
@AfterAll @AfterAll
@ -86,25 +92,18 @@ public class AbstractPolarisReporterAdapterTest {
@Test @Test
public void testServiceCallResult() throws URISyntaxException { public void testServiceCallResult() throws URISyntaxException {
APIConfig apiConfig = mock(APIConfig.class);
doReturn("0.0.0.0").when(apiConfig).getBindIP();
GlobalConfig globalConfig = mock(GlobalConfig.class);
doReturn(apiConfig).when(globalConfig).getAPI();
Configuration configuration = mock(Configuration.class);
doReturn(globalConfig).when(configuration).getGlobal();
doReturn(configuration).when(sdkContext).getConfig();
SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(reporterProperties, sdkContext);
ServiceCallResult serviceCallResult; ServiceCallResult serviceCallResult;
HttpHeaders requestHeaders = new HttpHeaders(); HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add(RouterConstant.ROUTER_LABEL_HEADER, "{\"k1\":\"v1\"}"); requestHeaders.add(RouterConstant.ROUTER_LABEL_HEADER, "{\"k1\":\"v1\"}");
serviceCallResult = adapter.createServiceCallResult( assertThat(PolarisEnhancedPluginUtils.getLabelMap(requestHeaders)).isEqualTo(new HashMap<String, String>() {{
put("k1", "v1");
}});
serviceCallResult = PolarisEnhancedPluginUtils.createServiceCallResult(
"0.0.0.0",
"test", "test",
null, null,
null, null,
@ -117,7 +116,8 @@ public class AbstractPolarisReporterAdapterTest {
); );
assertThat(serviceCallResult.getRetStatus()).isEqualTo(RetStatus.RetSuccess); assertThat(serviceCallResult.getRetStatus()).isEqualTo(RetStatus.RetSuccess);
serviceCallResult = adapter.createServiceCallResult( serviceCallResult = PolarisEnhancedPluginUtils.createServiceCallResult(
"0.0.0.0",
"test", "test",
null, null,
null, null,
@ -130,7 +130,8 @@ public class AbstractPolarisReporterAdapterTest {
); );
assertThat(serviceCallResult.getRetStatus()).isEqualTo(RetStatus.RetFail); assertThat(serviceCallResult.getRetStatus()).isEqualTo(RetStatus.RetFail);
serviceCallResult = adapter.createServiceCallResult( serviceCallResult = PolarisEnhancedPluginUtils.createServiceCallResult(
"0.0.0.0",
"test", "test",
null, null,
null, null,
@ -143,7 +144,8 @@ public class AbstractPolarisReporterAdapterTest {
); );
assertThat(serviceCallResult.getRetStatus()).isEqualTo(RetStatus.RetTimeout); assertThat(serviceCallResult.getRetStatus()).isEqualTo(RetStatus.RetTimeout);
serviceCallResult = adapter.createServiceCallResult( serviceCallResult = PolarisEnhancedPluginUtils.createServiceCallResult(
"0.0.0.0",
"test", "test",
"0.0.0.0", "0.0.0.0",
8080, 8080,
@ -162,11 +164,9 @@ public class AbstractPolarisReporterAdapterTest {
@Test @Test
public void testResourceStat() throws URISyntaxException { public void testResourceStat() throws URISyntaxException {
SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(reporterProperties, sdkContext);
ResourceStat resourceStat; ResourceStat resourceStat;
resourceStat = adapter.createInstanceResourceStat("test", resourceStat = PolarisEnhancedPluginUtils.createInstanceResourceStat("test",
null, null,
null, null,
new URI("http://0.0.0.0/"), new URI("http://0.0.0.0/"),
@ -176,7 +176,7 @@ public class AbstractPolarisReporterAdapterTest {
); );
assertThat(resourceStat.getRetStatus()).isEqualTo(RetStatus.RetSuccess); assertThat(resourceStat.getRetStatus()).isEqualTo(RetStatus.RetSuccess);
resourceStat = adapter.createInstanceResourceStat("test", resourceStat = PolarisEnhancedPluginUtils.createInstanceResourceStat("test",
null, null,
null, null,
new URI("http://0.0.0.0/"), new URI("http://0.0.0.0/"),
@ -186,7 +186,7 @@ public class AbstractPolarisReporterAdapterTest {
); );
assertThat(resourceStat.getRetStatus()).isEqualTo(RetStatus.RetTimeout); assertThat(resourceStat.getRetStatus()).isEqualTo(RetStatus.RetTimeout);
resourceStat = adapter.createInstanceResourceStat("test", resourceStat = PolarisEnhancedPluginUtils.createInstanceResourceStat("test",
null, null,
null, null,
new URI("http://0.0.0.0/"), new URI("http://0.0.0.0/"),
@ -200,13 +200,32 @@ public class AbstractPolarisReporterAdapterTest {
@Test @Test
public void testApplyWithDefaultConfig() { public void testApplyWithDefaultConfig() {
RpcEnhancementReporterProperties properties = new RpcEnhancementReporterProperties(); RpcEnhancementReporterProperties properties = new RpcEnhancementReporterProperties();
// Mock Condition
SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties, sdkContext);
ApplicationContext applicationContext = mock(ApplicationContext.class);
doReturn(properties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
// Assert
assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.OK)).isEqualTo(false);
assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false);
assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true);
}
@Test
public void testApplyWithHttpStatus() {
RpcEnhancementReporterProperties properties = new RpcEnhancementReporterProperties();
properties.setStatuses(Arrays.asList(HttpStatus.BAD_GATEWAY, HttpStatus.INTERNAL_SERVER_ERROR));
ApplicationContext applicationContext = mock(ApplicationContext.class);
doReturn(properties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
// Assert // Assert
assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false); assertThat(PolarisEnhancedPluginUtils.apply(null)).isEqualTo(false);
assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.OK)).isEqualTo(false);
assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(true);
assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true);
} }
@Test @Test
@ -216,12 +235,16 @@ public class AbstractPolarisReporterAdapterTest {
properties.getStatuses().clear(); properties.getStatuses().clear();
properties.setIgnoreInternalServerError(false); properties.setIgnoreInternalServerError(false);
SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties, sdkContext); ApplicationContext applicationContext = mock(ApplicationContext.class);
doReturn(properties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
// Assert // Assert
assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.OK)).isEqualTo(false);
assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(true); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(true);
assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true);
} }
@Test @Test
@ -231,12 +254,16 @@ public class AbstractPolarisReporterAdapterTest {
properties.getStatuses().clear(); properties.getStatuses().clear();
properties.setIgnoreInternalServerError(true); properties.setIgnoreInternalServerError(true);
SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties, sdkContext); ApplicationContext applicationContext = mock(ApplicationContext.class);
doReturn(properties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
// Assert // Assert
assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.OK)).isEqualTo(false);
assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false);
assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true);
} }
@Test @Test
@ -246,12 +273,16 @@ public class AbstractPolarisReporterAdapterTest {
properties.getStatuses().clear(); properties.getStatuses().clear();
properties.getSeries().clear(); properties.getSeries().clear();
SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties, sdkContext); ApplicationContext applicationContext = mock(ApplicationContext.class);
doReturn(properties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
// Assert // Assert
assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.OK)).isEqualTo(false);
assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false);
assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true);
} }
@Test @Test
@ -262,65 +293,46 @@ public class AbstractPolarisReporterAdapterTest {
properties.getSeries().clear(); properties.getSeries().clear();
properties.getSeries().add(HttpStatus.Series.CLIENT_ERROR); properties.getSeries().add(HttpStatus.Series.CLIENT_ERROR);
SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties, sdkContext); ApplicationContext applicationContext = mock(ApplicationContext.class);
doReturn(properties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
// Assert // Assert
assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.OK)).isEqualTo(false);
assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false);
assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(false); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(false);
assertThat(adapter.apply(HttpStatus.FORBIDDEN)).isEqualTo(true); assertThat(PolarisEnhancedPluginUtils.apply(HttpStatus.FORBIDDEN)).isEqualTo(true);
} }
@Test @Test
public void testGetRetStatusFromRequest() { public void testGetRetStatusFromRequest() {
RpcEnhancementReporterProperties properties = new RpcEnhancementReporterProperties();
// Mock Condition
properties.getStatuses().clear();
properties.getSeries().clear();
properties.getSeries().add(HttpStatus.Series.CLIENT_ERROR);
SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties, sdkContext);
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
RetStatus ret = adapter.getRetStatusFromRequest(headers, RetStatus.RetFail); RetStatus ret = PolarisEnhancedPluginUtils.getRetStatusFromRequest(headers, RetStatus.RetFail);
assertThat(ret).isEqualTo(RetStatus.RetFail); assertThat(ret).isEqualTo(RetStatus.RetFail);
headers.set(HeaderConstant.INTERNAL_CALLEE_RET_STATUS, RetStatus.RetFlowControl.getDesc()); headers.set(HeaderConstant.INTERNAL_CALLEE_RET_STATUS, RetStatus.RetFlowControl.getDesc());
ret = adapter.getRetStatusFromRequest(headers, RetStatus.RetFail); ret = PolarisEnhancedPluginUtils.getRetStatusFromRequest(headers, RetStatus.RetFail);
assertThat(ret).isEqualTo(RetStatus.RetFlowControl); assertThat(ret).isEqualTo(RetStatus.RetFlowControl);
headers.set(HeaderConstant.INTERNAL_CALLEE_RET_STATUS, RetStatus.RetReject.getDesc()); headers.set(HeaderConstant.INTERNAL_CALLEE_RET_STATUS, RetStatus.RetReject.getDesc());
ret = adapter.getRetStatusFromRequest(headers, RetStatus.RetFail); ret = PolarisEnhancedPluginUtils.getRetStatusFromRequest(headers, RetStatus.RetFail);
assertThat(ret).isEqualTo(RetStatus.RetReject); assertThat(ret).isEqualTo(RetStatus.RetReject);
} }
@Test @Test
public void testGetActiveRuleNameFromRequest() { public void testGetActiveRuleNameFromRequest() {
RpcEnhancementReporterProperties properties = new RpcEnhancementReporterProperties();
// Mock Condition
properties.getStatuses().clear();
properties.getSeries().clear();
properties.getSeries().add(HttpStatus.Series.CLIENT_ERROR);
SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties, sdkContext);
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
String ruleName = adapter.getActiveRuleNameFromRequest(headers); String ruleName = PolarisEnhancedPluginUtils.getActiveRuleNameFromRequest(headers);
assertThat(ruleName).isEqualTo(""); assertThat(ruleName).isEqualTo("");
headers.set(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME, "mock_rule"); headers.set(HeaderConstant.INTERNAL_ACTIVE_RULE_NAME, "mock_rule");
ruleName = adapter.getActiveRuleNameFromRequest(headers); ruleName = PolarisEnhancedPluginUtils.getActiveRuleNameFromRequest(headers);
assertThat(ruleName).isEqualTo("mock_rule"); assertThat(ruleName).isEqualTo("mock_rule");
} }
/**
* Simple Polaris CircuitBreak Adapter Implements .
*/
public static class SimplePolarisReporterAdapter extends AbstractPolarisReporterAdapter {
protected SimplePolarisReporterAdapter(RpcEnhancementReporterProperties reportProperties, SDKContext context) {
super(reportProperties, context);
}
}
} }

@ -23,11 +23,7 @@ import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter; import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter;
import com.tencent.polaris.api.config.Configuration;
import com.tencent.polaris.api.config.global.APIConfig;
import com.tencent.polaris.api.config.global.GlobalConfig;
import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.client.api.SDKContext;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -40,6 +36,7 @@ import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.DefaultServiceInstance; import org.springframework.cloud.client.DefaultServiceInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
@ -60,8 +57,6 @@ import static org.mockito.Mockito.verify;
public class SuccessPolarisReporterTest { public class SuccessPolarisReporterTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils; private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@Mock @Mock
private SDKContext sdkContext;
@Mock
private RpcEnhancementReporterProperties reporterProperties; private RpcEnhancementReporterProperties reporterProperties;
@InjectMocks @InjectMocks
private SuccessPolarisReporter successPolarisReporter; private SuccessPolarisReporter successPolarisReporter;
@ -73,6 +68,12 @@ public class SuccessPolarisReporterTest {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn("unit-test"); .thenReturn("unit-test");
ApplicationContext applicationContext = mock(ApplicationContext.class);
RpcEnhancementReporterProperties reporterProperties = mock(RpcEnhancementReporterProperties.class);
doReturn(reporterProperties)
.when(applicationContext).getBean(RpcEnhancementReporterProperties.class);
mockedApplicationContextAwareUtils.when(ApplicationContextAwareUtils::getApplicationContext)
.thenReturn(applicationContext);
} }
@AfterAll @AfterAll
@ -93,7 +94,7 @@ public class SuccessPolarisReporterTest {
@Test @Test
public void testType() { public void testType() {
assertThat(successPolarisReporter.getType()).isEqualTo(EnhancedPluginType.POST); assertThat(successPolarisReporter.getType()).isEqualTo(EnhancedPluginType.Client.POST);
} }
@Test @Test
@ -105,31 +106,23 @@ public class SuccessPolarisReporterTest {
verify(context, times(0)).getRequest(); verify(context, times(0)).getRequest();
doReturn(true).when(reporterProperties).isEnabled(); doReturn(true).when(reporterProperties).isEnabled();
APIConfig apiConfig = mock(APIConfig.class);
doReturn("0.0.0.0").when(apiConfig).getBindIP();
GlobalConfig globalConfig = mock(GlobalConfig.class);
doReturn(apiConfig).when(globalConfig).getAPI();
Configuration configuration = mock(Configuration.class);
doReturn(globalConfig).when(configuration).getGlobal();
doReturn(configuration).when(sdkContext).getConfig();
EnhancedPluginContext pluginContext = new EnhancedPluginContext(); EnhancedPluginContext pluginContext = new EnhancedPluginContext();
EnhancedRequestContext request = EnhancedRequestContext.builder() EnhancedRequestContext request = EnhancedRequestContext.builder()
.httpMethod(HttpMethod.GET) .httpMethod(HttpMethod.GET)
.url(URI.create("http://0.0.0.0/")) .url(URI.create("http://0.0.0.0/"))
.build(); .build();
request.toString();
EnhancedResponseContext response = EnhancedResponseContext.builder() EnhancedResponseContext response = EnhancedResponseContext.builder()
.httpStatus(200) .httpStatus(200)
.build(); .build();
response.toString();
DefaultServiceInstance serviceInstance = new DefaultServiceInstance(); DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
serviceInstance.setServiceId(SERVICE_PROVIDER); serviceInstance.setServiceId(SERVICE_PROVIDER);
pluginContext.setRequest(request); pluginContext.setRequest(request);
pluginContext.setResponse(response); pluginContext.setResponse(response);
pluginContext.setServiceInstance(serviceInstance); pluginContext.setTargetServiceInstance(serviceInstance);
successPolarisReporter.run(pluginContext); successPolarisReporter.run(pluginContext);
successPolarisReporter.getOrder(); successPolarisReporter.getOrder();

@ -40,6 +40,7 @@ import org.mockito.MockedStatic;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
@ -65,6 +66,8 @@ public class EnhancedRestTemplateInterceptorTest {
@Mock @Mock
private SDKContext sdkContext; private SDKContext sdkContext;
@Mock @Mock
Registration registration;
@Mock
private ClientHttpRequestExecution mockClientHttpRequestExecution; private ClientHttpRequestExecution mockClientHttpRequestExecution;
@Mock @Mock
private ClientHttpResponse mockClientHttpResponse; private ClientHttpResponse mockClientHttpResponse;
@ -109,7 +112,7 @@ public class EnhancedRestTemplateInterceptorTest {
doReturn(mockHttpHeaders).when(mockHttpRequest).getHeaders(); doReturn(mockHttpHeaders).when(mockHttpRequest).getHeaders();
doReturn(mockClientHttpResponse).when(mockClientHttpRequestExecution).execute(mockHttpRequest, inputBody); doReturn(mockClientHttpResponse).when(mockClientHttpRequestExecution).execute(mockHttpRequest, inputBody);
EnhancedRestTemplateInterceptor reporter = new EnhancedRestTemplateInterceptor(new DefaultEnhancedPluginRunner(new ArrayList<>())); EnhancedRestTemplateInterceptor reporter = new EnhancedRestTemplateInterceptor(new DefaultEnhancedPluginRunner(new ArrayList<>(), registration, null));
actualResult = reporter.intercept(mockHttpRequest, inputBody, mockClientHttpRequestExecution); actualResult = reporter.intercept(mockHttpRequest, inputBody, mockClientHttpRequestExecution);
assertThat(actualResult).isEqualTo(mockClientHttpResponse); assertThat(actualResult).isEqualTo(mockClientHttpResponse);

@ -17,13 +17,11 @@
package com.tencent.cloud.rpc.enhancement.resttemplate; package com.tencent.cloud.rpc.enhancement.resttemplate;
import com.tencent.cloud.common.constant.HeaderConstant;
import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.common.metadata.StaticMetadataManager;
import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -36,7 +34,9 @@ import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.ServiceInstance;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpRequest;
import static com.tencent.cloud.rpc.enhancement.resttemplate.PolarisLoadBalancerRequestTransformer.LOAD_BALANCER_SERVICE_INSTANCE;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -45,13 +45,16 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
public class BlockingLoadBalancerClientAspectTest { public class PolarisLoadBalancerRequestTransformerTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils; private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
private PolarisLoadBalancerRequestTransformer transformer = new PolarisLoadBalancerRequestTransformer();
@Mock @Mock
private ProceedingJoinPoint proceedingJoinPoint; private HttpRequest clientRequest;
private BlockingLoadBalancerClientAspect aspect = new BlockingLoadBalancerClientAspect(); @Mock
private ServiceInstance serviceInstance;
@BeforeAll @BeforeAll
static void beforeAll() { static void beforeAll() {
@ -79,14 +82,8 @@ public class BlockingLoadBalancerClientAspectTest {
@Test @Test
public void test() throws Throwable { public void test() throws Throwable {
ServiceInstance serviceInstance = mock(ServiceInstance.class); transformer.transformRequest(clientRequest, serviceInstance);
doReturn("0.0.0.0").when(serviceInstance).getHost(); assertThat(MetadataContextHolder.get().getLoadbalancerMetadata().get(LOAD_BALANCER_SERVICE_INSTANCE)).isEqualTo(serviceInstance);
doReturn(80).when(serviceInstance).getPort();
doReturn(new Object[]{ serviceInstance }).when(proceedingJoinPoint).getArgs();
aspect.invoke(proceedingJoinPoint);
aspect.pointcut();
assertThat(MetadataContextHolder.get().getLoadbalancerMetadata().get(HeaderConstant.INTERNAL_CALLEE_INSTANCE_HOST)).isEqualTo("0.0.0.0");
assertThat(MetadataContextHolder.get().getLoadbalancerMetadata().get(HeaderConstant.INTERNAL_CALLEE_INSTANCE_PORT)).isEqualTo("80");
} }
} }

@ -39,6 +39,7 @@ import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.route.Route; import org.springframework.cloud.gateway.route.Route;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@ -62,6 +63,8 @@ public class EnhancedGatewayGlobalFilterTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils; private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@Mock @Mock
Registration registration;
@Mock
ServerWebExchange exchange; ServerWebExchange exchange;
@Mock @Mock
GatewayFilterChain chain; GatewayFilterChain chain;
@ -115,7 +118,7 @@ public class EnhancedGatewayGlobalFilterTest {
doReturn(request).when(exchange).getRequest(); doReturn(request).when(exchange).getRequest();
doReturn(response).when(exchange).getResponse(); doReturn(response).when(exchange).getResponse();
EnhancedGatewayGlobalFilter reporter = new EnhancedGatewayGlobalFilter(new DefaultEnhancedPluginRunner(new ArrayList<>())); EnhancedGatewayGlobalFilter reporter = new EnhancedGatewayGlobalFilter(new DefaultEnhancedPluginRunner(new ArrayList<>(), registration, null));
reporter.getOrder(); reporter.getOrder();
reporter.filter(exchange, chain).block(); reporter.filter(exchange, chain).block();

@ -39,9 +39,11 @@ import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.client.ClientRequest; import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.ExchangeFunction; import org.springframework.web.reactive.function.client.ExchangeFunction;
@ -56,7 +58,7 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
public class EnhancedWebClientReporterTest { public class EnhancedWebClientExchangeFilterFunctionTest {
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils; private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@Mock @Mock
@ -64,6 +66,8 @@ public class EnhancedWebClientReporterTest {
@Mock @Mock
private SDKContext sdkContext; private SDKContext sdkContext;
@Mock @Mock
private Registration registration;
@Mock
private ClientRequest clientRequest; private ClientRequest clientRequest;
@Mock @Mock
private ExchangeFunction exchangeFunction; private ExchangeFunction exchangeFunction;
@ -101,9 +105,10 @@ public class EnhancedWebClientReporterTest {
doReturn(HttpMethod.GET).when(clientRequest).method(); doReturn(HttpMethod.GET).when(clientRequest).method();
ClientResponse.Headers headers = mock(ClientResponse.Headers.class); ClientResponse.Headers headers = mock(ClientResponse.Headers.class);
doReturn(headers).when(clientResponse).headers(); doReturn(headers).when(clientResponse).headers();
doReturn(HttpStatus.valueOf(200)).when(clientResponse).statusCode();
doReturn(Mono.just(clientResponse)).when(exchangeFunction).exchange(any()); doReturn(Mono.just(clientResponse)).when(exchangeFunction).exchange(any());
EnhancedWebClientReporter reporter = new EnhancedWebClientReporter(new DefaultEnhancedPluginRunner(new ArrayList<>())); EnhancedWebClientExchangeFilterFunction reporter = new EnhancedWebClientExchangeFilterFunction(new DefaultEnhancedPluginRunner(new ArrayList<>(), registration, null));
ClientResponse clientResponse1 = reporter.filter(clientRequest, exchangeFunction).block(); ClientResponse clientResponse1 = reporter.filter(clientRequest, exchangeFunction).block();
assertThat(clientResponse1).isEqualTo(clientResponse); assertThat(clientResponse1).isEqualTo(clientResponse);

@ -17,7 +17,6 @@
package com.tencent.cloud.rpc.enhancement.webclient; package com.tencent.cloud.rpc.enhancement.webclient;
import com.tencent.cloud.common.constant.HeaderConstant;
import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.common.metadata.StaticMetadataManager;
@ -37,6 +36,7 @@ import org.springframework.cloud.client.ServiceInstance;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.web.reactive.function.client.ClientRequest; import org.springframework.web.reactive.function.client.ClientRequest;
import static com.tencent.cloud.rpc.enhancement.resttemplate.PolarisLoadBalancerRequestTransformer.LOAD_BALANCER_SERVICE_INSTANCE;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -83,8 +83,7 @@ public class PolarisLoadBalancerClientRequestTransformerTest {
@Test @Test
public void test() throws Throwable { public void test() throws Throwable {
doReturn("test").when(serviceInstance).getServiceId();
transformer.transformRequest(clientRequest, serviceInstance); transformer.transformRequest(clientRequest, serviceInstance);
assertThat(MetadataContextHolder.get().getLoadbalancerMetadata().get(HeaderConstant.INTERNAL_CALLEE_SERVICE_ID)).isEqualTo("test"); assertThat(MetadataContextHolder.get().getLoadbalancerMetadata().get(LOAD_BALANCER_SERVICE_INSTANCE)).isEqualTo(serviceInstance);
} }
} }

Loading…
Cancel
Save