feat: merge lane router and lossless features from 2023 (#1288)

* feat:  add lane router and lossless features from 2023

* Update CHANGELOG.md

* fix: change application.yml to bootstrap.yml
pull/1295/head
andrew shan 1 year ago committed by GitHub
parent 7ad631d32d
commit b6863b755d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -9,3 +9,4 @@
- [feat:add polaris ThreadLocal plugin.](https://github.com/Tencent/spring-cloud-tencent/pull/1255)
- [feat:upgrade jackson version.](https://github.com/Tencent/spring-cloud-tencent/pull/1257)
- [fix:fix wrong report when using Zuul with instance not found exception.](https://github.com/Tencent/spring-cloud-tencent/pull/1283)
- [feat: merge lane router and lossless features from 2023](https://github.com/Tencent/spring-cloud-tencent/pull/1288)

@ -74,7 +74,7 @@
<revision>1.14.0-Hoxton.SR12-SNAPSHOT</revision>
<!-- Polaris SDK version -->
<polaris.version>1.15.3</polaris.version>
<polaris.version>1.15.5-SNAPSHOT</polaris.version>
<!-- Dependencies -->
<guava.version>32.0.1-jre</guava.version>

@ -0,0 +1,63 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>lossless-example</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>lossless-callee-service</artifactId>
<name>Spring Cloud Starter Tencent Lossless Callee Service Example</name>
<dependencies>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-lossless-plugin</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,95 @@
/*
* 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.lossless.callee;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import com.tencent.cloud.common.constant.MetadataConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import static com.tencent.cloud.common.constant.ContextConstant.UTF_8;
@RestController
@RequestMapping("/lossless/callee")
public class LosslessCalleeController {
private static final Logger LOG = LoggerFactory.getLogger(LosslessCalleeController.class);
@Value("${lossless.healthy.delay.second:0}")
private int healthyDelay;
private final AtomicBoolean calledHealthyEndpoint = new AtomicBoolean(false);
private final AtomicInteger healthy = new AtomicInteger(0);
@GetMapping("/health")
public ResponseEntity<String> health() {
if (healthy.get() == 1) {
return new ResponseEntity<>("OK", HttpStatus.OK);
}
else {
if (calledHealthyEndpoint.compareAndSet(false, true)) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
if (healthyDelay > 0) {
try {
Thread.sleep(healthyDelay * 1000L);
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
healthy.set(1);
}
});
thread.start();
}
return new ResponseEntity<>("NOK", HttpStatus.SERVICE_UNAVAILABLE);
}
}
/**
* Get metadata in HTTP query.
*
* @param metadataStr metadata string
* @return metadata in HTTP header
* @throws UnsupportedEncodingException encoding exception
*/
@RequestMapping("/echo")
public String echoHeader(@RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String metadataStr)
throws UnsupportedEncodingException {
LOG.info(URLDecoder.decode(metadataStr, UTF_8));
metadataStr = URLDecoder.decode(metadataStr, UTF_8);
return metadataStr;
}
}

@ -0,0 +1,29 @@
/*
* 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.lossless.callee;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class LosslessCalleeService {
public static void main(String[] args) {
SpringApplication.run(LosslessCalleeService.class, args);
}
}

@ -0,0 +1,36 @@
server:
port: 48090
spring:
application:
name: LosslessCalleeService
cloud:
polaris:
address: grpc://119.91.66.223:8091
namespace: default
enabled: true
discovery:
enabled: true
register: true
contract:
exposure: true
report:
enabled: true
stat:
enabled: true
port: 28084
lossless:
enabled: true
port: 28084
#healthCheckPath: /actuator/health
#healthCheckInterval: 5000
lossless:
healthy:
delay:
second: 20
management:
endpoints:
web:
exposure:
include:
- polaris-discovery
- health

@ -0,0 +1,69 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>lossless-example</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.tencent.polaris</groupId>
<artifactId>lossless-nacos-callee-service</artifactId>
<name>Spring Cloud Starter Tencent Lossless Nacos Callee Service Example</name>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.10-RC2</version>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-discovery-adapter-plugin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-lossless-plugin</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,95 @@
/*
* 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.lossless.nacos.callee;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import com.tencent.cloud.common.constant.MetadataConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import static com.tencent.cloud.common.constant.ContextConstant.UTF_8;
@RestController
@RequestMapping("/lossless/nacos/callee")
public class LosslessNacosCalleeController {
private static final Logger LOG = LoggerFactory.getLogger(LosslessNacosCalleeController.class);
@Value("${lossless.healthy.delay.second:0}")
private int healthyDelay;
private final AtomicBoolean calledHealthyEndpoint = new AtomicBoolean(false);
private final AtomicInteger healthy = new AtomicInteger(0);
@GetMapping("/health")
public ResponseEntity<String> health() {
if (healthy.get() == 1) {
return new ResponseEntity<>("OK", HttpStatus.OK);
}
else {
if (calledHealthyEndpoint.compareAndSet(false, true)) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
if (healthyDelay > 0) {
try {
Thread.sleep(healthyDelay * 1000L);
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
healthy.set(1);
}
});
thread.start();
}
return new ResponseEntity<>("NOK", HttpStatus.SERVICE_UNAVAILABLE);
}
}
/**
* Get metadata in HTTP query.
*
* @param metadataStr metadata string
* @return metadata in HTTP header
* @throws UnsupportedEncodingException encoding exception
*/
@RequestMapping("/echo")
public String echoHeader(@RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String metadataStr)
throws UnsupportedEncodingException {
LOG.info(URLDecoder.decode(metadataStr, UTF_8));
metadataStr = URLDecoder.decode(metadataStr, UTF_8);
return metadataStr;
}
}

@ -13,26 +13,19 @@
* 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.plugin.lossless.transfomer;
package com.tencent.cloud.lossless.nacos.callee;
import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Discovery namespace getter for Polaris.
*
* @author Shedfree Wu
*/
public class PolarisDiscoveryNamespaceGetter implements DiscoveryNamespaceGetter {
@SpringBootApplication
public class LosslessNacosCalleeService {
private String namespace;
public PolarisDiscoveryNamespaceGetter(PolarisDiscoveryProperties polarisDiscoveryProperties) {
this.namespace = polarisDiscoveryProperties.getNamespace();
public static void main(String[] args) {
SpringApplication.run(LosslessNacosCalleeService.class, args);
}
public String getNamespace() {
return namespace;
}
}

@ -0,0 +1,20 @@
server:
port: 48091
spring:
application:
name: LosslessNacosCalleeService
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
enabled: true
polaris:
lossless:
enabled: true
port: 28085
healthCheckPath: /actuator/health
healthCheckInterval: 5000
lossless:
healthy:
delay:
second: 20

@ -0,0 +1,18 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>spring-cloud-tencent-examples</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modules>
<module>lossless-callee-service</module>
<module>lossless-nacos-callee-service</module>
</modules>
<modelVersion>4.0.0</modelVersion>
<artifactId>lossless-example</artifactId>
<packaging>pom</packaging>
<name>Spring Cloud Starter Tencent Lossless Example</name>
</project>

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-tencent-examples</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modules>
<module>router-grayrelease-lane-gateway</module>
<module>router-grayrelease-lane-caller-service</module>
<module>router-grayrelease-lane-callee-service</module>
</modules>
<modelVersion>4.0.0</modelVersion>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-router-grayrelease-lane-example</artifactId>
<packaging>pom</packaging>
<name>Spring Cloud Tencent Polaris Router Lane Example</name>
<description>Example of Spring Cloud Tencent Polaris Router Lane</description>
</project>

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-router-grayrelease-lane-example</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>route-grayrelease-lane-callee-service</artifactId>
<dependencies>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
<groupId>com.tencent.cloud</groupId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,47 @@
/*
* 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.lane.callee;
import java.util.HashMap;
import java.util.Map;
import com.tencent.cloud.common.spi.InstanceMetadataProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* Custom metadata for instance.
*
* @author Haotian Zhang
*/
@Component
public class CustomMetadata implements InstanceMetadataProvider {
@Value("${service.lane:base}")
private String lane;
@Override
public Map<String, String> getMetadata() {
Map<String, String> metadata = new HashMap<>();
if (!"base".equals(lane)) {
metadata.put("lane", lane);
}
return metadata;
}
}

@ -0,0 +1,29 @@
/*
* 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.lane.callee;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class LaneRouterCalleeApplication {
public static void main(String[] args) {
SpringApplication.run(LaneRouterCalleeApplication.class, args);
}
}

@ -0,0 +1,91 @@
/*
* 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.lane.callee;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import com.tencent.cloud.common.constant.MetadataConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import static com.tencent.cloud.common.constant.ContextConstant.UTF_8;
@RestController
@RequestMapping("/lane/callee")
public class LaneRouterCalleeController {
private static final Logger LOG = LoggerFactory.getLogger(LaneRouterCalleeController.class);
@Value("${server.port:0}")
private int port;
@Value("${spring.cloud.client.ip-address:127.0.0.1}")
private String ip;
@Value("${appName:${spring.application.name}}")
private String appName;
@Value("${service.lane:base}")
private String lane;
/**
* Get sum of two value.
* @param value1 value 1
* @param value2 value 2
* @return sum
*/
@GetMapping("/sum")
public String sum(@RequestParam int value1, @RequestParam int value2) {
LOG.info("Lane [{}] Callee Service [{} - {}:{}] is called and sum is [{}].", lane, appName, ip, port, value1 + value2);
return String.format("Lane [%s] Callee Service [%s - %s:%s] is called and sum is [%s].", lane, appName, ip, port, value1 + value2);
}
/**
* Get information of callee.
* @return information of callee
*/
@GetMapping("/info")
public String info() {
LOG.info("Lane [{}] Service [{} - {}:{}] is called.", lane, appName, ip, port);
return String.format("Lane [%s] Service [%s - %s:%s] is called.", lane, appName, ip, port);
}
/**
* Get metadata in HTTP header.
*
* @param metadataStr metadata string
* @return metadata in HTTP header
* @throws UnsupportedEncodingException encoding exception
*/
@RequestMapping("/echo")
public String echoHeader(@RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String metadataStr)
throws UnsupportedEncodingException {
LOG.info(URLDecoder.decode(metadataStr, UTF_8));
metadataStr = URLDecoder.decode(metadataStr, UTF_8);
return String.format("Lane [%s]: %s", lane, metadataStr);
}
}

@ -0,0 +1,36 @@
server:
port: 48093
spring:
application:
name: LaneCalleeService
cloud:
polaris:
address: grpc://119.91.66.223:8091
namespace: default
enabled: true
discovery:
enabled: true
register: true
contract:
exposure: true
report:
enabled: true
stat:
enabled: true
port: 28083
# pushgateway:
# enabled: true
# address: 127.0.0.1:9091
config:
address: grpc://9.134.5.52:8093
auto-refresh: true
groups:
- name: ${spring.application.name}
files: [ "config/callee.properties" ]
management:
endpoints:
web:
exposure:
include:
- polaris-discovery
- polaris-config

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-router-grayrelease-lane-example</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>route-grayrelease-lane-caller-service</artifactId>
<dependencies>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
<groupId>com.tencent.cloud</groupId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,47 @@
/*
* 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.lane.caller;
import java.util.HashMap;
import java.util.Map;
import com.tencent.cloud.common.spi.InstanceMetadataProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* Custom metadata for instance.
*
* @author Haotian Zhang
*/
@Component
public class CustomMetadata implements InstanceMetadataProvider {
@Value("${service.lane:base}")
private String lane;
@Override
public Map<String, String> getMetadata() {
Map<String, String> metadata = new HashMap<>();
if (!"base".equals(lane)) {
metadata.put("lane", lane);
}
return metadata;
}
}

@ -0,0 +1,41 @@
/*
* 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.lane.caller;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Quickstart callee feign client.
*
* @author Haotian Zhang
*/
@FeignClient("LaneCalleeService")
public interface LaneRouterCalleeService {
/**
* Get sum of two value.
*
* @param value1 value 1
* @param value2 value 2
* @return sum
*/
@GetMapping("/lane/callee/sum")
String sum(@RequestParam("value1") int value1, @RequestParam("value2") int value2);
}

@ -0,0 +1,57 @@
/*
* 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.lane.caller;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.DefaultUriBuilderFactory;
@SpringBootApplication
@EnableFeignClients
public class LaneRouterCallerApplication {
public static void main(String[] args) {
SpringApplication.run(LaneRouterCallerApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
@LoadBalanced
public RestTemplate defaultRestTemplate() {
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory("http://QuickstartCalleeService");
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(uriBuilderFactory);
return restTemplate;
}
@LoadBalanced
@Bean
WebClient.Builder webClientBuilder() {
return WebClient.builder().baseUrl("http://QuickstartCalleeService");
}
}

@ -0,0 +1,114 @@
/*
* 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.lane.caller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
@RestController
@RequestMapping("/lane/caller")
public class LaneRouterCallerController {
private static final Logger LOG = LoggerFactory.getLogger(LaneRouterCallerController.class);
@Value("${server.port:0}")
private int port;
@Value("${spring.cloud.client.ip-address:127.0.0.1}")
private String ip;
@Autowired
private RestTemplate restTemplate;
@Autowired
private LaneRouterCalleeService quickstartCalleeService;
@Autowired
private WebClient.Builder webClientBuilder;
@Value("${service.lane:base}")
private String lane;
@Value("${appName:${spring.application.name}}")
private String appName;
/**
* Get sum of two value.
* @param value1 value 1
* @param value2 value 2
* @return sum
*/
@GetMapping("/feign")
public String feign(@RequestParam int value1, @RequestParam int value2) {
String value = quickstartCalleeService.sum(value1, value2);
return String.format("Lane [%s] Caller Service [%s - %s:%s] -> %s", lane, appName, ip, port, value);
}
/**
* Get information of callee.
* @return information of callee
*/
@GetMapping("/rest")
public String rest() {
String value = restTemplate.getForObject("http://LaneCalleeService/lane/callee/info", String.class);
return String.format("Lane [%s] Caller Service [%s - %s:%s] -> %s", lane, appName, ip, port, value);
}
/**
* Get information of callee.
* @return information of callee
*/
@GetMapping("/webclient")
public Mono<String> webclient() {
return webClientBuilder
.build()
.get()
.uri("/quickstart/callee/echo")
.retrieve()
.bodyToMono(String.class);
}
/**
* Get information of caller.
* @return information of caller
*/
@GetMapping("/info")
public String info() {
LOG.info("Lane {} Service [{} - {}:{}] is called.", lane, appName, ip, port);
return String.format("Lane [%s] Service [%s - %s:%s] is called.", lane, appName, ip, port);
}
/**
* health check.
* @return health check info
*/
@GetMapping("/healthCheck")
public String healthCheck() {
return "ok";
}
}

@ -0,0 +1,42 @@
server:
port: 48092
spring:
application:
name: LaneCallerService
cloud:
polaris:
address: grpc://119.91.66.223:8091
namespace: default
enabled: true
discovery:
enabled: true
register: true
heartbeat:
enabled: true
health-check-url: /lane/caller/healthCheck
contract:
exposure: true
report:
enabled: true
circuitbreaker:
enabled: true
stat:
enabled: true
port: 28082
# pushgateway:
# enabled: true
# address: 127.0.0.1:9091
tencent:
rpc-enhancement:
enabled: true
reporter:
enabled: true
ignore-internal-server-error: true
series: server_error
statuses: gateway_timeout, bad_gateway, service_unavailable
management:
endpoints:
web:
exposure:
include:
- polaris-discovery

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-router-grayrelease-lane-example</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>router-grayrelease-lane-gateway</artifactId>
<dependencies>
<dependency>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
<groupId>com.tencent.cloud</groupId>
</dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,29 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.lane.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class LaneRouterGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(LaneRouterGatewayApplication.class, args);
}
}

@ -0,0 +1,39 @@
server:
port: 48090
spring:
application:
name: LaneRouterGatewayService
config:
import: optional:polaris
cloud:
polaris:
address: grpc://119.91.66.223:8091
namespace: default
enabled: true
contract:
exposure: true
report:
enabled: true
stat:
enabled: true
port: 28081
gateway:
discovery:
locator:
enabled: true
'predicates[0]':
name: Path
args:
patterns: '''/'' + serviceId + ''/**'''
'filters[0]':
name: RewritePath
args:
regexp: '''/'' + serviceId + ''/(?<remaining>.*)'''
replacement: '''/$\{remaining}'''
routes:
- id: LaneRouterCallerService
uri: lb://LaneCallerService
predicates:
- Path=/LaneCallerService/**
filters:
- StripPrefix=1

@ -21,6 +21,8 @@
<module>polaris-router-grayrelease-example</module>
<module>polaris-router-featureenv-example</module>
<module>quickstart-example</module>
<module>lossless-example</module>
<module>polaris-router-grayrelease-lane-example</module>
</modules>
<properties>

@ -19,8 +19,10 @@
package com.tencent.cloud.plugin.discovery.adapter.config;
import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosInstanceTransformer;
import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosRegistrationTransformer;
import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerAutoConfiguration;
import com.tencent.cloud.polaris.loadbalancer.transformer.InstanceTransformer;
import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer;
import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@ -41,9 +43,16 @@ public class NacosDiscoveryAdapterAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(name = "com.alibaba.cloud.nacos.ribbon.NacosServer")
@ConditionalOnClass(name = "com.alibaba.cloud.nacos.NacosServiceInstance")
public InstanceTransformer instanceTransformer() {
return new NacosInstanceTransformer();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(name = "com.alibaba.cloud.nacos.registry.NacosRegistration")
public RegistrationTransformer registrationTransformer() {
return new NacosRegistrationTransformer();
}
}

@ -18,10 +18,11 @@
package com.tencent.cloud.plugin.discovery.adapter.transformer;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.netflix.loadbalancer.Server;
import com.tencent.cloud.polaris.loadbalancer.transformer.InstanceTransformer;
import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer;
import com.tencent.polaris.api.pojo.DefaultInstance;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.client.ServiceInstance;
/**
* NacosInstanceTransformer.
@ -31,12 +32,20 @@ import com.tencent.polaris.api.pojo.DefaultInstance;
public class NacosInstanceTransformer implements InstanceTransformer {
@Override
public void transformCustom(DefaultInstance instance, Server server) {
if ("com.alibaba.cloud.nacos.ribbon.NacosServer".equals(server.getClass().getName())) {
NacosServer nacosServer = (NacosServer) server;
instance.setWeight((int) (nacosServer.getInstance().getWeight() * 100));
instance.setHealthy(nacosServer.getInstance().isHealthy());
instance.setMetadata(nacosServer.getMetadata());
public void transformCustom(DefaultInstance instance, ServiceInstance serviceInstance) {
if ("com.alibaba.cloud.nacos.NacosServiceInstance".equals(serviceInstance.getClass().getName())) {
String nacosWeight = serviceInstance.getMetadata().get("nacos.weight");
instance.setWeight(
StringUtils.isBlank(nacosWeight) ? 100 : (int) Double.parseDouble(nacosWeight) * 100
);
String nacosHealthy = serviceInstance.getMetadata().get("nacos.healthy");
instance.setHealthy(
!StringUtils.isBlank(nacosHealthy) && Boolean.parseBoolean(nacosHealthy)
);
String nacosInstanceId = serviceInstance.getMetadata().get("nacos.instanceId");
instance.setId(nacosInstanceId);
}
}
}

@ -0,0 +1,49 @@
/*
* 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.plugin.discovery.adapter.transformer;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.registry.NacosRegistration;
import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer;
import com.tencent.polaris.api.pojo.DefaultInstance;
import com.tencent.polaris.api.utils.StringUtils;
import org.springframework.cloud.client.serviceregistry.Registration;
public class NacosRegistrationTransformer implements RegistrationTransformer {
@Override
public String getRegistry() {
return "nacos";
}
@Override
public void transformCustom(DefaultInstance instance, Registration registration) {
if (registration instanceof NacosRegistration) {
NacosRegistration nacosRegistration = (NacosRegistration) registration;
NacosDiscoveryProperties nacosDiscoveryProperties = nacosRegistration.getNacosDiscoveryProperties();
String namespace = nacosDiscoveryProperties.getNamespace();
if (StringUtils.isBlank(namespace)) {
namespace = "default";
}
instance.setNamespace(namespace);
}
}
}

@ -19,6 +19,7 @@
package com.tencent.cloud.plugin.discovery.adapter.config;
import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosInstanceTransformer;
import com.tencent.cloud.rpc.enhancement.transformer.PolarisInstanceTransformer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
@ -44,6 +45,7 @@ public class NacosDiscoveryAdapterAutoConfigurationTest {
public void testDefaultInitialization() {
this.contextRunner.run(context -> {
assertThat(context).hasSingleBean(NacosInstanceTransformer.class);
assertThat(context).doesNotHaveBean(PolarisInstanceTransformer.class);
});
}
}

@ -18,10 +18,12 @@
package com.tencent.cloud.plugin.discovery.adapter.config;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import java.util.HashMap;
import com.alibaba.cloud.nacos.NacosServiceInstance;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.plugin.discovery.adapter.transformer.NacosInstanceTransformer;
import com.tencent.polaris.api.pojo.DefaultInstance;
import com.tencent.polaris.api.pojo.Instance;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
@ -51,14 +53,13 @@ public class NacosInstanceTransformerTest {
@Test
public void test() {
NacosInstanceTransformer nacosInstanceTransformer = new NacosInstanceTransformer();
com.alibaba.nacos.api.naming.pojo.Instance nacosInstance = new com.alibaba.nacos.api.naming.pojo.Instance();
nacosInstance.setHealthy(true);
NacosServer nacosServer = new NacosServer(nacosInstance);
DefaultInstance instance = new DefaultInstance();
nacosInstanceTransformer.transformCustom(instance, nacosServer);
NacosServiceInstance nacosServiceInstance = new NacosServiceInstance();
nacosServiceInstance.setMetadata(new HashMap<String, String>() {{
put("nacos.weight", "0.01");
put("nacos.healthy", "true");
put("nacos.instanceId", "xxx");
}});
Instance instance = nacosInstanceTransformer.transform(nacosServiceInstance);
assertThat(instance.isHealthy()).isEqualTo(true);
}

@ -58,13 +58,6 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2.2.9.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-test-mock-discovery</artifactId>

@ -18,8 +18,9 @@
package com.tencent.cloud.plugin.lossless;
import com.tencent.cloud.plugin.lossless.config.LosslessProperties;
import com.tencent.cloud.plugin.lossless.transfomer.DiscoveryNamespaceGetter;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer;
import com.tencent.polaris.api.pojo.BaseInstance;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
@ -37,7 +38,7 @@ import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
@Aspect
public class LosslessRegistryAspect {
private ServiceRegistry serviceRegistry;
private ServiceRegistry<Registration> serviceRegistry;
private Registration registration;
@ -45,16 +46,19 @@ public class LosslessRegistryAspect {
private PolarisSDKContextManager polarisSDKContextManager;
private DiscoveryNamespaceGetter discoveryNamespaceGetter;
private RegistrationTransformer registrationTransformer;
public LosslessRegistryAspect(ServiceRegistry serviceRegistry, Registration registration,
LosslessProperties losslessProperties, PolarisSDKContextManager polarisSDKContextManager,
DiscoveryNamespaceGetter discoveryNamespaceGetter) {
private PolarisContextProperties properties;
public LosslessRegistryAspect(ServiceRegistry<Registration> serviceRegistry, Registration registration,
PolarisContextProperties properties, LosslessProperties losslessProperties,
PolarisSDKContextManager polarisSDKContextManager, RegistrationTransformer registrationTransformer) {
this.serviceRegistry = serviceRegistry;
this.registration = registration;
this.losslessProperties = losslessProperties;
this.polarisSDKContextManager = polarisSDKContextManager;
this.discoveryNamespaceGetter = discoveryNamespaceGetter;
this.registrationTransformer = registrationTransformer;
this.properties = properties;
}
@Pointcut("execution(public * org.springframework.cloud.client.serviceregistry.ServiceRegistry.register(..))")
@ -71,7 +75,7 @@ public class LosslessRegistryAspect {
public Object invokeRegister(ProceedingJoinPoint joinPoint) throws Throwable {
// web started, get port from registration
BaseInstance instance = SpringCloudLosslessActionProvider.getBaseInstance(registration, discoveryNamespaceGetter);
BaseInstance instance = SpringCloudLosslessActionProvider.getBaseInstance(registration, registrationTransformer);
Runnable registerAction = () -> executeJoinPoint(joinPoint);

@ -22,11 +22,10 @@ import java.util.Map;
import com.tencent.cloud.common.util.OkHttpUtil;
import com.tencent.cloud.plugin.lossless.config.LosslessProperties;
import com.tencent.cloud.plugin.lossless.transfomer.DiscoveryNamespaceGetter;
import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer;
import com.tencent.polaris.api.plugin.lossless.InstanceProperties;
import com.tencent.polaris.api.plugin.lossless.LosslessActionProvider;
import com.tencent.polaris.api.pojo.BaseInstance;
import com.tencent.polaris.api.pojo.DefaultBaseInstance;
import com.tencent.polaris.api.utils.StringUtils;
import org.springframework.cloud.client.serviceregistry.Registration;
@ -89,20 +88,8 @@ public class SpringCloudLosslessActionProvider implements LosslessActionProvider
losslessProperties.getHealthCheckPath(), headers);
}
public static BaseInstance getBaseInstance(Registration registration, DiscoveryNamespaceGetter namespaceGetter) {
return getBaseInstance(registration, registration.getPort(), namespaceGetter);
public static BaseInstance getBaseInstance(Registration registration, RegistrationTransformer registrationTransformer) {
return registrationTransformer.transform(registration);
}
public static BaseInstance getBaseInstance(Registration registration, Integer port,
DiscoveryNamespaceGetter namespaceGetter) {
DefaultBaseInstance baseInstance = new DefaultBaseInstance();
if (namespaceGetter != null) {
baseInstance.setNamespace(namespaceGetter.getNamespace());
}
baseInstance.setService(registration.getServiceId());
// before web start, port in registration not init
baseInstance.setPort(port);
baseInstance.setHost(registration.getHost());
return baseInstance;
}
}

@ -18,20 +18,12 @@
package com.tencent.cloud.plugin.lossless.config;
import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.tencent.cloud.plugin.lossless.LosslessRegistryAspect;
import com.tencent.cloud.plugin.lossless.transfomer.DiscoveryNamespaceGetter;
import com.tencent.cloud.plugin.lossless.transfomer.NacosDiscoveryNamespaceGetter;
import com.tencent.cloud.plugin.lossless.transfomer.PolarisDiscoveryNamespaceGetter;
import com.tencent.cloud.polaris.PolarisDiscoveryProperties;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import com.tencent.cloud.polaris.discovery.ConditionalOnPolarisDiscoveryEnabled;
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
@ -51,34 +43,12 @@ public class LosslessAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public LosslessRegistryAspect losslessRegistryAspect(ServiceRegistry serviceRegistry, Registration registration,
LosslessProperties losslessProperties, PolarisSDKContextManager polarisSDKContextManager,
@Autowired(required = false) DiscoveryNamespaceGetter discoveryNamespaceGetter) {
return new LosslessRegistryAspect(serviceRegistry, registration, losslessProperties, polarisSDKContextManager, discoveryNamespaceGetter);
public LosslessRegistryAspect losslessRegistryAspect(
ServiceRegistry serviceRegistry, Registration registration, PolarisContextProperties properties,
LosslessProperties losslessProperties, PolarisSDKContextManager polarisSDKContextManager,
RegistrationTransformer registrationTransformer) {
return new LosslessRegistryAspect(serviceRegistry, registration, properties, losslessProperties,
polarisSDKContextManager, registrationTransformer);
}
@ConditionalOnClass(name = "com.alibaba.cloud.nacos.NacosDiscoveryProperties")
static class Nacos {
@Bean
@ConditionalOnMissingBean
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnBean(NacosDiscoveryProperties.class)
public NacosDiscoveryNamespaceGetter nacosDiscoveryNamespaceGetter(
NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosDiscoveryNamespaceGetter(nacosDiscoveryProperties);
}
}
@ConditionalOnClass(name = "com.tencent.cloud.polaris.PolarisDiscoveryProperties")
static class Polaris {
@Bean
@ConditionalOnMissingBean
@ConditionalOnPolarisDiscoveryEnabled
@ConditionalOnBean(PolarisDiscoveryProperties.class)
public PolarisDiscoveryNamespaceGetter polarisDiscoveryNamespaceGetter(
PolarisDiscoveryProperties polarisDiscoveryProperties) {
return new PolarisDiscoveryNamespaceGetter(polarisDiscoveryProperties);
}
}
}

@ -1,47 +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.plugin.lossless.transfomer;
import java.lang.reflect.Method;
import java.util.Properties;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.client.naming.utils.InitUtils;
import org.springframework.util.ReflectionUtils;
/**
* Discovery namespace getter for Nacos.
*
* @author Shedfree Wu
*/
public class NacosDiscoveryNamespaceGetter implements DiscoveryNamespaceGetter {
private String namespace;
public NacosDiscoveryNamespaceGetter(NacosDiscoveryProperties nacosDiscoveryProperties) {
// getNacosProperties is private in low version of spring-cloud-starter-alibaba-nacos-discovery
Method method = ReflectionUtils.findMethod(NacosDiscoveryProperties.class, "getNacosProperties");
method.setAccessible(true);
this.namespace = InitUtils.initNamespaceForNaming(
(Properties) ReflectionUtils.invokeMethod(method, nacosDiscoveryProperties));
}
public String getNamespace() {
return namespace;
}
}

@ -19,22 +19,15 @@ package com.tencent.cloud.plugin.lossless;
import java.util.Collections;
import com.alibaba.cloud.nacos.NacosServiceAutoConfiguration;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration;
import com.alibaba.cloud.nacos.registry.NacosRegistration;
import com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration;
import com.alibaba.cloud.nacos.util.UtilIPv6AutoConfiguration;
import com.tencent.cloud.common.util.OkHttpUtil;
import com.tencent.cloud.plugin.lossless.config.LosslessAutoConfiguration;
import com.tencent.cloud.plugin.lossless.config.LosslessPropertiesBootstrapConfiguration;
import com.tencent.cloud.plugin.lossless.transfomer.DiscoveryNamespaceGetter;
import com.tencent.cloud.polaris.context.PolarisSDKContextManager;
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClientConfiguration;
import com.tencent.cloud.polaris.registry.PolarisRegistration;
import com.tencent.cloud.polaris.registry.PolarisServiceRegistry;
import com.tencent.polaris.api.pojo.BaseInstance;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.test.mock.discovery.NamingServer;
import org.junit.jupiter.api.AfterAll;
@ -46,10 +39,7 @@ import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationUtils;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.commons.util.UtilAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
@ -72,8 +62,6 @@ public class LosslessRegistryAspectTest {
private static int LOSSLESS_PORT_1 = 28083;
private static int NACOS_LOSSLESS_PORT = 28093;
private static NamingServer namingServer;
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
@ -116,31 +104,6 @@ public class LosslessRegistryAspectTest {
.withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST)
.withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx");
private final WebApplicationContextRunner nacosContextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
AutoServiceRegistrationProperties.class,
UtilAutoConfiguration.class,
UtilIPv6AutoConfiguration.class,
NacosDiscoveryAutoConfiguration.class,
NacosServiceAutoConfiguration.class,
NacosServiceRegistryAutoConfiguration.class,
LosslessAutoConfiguration.class,
LosslessPropertiesBootstrapConfiguration.class,
PolarisContextAutoConfiguration.class)
)
.withPropertyValues("spring.cloud.nacos.discovery.enabled=true")
.withPropertyValues("spring.cloud.nacos.discovery.namespace=" + NAMESPACE_TEST)
.withPropertyValues("spring.cloud.polaris.discovery.enabled=false")
.withPropertyValues("spring.cloud.polaris.lossless.delayRegisterInterval=5000")
.withPropertyValues("spring.cloud.polaris.lossless.healthCheckPath=")
.withPropertyValues("spring.cloud.polaris.lossless.port=" + NACOS_LOSSLESS_PORT)
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + APPLICATION_PORT)
.withPropertyValues("spring.cloud.polaris.localIpAddress=" + HOST)
.withPropertyValues("spring.cloud.polaris.localPort=" + APPLICATION_PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081")
.withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx");
@BeforeAll
static void beforeAll() throws Exception {
namingServer = NamingServer.startNamingServer(10081);
@ -220,22 +183,6 @@ public class LosslessRegistryAspectTest {
});
}
@Test
public void testNaocsRegister() {
this.nacosContextRunner.run(context -> {
DiscoveryNamespaceGetter discoveryNamespaceGetter = context.getBean(DiscoveryNamespaceGetter.class);
Registration registration = context.getBean(Registration.class);
assertThat(registration instanceof NacosRegistration).isTrue();
assertThat(discoveryNamespaceGetter.getNamespace()).isEqualTo(NAMESPACE_TEST);
BaseInstance baseInstance = SpringCloudLosslessActionProvider.getBaseInstance(registration, discoveryNamespaceGetter);
assertThat(baseInstance.getNamespace()).isEqualTo(NAMESPACE_TEST);
});
}
@Configuration
@EnableAutoConfiguration
static class PolarisPropertiesConfiguration {

@ -35,6 +35,10 @@ import com.tencent.cloud.rpc.enhancement.plugin.reporter.SuccessPolarisReporter;
import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateInterceptor;
import com.tencent.cloud.rpc.enhancement.resttemplate.PolarisLoadBalancerRequestTransformer;
import com.tencent.cloud.rpc.enhancement.scg.EnhancedGatewayGlobalFilter;
import com.tencent.cloud.rpc.enhancement.transformer.InstanceTransformer;
import com.tencent.cloud.rpc.enhancement.transformer.PolarisInstanceTransformer;
import com.tencent.cloud.rpc.enhancement.transformer.PolarisRegistrationTransformer;
import com.tencent.cloud.rpc.enhancement.transformer.RegistrationTransformer;
import com.tencent.cloud.rpc.enhancement.webclient.EnhancedWebClientExchangeFilterFunction;
import com.tencent.cloud.rpc.enhancement.webclient.PolarisLoadBalancerClientRequestTransformer;
import com.tencent.cloud.rpc.enhancement.webclient.RibbonLoadBalancerClientAspect;
@ -84,6 +88,20 @@ import static javax.servlet.DispatcherType.REQUEST;
@AutoConfigureAfter(PolarisContextAutoConfiguration.class)
public class RpcEnhancementAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(name = "com.tencent.cloud.common.pojo.PolarisServiceInstance")
public InstanceTransformer instanceTransformer() {
return new PolarisInstanceTransformer();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(name = "com.tencent.cloud.polaris.registry.PolarisRegistration")
public RegistrationTransformer registrationTransformer() {
return new PolarisRegistrationTransformer();
}
@Bean
@Lazy
public EnhancedPluginRunner enhancedFeignPluginRunner(

@ -0,0 +1,53 @@
/*
* 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.transformer;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.polaris.api.pojo.DefaultInstance;
import com.tencent.polaris.api.pojo.Instance;
import org.springframework.cloud.client.ServiceInstance;
/**
* InstanceTransformer.
*
* @author sean yu
*/
public interface InstanceTransformer {
default Instance transform(ServiceInstance serviceInstance) {
DefaultInstance instance = new DefaultInstance();
transformDefault(instance, serviceInstance);
transformCustom(instance, serviceInstance);
return instance;
}
default void transformDefault(DefaultInstance instance, ServiceInstance serviceInstance) {
instance.setNamespace(MetadataContext.LOCAL_NAMESPACE);
instance.setService(serviceInstance.getServiceId());
instance.setProtocol(serviceInstance.getScheme());
instance.setId(serviceInstance.getInstanceId());
instance.setHost(serviceInstance.getHost());
instance.setPort(serviceInstance.getPort());
instance.setMetadata(serviceInstance.getMetadata());
}
void transformCustom(DefaultInstance instance, ServiceInstance serviceInstance);
}

@ -0,0 +1,44 @@
/*
* 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.transformer;
import com.tencent.cloud.common.pojo.PolarisServiceInstance;
import com.tencent.polaris.api.pojo.DefaultInstance;
import org.springframework.cloud.client.ServiceInstance;
/**
* PolarisInstanceTransformer.
*
* @author sean yu
*/
public class PolarisInstanceTransformer implements InstanceTransformer {
@Override
public void transformCustom(DefaultInstance instance, ServiceInstance serviceInstance) {
if (serviceInstance instanceof PolarisServiceInstance) {
PolarisServiceInstance polarisServiceInstance = (PolarisServiceInstance) serviceInstance;
instance.setRegion(polarisServiceInstance.getPolarisInstance().getRegion());
instance.setZone(polarisServiceInstance.getPolarisInstance().getZone());
instance.setCampus(polarisServiceInstance.getPolarisInstance().getCampus());
instance.setWeight(polarisServiceInstance.getPolarisInstance().getWeight());
}
}
}

@ -13,16 +13,15 @@
* 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.plugin.lossless.transfomer;
package com.tencent.cloud.rpc.enhancement.transformer;
/**
* Interface for discovery namespace getter.
*
* @author Shedfree Wu
*/
public interface DiscoveryNamespaceGetter {
public class PolarisRegistrationTransformer implements RegistrationTransformer {
String getNamespace();
@Override
public String getRegistry() {
return "polaris";
}
}

@ -0,0 +1,58 @@
/*
* 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.transformer;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.polaris.api.pojo.DefaultInstance;
import com.tencent.polaris.api.pojo.Instance;
import org.springframework.cloud.client.serviceregistry.Registration;
/**
* RegistrationTransformer extensions to adapt 3rd registration to polaris instance.
*
* @author andrew shan
*/
public interface RegistrationTransformer {
String getRegistry();
default Instance transform(Registration registration) {
DefaultInstance instance = new DefaultInstance();
transformDefault(instance, registration);
transformCustom(instance, registration);
return instance;
}
default void transformDefault(DefaultInstance instance, Registration registration) {
instance.setRegistry(getRegistry());
instance.setNamespace(MetadataContext.LOCAL_NAMESPACE);
instance.setService(registration.getServiceId());
instance.setProtocol(registration.getScheme());
instance.setId(registration.getInstanceId());
instance.setHost(registration.getHost());
instance.setPort(registration.getPort());
instance.setMetadata(registration.getMetadata());
}
default void transformCustom(DefaultInstance instance, Registration registration) {
}
}
Loading…
Cancel
Save