Skip to content

feat: support gateway context, feign eager-load support default value. #1576

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@

- [feat: implement circuit breaker in enhance plugin, support listen config group, support refresh single config in refresh_context mode.](https://github.com/Tencent/spring-cloud-tencent/pull/1566)
- [feat:support polaris event.](https://github.com/Tencent/spring-cloud-tencent/pull/1571)
- [feat:support circuit breaker metrics reporting.](https://github.com/Tencent/spring-cloud-tencent/pull/1572)
- [feat:support circuit breaker metrics reporting.](https://github.com/Tencent/spring-cloud-tencent/pull/1573)
- [feat: support gateway context, feign eager-load support default value.](https://github.com/Tencent/spring-cloud-tencent/pull/1576)
5 changes: 5 additions & 0 deletions spring-cloud-starter-tencent-all/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@
<artifactId>spring-cloud-starter-tencent-trace-plugin</artifactId>
</dependency>

<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-gateway-plugin</artifactId>
</dependency>

<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-auth</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.constant.OrderConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.common.util.UrlUtils;
Expand Down Expand Up @@ -95,6 +96,11 @@ public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain web
MetadataConstant.HeaderName.METADATA_CONTEXT,
MetadataContextHolder.get());

String targetNamespace = serverWebExchange.getRequest().getHeaders().getFirst(MetadataConstant.HeaderName.NAMESPACE);
if (StringUtils.isNotBlank(targetNamespace)) {
MetadataContextHolder.get().putFragmentContext(MetadataContext.FRAGMENT_APPLICATION_NONE,
MetadataConstant.POLARIS_TARGET_NAMESPACE, targetNamespace);
}
TransHeadersTransfer.transfer(serverHttpRequest);
return webFilterChain.filter(serverWebExchange)
.doFinally((type) -> MetadataContextHolder.remove());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedRequestContext;
import com.tencent.cloud.rpc.enhancement.plugin.EnhancedResponseContext;
import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter;
import com.tencent.polaris.api.utils.StringUtils;
import com.tencent.polaris.circuitbreak.client.exception.CallAbortedException;
import com.tencent.polaris.metadata.core.MetadataType;
import org.slf4j.Logger;
Expand Down Expand Up @@ -69,10 +70,10 @@ public void run(EnhancedPluginContext context) throws Throwable {
EnhancedRequestContext request = context.getRequest();
EnhancedResponseContext response = context.getResponse();

String governanceNamespace = MetadataContext.LOCAL_NAMESPACE;

String host = request.getServiceUrl() != null ? request.getServiceUrl().getHost() : request.getUrl().getHost();
String path = request.getServiceUrl() != null ? request.getServiceUrl().getPath() : request.getUrl().getPath();
String governanceNamespace = StringUtils.isNotEmpty(request.getGovernanceNamespace()) ? request.getGovernanceNamespace() : MetadataContext.LOCAL_NAMESPACE;

String httpMethod = request.getHttpMethod().name();

CircuitBreaker circuitBreaker = circuitBreakerFactory.create(governanceNamespace + "#" + host + "#" + path + "#http#" + httpMethod);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.tencent.cloud.polaris.config.config.PolarisConfigProperties;
import com.tencent.cloud.polaris.config.enums.ConfigFileFormat;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.polaris.api.utils.ClassUtils;
import com.tencent.polaris.configuration.api.core.ConfigFileMetadata;
import com.tencent.polaris.configuration.api.core.ConfigFileService;
import com.tencent.polaris.configuration.api.core.ConfigKVFile;
Expand Down Expand Up @@ -213,13 +214,17 @@ void initTsfConfigGroups(CompositePropertySource compositePropertySource) {
String tsfNamespaceName = environment.getProperty("tsf_namespace_name");
String tsfGroupName = environment.getProperty("tsf_group_name");

if (StringUtils.isEmpty(tsfId) || StringUtils.isEmpty(tsfNamespaceName) || StringUtils.isEmpty(tsfGroupName)) {
if (StringUtils.isEmpty(tsfNamespaceName) || StringUtils.isEmpty(tsfGroupName)) {
return;
}
String namespace = polarisContextProperties.getNamespace();
List<String> tsfConfigGroups = Arrays.asList(
tsfId + "." + tsfGroupName + ".application_config_group",
tsfId + "." + tsfNamespaceName + ".global_config_group");
List<String> tsfConfigGroups = new ArrayList<>();
tsfConfigGroups.add((StringUtils.hasText(tsfId) ? tsfId + "." : "") + tsfGroupName + ".application_config_group");
tsfConfigGroups.add((StringUtils.hasText(tsfId) ? tsfId + "." : "") + tsfNamespaceName + ".global_config_group");

if (ClassUtils.isClassPresent("org.springframework.cloud.gateway.filter.GlobalFilter")) {
tsfConfigGroups.add((StringUtils.hasText(tsfId) ? tsfId + "." : "") + tsfGroupName + ".gateway_config_group");
}
for (String tsfConfigGroup : tsfConfigGroups) {
PolarisPropertySource polarisPropertySource = loadGroupPolarisPropertySource(configFileService, namespace, tsfConfigGroup);
if (polarisPropertySource == null) {
Expand Down
12 changes: 12 additions & 0 deletions spring-cloud-starter-tencent-polaris-discovery/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@
</dependency>
<!-- Polaris dependencies end -->

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-core</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

package com.tencent.cloud.polaris.discovery;

import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import com.tencent.polaris.api.core.ConsumerAPI;
Expand Down Expand Up @@ -49,7 +52,9 @@ public PolarisDiscoveryHandler(PolarisDiscoveryProperties polarisDiscoveryProper
* @return list of healthy instances
*/
public InstancesResponse getHealthyInstances(String service) {
String namespace = polarisDiscoveryProperties.getNamespace();
String namespace = MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_APPLICATION_NONE,
MetadataConstant.POLARIS_TARGET_NAMESPACE, polarisDiscoveryProperties.getNamespace());

GetHealthyInstancesRequest getHealthyInstancesRequest = new GetHealthyInstancesRequest();
getHealthyInstancesRequest.setNamespace(namespace);
getHealthyInstancesRequest.setService(service);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import org.springframework.context.annotation.Configuration;

@Configuration
@ConditionalOnProperty(name = "spring.cloud.polaris.discovery.eager-load.enabled", havingValue = "true")
@ConditionalOnProperty(name = "spring.cloud.polaris.discovery.eager-load.enabled", havingValue = "true", matchIfMissing = true)
public class PolarisEagerLoadAutoConfiguration {

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@

package com.tencent.cloud.polaris.eager.instrument.feign;

import com.tencent.cloud.common.util.FeignUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;

import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClient;
import com.tencent.cloud.polaris.discovery.reactive.PolarisReactiveDiscoveryClient;
import com.tencent.polaris.api.utils.StringUtils;
import feign.Target;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.ApplicationContext;
import org.springframework.context.SmartLifecycle;

Expand All @@ -47,36 +51,59 @@ public FeignEagerLoadSmartLifecycle(ApplicationContext applicationContext, Polar
@Override
public void start() {
LOG.info("feign eager-load start");
for (String name : applicationContext.getBeanDefinitionNames()) {
for (Object bean : applicationContext.getBeansWithAnnotation(FeignClient.class).values()) {
try {
if (name.contains(FeignUtil.FEIGN_CLIENT_SPECIF) && !name.startsWith(FeignUtil.FEIGN_CLIENT_DEFAULT)) {
String feignName = FeignUtil.analysisFeignName(name, applicationContext);
if (StringUtils.isNotBlank(feignName)) {
LOG.info("[{}] eager-load start", feignName);
if (polarisDiscoveryClient != null) {
polarisDiscoveryClient.getInstances(feignName);
}
else if (polarisReactiveDiscoveryClient != null) {
polarisReactiveDiscoveryClient.getInstances(feignName).subscribe();
}
else {
LOG.warn("[{}] no discovery client found.", feignName);
if (Proxy.isProxyClass(bean.getClass())) {
Target.HardCodedTarget<?> hardCodedTarget = getHardCodedTarget(bean);
if (hardCodedTarget != null) {
FeignClient feignClient = hardCodedTarget.type().getAnnotation(FeignClient.class);
// if feignClient contains url, it doesn't need to eager load.
if (StringUtils.isEmpty(feignClient.url())) {
// support variables and default values.
String feignName = hardCodedTarget.name();
LOG.info("[{}] eager-load start", feignName);
if (polarisDiscoveryClient != null) {
polarisDiscoveryClient.getInstances(feignName);
}
else if (polarisReactiveDiscoveryClient != null) {
polarisReactiveDiscoveryClient.getInstances(feignName).subscribe();
}
else {
LOG.warn("[{}] no discovery client found.", feignName);
}
LOG.info("[{}] eager-load end", feignName);
}
LOG.info("[{}] eager-load end", feignName);
}
else {
LOG.warn("feign name is blank.");
}
}
}
catch (Exception e) {
LOG.error("[{}] eager-load failed.", name, e);
LOG.debug("[{}] eager-load failed.", bean, e);
}
}
LOG.info("feign eager-load end");

}

public static Target.HardCodedTarget<?> getHardCodedTarget(Object proxy) {
try {
Object invocationHandler = Proxy.getInvocationHandler(proxy);

for (Field field : invocationHandler.getClass().getDeclaredFields()) {
field.setAccessible(true);
Object fieldValue = field.get(invocationHandler);
if (fieldValue instanceof Target.HardCodedTarget) {
return (Target.HardCodedTarget<?>) fieldValue;
}
}
}
catch (Exception e) {
if (LOG.isDebugEnabled()) {
LOG.debug("proxy:{}, getTarget failed.", proxy, e);
}
}
return null;
}

@Override
public void stop() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
import java.util.function.Function;
import java.util.stream.Collectors;

import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer;
import com.tencent.polaris.api.pojo.DefaultServiceInstances;
import com.tencent.polaris.api.pojo.Instance;
Expand Down Expand Up @@ -72,7 +74,10 @@ public static ServiceInstances transferServersToServiceInstances(Flux<List<Servi
serviceMetadata = instanceList.get(0).getServiceMetadata();
}

ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, serviceName);
String namespace = MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_APPLICATION_NONE,
MetadataConstant.POLARIS_TARGET_NAMESPACE, MetadataContext.LOCAL_NAMESPACE);

ServiceKey serviceKey = new ServiceKey(namespace, serviceName);

return new DefaultServiceInstances(serviceKey, instanceList, serviceMetadata);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ public void testTransferNotEmptyInstances() {
.thenReturn(testNamespaceAndService);
MetadataContext metadataContext = Mockito.mock(MetadataContext.class);
mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext);
Mockito.when(metadataContext.getContext(anyString(), anyString(), anyString()))
.thenReturn(testNamespaceAndService);

int instanceSize = 100;
int weight = 50;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ public final class MetadataConstant {
* polaris transitive header prefix length.
*/
public static final int POLARIS_TRANSITIVE_HEADER_PREFIX_LENGTH = POLARIS_TRANSITIVE_HEADER_PREFIX.length();
/**
* Name of polaris target namespace.
*/
public static final String POLARIS_TARGET_NAMESPACE = "POLARIS_TARGET_NAMESPACE";

private MetadataConstant() {

Expand Down Expand Up @@ -70,6 +74,10 @@ public static class HeaderName {
* Metadata context.
*/
public static final String METADATA_CONTEXT = "SCT-METADATA-CONTEXT";
/**
* Namespace context.
*/
public static final String NAMESPACE = "SCT-NAMESPACE";
}

public static class DefaultMetadata {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ public class MetadataContext extends com.tencent.polaris.metadata.core.manager.M
* disposable Context.
*/
public static final String FRAGMENT_APPLICATION = "application";
/**
* none Context.
*/
public static final String FRAGMENT_APPLICATION_NONE = "application-none";

/**
* upstream disposable Context.
Expand Down Expand Up @@ -125,6 +129,10 @@ public MetadataContext() {
super(MetadataConstant.POLARIS_TRANSITIVE_HEADER_PREFIX);
}

public static void setLocalService(String service) {
LOCAL_SERVICE = service;
}

private Map<String, String> getMetadataAsMap(MetadataType metadataType, TransitiveType transitiveType, boolean caller) {
MetadataContainer metadataContainer = getMetadataContainer(metadataType, caller);
Map<String, String> values = new HashMap<>();
Expand Down Expand Up @@ -266,6 +274,8 @@ public Map<String, String> getFragmentContext(String fragment) {
return getMetadataAsMap(MetadataType.CUSTOM, TransitiveType.DISPOSABLE, true);
case FRAGMENT_APPLICATION:
return getMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, false);
case FRAGMENT_APPLICATION_NONE:
return getMetadataAsMap(MetadataType.APPLICATION, TransitiveType.NONE, false);
case FRAGMENT_UPSTREAM_APPLICATION:
return getMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, true);
case FRAGMENT_RAW_TRANSHEADERS:
Expand All @@ -277,6 +287,10 @@ public Map<String, String> getFragmentContext(String fragment) {
}
}

public String getContext(String fragment, String key, String defaultValue) {
return getFragmentContext(fragment).getOrDefault(key, defaultValue);
}

public String getContext(String fragment, String key) {
Map<String, String> fragmentContext = getFragmentContext(fragment);
if (fragmentContext == null) {
Expand Down Expand Up @@ -305,6 +319,9 @@ public void putFragmentContext(String fragment, Map<String, String> context) {
case FRAGMENT_APPLICATION:
putMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, false, context);
break;
case FRAGMENT_APPLICATION_NONE:
putMetadataAsMap(MetadataType.APPLICATION, TransitiveType.NONE, false, context);
break;
case FRAGMENT_UPSTREAM_APPLICATION:
putMetadataAsMap(MetadataType.APPLICATION, TransitiveType.DISPOSABLE, true, context);
break;
Expand All @@ -320,7 +337,9 @@ public void putFragmentContext(String fragment, Map<String, String> context) {
}
}

public static void setLocalService(String service) {
LOCAL_SERVICE = service;
public void putFragmentContext(String fragment, String key, String value) {
Map<String, String> context = new HashMap<>(1);
context.put(key, value);
putFragmentContext(fragment, context);
}
}
Loading
Loading