diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index b901097f2..000000000 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar index 2cc7d4a55..c1dd12f17 100644 Binary files a/.mvn/wrapper/maven-wrapper.jar and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 642d572ce..b74bf7fcd 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,2 +1,2 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f081b67a..b7ba786b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,4 +3,13 @@ - [Bugfix: optimize ratelimit actuator](https://github.com/Tencent/spring-cloud-tencent/pull/419) - [Feature: add rate limit filter debug log](https://github.com/Tencent/spring-cloud-tencent/pull/436) -- [Optimize: add EncodeTransferMedataRestTemplateInterceptor to RestTemplate](https://github.com/Tencent/spring-cloud-tencent/pull/434) \ No newline at end of file +- [Optimize: add EncodeTransferMedataRestTemplateInterceptor to RestTemplate](https://github.com/Tencent/spring-cloud-tencent/pull/439) +- [Add configurable heartbeat interval support](https://github.com/Tencent/spring-cloud-tencent/pull/443) +- [feat:enhance Feign and RestTemplate and support Polaris monitor.](https://github.com/Tencent/spring-cloud-tencent/pull/446) +- [Optimize feign & rest-template circuit-breaker logic](https://github.com/Tencent/spring-cloud-tencent/pull/453) +- [Bugfix: Removed unused class for circuit-breaker module](https://github.com/Tencent/spring-cloud-tencent/pull/456) +- [Feature: Add disposable metadata transfer support](https://github.com/Tencent/spring-cloud-tencent/pull/458) +- [loadBalancer module add unit test.](https://github.com/Tencent/spring-cloud-tencent/pull/468) +- [docs:update mvnw.](https://github.com/Tencent/spring-cloud-tencent/pull/475) +- [docs:update configuration metadata.](https://github.com/Tencent/spring-cloud-tencent/pull/473) +- [Feature: delete implement ServiceInstance](https://github.com/Tencent/spring-cloud-tencent/pull/482) \ No newline at end of file diff --git a/README-zh.md b/README-zh.md index 999fe31ba..3390a3944 100644 --- a/README-zh.md +++ b/README-zh.md @@ -42,6 +42,7 @@ Spring Cloud Tencent提供的能力包括但不限于: - 密码:polaris - 控制面地址: `grpc://183.47.111.80:8091` - + `spring-cloud-tencent-example` 下 example 地址都默认指向了体验服务地址(`grpc://183.47.111.80:8091`),如果您只是体验 Spring Cloud Tencent,可直接一键运行任何 example。 @@ -53,6 +54,10 @@ Tencent,可直接一键运行任何 example。 Spring Cloud Tencent 所有组件都已上传到 Maven 中央仓库,只需要引入依赖即可。 +> 注意: +> +> Spring Cloud Tencent 的版本列表可以查看 [Spring Cloud Tencent 版本管理](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86) 。 + 例如: ```` xml @@ -80,18 +85,38 @@ Spring Cloud Tencent 所有组件都已上传到 Maven 中央仓库,只需要 ```` -- ### 快速开始 - - [Spring Cloud Tencent 版本管理](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86) - - [Spring Cloud Tencent 服务注册与发现](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Discovery-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - - [Spring Cloud Tencent 配置中心](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Config-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - - [Spring Cloud Tencent 限流](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Rate-Limit-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - - [Spring Cloud Tencent 熔断](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Circuitbreaker-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - - [Spring Cloud Tencent 服务路由](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Router-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - - [Spring Cloud Tencent 标签传递](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Metadata-Transfer-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97) - -- ### 开发文档 - - [项目概览](https://github.com/Tencent/spring-cloud-tencent/wiki/%E9%A1%B9%E7%9B%AE%E6%A6%82%E8%A7%88) - - [参与共建](https://github.com/Tencent/spring-cloud-tencent/wiki/%E5%8F%82%E4%B8%8E%E5%85%B1%E5%BB%BA) +## 开发入门 + +You can build this project with command: + +```shell +## MacOS or Linux +./mvnw clean package + +## Win +.\mvnw.cmd clean package +``` + +## 文档 + +- 使用文档 + - [Spring Cloud Tencent Version Management](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86) + - [Spring Cloud Tencent Discovery](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Discovery-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) + - [Spring Cloud Tencent Config](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Config-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) + - [Spring Cloud Tencent Rate Limit](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Rate-Limit-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) + - [Spring Cloud Tencent CircuitBreaker](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Circuitbreaker-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) + - [Spring Cloud Tencent Router](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Router-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) + - [Spring Cloud Starter Tencent RPC Enhancement](https://github.com/Tencent/spring-cloud-tencent/wiki/RPC%E5%A2%9E%E5%BC%BA) + - [Spring Cloud Tencent Metadata Transfer](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Metadata-Transfer-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97) + - [Actuator Endpoint Extension](https://github.com/Tencent/spring-cloud-tencent/wiki/Actuator-Endpoint-%E6%89%A9%E5%B1%95) + +- 最佳实践 + - [Multi-feature environment](https://github.com/Tencent/spring-cloud-tencent/wiki/多特性环境) + - [Multi-registration and multi-discovery](https://github.com/Tencent/spring-cloud-tencent/wiki/Multi-registration-and-multi-discovery) + +- 开发文档 + - [Project Structure Overview](https://github.com/Tencent/spring-cloud-tencent/wiki/%E9%A1%B9%E7%9B%AE%E6%A6%82%E8%A7%88) + - [Participate in co-construction](https://github.com/Tencent/spring-cloud-tencent/wiki/%E5%8F%82%E4%B8%8E%E5%85%B1%E5%BB%BA) ## 交流群 diff --git a/README.md b/README.md index 4d383a392..21fe1d82c 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,10 @@ directly with one click. All the components of Spring Cloud Tencent have been uploaded to the Maven central repository, just need to introduce dependencies. +> Notice: +> +> The version list of Spring Cloud Tencent can be found in [Spring Cloud Tencent Version Management](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86). + For example: ```` xml @@ -83,16 +87,36 @@ For example: ```` -- ### Quick Start +## Develop Guide + +You can build this project with command: + +```shell +## MacOS or Linux +./mvnw clean package + +## Win +.\mvnw.cmd clean package +``` + +## Documents + +- Usage Doc - [Spring Cloud Tencent Version Management](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86) - [Spring Cloud Tencent Discovery](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Discovery-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - [Spring Cloud Tencent Config](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Config-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - [Spring Cloud Tencent Rate Limit](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Rate-Limit-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - [Spring Cloud Tencent CircuitBreaker](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Circuitbreaker-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - [Spring Cloud Tencent Router](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Router-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) + - [Spring Cloud Starter Tencent RPC Enhancement](https://github.com/Tencent/spring-cloud-tencent/wiki/RPC%E5%A2%9E%E5%BC%BA) - [Spring Cloud Tencent Metadata Transfer](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Metadata-Transfer-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97) + - [Actuator Endpoint Extension](https://github.com/Tencent/spring-cloud-tencent/wiki/Actuator-Endpoint-%E6%89%A9%E5%B1%95) + +- Best Practices + - [Multi-feature environment](https://github.com/Tencent/spring-cloud-tencent/wiki/多特性环境) + - [Multi-registration and multi-discovery](https://github.com/Tencent/spring-cloud-tencent/wiki/Multi-registration-and-multi-discovery) -- ### Development Documentation +- Development documentation - [Project Structure Overview](https://github.com/Tencent/spring-cloud-tencent/wiki/%E9%A1%B9%E7%9B%AE%E6%A6%82%E8%A7%88) - [Participate in co-construction](https://github.com/Tencent/spring-cloud-tencent/wiki/%E5%8F%82%E4%B8%8E%E5%85%B1%E5%BB%BA) diff --git a/mvnw b/mvnw index 41c0f0c23..8a8fb2282 100755 --- a/mvnw +++ b/mvnw @@ -8,7 +8,7 @@ # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an @@ -36,6 +36,10 @@ if [ -z "$MAVEN_SKIP_RC" ] ; then + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + if [ -f /etc/mavenrc ] ; then . /etc/mavenrc fi @@ -145,7 +149,7 @@ if [ -z "$JAVACMD" ] ; then JAVACMD="$JAVA_HOME/bin/java" fi else - JAVACMD="`which java`" + JAVACMD="`\\unset -f command; \\command -v java`" fi fi @@ -212,9 +216,9 @@ else echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." fi if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" else - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" fi while IFS="=" read key value; do case "$key" in (wrapperUrl) jarUrl="$value"; break ;; @@ -233,9 +237,9 @@ else echo "Found wget ... using wget" fi if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" + wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" fi elif command -v curl > /dev/null; then if [ "$MVNW_VERBOSE" = true ]; then @@ -305,6 +309,8 @@ WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain exec "$JAVACMD" \ $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + "-Dmaven.home=${M2_HOME}" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd index 86115719e..1d8ab018e 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -7,7 +7,7 @@ @REM "License"); you may not use this file except in compliance @REM with the License. You may obtain a copy of the License at @REM -@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM https://www.apache.org/licenses/LICENSE-2.0 @REM @REM Unless required by applicable law or agreed to in writing, @REM software distributed under the License is distributed on an @@ -46,8 +46,8 @@ if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") @REM Execute a user defined script before this one if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre @REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* :skipRcPre @setlocal @@ -120,9 +120,9 @@ SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" -FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B ) @@ -134,7 +134,7 @@ if exist %WRAPPER_JAR% ( ) ) else ( if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" ) if "%MVNW_VERBOSE%" == "true" ( echo Couldn't find %WRAPPER_JAR%, downloading it ... @@ -158,7 +158,13 @@ if exist %WRAPPER_JAR% ( @REM work with both Windows and non-Windows executions. set MAVEN_CMD_LINE_ARGS=%* -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* if ERRORLEVEL 1 goto error goto end @@ -168,15 +174,15 @@ set ERROR_CODE=1 :end @endlocal & set ERROR_CODE=%ERROR_CODE% -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost @REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" :skipRcPost @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause +if "%MAVEN_BATCH_PAUSE%"=="on" pause -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% -exit /B %ERROR_CODE% +cmd /C exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml index 22e8d95b1..9058818aa 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,7 @@ spring-cloud-tencent-commons spring-cloud-tencent-polaris-context + spring-cloud-tencent-rpc-enhancement spring-cloud-tencent-polaris-loadbalancer spring-cloud-starter-tencent-metadata-transfer spring-cloud-starter-tencent-polaris-config diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java index 7ef89920f..957493cad 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataReactiveFilter.java @@ -39,6 +39,8 @@ import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** * Filter used for storing the metadata from upstream temporarily when web application is @@ -60,14 +62,17 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered // Get metadata string from http header. ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest(); - Map internalTransitiveMetadata = getIntervalTransitiveMetadata(serverHttpRequest); + Map internalTransitiveMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_METADATA); Map customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(serverWebExchange); Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata); - MetadataContextHolder.init(mergedTransitiveMetadata); + Map internalDisposableMetadata = getIntervalMetadata(serverHttpRequest, CUSTOM_DISPOSABLE_METADATA); + Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); + + MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata); // Save to ServerWebExchange. serverWebExchange.getAttributes().put( @@ -80,10 +85,9 @@ public class DecodeTransferMetadataReactiveFilter implements WebFilter, Ordered .doFinally((type) -> MetadataContextHolder.remove()); } - private Map getIntervalTransitiveMetadata(ServerHttpRequest serverHttpRequest) { + private Map getIntervalMetadata(ServerHttpRequest serverHttpRequest, String headerName) { HttpHeaders httpHeaders = serverHttpRequest.getHeaders(); - String customMetadataStr = httpHeaders - .getFirst(MetadataConstant.HeaderName.CUSTOM_METADATA); + String customMetadataStr = httpHeaders.getFirst(headerName); try { if (StringUtils.hasText(customMetadataStr)) { customMetadataStr = URLDecoder.decode(customMetadataStr, UTF_8); diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java index 3abf391e3..a67563915 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/DecodeTransferMetadataServletFilter.java @@ -36,10 +36,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; +import org.springframework.lang.NonNull; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** * Filter used for storing the metadata from upstream temporarily when web application is @@ -53,29 +56,27 @@ public class DecodeTransferMetadataServletFilter extends OncePerRequestFilter { private static final Logger LOG = LoggerFactory.getLogger(DecodeTransferMetadataServletFilter.class); @Override - protected void doFilterInternal(HttpServletRequest httpServletRequest, - HttpServletResponse httpServletResponse, FilterChain filterChain) + protected void doFilterInternal(@NonNull HttpServletRequest httpServletRequest, + @NonNull HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { - Map internalTransitiveMetadata = getInternalTransitiveMetadata(httpServletRequest); + Map internalTransitiveMetadata = getInternalMetadata(httpServletRequest, CUSTOM_METADATA); Map customTransitiveMetadata = CustomTransitiveMetadataResolver.resolve(httpServletRequest); Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(internalTransitiveMetadata); mergedTransitiveMetadata.putAll(customTransitiveMetadata); - try { - MetadataContextHolder.init(mergedTransitiveMetadata); + Map internalDisposableMetadata = getInternalMetadata(httpServletRequest, CUSTOM_DISPOSABLE_METADATA); + Map mergedDisposableMetadata = new HashMap<>(internalDisposableMetadata); - filterChain.doFilter(httpServletRequest, httpServletResponse); - } - catch (IOException | ServletException | RuntimeException e) { - throw e; - } + MetadataContextHolder.init(mergedTransitiveMetadata, mergedDisposableMetadata); + + filterChain.doFilter(httpServletRequest, httpServletResponse); } - private Map getInternalTransitiveMetadata(HttpServletRequest httpServletRequest) { + private Map getInternalMetadata(HttpServletRequest httpServletRequest, String headerName) { // Get custom metadata string from http header. - String customMetadataStr = httpServletRequest.getHeader(MetadataConstant.HeaderName.CUSTOM_METADATA); + String customMetadataStr = httpServletRequest.getHeader(headerName); try { if (StringUtils.hasText(customMetadataStr)) { customMetadataStr = URLDecoder.decode(customMetadataStr, UTF_8); diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java index a6af9e15e..fa63f3df8 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataFeignInterceptor.java @@ -19,7 +19,7 @@ package com.tencent.cloud.metadata.core; import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; +import java.util.HashMap; import java.util.Map; import com.tencent.cloud.common.constant.MetadataConstant; @@ -33,9 +33,12 @@ import org.slf4j.LoggerFactory; import org.springframework.core.Ordered; import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; +import static java.net.URLEncoder.encode; /** * Interceptor used for adding the metadata in http headers from context when web client @@ -57,17 +60,37 @@ public class EncodeTransferMedataFeignInterceptor implements RequestInterceptor, // get metadata of current thread MetadataContext metadataContext = MetadataContextHolder.get(); Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Map disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); - if (!CollectionUtils.isEmpty(customMetadata)) { - String encodedTransitiveMetadata = JacksonUtils.serialize2Json(customMetadata); - requestTemplate.removeHeader(CUSTOM_METADATA); + // Clean up one-time metadata coming from upstream . + Map newestCustomMetadata = new HashMap<>(); + customMetadata.forEach((key, value) -> { + if (!disposableMetadata.containsKey(key)) { + newestCustomMetadata.put(key, value); + } + }); + this.buildMetadataHeader(requestTemplate, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + + // process custom metadata finally + this.buildMetadataHeader(requestTemplate, newestCustomMetadata, CUSTOM_METADATA); + } + + /** + * Set metadata into the request header for {@link RestTemplate} . + * @param requestTemplate instance of {@link RestTemplate} + * @param metadata metadata map . + * @param headerName target metadata http header name . + */ + private void buildMetadataHeader(RequestTemplate requestTemplate, Map metadata, String headerName) { + if (!CollectionUtils.isEmpty(metadata)) { + String encodedMetadata = JacksonUtils.serialize2Json(metadata); + requestTemplate.removeHeader(headerName); try { - requestTemplate.header(CUSTOM_METADATA, - URLEncoder.encode(encodedTransitiveMetadata, UTF_8)); + requestTemplate.header(headerName, encode(encodedMetadata, UTF_8)); } catch (UnsupportedEncodingException e) { LOG.error("Set header failed.", e); - requestTemplate.header(CUSTOM_METADATA, encodedTransitiveMetadata); + requestTemplate.header(headerName, encodedMetadata); } } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java index 75f198193..513310da4 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataRestTemplateInterceptor.java @@ -21,6 +21,7 @@ package com.tencent.cloud.metadata.core; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.util.HashMap; import java.util.Map; import com.tencent.cloud.common.constant.MetadataConstant; @@ -33,9 +34,12 @@ import org.springframework.http.HttpRequest; import org.springframework.http.client.ClientHttpRequestExecution; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpResponse; +import org.springframework.lang.NonNull; import org.springframework.util.CollectionUtils; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; /** * Interceptor used for adding the metadata in http headers from context when web client @@ -51,22 +55,44 @@ public class EncodeTransferMedataRestTemplateInterceptor implements ClientHttpRe } @Override - public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes, - ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { + public ClientHttpResponse intercept(@NonNull HttpRequest httpRequest, @NonNull byte[] bytes, + @NonNull ClientHttpRequestExecution clientHttpRequestExecution) throws IOException { // get metadata of current thread MetadataContext metadataContext = MetadataContextHolder.get(); Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Map disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); - if (!CollectionUtils.isEmpty(customMetadata)) { - String encodedTransitiveMetadata = JacksonUtils.serialize2Json(customMetadata); + Map newestCustomMetadata = new HashMap<>(); + customMetadata.forEach((key, value) -> { + if (!disposableMetadata.containsKey(key)) { + newestCustomMetadata.put(key, value); + } + }); + // build custom disposable metadata request header + this.buildMetadataHeader(httpRequest, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + + // build custom metadata request header + this.buildMetadataHeader(httpRequest, newestCustomMetadata, CUSTOM_METADATA); + + return clientHttpRequestExecution.execute(httpRequest, bytes); + } + + /** + * Set metadata into the request header for {@link HttpRequest} . + * + * @param request instance of {@link HttpRequest} + * @param metadata metadata map . + * @param headerName target metadata http header name . + */ + private void buildMetadataHeader(HttpRequest request, Map metadata, String headerName) { + if (!CollectionUtils.isEmpty(metadata)) { + String encodedMetadata = JacksonUtils.serialize2Json(metadata); try { - httpRequest.getHeaders().set(MetadataConstant.HeaderName.CUSTOM_METADATA, - URLEncoder.encode(encodedTransitiveMetadata, UTF_8)); + request.getHeaders().set(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); } catch (UnsupportedEncodingException e) { - httpRequest.getHeaders().set(MetadataConstant.HeaderName.CUSTOM_METADATA, encodedTransitiveMetadata); + request.getHeaders().set(headerName, encodedMetadata); } } - return clientHttpRequestExecution.execute(httpRequest, bytes); } } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java index 4f6c00103..95d7b5b2c 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/main/java/com/tencent/cloud/metadata/core/EncodeTransferMedataScgFilter.java @@ -20,6 +20,7 @@ package com.tencent.cloud.metadata.core; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.util.HashMap; import java.util.Map; import com.tencent.cloud.common.constant.MetadataConstant; @@ -36,6 +37,8 @@ import org.springframework.util.CollectionUtils; import org.springframework.web.server.ServerWebExchange; import static com.tencent.cloud.common.constant.ContextConstant.UTF_8; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_DISPOSABLE_METADATA; +import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUSTOM_METADATA; import static org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER; /** @@ -59,22 +62,42 @@ public class EncodeTransferMedataScgFilter implements GlobalFilter, Ordered { // get metadata of current thread MetadataContext metadataContext = exchange.getAttribute(MetadataConstant.HeaderName.METADATA_CONTEXT); - - // add new metadata and cover old if (metadataContext == null) { metadataContext = MetadataContextHolder.get(); } + Map customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); - if (!CollectionUtils.isEmpty(customMetadata)) { - String metadataStr = JacksonUtils.serialize2Json(customMetadata); + Map disposableMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_DISPOSABLE); + + // Clean upstream disposable metadata. + Map newestCustomMetadata = new HashMap<>(); + customMetadata.forEach((key, value) -> { + if (!disposableMetadata.containsKey(key)) { + newestCustomMetadata.put(key, value); + } + }); + + this.buildMetadataHeader(builder, newestCustomMetadata, CUSTOM_METADATA); + this.buildMetadataHeader(builder, disposableMetadata, CUSTOM_DISPOSABLE_METADATA); + + return chain.filter(exchange.mutate().request(builder.build()).build()); + } + + /** + * Set metadata into the request header for {@link ServerHttpRequest.Builder} . + * @param builder instance of {@link ServerHttpRequest.Builder} + * @param metadata metadata map . + * @param headerName target metadata http header name . + */ + private void buildMetadataHeader(ServerHttpRequest.Builder builder, Map metadata, String headerName) { + if (!CollectionUtils.isEmpty(metadata)) { + String encodedMetadata = JacksonUtils.serialize2Json(metadata); try { - builder.header(MetadataConstant.HeaderName.CUSTOM_METADATA, URLEncoder.encode(metadataStr, UTF_8)); + builder.header(headerName, URLEncoder.encode(encodedMetadata, UTF_8)); } catch (UnsupportedEncodingException e) { - builder.header(MetadataConstant.HeaderName.CUSTOM_METADATA, metadataStr); + builder.header(headerName, encodedMetadata); } } - - return chain.filter(exchange.mutate().request(builder.build()).build()); } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml b/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml index f79e46aab..20bf4bdf2 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/pom.xml @@ -18,36 +18,14 @@ com.tencent.cloud spring-cloud-tencent-polaris-loadbalancer - - - com.tencent.polaris - polaris-discovery-factory - - - com.tencent.polaris - router-rule - - - com.tencent.polaris - router-nearby - - - com.tencent.polaris - router-metadata - - - com.tencent.polaris - router-canary - - - com.tencent.polaris - router-set - - + com.tencent.cloud + spring-cloud-tencent-rpc-enhancement + + com.tencent.polaris polaris-circuitbreaker-factory @@ -84,28 +62,10 @@ - - org.springframework.cloud - spring-cloud-starter-openfeign - true - - - - org.springframework.boot - spring-boot-starter-web - test - - org.springframework.boot spring-boot-starter-test test - - - org.mockito - mockito-inline - test - diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfiguration.java index e8e1fa038..cd3f5373f 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfiguration.java @@ -17,84 +17,53 @@ package com.tencent.cloud.polaris.circuitbreaker.config; -import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisFeignBeanPostProcessor; -import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisResponseErrorHandler; -import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisRestTemplateModifier; -import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisRestTemplateResponseErrorHandler; -import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; -import com.tencent.polaris.api.core.ConsumerAPI; -import com.tencent.polaris.client.api.SDKContext; -import com.tencent.polaris.factory.api.DiscoveryAPIFactory; +import com.tencent.cloud.common.constant.ContextConstant; +import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.polaris.api.config.consumer.ServiceRouterConfig; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.plugins.router.healthy.RecoverRouterConfig; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.openfeign.FeignAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.annotation.Order; -import org.springframework.web.client.RestTemplate; - -import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE; /** - * Auto Configuration for Polaris {@link feign.Feign} OR {@link RestTemplate} which can automatically bring in the call - * results for reporting. + * Autoconfiguration at bootstrap phase. * - * @author Palmer.Xu 2022-06-29 + * @author lepdou 2022-03-29 */ @Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisEnabled +@ConditionalOnProperty(value = "spring.cloud.polaris.circuitbreaker.enabled", havingValue = "true", matchIfMissing = true) public class PolarisCircuitBreakerAutoConfiguration { - /** - * Configuration for Polaris {@link feign.Feign} which can automatically bring in the call - * results for reporting. - * - * @author Haotian Zhang - */ - @Configuration(proxyBeanMethods = false) - @ConditionalOnClass(name = "org.springframework.cloud.openfeign.FeignAutoConfiguration") - @AutoConfigureAfter(PolarisContextAutoConfiguration.class) - @AutoConfigureBefore(FeignAutoConfiguration.class) - @ConditionalOnProperty(value = "spring.cloud.polaris.circuitbreaker.enabled", havingValue = "true", matchIfMissing = true) - protected static class PolarisFeignClientAutoConfiguration { + @Bean + public CircuitBreakerConfigModifier circuitBreakerConfigModifier() { + return new CircuitBreakerConfigModifier(); + } - @Bean - public ConsumerAPI consumerAPI(SDKContext context) { - return DiscoveryAPIFactory.createConsumerAPIByContext(context); - } + public static class CircuitBreakerConfigModifier implements PolarisConfigModifier { - @Bean - @Order(HIGHEST_PRECEDENCE) - public PolarisFeignBeanPostProcessor polarisFeignBeanPostProcessor(ConsumerAPI consumerAPI) { - return new PolarisFeignBeanPostProcessor(consumerAPI); - } - } + @Override + public void modify(ConfigurationImpl configuration) { + // Turn on circuitbreaker configuration + configuration.getConsumer().getCircuitBreaker().setEnable(true); + + // Set excludeCircuitBreakInstances to false + RecoverRouterConfig recoverRouterConfig = configuration.getConsumer().getServiceRouter() + .getPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, RecoverRouterConfig.class); - /** - * Configuration for Polaris {@link RestTemplate} which can automatically bring in the call - * results for reporting. - * - * @author wh 2022/6/21 - */ - @Configuration(proxyBeanMethods = false) - @AutoConfigureAfter(PolarisContextAutoConfiguration.class) - @ConditionalOnClass(RestTemplate.class) - @ConditionalOnProperty(value = "spring.cloud.polaris.circuitbreaker.enabled", havingValue = "true", matchIfMissing = true) - protected static class PolarisRestTemplateAutoConfiguration { + recoverRouterConfig.setExcludeCircuitBreakInstances(true); - @Bean - public PolarisRestTemplateResponseErrorHandler polarisRestTemplateResponseErrorHandler( - ConsumerAPI consumerAPI, @Autowired(required = false) PolarisResponseErrorHandler polarisResponseErrorHandler) { - return new PolarisRestTemplateResponseErrorHandler(consumerAPI, polarisResponseErrorHandler); + // Update modified config to source properties + configuration.getConsumer().getServiceRouter() + .setPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, recoverRouterConfig); } - @Bean - public PolarisRestTemplateModifier polarisRestTemplateBeanPostProcessor( - PolarisRestTemplateResponseErrorHandler restTemplateResponseErrorHandler) { - return new PolarisRestTemplateModifier(restTemplateResponseErrorHandler); + @Override + public int getOrder() { + return ContextConstant.ModifierOrder.CIRCUIT_BREAKER_ORDER; } } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfiguration.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfiguration.java index e10387f27..9d21fbf0d 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfiguration.java @@ -17,54 +17,18 @@ package com.tencent.cloud.polaris.circuitbreaker.config; -import com.tencent.cloud.common.constant.ContextConstant; -import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; -import com.tencent.cloud.polaris.context.PolarisConfigModifier; -import com.tencent.polaris.api.config.consumer.ServiceRouterConfig; -import com.tencent.polaris.factory.config.ConfigurationImpl; -import com.tencent.polaris.plugins.router.healthy.RecoverRouterConfig; - import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; /** - * Auto configuration at bootstrap phase. + * Autoconfiguration at bootstrap phase. * * @author lepdou 2022-03-29 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnPolarisEnabled -@ConditionalOnProperty(value = "spring.cloud.polaris.circuitbreaker.enabled", havingValue = "true", - matchIfMissing = true) +@ConditionalOnProperty("spring.cloud.polaris.enabled") +@Import(PolarisCircuitBreakerAutoConfiguration.class) public class PolarisCircuitBreakerBootstrapConfiguration { - @Bean - public CircuitBreakerConfigModifier circuitBreakerConfigModifier() { - return new CircuitBreakerConfigModifier(); - } - - public static class CircuitBreakerConfigModifier implements PolarisConfigModifier { - - @Override - public void modify(ConfigurationImpl configuration) { - // Turn on circuitbreaker configuration - configuration.getConsumer().getCircuitBreaker().setEnable(true); - - // Set excludeCircuitBreakInstances to false - RecoverRouterConfig recoverRouterConfig = configuration.getConsumer().getServiceRouter() - .getPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, RecoverRouterConfig.class); - - recoverRouterConfig.setExcludeCircuitBreakInstances(true); - - // Update modified config to source properties - configuration.getConsumer().getServiceRouter() - .setPluginConfig(ServiceRouterConfig.DEFAULT_ROUTER_RECOVER, recoverRouterConfig); - } - - @Override - public int getOrder() { - return ContextConstant.ModifierOrder.CIRCUIT_BREAKER_ORDER; - } - } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/spring.factories index 2c72cfed9..418da24ab 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/spring.factories @@ -1,4 +1,4 @@ -org.springframework.cloud.bootstrap.BootstrapConfiguration=\ - com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerBootstrapConfiguration org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ + com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerBootstrapConfiguration diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisFeignClientAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfigurationTest.java similarity index 65% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisFeignClientAutoConfigurationTest.java rename to spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfigurationTest.java index 6858a627f..433e0bb03 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisFeignClientAutoConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerAutoConfigurationTest.java @@ -15,12 +15,8 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.circuitbreaker; +package com.tencent.cloud.polaris.circuitbreaker.config; -import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration; -import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisFeignBeanPostProcessor; -import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; -import com.tencent.polaris.api.core.ConsumerAPI; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -33,20 +29,16 @@ import static org.assertj.core.api.Assertions.assertThat; * * @author Haotian Zhang */ -public class PolarisFeignClientAutoConfigurationTest { - +public class PolarisCircuitBreakerAutoConfigurationTest { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withConfiguration( - AutoConfigurations.of( - PolarisContextAutoConfiguration.class, - PolarisCircuitBreakerAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(PolarisCircuitBreakerAutoConfiguration.class)) .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true"); @Test public void testDefaultInitialization() { this.contextRunner.run(context -> { - assertThat(context).hasSingleBean(ConsumerAPI.class); - assertThat(context).hasSingleBean(PolarisFeignBeanPostProcessor.class); + assertThat(context).hasSingleBean( + PolarisCircuitBreakerAutoConfiguration.CircuitBreakerConfigModifier.class); }); } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerBootstrapConfigurationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java similarity index 81% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerBootstrapConfigurationTest.java rename to spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java index e29c4a76f..a4430c1da 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerBootstrapConfigurationTest.java +++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfigurationTest.java @@ -15,9 +15,8 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.circuitbreaker; +package com.tencent.cloud.polaris.circuitbreaker.config; -import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerBootstrapConfiguration; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -31,15 +30,16 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Haotian Zhang */ public class PolarisCircuitBreakerBootstrapConfigurationTest { - private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(PolarisCircuitBreakerBootstrapConfiguration.class)) + .withPropertyValues("spring.cloud.polaris.enabled=true") .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true"); @Test public void testDefaultInitialization() { this.contextRunner.run(context -> { assertThat(context).hasSingleBean( - PolarisCircuitBreakerBootstrapConfiguration.CircuitBreakerConfigModifier.class); + PolarisCircuitBreakerAutoConfiguration.CircuitBreakerConfigModifier.class); }); } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application.yml b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application.yml deleted file mode 100644 index 06500ed95..000000000 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/resources/application.yml +++ /dev/null @@ -1,15 +0,0 @@ -spring: - cloud: - polaris: - address: grpc://127.0.0.1:8091 - -feign: - polaris: - enable: true - compression: - request: - enabled: false - mime-types: text/xml,application/xml,application/json - min-request-size: 2048 - response: - enabled: false diff --git a/spring-cloud-starter-tencent-polaris-discovery/pom.xml b/spring-cloud-starter-tencent-polaris-discovery/pom.xml index 62ad96fb6..a25d29874 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/pom.xml +++ b/spring-cloud-starter-tencent-polaris-discovery/pom.xml @@ -19,44 +19,13 @@ com.tencent.cloud spring-cloud-tencent-polaris-loadbalancer - - - - com.tencent.polaris - polaris-discovery-factory - - - com.tencent.polaris - router-rule - - - com.tencent.polaris - router-nearby - - - com.tencent.polaris - router-metadata - - - com.tencent.polaris - router-canary - - - com.tencent.polaris - router-set - - - com.tencent.polaris - router-isolated - - - com.tencent.polaris - router-healthy - - + com.tencent.cloud + spring-cloud-tencent-rpc-enhancement + + com.tencent.polaris polaris-test-common diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfiguration.java index 4eb2efd30..6e9f1b236 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/DiscoveryPropertiesAutoConfiguration.java @@ -20,11 +20,6 @@ package com.tencent.cloud.polaris; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; import com.tencent.cloud.polaris.extend.consul.ConsulContextProperties; -import com.tencent.polaris.api.core.ConsumerAPI; -import com.tencent.polaris.api.core.ProviderAPI; -import com.tencent.polaris.api.exception.PolarisException; -import com.tencent.polaris.client.api.SDKContext; -import com.tencent.polaris.factory.api.DiscoveryAPIFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; @@ -41,18 +36,6 @@ import org.springframework.context.annotation.Import; @Import({PolarisDiscoveryProperties.class, ConsulContextProperties.class}) public class DiscoveryPropertiesAutoConfiguration { - @Bean - @ConditionalOnMissingBean - public ProviderAPI polarisProvider(SDKContext polarisContext) throws PolarisException { - return DiscoveryAPIFactory.createProviderAPIByContext(polarisContext); - } - - @Bean - @ConditionalOnMissingBean - public ConsumerAPI polarisConsumer(SDKContext polarisContext) throws PolarisException { - return DiscoveryAPIFactory.createConsumerAPIByContext(polarisContext); - } - @Bean @ConditionalOnMissingBean public PolarisDiscoveryHandler polarisDiscoveryHandler() { diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java index a126a3ad2..05b9bcfee 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/PolarisDiscoveryProperties.java @@ -30,6 +30,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; +import static com.tencent.cloud.common.constant.ContextConstant.DEFAULT_REGISTRY_HEARTBEAT_TIME_INTERVAL; + /** * Properties for Polaris. * @@ -95,6 +97,13 @@ public class PolarisDiscoveryProperties { @Value("${spring.cloud.polaris.discovery.heartbeat.enabled:#{true}}") private Boolean heartbeatEnabled = true; + /** + * Heart beat interval (The time interval must be greater than zero). + * Time unit: millisecond. Default: 5000. + * @see ContextConstant#DEFAULT_REGISTRY_HEARTBEAT_TIME_INTERVAL + */ + private Integer heartbeatInterval = 5000; + /** * Custom health check url to override default. */ @@ -202,6 +211,17 @@ public class PolarisDiscoveryProperties { this.serviceListRefreshInterval = serviceListRefreshInterval; } + public Integer getHeartbeatInterval() { + if (this.heartbeatEnabled && this.heartbeatInterval <= 0) { + return DEFAULT_REGISTRY_HEARTBEAT_TIME_INTERVAL; + } + return heartbeatInterval; + } + + public void setHeartbeatInterval(Integer heartbeatInterval) { + this.heartbeatInterval = heartbeatInterval; + } + @Override public String toString() { return "PolarisDiscoveryProperties{" + @@ -215,6 +235,7 @@ public class PolarisDiscoveryProperties { ", enabled=" + enabled + ", registerEnabled=" + registerEnabled + ", heartbeatEnabled=" + heartbeatEnabled + + ", heartbeatInterval=" + heartbeatInterval + ", healthCheckUrl='" + healthCheckUrl + '\'' + ", serviceListRefreshInterval=" + serviceListRefreshInterval + '}'; diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscovery.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscovery.java index 771a3c57d..85c79897d 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscovery.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/discovery/PolarisServiceDiscovery.java @@ -18,6 +18,7 @@ package com.tencent.cloud.polaris.discovery; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -29,6 +30,7 @@ import com.tencent.polaris.api.pojo.ServiceInstances; import com.tencent.polaris.api.rpc.InstancesResponse; import org.springframework.cloud.client.ServiceInstance; +import org.springframework.util.CollectionUtils; /** * Polaris service discovery service. @@ -65,7 +67,10 @@ public class PolarisServiceDiscovery { * @throws PolarisException polarisException */ public List getServices() throws PolarisException { - return polarisDiscoveryHandler.GetServices().getServices().stream().map(ServiceInfo::getService) - .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(polarisDiscoveryHandler.GetServices().getServices())) { + return Collections.emptyList(); + } + return polarisDiscoveryHandler.GetServices().getServices().stream() + .map(ServiceInfo::getService).collect(Collectors.toList()); } } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java index d893836a6..835b84bac 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java @@ -30,7 +30,6 @@ import com.tencent.polaris.client.api.SDKContext; import org.apache.commons.lang.StringUtils; import org.springframework.cloud.client.DefaultServiceInstance; -import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.lang.Nullable; import org.springframework.util.CollectionUtils; @@ -40,7 +39,7 @@ import org.springframework.util.CollectionUtils; * * @author Haotian Zhang, Andrew Shan, Jie Cheng */ -public class PolarisRegistration implements Registration, ServiceInstance { +public class PolarisRegistration implements Registration { private static final String METADATA_KEY_IP = "internal-ip"; private static final String METADATA_KEY_ADDRESS = "internal-address"; diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java index 225c146d8..e9bd0fb6e 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistry.java @@ -20,7 +20,6 @@ package com.tencent.cloud.polaris.registry; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; @@ -42,6 +41,7 @@ import org.springframework.beans.BeanUtils; import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.ServiceRegistry; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.springframework.util.ReflectionUtils.rethrowRuntimeException; /** @@ -53,8 +53,6 @@ public class PolarisServiceRegistry implements ServiceRegistry { private static final Logger log = LoggerFactory.getLogger(PolarisServiceRegistry.class); - private static final int ttl = 5; - private final PolarisDiscoveryProperties polarisDiscoveryProperties; private final PolarisDiscoveryHandler polarisDiscoveryHandler; @@ -98,7 +96,7 @@ public class PolarisServiceRegistry implements ServiceRegistry { instanceRegisterRequest.setZone(staticMetadataManager.getZone()); instanceRegisterRequest.setCampus(staticMetadataManager.getCampus()); if (null != heartbeatExecutor) { - instanceRegisterRequest.setTtl(ttl); + instanceRegisterRequest.setTtl(polarisDiscoveryProperties.getHeartbeatInterval()); } instanceRegisterRequest.setMetadata(registration.getMetadata()); instanceRegisterRequest.setProtocol(polarisDiscoveryProperties.getProtocol()); @@ -218,6 +216,6 @@ public class PolarisServiceRegistry implements ServiceRegistry { catch (Exception e) { log.error("polaris heartbeat runtime error", e); } - }, ttl, ttl, TimeUnit.SECONDS); + }, polarisDiscoveryProperties.getHeartbeatInterval(), polarisDiscoveryProperties.getHeartbeatInterval(), MILLISECONDS); } } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 7743b5f6c..93372d6dc 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -24,6 +24,12 @@ "defaultValue": true, "description": "enable polaris registration or not." }, + { + "name": "spring.cloud.polaris.discovery.heartbeat-interval", + "type": "java.lang.Integer", + "defaultValue": "5000", + "description": "Millis interval of Heart beat. Default: 5000." + }, { "name": "spring.cloud.polaris.discovery.health-check-url", "type": "java.lang.String", diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisDiscoveryPropertiesTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisDiscoveryPropertiesTest.java index 390c6ea24..b371fac02 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisDiscoveryPropertiesTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/PolarisDiscoveryPropertiesTest.java @@ -41,6 +41,10 @@ public class PolarisDiscoveryPropertiesTest { polarisDiscoveryProperties.setHeartbeatEnabled(true); assertThat(polarisDiscoveryProperties.isHeartbeatEnabled()).isTrue(); + // HeartbeatEnabled + polarisDiscoveryProperties.setHeartbeatInterval(2000); + assertThat(polarisDiscoveryProperties.getHeartbeatInterval()).isEqualTo(2000); + // Namespace polarisDiscoveryProperties.setNamespace(NAMESPACE_TEST); assertThat(polarisDiscoveryProperties.getNamespace()).isEqualTo(NAMESPACE_TEST); @@ -96,6 +100,7 @@ public class PolarisDiscoveryPropertiesTest { + ", enabled=true" + ", registerEnabled=true" + ", heartbeatEnabled=true" + + ", heartbeatInterval=2000" + ", healthCheckUrl='/health'" + ", serviceListRefreshInterval=1000}"); } diff --git a/spring-cloud-starter-tencent-polaris-router/pom.xml b/spring-cloud-starter-tencent-polaris-router/pom.xml index e21ca43f8..f8445ef68 100644 --- a/spring-cloud-starter-tencent-polaris-router/pom.xml +++ b/spring-cloud-starter-tencent-polaris-router/pom.xml @@ -19,6 +19,10 @@ com.tencent.cloud spring-cloud-tencent-polaris-loadbalancer + + com.tencent.cloud + spring-cloud-tencent-rpc-enhancement + com.tencent.cloud spring-cloud-starter-tencent-metadata-transfer diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/ContextConstant.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/ContextConstant.java index e2b2608b3..8fa44f2fa 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/ContextConstant.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/ContextConstant.java @@ -36,6 +36,11 @@ public final class ContextConstant { */ public static final String UTF_8 = StandardCharsets.UTF_8.name(); + /** + * Default registry heartbeat time interval, default: 5000 (ms). + */ + public static final Integer DEFAULT_REGISTRY_HEARTBEAT_TIME_INTERVAL = 5000; + private ContextConstant() { } @@ -68,5 +73,10 @@ public final class ContextConstant { * Order of configuration modifier. */ public static Integer CONFIG_ORDER = 1; + + /** + * Order of stat reporter configuration modifier. + */ + public static Integer STAT_REPORTER_ORDER = 1; } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/MetadataConstant.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/MetadataConstant.java index 09e17e1e8..5e451f3de 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/MetadataConstant.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/constant/MetadataConstant.java @@ -26,6 +26,12 @@ import org.springframework.core.Ordered; */ public final class MetadataConstant { + /** + * Default Private Constructor. + */ + private MetadataConstant() { + } + /** * Order of filter, interceptor, ... */ @@ -57,6 +63,11 @@ public final class MetadataConstant { */ public static final String CUSTOM_METADATA = "SCT-CUSTOM-METADATA"; + /** + * Custom Disposable Metadata. + */ + public static final String CUSTOM_DISPOSABLE_METADATA = "SCT-CUSTOM-DISPOSABLE-METADATA"; + /** * System Metadata. */ diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java index bd18111a9..caa9ceef4 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContext.java @@ -40,6 +40,17 @@ public class MetadataContext { * transitive context. */ public static final String FRAGMENT_TRANSITIVE = "transitive"; + + /** + * disposable Context. + */ + public static final String FRAGMENT_DISPOSABLE = "disposable"; + + /** + * upstream disposable Context. + */ + public static final String FRAGMENT_UPSTREAM_DISPOSABLE = "upstream-disposable"; + private static final Logger LOG = LoggerFactory.getLogger(MetadataContext.class); /** * Namespace of local instance. diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java index 3d3064ba0..28520517b 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/MetadataContextHolder.java @@ -20,12 +20,17 @@ package com.tencent.cloud.common.metadata; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import org.springframework.util.CollectionUtils; +import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_DISPOSABLE; +import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_TRANSITIVE; +import static com.tencent.cloud.common.metadata.MetadataContext.FRAGMENT_UPSTREAM_DISPOSABLE; + /** * Metadata Context Holder. * @@ -36,6 +41,7 @@ public final class MetadataContextHolder { private static final ThreadLocal METADATA_CONTEXT = new InheritableThreadLocal<>(); private static MetadataLocalProperties metadataLocalProperties; + private static StaticMetadataManager staticMetadataManager; private MetadataContextHolder() { @@ -51,24 +57,55 @@ public final class MetadataContextHolder { } if (metadataLocalProperties == null) { - metadataLocalProperties = (MetadataLocalProperties) ApplicationContextAwareUtils - .getApplicationContext().getBean("metadataLocalProperties"); + metadataLocalProperties = ApplicationContextAwareUtils.getApplicationContext().getBean(MetadataLocalProperties.class); } if (staticMetadataManager == null) { - staticMetadataManager = (StaticMetadataManager) ApplicationContextAwareUtils - .getApplicationContext().getBean("metadataManager"); + staticMetadataManager = ApplicationContextAwareUtils.getApplicationContext().getBean(StaticMetadataManager.class); } // init static transitive metadata MetadataContext metadataContext = new MetadataContext(); - metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE, - staticMetadataManager.getMergedStaticTransitiveMetadata()); + metadataContext.putFragmentContext(FRAGMENT_TRANSITIVE, staticMetadataManager.getMergedStaticTransitiveMetadata()); + metadataContext.putFragmentContext(FRAGMENT_DISPOSABLE, staticMetadataManager.getMergedStaticDisposableMetadata()); METADATA_CONTEXT.set(metadataContext); return METADATA_CONTEXT.get(); } + /** + * Get disposable metadata value from thread local . + * @param key metadata key . + * @param upstream upstream disposable , otherwise will return local static disposable metadata . + * @return target disposable metadata value . + */ + public static Optional getDisposableMetadata(String key, boolean upstream) { + MetadataContext context = get(); + if (upstream) { + return Optional.ofNullable(context.getContext(FRAGMENT_UPSTREAM_DISPOSABLE, key)); + } + else { + return Optional.ofNullable(context.getContext(FRAGMENT_DISPOSABLE, key)); + } + } + + /** + * Get all disposable metadata value from thread local . + * @param upstream upstream disposable , otherwise will return local static disposable metadata . + * @return target disposable metadata value . + */ + public static Map getAllDisposableMetadata(boolean upstream) { + Map disposables = new HashMap<>(); + MetadataContext context = get(); + if (upstream) { + disposables.putAll(context.getFragmentContext(FRAGMENT_UPSTREAM_DISPOSABLE)); + } + else { + disposables.putAll(context.getFragmentContext(FRAGMENT_DISPOSABLE)); + } + return Collections.unmodifiableMap(disposables); + } + /** * Set metadata context. * @param metadataContext metadata context @@ -80,21 +117,26 @@ public final class MetadataContextHolder { /** * Save metadata map to thread local. * @param dynamicTransitiveMetadata custom metadata collection + * @param dynamicDisposableMetadata custom disposable metadata connection */ - public static void init(Map dynamicTransitiveMetadata) { + public static void init(Map dynamicTransitiveMetadata, Map dynamicDisposableMetadata) { // Init ThreadLocal. MetadataContextHolder.remove(); MetadataContext metadataContext = MetadataContextHolder.get(); // Save transitive metadata to ThreadLocal. if (!CollectionUtils.isEmpty(dynamicTransitiveMetadata)) { - Map staticTransitiveMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + Map staticTransitiveMetadata = metadataContext.getFragmentContext(FRAGMENT_TRANSITIVE); Map mergedTransitiveMetadata = new HashMap<>(); mergedTransitiveMetadata.putAll(staticTransitiveMetadata); mergedTransitiveMetadata.putAll(dynamicTransitiveMetadata); + metadataContext.putFragmentContext(FRAGMENT_TRANSITIVE, Collections.unmodifiableMap(mergedTransitiveMetadata)); + + Map mergedDisposableMetadata = new HashMap<>(dynamicDisposableMetadata); + metadataContext.putFragmentContext(FRAGMENT_UPSTREAM_DISPOSABLE, Collections.unmodifiableMap(mergedDisposableMetadata)); - metadataContext.putFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE, - Collections.unmodifiableMap(mergedTransitiveMetadata)); + Map staticDisposableMetadata = metadataContext.getFragmentContext(FRAGMENT_DISPOSABLE); + metadataContext.putFragmentContext(FRAGMENT_DISPOSABLE, Collections.unmodifiableMap(staticDisposableMetadata)); } MetadataContextHolder.set(metadataContext); } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java index a717db436..554694fa3 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java @@ -54,18 +54,22 @@ public class StaticMetadataManager { private static final String ENV_METADATA_PREFIX = "SCT_METADATA_CONTENT_"; private static final int ENV_METADATA_PREFIX_LENGTH = ENV_METADATA_PREFIX.length(); private static final String ENV_METADATA_CONTENT_TRANSITIVE = "SCT_METADATA_CONTENT_TRANSITIVE"; + private static final String ENV_METADATA_CONTENT_DISPOSABLE = "SCT_METADATA_CONTENT_DISPOSABLE"; private static final String ENV_METADATA_ZONE = "SCT_METADATA_ZONE"; private static final String ENV_METADATA_REGION = "SCT_METADATA_REGION"; private static final String ENV_METADATA_CAMPUS = "SCT_METADATA_CAMPUS"; private Map envMetadata; private Map envTransitiveMetadata; + private Map envDisposableMetadata; private Map configMetadata; private Map configTransitiveMetadata; + private Map configDisposableMetadata; private Map customSPIMetadata; private Map customSPITransitiveMetadata; - + private Map customSPIDisposableMetadata; private Map mergedStaticMetadata; private Map mergedStaticTransitiveMetadata; + private Map mergedStaticDisposableMetadata; private String zone; private String region; private String campus; @@ -85,6 +89,7 @@ public class StaticMetadataManager { LOGGER.info("[SCT] Loaded static metadata info. {}", this); } + @SuppressWarnings("DuplicatedCode") private void parseEnvMetadata() { Map allEnvs = System.getenv(); @@ -118,27 +123,54 @@ public class StaticMetadataManager { } } envTransitiveMetadata = Collections.unmodifiableMap(envTransitiveMetadata); + + envDisposableMetadata = new HashMap<>(); + // parse disposable metadata + String disposableKeys = allEnvs.get(ENV_METADATA_CONTENT_DISPOSABLE); + if (StringUtils.isNotBlank(disposableKeys)) { + String[] keyArr = StringUtils.split(disposableKeys, ","); + if (keyArr != null && keyArr.length > 0) { + for (String key : keyArr) { + String value = envMetadata.get(key); + if (StringUtils.isNotBlank(value)) { + envDisposableMetadata.put(key, value); + } + } + } + } + envDisposableMetadata = Collections.unmodifiableMap(envDisposableMetadata); } private void parseConfigMetadata(MetadataLocalProperties metadataLocalProperties) { Map allMetadata = metadataLocalProperties.getContent(); List transitiveKeys = metadataLocalProperties.getTransitive(); + List disposableKeys = metadataLocalProperties.getDisposable(); - Map result = new HashMap<>(); + Map transitiveResult = new HashMap<>(); for (String key : transitiveKeys) { if (allMetadata.containsKey(key)) { - result.put(key, allMetadata.get(key)); + transitiveResult.put(key, allMetadata.get(key)); } } - configTransitiveMetadata = Collections.unmodifiableMap(result); + Map disposableResult = new HashMap<>(); + for (String key : disposableKeys) { + if (allMetadata.containsKey(key)) { + disposableResult.put(key, allMetadata.get(key)); + } + } + + configTransitiveMetadata = Collections.unmodifiableMap(transitiveResult); + configDisposableMetadata = Collections.unmodifiableMap(disposableResult); configMetadata = Collections.unmodifiableMap(allMetadata); } + @SuppressWarnings("DuplicatedCode") private void parseCustomMetadata(InstanceMetadataProvider instanceMetadataProvider) { if (instanceMetadataProvider == null) { customSPIMetadata = Collections.emptyMap(); customSPITransitiveMetadata = Collections.emptyMap(); + customSPIDisposableMetadata = Collections.emptyMap(); return; } @@ -162,6 +194,17 @@ public class StaticMetadataManager { } } customSPITransitiveMetadata = Collections.unmodifiableMap(transitiveMetadata); + + Set disposableKeys = instanceMetadataProvider.getDisposableMetadataKeys(); + Map disposableMetadata = new HashMap<>(); + if (!CollectionUtils.isEmpty(disposableKeys)) { + for (String key : disposableKeys) { + if (customSPIMetadata.containsKey(key)) { + disposableMetadata.put(key, customSPIMetadata.get(key)); + } + } + } + customSPIDisposableMetadata = Collections.unmodifiableMap(disposableMetadata); } private void merge() { @@ -173,15 +216,19 @@ public class StaticMetadataManager { mergedMetadataResult.putAll(customSPIMetadata); // set location info as metadata mergedMetadataResult.putAll(getLocationMetadata()); - this.mergedStaticMetadata = Collections.unmodifiableMap(mergedMetadataResult); Map mergedTransitiveMetadataResult = new HashMap<>(); mergedTransitiveMetadataResult.putAll(configTransitiveMetadata); mergedTransitiveMetadataResult.putAll(envTransitiveMetadata); mergedTransitiveMetadataResult.putAll(customSPITransitiveMetadata); - this.mergedStaticTransitiveMetadata = Collections.unmodifiableMap(mergedTransitiveMetadataResult); + + Map mergedDisposableMetadataResult = new HashMap<>(); + mergedDisposableMetadataResult.putAll(configDisposableMetadata); + mergedDisposableMetadataResult.putAll(envDisposableMetadata); + mergedDisposableMetadataResult.putAll(customSPIDisposableMetadata); + this.mergedStaticDisposableMetadata = Collections.unmodifiableMap(mergedDisposableMetadataResult); } private void parseLocationMetadata(MetadataLocalProperties metadataLocalProperties, @@ -228,6 +275,10 @@ public class StaticMetadataManager { return envTransitiveMetadata; } + public Map getEnvDisposableMetadata() { + return envDisposableMetadata; + } + public Map getAllConfigMetadata() { return configMetadata; } @@ -236,6 +287,10 @@ public class StaticMetadataManager { return configTransitiveMetadata; } + public Map getConfigDisposableMetadata() { + return configDisposableMetadata; + } + public Map getAllCustomMetadata() { return customSPIMetadata; } @@ -244,6 +299,10 @@ public class StaticMetadataManager { return customSPITransitiveMetadata; } + public Map getCustomSPIDisposableMetadata() { + return customSPIDisposableMetadata; + } + public Map getMergedStaticMetadata() { return mergedStaticMetadata; } @@ -252,6 +311,10 @@ public class StaticMetadataManager { return mergedStaticTransitiveMetadata; } + public Map getMergedStaticDisposableMetadata() { + return mergedStaticDisposableMetadata; + } + public String getZone() { return zone; } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataLocalProperties.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataLocalProperties.java index 0d0039bc3..2964e0178 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataLocalProperties.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/config/MetadataLocalProperties.java @@ -43,6 +43,11 @@ public class MetadataLocalProperties { */ private List transitive; + /** + * A disposable metadata key list . + */ + private List disposable; + public Map getContent() { if (CollectionUtils.isEmpty(content)) { content = new HashMap<>(); @@ -64,4 +69,15 @@ public class MetadataLocalProperties { public void setTransitive(List transitive) { this.transitive = transitive; } + + public List getDisposable() { + if (CollectionUtils.isEmpty(disposable)) { + disposable = new ArrayList<>(); + } + return disposable; + } + + public void setDisposable(List disposable) { + this.disposable = disposable; + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/endpoint/PolarisMetadataEndpoint.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/endpoint/PolarisMetadataEndpoint.java index 360018ea2..ea7954c37 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/endpoint/PolarisMetadataEndpoint.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/endpoint/PolarisMetadataEndpoint.java @@ -45,9 +45,14 @@ public class PolarisMetadataEndpoint { result.put("Env", staticMetadataManager.getAllEnvMetadata()); result.put("EnvTransitive", staticMetadataManager.getEnvTransitiveMetadata()); result.put("ConfigTransitive", staticMetadataManager.getConfigTransitiveMetadata()); + result.put("ConfigDisposable", staticMetadataManager.getConfigDisposableMetadata()); result.put("Config", staticMetadataManager.getAllConfigMetadata()); result.put("MergeStatic", staticMetadataManager.getMergedStaticMetadata()); - result.put("CustomSPI", staticMetadataManager.getCustomSPITransitiveMetadata()); + result.put("MergeStaticTransitive", staticMetadataManager.getMergedStaticTransitiveMetadata()); + result.put("MergeStaticDisposable", staticMetadataManager.getMergedStaticDisposableMetadata()); + result.put("CustomSPI", staticMetadataManager.getAllCustomMetadata()); + result.put("CustomSPITransitive", staticMetadataManager.getCustomSPITransitiveMetadata()); + result.put("CustomSPIDisposable", staticMetadataManager.getCustomSPIDisposableMetadata()); result.put("zone", staticMetadataManager.getZone()); result.put("region", staticMetadataManager.getRegion()); result.put("campus", staticMetadataManager.getCampus()); diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/spi/InstanceMetadataProvider.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/spi/InstanceMetadataProvider.java index 5434aa140..44cfaf605 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/spi/InstanceMetadataProvider.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/spi/InstanceMetadataProvider.java @@ -43,6 +43,13 @@ public interface InstanceMetadataProvider { return Collections.emptySet(); } + /** + * @return the keys of disposable metadata. + */ + default Set getDisposableMetadataKeys() { + return Collections.emptySet(); + } + /** * The region of current instance. * diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java index ac7288f61..521866c34 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java @@ -22,6 +22,7 @@ import java.util.Map; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,7 +43,6 @@ public final class JacksonUtils { private static final Logger LOG = LoggerFactory.getLogger(JacksonUtils.class); private JacksonUtils() { - } /** @@ -52,8 +52,25 @@ public final class JacksonUtils { * @return Json String */ public static String serialize2Json(T object) { + return serialize2Json(object, false); + } + + /** + * Object to Json. + * @param object object to be serialized + * @param pretty pretty print + * @param type of object + * @return Json String + */ + public static String serialize2Json(T object, boolean pretty) { try { - return OM.writeValueAsString(object); + if (pretty) { + ObjectWriter objectWriter = OM.writerWithDefaultPrettyPrinter(); + return objectWriter.writeValueAsString(object); + } + else { + return OM.writeValueAsString(object); + } } catch (JsonProcessingException e) { LOG.error("Object to Json failed. {}", object, e); diff --git a/spring-cloud-tencent-commons/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-tencent-commons/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 390f49158..575ca9738 100644 --- a/spring-cloud-tencent-commons/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-tencent-commons/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -9,6 +9,11 @@ "name": "spring.cloud.tencent.metadata.transitive", "type": "java.util.List", "description": "Custom transitive metadata key list." + }, + { + "name": "spring.cloud.tencent.metadata.disposable", + "type": "java.util.List", + "description": "Custom disposable metadata key list." } ] } diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java index 811b3c2d5..c6b7cbcd2 100644 --- a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java +++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/metadata/MetadataContextHolderTest.java @@ -58,7 +58,7 @@ public class MetadataContextHolderTest { customMetadata.put("a", "1"); customMetadata.put("b", "22"); customMetadata.put("c", "3"); - MetadataContextHolder.init(customMetadata); + MetadataContextHolder.init(customMetadata, new HashMap<>()); metadataContext = MetadataContextHolder.get(); customMetadata = metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); Assertions.assertThat(customMetadata.get("a")).isEqualTo("1"); diff --git a/spring-cloud-tencent-coverage/pom.xml b/spring-cloud-tencent-coverage/pom.xml index 37903c143..277425753 100644 --- a/spring-cloud-tencent-coverage/pom.xml +++ b/spring-cloud-tencent-coverage/pom.xml @@ -1,63 +1,68 @@ - - spring-cloud-tencent - com.tencent.cloud - ${revision} - ../pom.xml - - 4.0.0 + xmlns="http://maven.apache.org/POM/4.0.0" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + spring-cloud-tencent + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 - spring-cloud-tencent-coverage - Spring Cloud Tencent Coverage - pom + spring-cloud-tencent-coverage + Spring Cloud Tencent Coverage + pom - - true - + + true + - - - com.tencent.cloud - spring-cloud-tencent-commons - + + + com.tencent.cloud + spring-cloud-tencent-commons + com.tencent.cloud spring-cloud-tencent-polaris-context + + com.tencent.cloud + spring-cloud-tencent-rpc-enhancement + + com.tencent.cloud spring-cloud-tencent-polaris-loadbalancer - - com.tencent.cloud - spring-cloud-starter-tencent-polaris-discovery - + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-discovery + - - com.tencent.cloud - spring-cloud-starter-tencent-polaris-ratelimit - + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-ratelimit + - - com.tencent.cloud - spring-cloud-starter-tencent-polaris-circuitbreaker - + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-circuitbreaker + - - com.tencent.cloud - spring-cloud-starter-tencent-metadata-transfer - + + com.tencent.cloud + spring-cloud-starter-tencent-metadata-transfer + - - com.tencent.cloud - spring-cloud-starter-tencent-polaris-router - + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-router + com.tencent.cloud @@ -65,24 +70,24 @@ - - - - org.jacoco - jacoco-maven-plugin - - - report-aggregate - test - - report-aggregate - - - ${basedir}/../target/site/jacoco - - - - - - + + + + org.jacoco + jacoco-maven-plugin + + + report-aggregate + test + + report-aggregate + + + ${basedir}/../target/site/jacoco + + + + + + diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 05a8ae915..f389d2b61 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -73,7 +73,7 @@ 1.7.0-2020.0.5-SNAPSHOT - 1.7.0 + 1.7.2 1.2.11 4.5.1 1.12.10 @@ -110,6 +110,12 @@ ${revision} + + com.tencent.cloud + spring-cloud-tencent-rpc-enhancement + ${revision} + + com.tencent.cloud spring-cloud-tencent-polaris-loadbalancer diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/README-zh.md b/spring-cloud-tencent-examples/metadata-transfer-example/README-zh.md index 9af9aff6d..764a80c38 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/README-zh.md +++ b/spring-cloud-tencent-examples/metadata-transfer-example/README-zh.md @@ -4,7 +4,7 @@ 本样例将介绍如何在Spring Cloud项目中使用```spring-cloud-starter-tencent-metadata-transfer```以使用其各项功能。 -本样例包括```metadata-callee-service```、```metadata-caller-service```。 +本样例包括```metadata-frontend```、```metadata-middle```、```metadata-backend```。 ## 使用说明 @@ -41,8 +41,9 @@ spring: ##### IDEA启动 分别启动 -- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service```的```MetadataCalleeService``` -- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service```的```MetadataCallerService``` +- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend```的```MetadataFrontendService``` +- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle```的```MetadataMiddleService``` +- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend```的```MetadataBackendService``` ##### Maven打包启动 @@ -53,7 +54,7 @@ spring: mvn clean package ``` -然后在```metadata-callee-service```、```metadata-caller-service```下找到生成的jar包,运行 +然后在```metadata-frontend```、```metadata-middle```、```metadata-backend```下找到生成的jar包,运行 ``` java -jar ${app.jar} @@ -63,7 +64,7 @@ java -jar ${app.jar} ### 元数据配置 -在```spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service```项目的```bootstrap.yml```配置文件中 +- 在```spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend```项目的```bootstrap.yml```配置文件中 ```yaml spring: @@ -76,10 +77,37 @@ spring: CUSTOM-METADATA-KEY-LOCAL: CUSTOM-VALUE-LOCAL # 示例:可传递元数据 CUSTOM-METADATA-KEY-TRANSITIVE: CUSTOM-VALUE-TRANSITIVE + # 示例:一次性元数据 + CUSTOM-METADATA-KEY-DISPOSABLE: CUSTOM-VALUE-DISPOSABLE-FRONTEND # 指定哪个元数据的键值将沿着链接传递 transitive: - CUSTOM-METADATA-KEY-TRANSITIVE + # 指定哪个元数据的键值只进行一次性传递(一跳) + disposable: + - CUSTOM-METADATA-KEY-DISPOSABLE +``` + +- 在```spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend```项目的```bootstrap.yml```配置文件中 +```yaml +spring: + cloud: + tencent: + metadata: + # 定义元数据的键值对 + content: + # 示例:本地元数据,默认不在链路中传递 + CUSTOM-METADATA-KEY-LOCAL-2: CUSTOM-VALUE-LOCAL-2 + # 示例:可传递元数据 + CUSTOM-METADATA-KEY-TRANSITIVE-2: CUSTOM-VALUE-TRANSITIVE-2 + # 示例:一次性元数据 + CUSTOM-METADATA-KEY-DISPOSABLE: CUSTOM-VALUE-DISPOSABLE-MIDDLE + # 指定哪个元数据的键值将沿着链接传递 + transitive: + - CUSTOM-METADATA-KEY-TRANSITIVE-2 + # 指定哪个元数据的键值只进行一次性传递(一跳) + disposable: + - CUSTOM-METADATA-KEY-DISPOSABLE ``` ### 验证 @@ -87,31 +115,85 @@ spring: #### 请求调用 ```shell -curl -L -X GET 'http://127.0.0.1:48080/metadata/service/caller/feign/info' +curl -L -X GET 'http://127.0.0.1:48080/metadata/service/frontend/feign/info' ``` 预期返回值 -``` +```json { - "caller-metadata-contents": { + "frontend-transitive-metadata": { + "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE" + }, + "frontend-upstream-disposable-metadata": { + }, + "frontend-local-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-FRONTEND" + }, + + "middle-transitive-metadata": { "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE", - "CUSTOM-METADATA-KEY-LOCAL": "CUSTOM-VALUE-LOCAL" + "CUSTOM-METADATA-KEY-TRANSITIVE-2": "CUSTOM-VALUE-TRANSITIVE-2" }, - "callee-transitive-metadata": { - "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE" + "middle-upstream-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-FRONTEND" }, - "caller-transitive-metadata": { - "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE" + "middle-local-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-MIDDLE" + }, + + "backend-transitive-metadata": { + "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE", + "CUSTOM-METADATA-KEY-TRANSITIVE-2": "CUSTOM-VALUE-TRANSITIVE-2" + }, + "backend-upstream-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-MIDDLE" + }, + "backend-local-disposable-metadata": { } } ``` 返回值解析 -- Key `caller-metadata-contents` 表示 `metadata-caller-service` 项目中默认配置的所有的元数据。 -- Key `caller-transitive-metadata` 表示 `metadata-caller-service` 项目中指定的可以在链路中传递的元数据列表。 -- Key `callee-transitive-metadata` 表示 `metadata-callee-service` 项目被 `metadata-caller-service` 调用时传递过来的上游的元数据列表。 +> `*`(星号),代表示例中的`frontend`、`middle`、`backend`。 + +- Key `*-transitive-metadata` 表示服务中默认配置的所有的可传递(全链路)的元数据。 +- Key `*-upstream-disposable-metadata` 表示服务中从上游请求中获取到的一次性传递的元数据。 +- Key `*-local-disposable-metadata` 表示当前服务配置的往下游传递的一次性的元数据。 + +### 如何通过Api获取传递的元数据 + +- 获取全局传递的元数据 + +```java +MetadataContext context = MetadataContextHolder.get(); + Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + +customMetadataMap.forEach((key, value) -> { + // ... +}); + +``` + +- 获取上游传递过来的一次性元数据 + +```java +Map upstreamDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(true); +upstreamDisposableMetadatas.forEach((key, value) -> { + // ... +}); +``` + +- 获取本地配置的一次性元数据 + +```java +Map localDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(false); +localDisposableMetadatas.forEach((key, value) -> { + // ... +}); +``` + ### Wiki参考 diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/README.md b/spring-cloud-tencent-examples/metadata-transfer-example/README.md index b0d912ce9..9fc663666 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/README.md +++ b/spring-cloud-tencent-examples/metadata-transfer-example/README.md @@ -2,9 +2,10 @@ ## Example Introduction -This example shows how to use ```spring-cloud-starter-tencent-metadata-transfer``` in Spring Cloud project for its features. +This example shows how to use ```spring-cloud-starter-tencent-metadata-transfer``` in Spring Cloud project for its +features. -This example contains ```metadata-callee-service```、```metadata-caller-service```. +This example contains ```metadata-frontend```、```metadata-middle```、```metadata-backend```. ## Instruction @@ -40,8 +41,10 @@ Reference to [Polaris Getting Started](https://github.com/PolarisMesh/polaris#ge - IDEA Launching -- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service```‘s```MetadataCalleeService``` -- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service```'s```MetadataCallerService``` +- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend```'s ```MetadataFrontendService``` +- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle```'s ```MetadataMiddleService``` +- ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend```'s ```MetadataBackendService``` + - Maven Package Launching @@ -51,7 +54,7 @@ Execute under ```spring-cloud-tencent-examples/metadata-transfer-example``` mvn clean package ``` -Then find the jars under ```metadata-callee-service```、```metadata-caller-service```, and run it: +Then find the jars under ```metadata-frontend```、```metadata-middle```、```metadata-backend```, and run it: ``` java -jar ${app.jar} @@ -62,7 +65,7 @@ Launch application, change ${app.jar} to jar's package name. ### Metadata Configuration -In the ```bootstrap.yml``` configuration file of the ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service``` project +- In the ```bootstrap.yml``` configuration file of the ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend``` project ```yaml spring: @@ -75,9 +78,38 @@ spring: CUSTOM-METADATA-KEY-LOCAL: CUSTOM-VALUE-LOCAL # Example: transitive CUSTOM-METADATA-KEY-TRANSITIVE: CUSTOM-VALUE-TRANSITIVE + # Example: disposable + CUSTOM-METADATA-KEY-DISPOSABLE: CUSTOM-VALUE-DISPOSABLE-FRONTEND # Assigned which metadata key-value will be passed along the link transitive: - CUSTOM-METADATA-KEY-TRANSITIVE + # Specify which metadata key value will be passed only once (one-step) + disposable: + - CUSTOM-METADATA-KEY-DISPOSABLE + +``` + +- In the ```bootstrap.yml``` configuration file of the ```spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle``` project + +```yaml +spring: + cloud: + tencent: + metadata: + # Defined your metadata keys & values + content: + # Example: intransitive + CUSTOM-METADATA-KEY-LOCAL-2: CUSTOM-VALUE-LOCAL-2 + # Example: transitive + CUSTOM-METADATA-KEY-TRANSITIVE-2: CUSTOM-VALUE-TRANSITIVE-2 + # Example: disposable + CUSTOM-METADATA-KEY-DISPOSABLE: CUSTOM-VALUE-DISPOSABLE-MIDDLE + # Assigned which metadata key-value will be passed along the link + transitive: + - CUSTOM-METADATA-KEY-TRANSITIVE-2 + # Specify which metadata key value will be passed only once (one-step) + disposable: + - CUSTOM-METADATA-KEY-DISPOSABLE ``` @@ -93,24 +125,77 @@ Expected return rate ``` { - "caller-metadata-contents": { + "frontend-transitive-metadata": { + "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE" + }, + "frontend-upstream-disposable-metadata": { + }, + "frontend-local-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-FRONTEND" + }, + + "middle-transitive-metadata": { "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE", - "CUSTOM-METADATA-KEY-LOCAL": "CUSTOM-VALUE-LOCAL" + "CUSTOM-METADATA-KEY-TRANSITIVE-2": "CUSTOM-VALUE-TRANSITIVE-2" }, - "callee-transitive-metadata": { - "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE" + "middle-upstream-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-FRONTEND" }, - "caller-transitive-metadata": { - "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE" + "middle-local-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-MIDDLE" + }, + + "backend-transitive-metadata": { + "CUSTOM-METADATA-KEY-TRANSITIVE": "CUSTOM-VALUE-TRANSITIVE", + "CUSTOM-METADATA-KEY-TRANSITIVE-2": "CUSTOM-VALUE-TRANSITIVE-2" + }, + "backend-upstream-disposable-metadata": { + "CUSTOM-METADATA-KEY-DISPOSABLE": "CUSTOM-VALUE-DISPOSABLE-MIDDLE" + }, + "backend-local-disposable-metadata": { } } ``` Response value description -- Key `caller-metadata-contents` represents all metadata configured by default in the `metadata-caller-service` project. -- Key `caller-transitive-metadata` represents the list of metadata that can be passed in the link specified in the `metadata-caller-service` item. -- Key `callee-transitive-metadata` represents the list of upstream metadata passed when the `metadata-callee-service` project is called by `metadata-caller-service`. +> `*` (asterisk), representing `frontend`, `middle`, `backend` in the example. + +- Key `*-transitive-metadata` represents all the passable (fully linked) metadata configured by default in the service. +- Key `*-upstream-disposable-metadata` indicates the one-time transmissible metadata obtained from upstream requests in the service. +- Key `*-local-disposable-metadata` indicates the one-time metadata passed downstream as configured by the current service. + +### How to get the passed metadata via Api + +- Get the metadata passed globally + +```java +MetadataContext context = MetadataContextHolder.get(); + Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + +customMetadataMap.forEach((key, value) -> { + // ... +}); +``` + +- Get disposable(one-time) metadata passed from upstream + +```java +Map upstreamDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(true); +upstreamDisposableMetadatas.forEach((key, value) -> { + // ... +}); +``` + +- Get disposable(one-time) metadata for local configuration + +```java +Map localDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(false); +localDisposableMetadatas.forEach((key, value) -> { + // ... +}); +``` + ### Wiki Reference diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/pom.xml b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/pom.xml similarity index 93% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/pom.xml rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/pom.xml index 1c1306805..106c2ed78 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/pom.xml +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/pom.xml @@ -10,8 +10,8 @@ 4.0.0 - metadata-caller-service - Spring Cloud Tencent Metadata Transfer Caller Service + metadata-backend + Spring Cloud Tencent Metadata Transfer Backend Service diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/java/com/tencent/cloud/metadata/service/callee/MetadataCalleeController.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendController.java similarity index 57% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/java/com/tencent/cloud/metadata/service/callee/MetadataCalleeController.java rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendController.java index 4966e9bdc..7da621e81 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/java/com/tencent/cloud/metadata/service/callee/MetadataCalleeController.java +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendController.java @@ -15,8 +15,9 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.metadata.service.callee; +package com.tencent.cloud.metadata.service.backend; +import java.util.HashMap; import java.util.Map; import com.tencent.cloud.common.metadata.MetadataContext; @@ -35,10 +36,10 @@ import org.springframework.web.bind.annotation.RestController; * @author Palmer Xu */ @RestController -@RequestMapping("/metadata/service/callee") -public class MetadataCalleeController { +@RequestMapping("/metadata/service/backend") +public class MetadataBackendController { - private static final Logger LOG = LoggerFactory.getLogger(MetadataCalleeController.class); + private static final Logger LOG = LoggerFactory.getLogger(MetadataBackendController.class); @Value("${server.port:0}") private int port; @@ -48,18 +49,36 @@ public class MetadataCalleeController { * @return information of callee */ @GetMapping("/info") - public Map info() { - LOG.info("Metadata Service Callee [{}] is called.", port); + public Map> info() { + LOG.info("Metadata Backend Service [{}] is called.", port); + Map> ret = new HashMap<>(); // Get Custom Metadata From Context MetadataContext context = MetadataContextHolder.get(); Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); customMetadataMap.forEach((key, value) -> { - LOG.info("Custom Metadata (Key-Value): {} : {}", key, value); + LOG.info("Metadata Backend Custom Metadata (Key-Value): {} : {}", key, value); }); - return customMetadataMap; - } + ret.put("backend-transitive-metadata", customMetadataMap); + + // Get All Disposable metadata from upstream service + Map upstreamDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(true); + upstreamDisposableMetadatas.forEach((key, value) -> { + LOG.info("Upstream Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("backend-upstream-disposable-metadata", upstreamDisposableMetadatas); + // Get All Disposable metadata from upstream service + Map localDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(false); + localDisposableMetadatas.forEach((key, value) -> { + LOG.info("Local Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("backend-local-disposable-metadata", localDisposableMetadatas); + + return ret; + } } diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/java/com/tencent/cloud/metadata/service/callee/MetadataCalleeService.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendService.java similarity index 86% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/java/com/tencent/cloud/metadata/service/callee/MetadataCalleeService.java rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendService.java index 06771a5e8..964cb8274 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/java/com/tencent/cloud/metadata/service/callee/MetadataCalleeService.java +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/java/com/tencent/cloud/metadata/service/backend/MetadataBackendService.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.metadata.service.callee; +package com.tencent.cloud.metadata.service.backend; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -26,10 +26,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; * @author Palmer Xu */ @SpringBootApplication -public class MetadataCalleeService { +public class MetadataBackendService { public static void main(String[] args) { - SpringApplication.run(MetadataCalleeService.class, args); + SpringApplication.run(MetadataBackendService.class, args); } - } diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/resources/bootstrap.yml similarity index 58% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/resources/bootstrap.yml rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/resources/bootstrap.yml index 85c842c7c..4188f3cc3 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-backend/src/main/resources/bootstrap.yml @@ -1,8 +1,8 @@ server: - port: 48084 + port: 48088 spring: application: - name: MetadataCalleeService + name: MetadataBackendService cloud: polaris: address: grpc://183.47.111.80:8091 @@ -11,3 +11,10 @@ spring: discovery: enabled: true register: true + +management: + endpoints: + web: + exposure: + include: + - polaris-metadata \ No newline at end of file diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCallerController.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCallerController.java deleted file mode 100644 index cf9ec84eb..000000000 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCallerController.java +++ /dev/null @@ -1,109 +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.metadata.service.caller; - -import java.util.Map; - -import com.google.common.collect.Maps; -import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.cloud.common.metadata.MetadataContextHolder; -import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.RestTemplate; - -/** - * Metadata caller controller. - * - * @author Palmer Xu - */ -@RestController -@RequestMapping("/metadata/service/caller") -public class MetadataCallerController { - - private final RestTemplate restTemplate; - - private final MetadataCalleeService metadataCalleeService; - - private final MetadataLocalProperties metadataLocalProperties; - - public MetadataCallerController(RestTemplate restTemplate, - MetadataCalleeService metadataCalleeService, - MetadataLocalProperties metadataLocalProperties) { - this.restTemplate = restTemplate; - this.metadataCalleeService = metadataCalleeService; - this.metadataLocalProperties = metadataLocalProperties; - } - - /** - * Get metadata info from remote service. - * @return metadata map - */ - @GetMapping("/feign/info") - public Map> feign() { - Map> ret = Maps.newHashMap(); - - // Call remote service with feign client - Map calleeMetadata = metadataCalleeService.info(); - ret.put("callee-transitive-metadata", calleeMetadata); - - // Get Custom Metadata From Context - MetadataContext context = MetadataContextHolder.get(); - Map callerTransitiveMetadata = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); - ret.put("caller-transitive-metadata", callerTransitiveMetadata); - ret.put("caller-metadata-contents", metadataLocalProperties.getContent()); - - return ret; - } - - /** - * Get metadata information of callee. - * @return information of callee - */ - @SuppressWarnings("unchecked") - @GetMapping("/rest/info") - public Map> rest() { - Map> ret = Maps.newHashMap(); - - // Call remote service with RestTemplate - Map calleeMetadata = restTemplate.getForObject( - "http://MetadataCalleeService/metadata/service/callee/info", - Map.class); - ret.put("callee-transitive-metadata", calleeMetadata); - - // Get Custom Metadata From Context - MetadataContext context = MetadataContextHolder.get(); - Map callerTransitiveMetadata = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); - ret.put("caller-transitive-metadata", callerTransitiveMetadata); - ret.put("caller-metadata-contents", metadataLocalProperties.getContent()); - - return ret; - } - - /** - * health check. - * @return health check info - */ - @GetMapping("/healthCheck") - public String healthCheck() { - return "pk ok"; - } - -} diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/pom.xml b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/pom.xml new file mode 100644 index 000000000..4b6adb14e --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/pom.xml @@ -0,0 +1,51 @@ + + + + metadata-transfer-example + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 + + metadata-frontend + Spring Cloud Tencent Metadata Transfer Frontent Service + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-discovery + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendController.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendController.java new file mode 100644 index 000000000..3d107f555 --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendController.java @@ -0,0 +1,155 @@ +/* + * 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.metadata.service.frontend; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +/** + * Metadata caller controller. + * + * @author Palmer Xu + */ +@RestController +@RequestMapping("/metadata/service/frontend") +public class MetadataFrontendController { + + private static final Logger LOG = LoggerFactory.getLogger(MetadataFrontendController.class); + + private final RestTemplate restTemplate; + + private final MetadataMiddleService metadataMiddleService; + + public MetadataFrontendController(RestTemplate restTemplate, + MetadataMiddleService metadataMiddleService) { + this.restTemplate = restTemplate; + this.metadataMiddleService = metadataMiddleService; + } + + /** + * Get metadata info from remote service. + * + * @return metadata map + */ + @GetMapping("/feign/info") + public Map> feign() { + Map> ret = new HashMap<>(); + + // Call remote service with feign client + Map> middleResult = metadataMiddleService.info(); + + if (middleResult != null) { + ret.putAll(middleResult); + } + + // Get Custom Metadata From Context + MetadataContext context = MetadataContextHolder.get(); + Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + + customMetadataMap.forEach((key, value) -> { + LOG.info("Metadata Middle Custom Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("frontend-transitive-metadata", customMetadataMap); + + // Get All Disposable metadata from upstream service + Map upstreamDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(true); + upstreamDisposableMetadatas.forEach((key, value) -> { + LOG.info("Upstream Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("frontend-upstream-disposable-metadata", upstreamDisposableMetadatas); + + // Get All Disposable metadata from upstream service + Map localDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(false); + localDisposableMetadatas.forEach((key, value) -> { + LOG.info("Local Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("frontend-local-disposable-metadata", localDisposableMetadatas); + + return ret; + } + + /** + * Get metadata information of callee. + * + * @return information of callee + */ + @SuppressWarnings("unchecked") + @GetMapping("/rest/info") + public Map> rest() { + Map> ret = new HashMap<>(); + + // Call remote service with RestTemplate + Map> middleResult = restTemplate.getForObject( + "http://MetadataMiddleService/metadata/service/middle/info", Map.class); + + if (middleResult != null) { + ret.putAll(middleResult); + } + + // Get Custom Metadata From Context + MetadataContext context = MetadataContextHolder.get(); + Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + + customMetadataMap.forEach((key, value) -> { + LOG.info("Metadata Middle Custom Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("frontend-transitive-metadata", customMetadataMap); + + // Get All Disposable metadata from upstream service + Map upstreamDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(true); + upstreamDisposableMetadatas.forEach((key, value) -> { + LOG.info("Upstream Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("frontend-upstream-disposable-metadata", upstreamDisposableMetadatas); + + // Get All Disposable metadata from upstream service + Map localDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(false); + localDisposableMetadatas.forEach((key, value) -> { + LOG.info("Local Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("frontend-local-disposable-metadata", localDisposableMetadatas); + + return ret; + } + + /** + * health check. + * + * @return health check info + */ + @GetMapping("/healthCheck") + public String healthCheck() { + return "pk ok"; + } +} diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCallerService.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendService.java similarity index 84% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCallerService.java rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendService.java index a586c7e72..cdea235d3 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCallerService.java +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataFrontendService.java @@ -15,11 +15,10 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.metadata.service.caller; +package com.tencent.cloud.metadata.service.frontend; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; @@ -31,12 +30,11 @@ import org.springframework.web.client.RestTemplate; * @author Palmer Xu */ @SpringBootApplication -@EnableDiscoveryClient @EnableFeignClients -public class MetadataCallerService { +public class MetadataFrontendService { public static void main(String[] args) { - SpringApplication.run(MetadataCallerService.class, args); + SpringApplication.run(MetadataFrontendService.class, args); } @Bean @@ -44,5 +42,4 @@ public class MetadataCallerService { public RestTemplate restTemplate() { return new RestTemplate(); } - } diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCalleeService.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataMiddleService.java similarity index 78% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCalleeService.java rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataMiddleService.java index 65bea6707..ea0bde432 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCalleeService.java +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataMiddleService.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.metadata.service.caller; +package com.tencent.cloud.metadata.service.frontend; import java.util.Map; @@ -27,15 +27,14 @@ import org.springframework.web.bind.annotation.GetMapping; * * @author Palmer Xu */ -@FeignClient(value = "MetadataCalleeService", - fallback = MetadataCalleeServiceFallback.class) -public interface MetadataCalleeService { +@FeignClient(value = "MetadataMiddleService", + fallback = MetadataMiddleServiceFallback.class) +public interface MetadataMiddleService { /** * Get information of callee. * @return information of callee */ - @GetMapping("/metadata/service/callee/info") - Map info(); - + @GetMapping("/metadata/service/middle/info") + Map> info(); } diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCalleeServiceFallback.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataMiddleServiceFallback.java similarity index 84% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCalleeServiceFallback.java rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataMiddleServiceFallback.java index ba508831a..727f65c63 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/java/com/tencent/cloud/metadata/service/caller/MetadataCalleeServiceFallback.java +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/java/com/tencent/cloud/metadata/service/frontend/MetadataMiddleServiceFallback.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.metadata.service.caller; +package com.tencent.cloud.metadata.service.frontend; import java.util.Map; @@ -29,11 +29,10 @@ import org.springframework.stereotype.Component; * @author Palmer Xu */ @Component -public class MetadataCalleeServiceFallback implements MetadataCalleeService { +public class MetadataMiddleServiceFallback implements MetadataMiddleService { @Override - public Map info() { + public Map> info() { return Maps.newHashMap(); } - } diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/resources/bootstrap.yml similarity index 71% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/resources/bootstrap.yml rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/resources/bootstrap.yml index a390f51a6..719424131 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-caller-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-frontend/src/main/resources/bootstrap.yml @@ -2,7 +2,7 @@ server: port: 48080 spring: application: - name: MetadataCallerService + name: MetadataFrontendService cloud: polaris: address: grpc://183.47.111.80:8091 @@ -12,18 +12,22 @@ spring: enabled: true register: true heartbeat-enabled: true - health-check-url: /metadata/service/caller/healthCheck + health-check-url: /metadata/service/frontend/healthCheck tencent: metadata: # Defined your metadata keys & values content: # Example: intransitive CUSTOM-METADATA-KEY-LOCAL: CUSTOM-VALUE-LOCAL + # Example: disposable + CUSTOM-METADATA-KEY-DISPOSABLE: CUSTOM-VALUE-DISPOSABLE # Example: transitive - CUSTOM-METADATA-KEY-TRANSITIVE: CUSTOM-VALUE-TRANSITIVE + CUSTOM-METADATA-KEY-TRANSITIVE: CUSTOM-VALUE-TRANSITIVE-FRONTEND # Assigned which metadata key-value will be passed along the link transitive: - CUSTOM-METADATA-KEY-TRANSITIVE + disposable: + - CUSTOM-METADATA-KEY-DISPOSABLE management: endpoints: web: diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/pom.xml b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/pom.xml similarity index 93% rename from spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/pom.xml rename to spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/pom.xml index 237c9877f..41c4cd13f 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-callee-service/pom.xml +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/pom.xml @@ -10,8 +10,8 @@ 4.0.0 - metadata-callee-service - Spring Cloud Tencent Metadata Transfer Callee Service + metadata-middle + Spring Cloud Tencent Metadata Transfer Middle Service diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataBackendService.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataBackendService.java new file mode 100644 index 000000000..b8e9855c9 --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataBackendService.java @@ -0,0 +1,40 @@ +/* + * 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.metadata.service.middle; + +import java.util.Map; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * Metadata callee feign client. + * + * @author Palmer Xu + */ +@FeignClient(value = "MetadataBackendService", + fallback = MetadataBackendServiceFallback.class) +public interface MetadataBackendService { + + /** + * Get information of callee. + * @return information of callee + */ + @GetMapping("/metadata/service/backend/info") + Map> info(); +} diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataBackendServiceFallback.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataBackendServiceFallback.java new file mode 100644 index 000000000..cbe5edd71 --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataBackendServiceFallback.java @@ -0,0 +1,38 @@ +/* + * 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.metadata.service.middle; + +import java.util.Map; + +import com.google.common.collect.Maps; + +import org.springframework.stereotype.Component; + +/** + * Metadata callee feign client fallback. + * + * @author Palmer Xu + */ +@Component +public class MetadataBackendServiceFallback implements MetadataBackendService { + + @Override + public Map> info() { + return Maps.newHashMap(); + } +} diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleController.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleController.java new file mode 100644 index 000000000..7ea673a50 --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleController.java @@ -0,0 +1,122 @@ +/* + * 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.metadata.service.middle; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +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.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import static com.tencent.cloud.common.util.JacksonUtils.serialize2Json; + +/** + * Metadata callee controller. + * + * @author Palmer Xu + */ +@RestController +@RequestMapping("/metadata/service/middle") +public class MetadataMiddleController { + + private static final Logger LOG = LoggerFactory.getLogger(MetadataMiddleController.class); + + @Value("${server.port:0}") + private int port; + + private final MetadataBackendService metadataBackendService; + + private final RestTemplate restTemplate; + + public MetadataMiddleController(MetadataBackendService metadataBackendService, RestTemplate restTemplate) { + this.metadataBackendService = metadataBackendService; + this.restTemplate = restTemplate; + } + + /** + * Get information of callee. + * + * @return information of callee + */ + @GetMapping("/info") + public Map> info() { + + // Build result + Map> ret = new HashMap<>(); + + LOG.info("Metadata Middle Service [{}] is called.", port); + + // Call remote service with RestTemplate + Map> backendResult = restTemplate.getForObject( + "http://MetadataBackendService/metadata/service/backend/info", Map.class); + + if (backendResult != null) { + LOG.info("RestTemplate Backend Metadata"); + LOG.info("\r{}", serialize2Json(backendResult, true)); + backendResult.clear(); + } + + // Call remote service with Feign + backendResult = metadataBackendService.info(); + if (backendResult != null) { + LOG.info("Feign Backend Metadata"); + LOG.info("\r{}", serialize2Json(backendResult, true)); + } + + if (backendResult != null) { + ret.putAll(backendResult); + } + + // Get Custom Metadata From Context + MetadataContext context = MetadataContextHolder.get(); + Map customMetadataMap = context.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + + customMetadataMap.forEach((key, value) -> { + LOG.info("Metadata Middle Custom Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("middle-transitive-metadata", customMetadataMap); + + // Get All Disposable metadata from upstream service + Map upstreamDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(true); + upstreamDisposableMetadatas.forEach((key, value) -> { + LOG.info("Upstream Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("middle-upstream-disposable-metadata", upstreamDisposableMetadatas); + + // Get All Disposable metadata from upstream service + Map localDisposableMetadatas = MetadataContextHolder.getAllDisposableMetadata(false); + localDisposableMetadatas.forEach((key, value) -> { + LOG.info("Local Custom Disposable Metadata (Key-Value): {} : {}", key, value); + }); + + ret.put("middle-local-disposable-metadata", localDisposableMetadatas); + + return ret; + } + +} diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleService.java b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleService.java new file mode 100644 index 000000000..f7c8d3d08 --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/java/com/tencent/cloud/metadata/service/middle/MetadataMiddleService.java @@ -0,0 +1,46 @@ +/* + * 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.metadata.service.middle; + +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; + +/** + * Metadata callee application. + * + * @author Palmer Xu + */ +@SpringBootApplication +@EnableFeignClients +public class MetadataMiddleService { + + public static void main(String[] args) { + SpringApplication.run(MetadataMiddleService.class, args); + } + + @Bean + @LoadBalanced + public RestTemplate restTemplate() { + return new RestTemplate(); + } + +} diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/resources/bootstrap.yml new file mode 100644 index 000000000..db78677b5 --- /dev/null +++ b/spring-cloud-tencent-examples/metadata-transfer-example/metadata-middle/src/main/resources/bootstrap.yml @@ -0,0 +1,35 @@ +server: + port: 48084 +spring: + application: + name: MetadataMiddleService + cloud: + polaris: + address: grpc://183.47.111.80:8091 + namespace: default + enabled: true + discovery: + enabled: true + register: true + tencent: + metadata: + # Defined your metadata keys & values + content: + # Example: intransitive + CUSTOM-METADATA-KEY-LOCAL-2: CUSTOM-VALUE-LOCAL-2 + # Example: transitive + CUSTOM-METADATA-KEY-TRANSITIVE-2: CUSTOM-VALUE-TRANSITIVE-2 + # Example: disposable + CUSTOM-METADATA-KEY-DISPOSABLE: CUSTOM-VALUE-DISPOSABLE-MIDDLE + # Assigned which metadata key-value will be passed along the link + transitive: + - CUSTOM-METADATA-KEY-TRANSITIVE-2 + disposable: + - CUSTOM-METADATA-KEY-DISPOSABLE + +management: + endpoints: + web: + exposure: + include: + - polaris-metadata \ No newline at end of file diff --git a/spring-cloud-tencent-examples/metadata-transfer-example/pom.xml b/spring-cloud-tencent-examples/metadata-transfer-example/pom.xml index bd2b961ec..2cbc55a3b 100644 --- a/spring-cloud-tencent-examples/metadata-transfer-example/pom.xml +++ b/spring-cloud-tencent-examples/metadata-transfer-example/pom.xml @@ -15,8 +15,9 @@ Spring Cloud Starter Tencent Metadata Transfer Example - metadata-callee-service - metadata-caller-service + metadata-frontend + metadata-middle + metadata-backend diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/resources/bootstrap.yml index a98ef90a1..de8c607b2 100644 --- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/resources/bootstrap.yml @@ -10,8 +10,19 @@ spring: enabled: true circuitbreaker: enabled: true + stat: + enabled: true + port: 28081 loadbalancer: configurations: polaris + tencent: + rpc-enhancement: + enabled: true + reporter: + ignore-internal-server-error: true + series: server_error + statuses: gateway_timeout, bad_gateway, service_unavailable + feign: circuitbreaker: enabled: true diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/src/main/resources/bootstrap.yml index 3805dfa5e..d6945b5b4 100644 --- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b/src/main/resources/bootstrap.yml @@ -8,3 +8,6 @@ spring: address: grpc://183.47.111.80:8091 namespace: default enabled: true + stat: + enabled: true + port: 28082 diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/src/main/resources/bootstrap.yml index f3720f09c..5ef89145c 100644 --- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-b2/src/main/resources/bootstrap.yml @@ -8,3 +8,6 @@ spring: address: grpc://183.47.111.80:8091 namespace: default enabled: true + stat: + enabled: true + port: 28083 diff --git a/spring-cloud-tencent-examples/polaris-discovery-example/discovery-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-discovery-example/discovery-callee-service/src/main/resources/bootstrap.yml index 75b4e33d9..1e42dc349 100644 --- a/spring-cloud-tencent-examples/polaris-discovery-example/discovery-callee-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-discovery-example/discovery-callee-service/src/main/resources/bootstrap.yml @@ -11,6 +11,9 @@ spring: discovery: enabled: true register: true + stat: + enabled: true + port: 28082 tencent: metadata: content: diff --git a/spring-cloud-tencent-examples/polaris-discovery-example/discovery-caller-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-discovery-example/discovery-caller-service/src/main/resources/bootstrap.yml index fcfdad35b..62b944010 100644 --- a/spring-cloud-tencent-examples/polaris-discovery-example/discovery-caller-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-discovery-example/discovery-caller-service/src/main/resources/bootstrap.yml @@ -19,6 +19,9 @@ spring: heartbeat: enabled: true health-check-url: /discovery/service/caller/healthCheck + stat: + enabled: true + port: 28081 # consul: # port: 8500 # host: 127.0.0.1 @@ -41,4 +44,4 @@ management: web: exposure: include: - - polaris-discovery \ No newline at end of file + - polaris-discovery diff --git a/spring-cloud-tencent-polaris-context/pom.xml b/spring-cloud-tencent-polaris-context/pom.xml index aa9b8523b..786f536b3 100644 --- a/spring-cloud-tencent-polaris-context/pom.xml +++ b/spring-cloud-tencent-polaris-context/pom.xml @@ -27,6 +27,33 @@ + + com.tencent.polaris + polaris-discovery-factory + + + com.tencent.polaris + router-rule + + + com.tencent.polaris + router-nearby + + + com.tencent.polaris + router-metadata + + + com.tencent.polaris + router-canary + + + com.tencent.polaris + router-set + + + + com.tencent.polaris polaris-client @@ -62,17 +89,6 @@ flow-cache-expired - - - com.tencent.polaris - router-isolated - - - - com.tencent.polaris - router-healthy - - com.tencent.polaris loadbalancer-random diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java index 51ba3eb6c..97722fb0e 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java @@ -21,8 +21,11 @@ package com.tencent.cloud.polaris.context.config; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import com.tencent.cloud.polaris.context.ModifyAddress; import com.tencent.cloud.polaris.context.ServiceRuleManager; +import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.polaris.api.core.ProviderAPI; import com.tencent.polaris.api.exception.PolarisException; import com.tencent.polaris.client.api.SDKContext; +import com.tencent.polaris.factory.api.DiscoveryAPIFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -46,6 +49,18 @@ public class PolarisContextAutoConfiguration { return SDKContext.initContextByConfig(properties.configuration()); } + @Bean + @ConditionalOnMissingBean + public ProviderAPI polarisProvider(SDKContext polarisContext) throws PolarisException { + return DiscoveryAPIFactory.createProviderAPIByContext(polarisContext); + } + + @Bean + @ConditionalOnMissingBean + public ConsumerAPI polarisConsumer(SDKContext polarisContext) throws PolarisException { + return DiscoveryAPIFactory.createConsumerAPIByContext(polarisContext); + } + @Bean @ConditionalOnMissingBean public ModifyAddress polarisConfigModifier() { diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingApplicationListener.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingApplicationListener.java new file mode 100644 index 000000000..52f1948a0 --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/logging/PolarisLoggingApplicationListener.java @@ -0,0 +1,56 @@ +/* + * 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.context.logging; + +import com.tencent.polaris.logging.PolarisLogging; + +import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; +import org.springframework.boot.context.event.ApplicationFailedEvent; +import org.springframework.boot.context.logging.LoggingApplicationListener; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.event.GenericApplicationListener; +import org.springframework.core.ResolvableType; + +/** + * Reload of Polaris logging configuration. + * + * @author Haotian Zhang + */ +public class PolarisLoggingApplicationListener implements GenericApplicationListener { + + private static final int ORDER = LoggingApplicationListener.DEFAULT_ORDER + 2; + + @Override + public boolean supportsEventType(ResolvableType resolvableType) { + Class type = resolvableType.getRawClass(); + if (type == null) { + return false; + } + return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(type) + || ApplicationFailedEvent.class.isAssignableFrom(type); + } + + @Override + public int getOrder() { + return ORDER; + } + + @Override + public void onApplicationEvent(ApplicationEvent applicationEvent) { + PolarisLogging.getInstance().loadConfiguration(); + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories b/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories index 723fc1d78..a121e3c26 100644 --- a/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-tencent-polaris-context/src/main/resources/META-INF/spring.factories @@ -3,3 +3,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.context.config.PolarisContextPostConfiguration org.springframework.cloud.bootstrap.BootstrapConfiguration=\ com.tencent.cloud.polaris.context.config.PolarisContextBootstrapAutoConfiguration +org.springframework.context.ApplicationListener=\ + com.tencent.cloud.polaris.context.logging.PolarisLoggingApplicationListener diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerTest.java b/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerTest.java new file mode 100644 index 000000000..b5cdabb60 --- /dev/null +++ b/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisLoadBalancerTest.java @@ -0,0 +1,126 @@ +/* + * 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.loadbalancer; + +import java.util.ArrayList; +import java.util.List; + +import com.tencent.cloud.common.pojo.PolarisServiceInstance; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerProperties; +import com.tencent.polaris.api.pojo.Instance; +import com.tencent.polaris.router.api.core.RouterAPI; +import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceResponse; +import org.assertj.core.api.Assertions; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.Request; +import org.springframework.cloud.client.loadbalancer.Response; +import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; + +import static com.tencent.cloud.common.metadata.MetadataContext.LOCAL_NAMESPACE; +import static com.tencent.cloud.common.metadata.MetadataContext.LOCAL_SERVICE; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + + +/** + * Test for {@link PolarisLoadBalancer}. + * + * @author rod.xu + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisLoadBalancerTest { + + @Mock + private RouterAPI routerAPI; + @Mock + private ObjectProvider supplierObjectProvider; + @Mock + private PolarisLoadBalancerProperties loadBalancerProperties; + + private static MockedStatic mockedApplicationContextAwareUtils; + private static Instance testInstance; + + @BeforeClass + public static void beforeClass() { + mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn("unit-test"); + + testInstance = Instance.createDefaultInstance("instance-id", LOCAL_NAMESPACE, + LOCAL_SERVICE, "host", 8090); + } + + @AfterClass + public static void afterClass() { + mockedApplicationContextAwareUtils.close(); + } + + @Test + public void chooseNormalLogicTest_thenReturnAvailablePolarisInstance() { + Request request = Mockito.mock(Request.class); + List mockInstanceList = new ArrayList<>(); + mockInstanceList.add(new PolarisServiceInstance(testInstance)); + + ServiceInstanceListSupplier serviceInstanceListSupplier = Mockito.mock(ServiceInstanceListSupplier.class); + when(serviceInstanceListSupplier.get(request)).thenReturn(Flux.just(mockInstanceList)); + + when(supplierObjectProvider.getIfAvailable(any())).thenReturn(serviceInstanceListSupplier); + when(loadBalancerProperties.getEnabled()).thenReturn(true); + + ProcessLoadBalanceResponse mockLbRes = new ProcessLoadBalanceResponse(testInstance); + when(routerAPI.processLoadBalance(any())).thenReturn(mockLbRes); + + // request construct and execute invoke + PolarisLoadBalancer polarisLoadBalancer = new PolarisLoadBalancer(LOCAL_SERVICE, supplierObjectProvider, + loadBalancerProperties, routerAPI); + Mono> responseMono = polarisLoadBalancer.choose(request); + ServiceInstance serviceInstance = responseMono.block().getServer(); + + // verify method has invoked + verify(loadBalancerProperties).getEnabled(); + verify(supplierObjectProvider).getIfAvailable(any()); + + //result assert + Assertions.assertThat(serviceInstance).isNotNull(); + Assertions.assertThat(serviceInstance instanceof PolarisServiceInstance).isTrue(); + + PolarisServiceInstance polarisServiceInstance = (PolarisServiceInstance) serviceInstance; + + Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getId()).isEqualTo("instance-id"); + Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getNamespace()).isEqualTo(LOCAL_NAMESPACE); + Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getService()).isEqualTo(LOCAL_SERVICE); + Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getHost()).isEqualTo("host"); + Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getPort()).isEqualTo(8090); + } +} diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisServiceInstanceListSupplierTest.java b/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisServiceInstanceListSupplierTest.java new file mode 100644 index 000000000..17f28543a --- /dev/null +++ b/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/PolarisServiceInstanceListSupplierTest.java @@ -0,0 +1,89 @@ +/* + * 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.loadbalancer; + +import java.util.ArrayList; +import java.util.List; + +import com.tencent.cloud.common.pojo.PolarisServiceInstance; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import org.assertj.core.api.Assertions; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import org.springframework.cloud.client.DefaultServiceInstance; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; + +import static com.tencent.cloud.common.metadata.MetadataContext.LOCAL_NAMESPACE; +import static org.mockito.ArgumentMatchers.anyString; + +/** + * Test for {@link PolarisServiceInstanceListSupplier}. + * + * @author rod.xu + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisServiceInstanceListSupplierTest { + + @Mock + private ServiceInstanceListSupplier serviceInstanceListSupplier; + + @Test + public void chooseInstancesTest() { + try (MockedStatic mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class)) { + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn("test-unit"); + + PolarisServiceInstanceListSupplier instanceListSupplier = + new PolarisServiceInstanceListSupplier(serviceInstanceListSupplier); + + List allServers = new ArrayList<>(); + ServiceInstance instance1 = new DefaultServiceInstance("unit-test-instanceId-01", + "unit-test-serviceId", "unit-test-host-01", 8090, false); + ServiceInstance instance2 = new DefaultServiceInstance("unit-test-instanceId-02", + "unit-test-serviceId", "unit-test-host-02", 8090, false); + + allServers.add(instance1); + allServers.add(instance2); + + List polarisInstanceList = instanceListSupplier.chooseInstances(allServers); + + Assertions.assertThat(polarisInstanceList).isNotNull(); + Assertions.assertThat(polarisInstanceList.size()).isEqualTo(allServers.size()); + + for (ServiceInstance serviceInstance : polarisInstanceList) { + Assertions.assertThat(serviceInstance instanceof PolarisServiceInstance).isTrue(); + + PolarisServiceInstance polarisServiceInstance = (PolarisServiceInstance) serviceInstance; + + Assertions.assertThat(polarisServiceInstance.isSecure()).isFalse(); + Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getService()).isEqualTo("unit-test-serviceId"); + Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getNamespace()).isEqualTo(LOCAL_NAMESPACE); + Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getPort()).isEqualTo(8090); + Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getId().startsWith("unit-test-instanceId")).isTrue(); + Assertions.assertThat(polarisServiceInstance.getPolarisInstance().getHost().startsWith("unit-test-host")).isTrue(); + } + } + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/pom.xml b/spring-cloud-tencent-rpc-enhancement/pom.xml new file mode 100644 index 000000000..9709c9c5b --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/pom.xml @@ -0,0 +1,62 @@ + + + + spring-cloud-tencent + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 + + spring-cloud-tencent-rpc-enhancement + Spring Cloud Starter Tencent RPC Enhancement + + + + + com.tencent.cloud + spring-cloud-tencent-polaris-loadbalancer + + + + + + com.tencent.polaris + stat-prometheus + + + + + org.springframework.cloud + spring-cloud-starter-openfeign + true + + + + com.tencent.polaris + polaris-test-common + test + + + + org.springframework.boot + spring-boot-starter-web + test + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.mockito + mockito-inline + test + + + + \ No newline at end of file diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/AbstractPolarisReporterAdapter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/AbstractPolarisReporterAdapter.java new file mode 100644 index 000000000..6ba28617d --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/AbstractPolarisReporterAdapter.java @@ -0,0 +1,119 @@ +/* + * 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; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.http.HttpStatus; +import org.springframework.lang.Nullable; + +import static org.springframework.http.HttpStatus.BAD_GATEWAY; +import static org.springframework.http.HttpStatus.BANDWIDTH_LIMIT_EXCEEDED; +import static org.springframework.http.HttpStatus.GATEWAY_TIMEOUT; +import static org.springframework.http.HttpStatus.HTTP_VERSION_NOT_SUPPORTED; +import static org.springframework.http.HttpStatus.INSUFFICIENT_STORAGE; +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; +import static org.springframework.http.HttpStatus.LOOP_DETECTED; +import static org.springframework.http.HttpStatus.NETWORK_AUTHENTICATION_REQUIRED; +import static org.springframework.http.HttpStatus.NOT_EXTENDED; +import static org.springframework.http.HttpStatus.NOT_IMPLEMENTED; +import static org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE; +import static org.springframework.http.HttpStatus.VARIANT_ALSO_NEGOTIATES; + +/** + * Abstract Polaris Reporter Adapter . + * + * @author Elve.Xu 2022-07-11 + */ +public abstract class AbstractPolarisReporterAdapter { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractPolarisReporterAdapter.class); + private static final List 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 properties; + + /** + * Constructor With {@link RpcEnhancementReporterProperties} . + * + * @param properties instance of {@link RpcEnhancementReporterProperties}. + */ + protected AbstractPolarisReporterAdapter(RpcEnhancementReporterProperties properties) { + this.properties = properties; + } + + /** + * Convert items to List. + * + * @param items item arrays + * @param Object Generics. + * @return list + */ + @SafeVarargs + private static List toList(T... items) { + return new ArrayList<>(Arrays.asList(items)); + } + + /** + * Callback after completion of request processing, Check if business meltdown reporting is required. + * + * @param httpStatus request http status code + * @return true , otherwise return false . + */ + protected boolean apply(@Nullable HttpStatus httpStatus) { + if (Objects.isNull(httpStatus)) { + return false; + } + else { + // statuses > series + List status = properties.getStatuses(); + + if (status.isEmpty()) { + List series = properties.getSeries(); + // Check INTERNAL_SERVER_ERROR (500) status. + if (properties.isIgnoreInternalServerError() && Objects.equals(httpStatus, INTERNAL_SERVER_ERROR)) { + return false; + } + if (series.isEmpty()) { + return HTTP_STATUSES.contains(httpStatus); + } + else { + try { + return series.contains(HttpStatus.Series.valueOf(httpStatus)); + } + catch (Exception e) { + LOG.warn("Decode http status failed.", e); + } + } + } + else { + // Use the user-specified fuse status code. + return status.contains(httpStatus); + } + } + // DEFAULT RETURN FALSE. + return false; + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java new file mode 100644 index 000000000..ab22b6b5c --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfiguration.java @@ -0,0 +1,113 @@ +/* + * 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.config; + +import java.util.List; + +import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; +import com.tencent.cloud.rpc.enhancement.feign.EnhancedFeignBeanPostProcessor; +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin; +import com.tencent.cloud.rpc.enhancement.feign.plugin.reporter.ExceptionPolarisReporter; +import com.tencent.cloud.rpc.enhancement.feign.plugin.reporter.SuccessPolarisReporter; +import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateModifier; +import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateReporter; +import com.tencent.cloud.rpc.enhancement.resttemplate.PolarisResponseErrorHandler; +import com.tencent.polaris.api.core.ConsumerAPI; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.web.client.RestTemplate; + +import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE; + +/** + * Auto Configuration for Polaris {@link feign.Feign} OR {@link RestTemplate} which can automatically bring in the call + * results for reporting. + * + * @author Palmer.Xu 2022-06-29 + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnProperty(value = "spring.cloud.tencent.rpc-enhancement.enabled", havingValue = "true", matchIfMissing = true) +@EnableConfigurationProperties(RpcEnhancementReporterProperties.class) +@AutoConfigureAfter(PolarisContextAutoConfiguration.class) +public class RpcEnhancementAutoConfiguration { + + /** + * Configuration for Polaris {@link feign.Feign} which can automatically bring in the call + * results for reporting. + * + * @author Haotian Zhang + */ + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(name = "org.springframework.cloud.openfeign.FeignAutoConfiguration") + @AutoConfigureBefore(name = "org.springframework.cloud.openfeign.FeignAutoConfiguration") + protected static class PolarisFeignClientAutoConfiguration { + + @Bean + @Order(HIGHEST_PRECEDENCE) + public EnhancedFeignBeanPostProcessor polarisFeignBeanPostProcessor( + @Autowired(required = false) List enhancedFeignPlugins) { + return new EnhancedFeignBeanPostProcessor(enhancedFeignPlugins); + } + + @Configuration + static class PolarisReporterConfig { + + @Bean + public SuccessPolarisReporter successPolarisReporter(RpcEnhancementReporterProperties properties) { + return new SuccessPolarisReporter(properties); + } + + @Bean + public ExceptionPolarisReporter exceptionPolarisReporter() { + return new ExceptionPolarisReporter(); + } + } + } + + /** + * Configuration for Polaris {@link RestTemplate} which can automatically bring in the call + * results for reporting. + * + * @author wh 2022/6/21 + */ + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(name = "org.springframework.web.client.RestTemplate") + protected static class PolarisRestTemplateAutoConfiguration { + + @Bean + public EnhancedRestTemplateReporter polarisRestTemplateResponseErrorHandler( + RpcEnhancementReporterProperties properties, ConsumerAPI consumerAPI, + @Autowired(required = false) PolarisResponseErrorHandler polarisResponseErrorHandler) { + return new EnhancedRestTemplateReporter(properties, consumerAPI, polarisResponseErrorHandler); + } + + @Bean + public EnhancedRestTemplateModifier polarisRestTemplateBeanPostProcessor( + EnhancedRestTemplateReporter restTemplateResponseErrorHandler) { + return new EnhancedRestTemplateModifier(restTemplateResponseErrorHandler); + } + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementReporterProperties.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementReporterProperties.java new file mode 100644 index 000000000..a044f459c --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementReporterProperties.java @@ -0,0 +1,86 @@ +/* + * 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.config; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.http.HttpStatus; + +/** + * Properties of Polaris CircuitBreaker . + * + * @author Elve.Xu 2022-07-08 + */ +@ConfigurationProperties("spring.cloud.tencent.rpc-enhancement.reporter") +public class RpcEnhancementReporterProperties { + + /** + * Specify the Http status code(s) that needs to be reported as FAILED. + */ + private List statuses = new ArrayList<>(); + + /** + * Specify List of HTTP status series that needs to be reported as FAILED when status list is empty. + */ + private List series = toList(HttpStatus.Series.SERVER_ERROR); + + /** + * If ignore "Internal Server Error Http Status Code (500)", + * Only takes effect if the attribute {@link RpcEnhancementReporterProperties#series} is not empty. + */ + private boolean ignoreInternalServerError = true; + + /** + * Convert items to List. + * + * @param items item arrays + * @param Object Generics. + * @return list + */ + @SafeVarargs + private static List toList(T... items) { + return new ArrayList<>(Arrays.asList(items)); + } + + public List getStatuses() { + return statuses; + } + + public void setStatuses(List statuses) { + this.statuses = statuses; + } + + public List getSeries() { + return series; + } + + public void setSeries(List series) { + this.series = series; + } + + public boolean isIgnoreInternalServerError() { + return ignoreInternalServerError; + } + + public void setIgnoreInternalServerError(boolean ignoreInternalServerError) { + this.ignoreInternalServerError = ignoreInternalServerError; + } +} diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignBeanPostProcessor.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignBeanPostProcessor.java similarity index 76% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignBeanPostProcessor.java rename to spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignBeanPostProcessor.java index 4b0193800..6901128a1 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignBeanPostProcessor.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignBeanPostProcessor.java @@ -15,9 +15,11 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.circuitbreaker.feign; +package com.tencent.cloud.rpc.enhancement.feign; -import com.tencent.polaris.api.core.ConsumerAPI; +import java.util.List; + +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin; import feign.Client; import org.springframework.beans.BeansException; @@ -36,14 +38,14 @@ import org.springframework.lang.NonNull; * * @author Haotian Zhang */ -public class PolarisFeignBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware { +public class EnhancedFeignBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware { - private final ConsumerAPI consumerAPI; + private final List enhancedFeignPlugins; private BeanFactory factory; - public PolarisFeignBeanPostProcessor(ConsumerAPI consumerAPI) { - this.consumerAPI = consumerAPI; + public EnhancedFeignBeanPostProcessor(List enhancedFeignPlugins) { + this.enhancedFeignPlugins = enhancedFeignPlugins; } @Override @@ -63,7 +65,7 @@ public class PolarisFeignBeanPostProcessor implements BeanPostProcessor, BeanFac delegate = ((FeignBlockingLoadBalancerClient) bean).getDelegate(); } if (delegate != null) { - return new PolarisFeignBlockingLoadBalancerClient(createPolarisFeignClient(delegate), + return new EnhancedFeignBlockingLoadBalancerClient(createPolarisFeignClient(delegate), factory.getBean(BlockingLoadBalancerClient.class), factory.getBean(LoadBalancerProperties.class), factory.getBean(LoadBalancerClientFactory.class)); @@ -75,12 +77,12 @@ public class PolarisFeignBeanPostProcessor implements BeanPostProcessor, BeanFac } private boolean isNeedWrap(Object bean) { - return bean instanceof Client && !(bean instanceof PolarisFeignClient) - && !(bean instanceof PolarisFeignBlockingLoadBalancerClient); + return bean instanceof Client && !(bean instanceof EnhancedFeignClient) + && !(bean instanceof EnhancedFeignBlockingLoadBalancerClient); } - private PolarisFeignClient createPolarisFeignClient(Client delegate) { - return new PolarisFeignClient(delegate, consumerAPI); + private EnhancedFeignClient createPolarisFeignClient(Client delegate) { + return new EnhancedFeignClient(delegate, enhancedFeignPlugins); } @Override diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignBlockingLoadBalancerClient.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignBlockingLoadBalancerClient.java similarity index 84% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignBlockingLoadBalancerClient.java rename to spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignBlockingLoadBalancerClient.java index ef2b82bc5..62fd878ed 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignBlockingLoadBalancerClient.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignBlockingLoadBalancerClient.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.circuitbreaker.feign; +package com.tencent.cloud.rpc.enhancement.feign; import feign.Client; @@ -29,9 +29,9 @@ import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalance * * @author Haotian Zhang */ -public class PolarisFeignBlockingLoadBalancerClient extends FeignBlockingLoadBalancerClient { +public class EnhancedFeignBlockingLoadBalancerClient extends FeignBlockingLoadBalancerClient { - public PolarisFeignBlockingLoadBalancerClient(Client delegate, LoadBalancerClient loadBalancerClient, + public EnhancedFeignBlockingLoadBalancerClient(Client delegate, LoadBalancerClient loadBalancerClient, LoadBalancerProperties properties, LoadBalancerClientFactory loadBalancerClientFactory) { super(delegate, loadBalancerClient, properties, loadBalancerClientFactory); } diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java new file mode 100644 index 000000000..18b06c366 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClient.java @@ -0,0 +1,153 @@ +/* + * 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.feign; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext; +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin; +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType; +import feign.Client; +import feign.Request; +import feign.Request.Options; +import feign.Response; + +import org.springframework.util.CollectionUtils; + +import static feign.Util.checkNotNull; + +/** + * Wrap for {@link Client}. + * + * @author Haotian Zhang + */ +public class EnhancedFeignClient implements Client { + + private final Client delegate; + + private List preEnhancedFeignPlugins; + + private List postEnhancedFeignPlugins; + + private List exceptionEnhancedFeignPlugins; + + private List finallyEnhancedFeignPlugins; + + public EnhancedFeignClient(Client target, List enhancedFeignPlugins) { + this.delegate = checkNotNull(target, "target"); + + // Init the EnhancedFeignPlugins list. + this.preEnhancedFeignPlugins = new ArrayList<>(); + this.postEnhancedFeignPlugins = new ArrayList<>(); + this.exceptionEnhancedFeignPlugins = new ArrayList<>(); + this.finallyEnhancedFeignPlugins = new ArrayList<>(); + if (!CollectionUtils.isEmpty(enhancedFeignPlugins)) { + for (EnhancedFeignPlugin feignPlugin : enhancedFeignPlugins) { + if (feignPlugin.getType().equals(EnhancedFeignPluginType.PRE)) { + this.preEnhancedFeignPlugins.add(feignPlugin); + } + else if (feignPlugin.getType().equals(EnhancedFeignPluginType.POST)) { + this.postEnhancedFeignPlugins.add(feignPlugin); + } + else if (feignPlugin.getType().equals(EnhancedFeignPluginType.EXCEPTION)) { + this.exceptionEnhancedFeignPlugins.add(feignPlugin); + } + else if (feignPlugin.getType().equals(EnhancedFeignPluginType.FINALLY)) { + this.finallyEnhancedFeignPlugins.add(feignPlugin); + } + } + } + // Set the ordered enhanced feign plugins. + this.preEnhancedFeignPlugins = getSortedEnhancedFeignPlugin(this.preEnhancedFeignPlugins); + this.postEnhancedFeignPlugins = getSortedEnhancedFeignPlugin(this.postEnhancedFeignPlugins); + this.exceptionEnhancedFeignPlugins = getSortedEnhancedFeignPlugin(this.exceptionEnhancedFeignPlugins); + this.finallyEnhancedFeignPlugins = getSortedEnhancedFeignPlugin(this.finallyEnhancedFeignPlugins); + } + + @Override + public Response execute(Request request, Options options) throws IOException { + EnhancedFeignContext enhancedFeignContext = new EnhancedFeignContext(); + enhancedFeignContext.setRequest(request); + enhancedFeignContext.setOptions(options); + + // Run pre enhanced feign plugins. + for (EnhancedFeignPlugin plugin : preEnhancedFeignPlugins) { + try { + plugin.run(enhancedFeignContext); + } + catch (Throwable throwable) { + plugin.handlerThrowable(enhancedFeignContext, throwable); + } + } + try { + Response response = delegate.execute(request, options); + enhancedFeignContext.setResponse(response); + + // Run post enhanced feign plugins. + for (EnhancedFeignPlugin plugin : postEnhancedFeignPlugins) { + try { + plugin.run(enhancedFeignContext); + } + catch (Throwable throwable) { + plugin.handlerThrowable(enhancedFeignContext, throwable); + } + } + return response; + } + catch (IOException origin) { + enhancedFeignContext.setException(origin); + // Run exception enhanced feign plugins. + for (EnhancedFeignPlugin plugin : exceptionEnhancedFeignPlugins) { + try { + plugin.run(enhancedFeignContext); + } + catch (Throwable throwable) { + plugin.handlerThrowable(enhancedFeignContext, throwable); + } + } + throw origin; + } + finally { + // Run finally enhanced feign plugins. + for (EnhancedFeignPlugin plugin : finallyEnhancedFeignPlugins) { + try { + plugin.run(enhancedFeignContext); + } + catch (Throwable throwable) { + plugin.handlerThrowable(enhancedFeignContext, throwable); + } + } + } + } + + /** + * Ascending, which means the lower order number, the earlier executing enhanced feign plugin. + * + * @return sorted feign pre plugin list + */ + private List getSortedEnhancedFeignPlugin(List preEnhancedFeignPlugins) { + return new ArrayList<>(preEnhancedFeignPlugins) + .stream() + .sorted(Comparator.comparing(EnhancedFeignPlugin::getOrder)) + .collect(Collectors.toList()); + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/EnhancedFeignContext.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/EnhancedFeignContext.java new file mode 100644 index 000000000..e6f3be612 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/EnhancedFeignContext.java @@ -0,0 +1,69 @@ +/* + * 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.feign.plugin; + +import feign.Request; +import feign.Response; + +/** + * Context used by EnhancedFeignPlugin. + * + * @author Haotian Zhang + */ +public class EnhancedFeignContext { + + private Request request; + + private Request.Options options; + + private Response response; + + private Exception exception; + + public Request getRequest() { + return request; + } + + public void setRequest(Request request) { + this.request = request; + } + + public Request.Options getOptions() { + return options; + } + + public void setOptions(Request.Options options) { + this.options = options; + } + + public Response getResponse() { + return response; + } + + public void setResponse(Response response) { + this.response = response; + } + + public Exception getException() { + return exception; + } + + public void setException(Exception exception) { + this.exception = exception; + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/EnhancedFeignPlugin.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/EnhancedFeignPlugin.java new file mode 100644 index 000000000..bfe141d34 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/EnhancedFeignPlugin.java @@ -0,0 +1,62 @@ +/* + * 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.feign.plugin; + +import org.springframework.core.Ordered; + +/** + * Pre plugin used by EnhancedFeignClient. + * + * @author Haotian Zhang + */ +public interface EnhancedFeignPlugin extends Ordered { + + /** + * Get name of plugin. + * + * @return name + */ + default String getName() { + return this.getClass().getName(); + } + + /** + * Get type of plugin. + * + * @return {@link EnhancedFeignPluginType} + */ + EnhancedFeignPluginType getType(); + + /** + * Run the plugin. + * + * @param context context in enhanced feign client. + * @throws Throwable throwable thrown from run method. + */ + void run(EnhancedFeignContext context) throws Throwable; + + /** + * Handler throwable from {@link EnhancedFeignPlugin#run(EnhancedFeignContext)}. + * + * @param context context in enhanced feign client. + * @param throwable throwable thrown from run method. + */ + default void handlerThrowable(EnhancedFeignContext context, Throwable throwable) { + + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/EnhancedFeignPluginType.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/EnhancedFeignPluginType.java new file mode 100644 index 000000000..fef181d83 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/EnhancedFeignPluginType.java @@ -0,0 +1,46 @@ +/* + * 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.feign.plugin; + +/** + * Type of EnhancedFeignPlugin. + * + * @author Haotian Zhang + */ +public enum EnhancedFeignPluginType { + + /** + * Pre feign plugin. + */ + PRE, + + /** + * Post feign plugin. + */ + POST, + + /** + * Exception feign plugin. + */ + EXCEPTION, + + /** + * Finally feign plugin. + */ + FINALLY +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/ExceptionPolarisReporter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/ExceptionPolarisReporter.java new file mode 100644 index 000000000..bfbec80c0 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/ExceptionPolarisReporter.java @@ -0,0 +1,85 @@ +/* + * 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.feign.plugin.reporter; + +import java.net.SocketTimeoutException; + +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext; +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin; +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType; +import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.polaris.api.pojo.RetStatus; +import com.tencent.polaris.api.rpc.ServiceCallResult; +import feign.Request; +import feign.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.Ordered; + +/** + * Polaris reporter when feign call is successful. + * + * @author Haotian Zhang + */ +public class ExceptionPolarisReporter implements EnhancedFeignPlugin { + + private static final Logger LOG = LoggerFactory.getLogger(ExceptionPolarisReporter.class); + + @Autowired(required = false) + private ConsumerAPI consumerAPI; + + @Override + public String getName() { + return ExceptionPolarisReporter.class.getName(); + } + + @Override + public EnhancedFeignPluginType getType() { + return EnhancedFeignPluginType.EXCEPTION; + } + + @Override + public void run(EnhancedFeignContext context) { + if (consumerAPI != null) { + Request request = context.getRequest(); + Response response = context.getResponse(); + Exception exception = context.getException(); + RetStatus retStatus = RetStatus.RetFail; + if (exception instanceof SocketTimeoutException) { + retStatus = RetStatus.RetTimeout; + } + LOG.debug("Will report result of {}. Request=[{}]. Response=[{}].", retStatus.name(), request, response); + ServiceCallResult resultRequest = ReporterUtils.createServiceCallResult(request, retStatus); + consumerAPI.updateServiceCallResult(resultRequest); + } + } + + @Override + public void handlerThrowable(EnhancedFeignContext context, Throwable throwable) { + Request request = context.getRequest(); + Response response = context.getResponse(); + LOG.error("ExceptionPolarisReporter runs failed. Request=[{}]. Response=[{}].", request, response, throwable); + } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE + 1; + } +} diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClient.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/ReporterUtils.java similarity index 51% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClient.java rename to spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/ReporterUtils.java index b4b03703a..432b911e2 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClient.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/ReporterUtils.java @@ -15,69 +15,28 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.circuitbreaker.feign; +package com.tencent.cloud.rpc.enhancement.feign.plugin.reporter; -import java.io.IOException; import java.net.URI; import com.tencent.cloud.common.metadata.MetadataContext; -import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.pojo.RetStatus; import com.tencent.polaris.api.pojo.ServiceKey; import com.tencent.polaris.api.rpc.ServiceCallResult; -import feign.Client; import feign.Request; -import feign.Request.Options; -import feign.Response; import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import static feign.Util.checkNotNull; /** - * Wrap for {@link Client}. + * Util for polaris reporter. * * @author Haotian Zhang */ -public class PolarisFeignClient implements Client { - - - private static final Logger LOG = LoggerFactory.getLogger(PolarisFeignClient.class); - - private final Client delegate; - - private final ConsumerAPI consumerAPI; +public final class ReporterUtils { - public PolarisFeignClient(Client target, ConsumerAPI consumerAPI) { - this.delegate = checkNotNull(target, "target"); - this.consumerAPI = checkNotNull(consumerAPI, "CircuitBreakAPI"); - } - - @Override - public Response execute(Request request, Options options) throws IOException { - final ServiceCallResult resultRequest = createServiceCallResult(request); - try { - Response response = delegate.execute(request, options); - // HTTP code greater than 500 is an exception - if (response.status() > 500) { - resultRequest.setRetStatus(RetStatus.RetFail); - } - LOG.debug("Will report result of {}. Request=[{}]. Response=[{}].", - resultRequest.getRetStatus().name(), request, response); - return response; - } - catch (IOException origin) { - resultRequest.setRetStatus(RetStatus.RetFail); - LOG.debug("Will report result of {}. Request=[{}].", resultRequest.getRetStatus().name(), request, origin); - throw origin; - } - finally { - consumerAPI.updateServiceCallResult(resultRequest); - } + private ReporterUtils() { } - private ServiceCallResult createServiceCallResult(final Request request) { + public static ServiceCallResult createServiceCallResult(final Request request, RetStatus retStatus) { ServiceCallResult resultRequest = new ServiceCallResult(); resultRequest.setNamespace(MetadataContext.LOCAL_NAMESPACE); @@ -85,7 +44,7 @@ public class PolarisFeignClient implements Client { resultRequest.setService(serviceName); URI uri = URI.create(request.url()); resultRequest.setMethod(uri.getPath()); - resultRequest.setRetStatus(RetStatus.RetSuccess); + resultRequest.setRetStatus(retStatus); String sourceNamespace = MetadataContext.LOCAL_NAMESPACE; String sourceService = MetadataContext.LOCAL_SERVICE; if (StringUtils.isNotBlank(sourceNamespace) && StringUtils.isNotBlank(sourceService)) { diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporter.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporter.java new file mode 100644 index 000000000..d4dc77344 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporter.java @@ -0,0 +1,88 @@ +/* + * 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.feign.plugin.reporter; + +import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter; +import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext; +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin; +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType; +import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.polaris.api.pojo.RetStatus; +import com.tencent.polaris.api.rpc.ServiceCallResult; +import feign.Request; +import feign.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.Ordered; +import org.springframework.http.HttpStatus; + +/** + * Polaris reporter when feign call is successful. + * + * @author Haotian Zhang + */ +public class SuccessPolarisReporter extends AbstractPolarisReporterAdapter implements EnhancedFeignPlugin { + + private static final Logger LOG = LoggerFactory.getLogger(SuccessPolarisReporter.class); + @Autowired(required = false) + private ConsumerAPI consumerAPI; + + public SuccessPolarisReporter(RpcEnhancementReporterProperties properties) { + super(properties); + } + + @Override + public String getName() { + return SuccessPolarisReporter.class.getName(); + } + + @Override + public EnhancedFeignPluginType getType() { + return EnhancedFeignPluginType.POST; + } + + @Override + public void run(EnhancedFeignContext context) { + if (consumerAPI != null) { + Request request = context.getRequest(); + Response response = context.getResponse(); + RetStatus retStatus = RetStatus.RetSuccess; + if (apply(HttpStatus.resolve(response.status()))) { + retStatus = RetStatus.RetFail; + } + LOG.debug("Will report result of {}. Request=[{}]. Response=[{}].", retStatus.name(), request, response); + ServiceCallResult resultRequest = ReporterUtils.createServiceCallResult(request, retStatus); + consumerAPI.updateServiceCallResult(resultRequest); + } + } + + @Override + public void handlerThrowable(EnhancedFeignContext context, Throwable throwable) { + Request request = context.getRequest(); + Response response = context.getResponse(); + LOG.error("SuccessPolarisReporter runs failed. Request=[{}]. Response=[{}].", request, response, throwable); + } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE + 1; + } +} diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateModifier.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateModifier.java similarity index 72% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateModifier.java rename to spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateModifier.java index 4ce1701dc..e4cf02114 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateModifier.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateModifier.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.circuitbreaker.resttemplate; +package com.tencent.cloud.rpc.enhancement.resttemplate; import java.util.Map; @@ -28,19 +28,19 @@ import org.springframework.util.ObjectUtils; import org.springframework.web.client.RestTemplate; /** - * Auto configuration RestTemplate, Find the RestTemplate bean annotated with {@link LoadBalanced}, + * Autoconfiguration RestTemplate, Find the RestTemplate bean annotated with {@link LoadBalanced}, * then replace {@link org.springframework.web.client.ResponseErrorHandler} - * with {@link PolarisRestTemplateResponseErrorHandler}. + * with {@link EnhancedRestTemplateReporter} . * * @author wh 2022/6/21 */ -public class PolarisRestTemplateModifier implements ApplicationContextAware, SmartInitializingSingleton { +public class EnhancedRestTemplateModifier implements ApplicationContextAware, SmartInitializingSingleton { - private final PolarisRestTemplateResponseErrorHandler polarisRestTemplateResponseErrorHandler; + private final EnhancedRestTemplateReporter enhancedRestTemplateReporter; private ApplicationContext applicationContext; - public PolarisRestTemplateModifier(PolarisRestTemplateResponseErrorHandler polarisRestTemplateResponseErrorHandler) { - this.polarisRestTemplateResponseErrorHandler = polarisRestTemplateResponseErrorHandler; + public EnhancedRestTemplateModifier(EnhancedRestTemplateReporter enhancedRestTemplateReporter) { + this.enhancedRestTemplateReporter = enhancedRestTemplateReporter; } @Override @@ -54,7 +54,7 @@ public class PolarisRestTemplateModifier implements ApplicationContextAware, Sma private void initRestTemplate(String beanName, Object bean) { if (bean instanceof RestTemplate) { RestTemplate restTemplate = (RestTemplate) bean; - restTemplate.setErrorHandler(polarisRestTemplateResponseErrorHandler); + restTemplate.setErrorHandler(enhancedRestTemplateReporter); } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateResponseErrorHandler.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporter.java similarity index 79% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateResponseErrorHandler.java rename to spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporter.java index 2dfbf2284..b3c8e9a09 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateResponseErrorHandler.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporter.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.circuitbreaker.resttemplate; +package com.tencent.cloud.rpc.enhancement.resttemplate; import java.io.IOException; import java.net.HttpURLConnection; @@ -25,6 +25,8 @@ import java.util.Objects; import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.util.ReflectionUtils; +import com.tencent.cloud.rpc.enhancement.AbstractPolarisReporterAdapter; +import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.pojo.RetStatus; import com.tencent.polaris.api.pojo.ServiceKey; @@ -43,9 +45,9 @@ import org.springframework.web.client.ResponseErrorHandler; * * @author wh 2022/6/21 */ -public class PolarisRestTemplateResponseErrorHandler implements ResponseErrorHandler { +public class EnhancedRestTemplateReporter extends AbstractPolarisReporterAdapter implements ResponseErrorHandler { - private static final Logger LOG = LoggerFactory.getLogger(PolarisRestTemplateResponseErrorHandler.class); + private static final Logger LOG = LoggerFactory.getLogger(EnhancedRestTemplateReporter.class); private static final String FIELD_NAME = "connection"; @@ -53,8 +55,9 @@ public class PolarisRestTemplateResponseErrorHandler implements ResponseErrorHan private final PolarisResponseErrorHandler polarisResponseErrorHandler; - public PolarisRestTemplateResponseErrorHandler( - ConsumerAPI consumerAPI, PolarisResponseErrorHandler polarisResponseErrorHandler) { + public EnhancedRestTemplateReporter(RpcEnhancementReporterProperties properties, ConsumerAPI consumerAPI, + PolarisResponseErrorHandler polarisResponseErrorHandler) { + super(properties); this.consumerAPI = consumerAPI; this.polarisResponseErrorHandler = polarisResponseErrorHandler; } @@ -74,7 +77,8 @@ public class PolarisRestTemplateResponseErrorHandler implements ResponseErrorHan } @Override - public void handleError(@NonNull URI url, @NonNull HttpMethod method, @NonNull ClientHttpResponse response) throws IOException { + public void handleError(@NonNull URI url, @NonNull HttpMethod method, @NonNull ClientHttpResponse response) + throws IOException { ServiceCallResult resultRequest = createServiceCallResult(url); try { HttpURLConnection connection = (HttpURLConnection) ReflectionUtils.getFieldValue(response, FIELD_NAME); @@ -84,15 +88,18 @@ public class PolarisRestTemplateResponseErrorHandler implements ResponseErrorHan resultRequest.setPort(realURL.getPort()); } - if (response.getStatusCode().value() > 500) { + if (apply(response.getStatusCode())) { resultRequest.setRetStatus(RetStatus.RetFail); } } catch (Exception e) { LOG.error("Will report response of {} url {}", response, url, e); + resultRequest.setRetStatus(RetStatus.RetFail); throw e; } finally { + LOG.debug("Will report result of {}. URL=[{}]. Response=[{}].", resultRequest.getRetStatus().name(), + url, response); consumerAPI.updateServiceCallResult(resultRequest); } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisResponseErrorHandler.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/PolarisResponseErrorHandler.java similarity index 94% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisResponseErrorHandler.java rename to spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/PolarisResponseErrorHandler.java index 3c690b1cc..fa49521eb 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisResponseErrorHandler.java +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/resttemplate/PolarisResponseErrorHandler.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.circuitbreaker.resttemplate; +package com.tencent.cloud.rpc.enhancement.resttemplate; import org.springframework.web.client.ResponseErrorHandler; diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatProperties.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatProperties.java new file mode 100644 index 000000000..b8b918202 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatProperties.java @@ -0,0 +1,82 @@ +/* + * 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.stat.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * The properties for stat reporter. + * + * @author Haotian Zhang + */ +@ConfigurationProperties("spring.cloud.polaris.stat") +public class PolarisStatProperties { + + /** + * If state reporter enabled. + */ + private boolean enabled = false; + + /** + * Local host for prometheus to pull. + */ + private String host; + + /** + * Port for prometheus to pull. + */ + private int port = 28080; + + /** + * Path for prometheus to pull. + */ + private String path = "/metrics"; + + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java new file mode 100644 index 000000000..d21c21fba --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfiguration.java @@ -0,0 +1,43 @@ +/* + * 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.stat.config; + +import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.env.Environment; + +/** + * Autoconfiguration of stat reporter. + * + * @author Haotian Zhang + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnPolarisEnabled +@Import({PolarisStatProperties.class}) +public class PolarisStatPropertiesAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public StatConfigModifier statReporterConfigModifier(PolarisStatProperties polarisStatProperties, Environment environment) { + return new StatConfigModifier(polarisStatProperties, environment); + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesBootstrapConfiguration.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesBootstrapConfiguration.java new file mode 100644 index 000000000..d71d9bce1 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesBootstrapConfiguration.java @@ -0,0 +1,34 @@ +/* + * 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.stat.config; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * Autoconfiguration of stat reporter at bootstrap phase. + * + * @author lepdou 2022-03-29 + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnProperty("spring.cloud.polaris.enabled") +@Import(PolarisStatPropertiesAutoConfiguration.class) +public class PolarisStatPropertiesBootstrapConfiguration { + +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java new file mode 100644 index 000000000..6306f68d3 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/java/com/tencent/cloud/rpc/enhancement/stat/config/StatConfigModifier.java @@ -0,0 +1,70 @@ +/* + * 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.stat.config; + +import com.tencent.cloud.common.constant.ContextConstant; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.polaris.factory.config.ConfigurationImpl; +import com.tencent.polaris.plugins.stat.prometheus.handler.PrometheusHandlerConfig; + +import org.springframework.core.env.Environment; +import org.springframework.util.StringUtils; + +import static com.tencent.polaris.api.config.global.StatReporterConfig.DEFAULT_REPORTER_PROMETHEUS; + +/** + * Config modifier for stat reporter. + * + * @author Haotian Zhang + */ +public class StatConfigModifier implements PolarisConfigModifier { + + private final PolarisStatProperties polarisStatProperties; + + private final Environment environment; + + public StatConfigModifier(PolarisStatProperties polarisStatProperties, Environment environment) { + this.polarisStatProperties = polarisStatProperties; + this.environment = environment; + } + + @Override + public void modify(ConfigurationImpl configuration) { + // Turn on stat reporter configuration. + configuration.getGlobal().getStatReporter().setEnable(polarisStatProperties.isEnabled()); + + // Set prometheus plugin. + if (polarisStatProperties.isEnabled()) { + PrometheusHandlerConfig prometheusHandlerConfig = configuration.getGlobal().getStatReporter() + .getPluginConfig(DEFAULT_REPORTER_PROMETHEUS, PrometheusHandlerConfig.class); + if (!StringUtils.hasText(polarisStatProperties.getHost())) { + polarisStatProperties.setHost(environment.getProperty("spring.cloud.client.ip-address")); + } + prometheusHandlerConfig.setHost(polarisStatProperties.getHost()); + prometheusHandlerConfig.setPort(polarisStatProperties.getPort()); + prometheusHandlerConfig.setPath(polarisStatProperties.getPath()); + configuration.getGlobal().getStatReporter() + .setPluginConfig(DEFAULT_REPORTER_PROMETHEUS, prometheusHandlerConfig); + } + } + + @Override + public int getOrder() { + return ContextConstant.ModifierOrder.STAT_REPORTER_ORDER; + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..c76a18566 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,51 @@ +{ + "properties": [ + { + "name": "spring.cloud.tencent.rpc-enhancement.enabled", + "type": "java.lang.Boolean", + "defaultValue": true, + "description": "If rpc enhancement enabled." + }, + { + "name": "spring.cloud.tencent.rpc-enhancement.reporter.ignore-internal-server-error", + "type": "java.lang.Boolean", + "defaultValue": true, + "description": "If ignore \"Internal Server Error Http Status Code (500)\"." + }, + { + "name": "spring.cloud.tencent.rpc-enhancement.reporter.series", + "type": "java.util.List", + "defaultValue": "HttpStatus.Series.SERVER_ERROR", + "description": "Specify List of HTTP status series that needs to be reported as FAILED when status list is empty." + }, + { + "name": "spring.cloud.tencent.rpc-enhancement.reporter.statuses", + "type": "java.util.List", + "defaultValue": "", + "description": "Specify the Http status code(s) that needs to be reported as FAILED." + }, + { + "name": "spring.cloud.polaris.stat.enabled", + "type": "java.lang.Boolean", + "defaultValue": false, + "description": "Enable polaris stat reporter or not." + }, + { + "name": "spring.cloud.polaris.stat.host", + "type": "java.lang.String", + "description": "Local host for prometheus to pull." + }, + { + "name": "spring.cloud.polaris.stat.port", + "type": "java.lang.Integer", + "defaultValue": "28080", + "description": "Port for prometheus to pull." + }, + { + "name": "spring.cloud.polaris.stat.path", + "type": "java.lang.String", + "defaultValue": "/metrics", + "description": "Path for prometheus to pull." + } + ] +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/spring.factories b/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..990b75001 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/main/resources/META-INF/spring.factories @@ -0,0 +1,5 @@ +org.springframework.cloud.bootstrap.BootstrapConfiguration=\ + com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatPropertiesBootstrapConfiguration +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.tencent.cloud.rpc.enhancement.config.RpcEnhancementAutoConfiguration,\ + com.tencent.cloud.rpc.enhancement.stat.config.PolarisStatPropertiesAutoConfiguration diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/AbstractPolarisReporterAdapterTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/AbstractPolarisReporterAdapterTest.java new file mode 100644 index 000000000..a14655de3 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/AbstractPolarisReporterAdapterTest.java @@ -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; + +import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; +import org.assertj.core.api.Assertions; +import org.junit.Test; + +import org.springframework.http.HttpStatus; + +/** + * Test For {@link AbstractPolarisReporterAdapter}. + * + * @author Elve.Xu 2022/7/11 + */ +public class AbstractPolarisReporterAdapterTest { + + @Test + public void testApplyWithDefaultConfig() { + RpcEnhancementReporterProperties properties = new RpcEnhancementReporterProperties(); + // Mock Condition + SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties); + + // Assert + Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false); + Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false); + Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true); + } + + @Test + public void testApplyWithoutIgnoreInternalServerError() { + RpcEnhancementReporterProperties properties = new RpcEnhancementReporterProperties(); + // Mock Condition + properties.getStatuses().clear(); + properties.setIgnoreInternalServerError(false); + + SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties); + + // Assert + Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false); + Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(true); + Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true); + } + + @Test + public void testApplyWithIgnoreInternalServerError() { + RpcEnhancementReporterProperties properties = new RpcEnhancementReporterProperties(); + // Mock Condition + properties.getStatuses().clear(); + properties.setIgnoreInternalServerError(true); + + SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties); + + // Assert + Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false); + Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false); + Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true); + } + + @Test + public void testApplyWithoutSeries() { + RpcEnhancementReporterProperties properties = new RpcEnhancementReporterProperties(); + // Mock Condition + properties.getStatuses().clear(); + properties.getSeries().clear(); + + SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties); + + // Assert + Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false); + Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false); + Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(true); + } + + @Test + public void testApplyWithSeries() { + RpcEnhancementReporterProperties properties = new RpcEnhancementReporterProperties(); + // Mock Condition + properties.getStatuses().clear(); + properties.getSeries().clear(); + properties.getSeries().add(HttpStatus.Series.CLIENT_ERROR); + + SimplePolarisReporterAdapter adapter = new SimplePolarisReporterAdapter(properties); + + // Assert + Assertions.assertThat(adapter.apply(HttpStatus.OK)).isEqualTo(false); + Assertions.assertThat(adapter.apply(HttpStatus.INTERNAL_SERVER_ERROR)).isEqualTo(false); + Assertions.assertThat(adapter.apply(HttpStatus.BAD_GATEWAY)).isEqualTo(false); + Assertions.assertThat(adapter.apply(HttpStatus.FORBIDDEN)).isEqualTo(true); + } + + /** + * Simple Polaris CircuitBreak Adapter Implements . + */ + public static class SimplePolarisReporterAdapter extends AbstractPolarisReporterAdapter { + + public SimplePolarisReporterAdapter(RpcEnhancementReporterProperties properties) { + super(properties); + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisRestTemplateAutoConfigurationTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfigurationTest.java similarity index 57% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisRestTemplateAutoConfigurationTest.java rename to spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfigurationTest.java index 4bb4458de..fd5afc187 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisRestTemplateAutoConfigurationTest.java +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementAutoConfigurationTest.java @@ -13,19 +13,20 @@ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. - * */ -package com.tencent.cloud.polaris.circuitbreaker; +package com.tencent.cloud.rpc.enhancement.config; -import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerAutoConfiguration; -import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisRestTemplateModifier; -import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisRestTemplateResponseErrorHandler; import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration; +import com.tencent.cloud.rpc.enhancement.feign.EnhancedFeignBeanPostProcessor; +import com.tencent.cloud.rpc.enhancement.feign.plugin.reporter.ExceptionPolarisReporter; +import com.tencent.cloud.rpc.enhancement.feign.plugin.reporter.SuccessPolarisReporter; +import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateModifier; +import com.tencent.cloud.rpc.enhancement.resttemplate.EnhancedRestTemplateReporter; +import com.tencent.polaris.api.core.ConsumerAPI; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.context.annotation.Bean; @@ -35,31 +36,33 @@ import org.springframework.web.client.RestTemplate; import static org.assertj.core.api.Assertions.assertThat; /** - * Test For {@link PolarisCircuitBreakerAutoConfiguration} . + * Test For {@link RpcEnhancementAutoConfiguration}. * - * @author Palmer Xu 2022-06-28 + * @author Haotian Zhang, wh, Palmer Xu */ -public class PolarisRestTemplateAutoConfigurationTest { +public class RpcEnhancementAutoConfigurationTest { private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() .withConfiguration(AutoConfigurations.of( - PolarisRestTemplateAutoConfigurationTester.class, PolarisContextAutoConfiguration.class, - PolarisCircuitBreakerAutoConfiguration.class)) + RpcEnhancementAutoConfiguration.class, + PolarisRestTemplateAutoConfigurationTester.class)) .withPropertyValues("spring.cloud.polaris.circuitbreaker.enabled=true"); @Test - public void testInitialization() { - this.contextRunner - .run(context -> { - assertThat(context).hasSingleBean(PolarisRestTemplateModifier.class); - assertThat(context).hasSingleBean(PolarisRestTemplateResponseErrorHandler.class); - }); + public void testDefaultInitialization() { + this.contextRunner.run(context -> { + assertThat(context).hasSingleBean(ConsumerAPI.class); + assertThat(context).hasSingleBean(EnhancedFeignBeanPostProcessor.class); + assertThat(context).hasSingleBean(SuccessPolarisReporter.class); + assertThat(context).hasSingleBean(ExceptionPolarisReporter.class); + assertThat(context).hasSingleBean(EnhancedRestTemplateModifier.class); + assertThat(context).hasSingleBean(EnhancedRestTemplateReporter.class); + }); } @Configuration @EnableAutoConfiguration - @AutoConfigureBefore(PolarisCircuitBreakerAutoConfiguration.class) static class PolarisRestTemplateAutoConfigurationTester { @Bean diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementReporterPropertiesTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementReporterPropertiesTest.java new file mode 100644 index 000000000..48c61233b --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/config/RpcEnhancementReporterPropertiesTest.java @@ -0,0 +1,64 @@ +/* + * 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.config; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.http.HttpStatus.MOVED_PERMANENTLY; +import static org.springframework.http.HttpStatus.MULTIPLE_CHOICES; +import static org.springframework.http.HttpStatus.Series.CLIENT_ERROR; +import static org.springframework.http.HttpStatus.Series.SERVER_ERROR; + +/** + * Test For {@link RpcEnhancementReporterProperties}. + * + * @author Haotian Zhang + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = RpcEnhancementReporterPropertiesTest.TestApplication.class) +@ActiveProfiles("test") +public class RpcEnhancementReporterPropertiesTest { + + @Autowired + private RpcEnhancementReporterProperties rpcEnhancementReporterProperties; + + @Test + public void testDefaultInitialization() { + assertThat(rpcEnhancementReporterProperties).isNotNull(); + assertThat(rpcEnhancementReporterProperties.isIgnoreInternalServerError()).isFalse(); + assertThat(rpcEnhancementReporterProperties.getSeries()).isNotEmpty(); + assertThat(rpcEnhancementReporterProperties.getSeries().get(0)).isEqualTo(CLIENT_ERROR); + assertThat(rpcEnhancementReporterProperties.getSeries().get(1)).isEqualTo(SERVER_ERROR); + assertThat(rpcEnhancementReporterProperties.getStatuses()).isNotEmpty(); + assertThat(rpcEnhancementReporterProperties.getStatuses().get(0)).isEqualTo(MULTIPLE_CHOICES); + assertThat(rpcEnhancementReporterProperties.getStatuses().get(1)).isEqualTo(MOVED_PERMANENTLY); + } + + @SpringBootApplication + protected static class TestApplication { + + } +} diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignBeanPostProcessorTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignBeanPostProcessorTest.java similarity index 68% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignBeanPostProcessorTest.java rename to spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignBeanPostProcessorTest.java index 3ff260567..b22b7c189 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignBeanPostProcessorTest.java +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignBeanPostProcessorTest.java @@ -15,9 +15,8 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.circuitbreaker.feign; +package com.tencent.cloud.rpc.enhancement.feign; -import com.tencent.polaris.api.core.ConsumerAPI; import feign.Client; import org.junit.Before; import org.junit.Test; @@ -35,19 +34,17 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; /** - * Test for {@link PolarisFeignBeanPostProcessor}. + * Test for {@link EnhancedFeignBeanPostProcessor}. * * @author Haotian Zhang */ -public class PolarisFeignBeanPostProcessorTest { +public class EnhancedFeignBeanPostProcessorTest { - private PolarisFeignBeanPostProcessor polarisFeignBeanPostProcessor; + private EnhancedFeignBeanPostProcessor enhancedFeignBeanPostProcessor; @Before public void setUp() { - ConsumerAPI consumerAPI = mock(ConsumerAPI.class); - - polarisFeignBeanPostProcessor = new PolarisFeignBeanPostProcessor(consumerAPI); + enhancedFeignBeanPostProcessor = new EnhancedFeignBeanPostProcessor(null); } @Test @@ -66,24 +63,24 @@ public class PolarisFeignBeanPostProcessorTest { } return null; }).when(beanFactory).getBean(any(Class.class)); - polarisFeignBeanPostProcessor.setBeanFactory(beanFactory); + enhancedFeignBeanPostProcessor.setBeanFactory(beanFactory); // isNeedWrap(bean) == false Object bean1 = new Object(); - Object bean = polarisFeignBeanPostProcessor.postProcessBeforeInitialization(bean1, "bean1"); + Object bean = enhancedFeignBeanPostProcessor.postProcessBeforeInitialization(bean1, "bean1"); assertThat(bean).isNotInstanceOfAny( - PolarisFeignClient.class, - PolarisFeignBlockingLoadBalancerClient.class); + EnhancedFeignClient.class, + EnhancedFeignBlockingLoadBalancerClient.class); // bean instanceOf Client.class Client bean2 = mock(Client.class); - bean = polarisFeignBeanPostProcessor.postProcessBeforeInitialization(bean2, "bean2"); - assertThat(bean).isInstanceOf(PolarisFeignClient.class); + bean = enhancedFeignBeanPostProcessor.postProcessBeforeInitialization(bean2, "bean2"); + assertThat(bean).isInstanceOf(EnhancedFeignClient.class); // bean instanceOf FeignBlockingLoadBalancerClient.class - FeignBlockingLoadBalancerClient bean3 = mock(FeignBlockingLoadBalancerClient.class); - doReturn(mock(Client.class)).when(bean3).getDelegate(); - bean = polarisFeignBeanPostProcessor.postProcessBeforeInitialization(bean3, "bean3"); - assertThat(bean).isInstanceOf(PolarisFeignBlockingLoadBalancerClient.class); + FeignBlockingLoadBalancerClient bean4 = mock(FeignBlockingLoadBalancerClient.class); + doReturn(mock(Client.class)).when(bean4).getDelegate(); + bean = enhancedFeignBeanPostProcessor.postProcessBeforeInitialization(bean4, "bean4"); + assertThat(bean).isInstanceOf(EnhancedFeignBlockingLoadBalancerClient.class); } } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignBlockingLoadBalancerClientTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignBlockingLoadBalancerClientTest.java similarity index 79% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignBlockingLoadBalancerClientTest.java rename to spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignBlockingLoadBalancerClientTest.java index 71708d9dc..584e453ff 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignBlockingLoadBalancerClientTest.java +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignBlockingLoadBalancerClientTest.java @@ -15,22 +15,22 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.circuitbreaker.feign; +package com.tencent.cloud.rpc.enhancement.feign; import org.assertj.core.api.Assertions; import org.junit.Test; /** - * Test for {@link PolarisFeignBlockingLoadBalancerClient}. + * Test for {@link EnhancedFeignBlockingLoadBalancerClient}. * * @author Haotian Zhang */ -public class PolarisFeignBlockingLoadBalancerClientTest { +public class EnhancedFeignBlockingLoadBalancerClientTest { @Test public void testConstructor() { try { - new PolarisFeignBlockingLoadBalancerClient(null, null, null, null); + new EnhancedFeignBlockingLoadBalancerClient(null, null, null, null); } catch (Exception e) { Assertions.fail("Exception encountered.", e); diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClientTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClientTest.java similarity index 58% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClientTest.java rename to spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClientTest.java index a3228f779..6f8067beb 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/feign/PolarisFeignClientTest.java +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/EnhancedFeignClientTest.java @@ -15,13 +15,16 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.circuitbreaker.feign; +package com.tencent.cloud.rpc.enhancement.feign; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import com.google.common.collect.Maps; -import com.tencent.polaris.api.core.ConsumerAPI; -import com.tencent.polaris.api.rpc.ServiceCallResult; +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext; +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPlugin; +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType; import feign.Client; import feign.Request; import feign.RequestTemplate; @@ -39,23 +42,22 @@ import static org.assertj.core.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; /** - * Test for {@link PolarisFeignClient}. + * Test for {@link EnhancedFeignClient}. * * @author Haotian Zhang */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = PolarisFeignClientTest.TestApplication.class, +@SpringBootTest(classes = EnhancedFeignClientTest.TestApplication.class, properties = {"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp"}) -public class PolarisFeignClientTest { +public class EnhancedFeignClientTest { @Test public void testConstructor() { try { - new PolarisFeignClient(null, null); + new EnhancedFeignClient(null, null); fail("NullPointerException should be thrown."); } catch (Throwable e) { @@ -64,16 +66,15 @@ public class PolarisFeignClientTest { } try { - new PolarisFeignClient(mock(Client.class), null); - fail("NullPointerException should be thrown."); + new EnhancedFeignClient(mock(Client.class), null); } catch (Throwable e) { - assertThat(e).isInstanceOf(NullPointerException.class); - assertThat(e.getMessage()).isEqualTo("CircuitBreakAPI"); + fail("Exception encountered.", e); } + List enhancedFeignPlugins = getMockEnhancedFeignPlugins(); try { - assertThat(new PolarisFeignClient(mock(Client.class), mock(ConsumerAPI.class))).isInstanceOf(PolarisFeignClient.class); + new EnhancedFeignClient(mock(Client.class), enhancedFeignPlugins); } catch (Throwable e) { fail("Exception encountered.", e); @@ -95,10 +96,6 @@ public class PolarisFeignClientTest { throw new IOException("Mock exception."); }).when(delegate).execute(any(Request.class), nullable(Request.Options.class)); - // mock ConsumerAPI.class - ConsumerAPI consumerAPI = mock(ConsumerAPI.class); - doNothing().when(consumerAPI).updateServiceCallResult(any(ServiceCallResult.class)); - // mock target Target target = Target.EmptyTarget.create(Object.class); @@ -106,7 +103,7 @@ public class PolarisFeignClientTest { RequestTemplate requestTemplate = new RequestTemplate(); requestTemplate.feignTarget(target); - PolarisFeignClient polarisFeignClient = new PolarisFeignClient(delegate, consumerAPI); + EnhancedFeignClient polarisFeignClient = new EnhancedFeignClient(delegate, getMockEnhancedFeignPlugins()); // 200 Response response = polarisFeignClient.execute(Request.create(Request.HttpMethod.GET, "http://localhost:8080/test", @@ -130,6 +127,101 @@ public class PolarisFeignClientTest { } } + private List getMockEnhancedFeignPlugins() { + List enhancedFeignPlugins = new ArrayList<>(); + + enhancedFeignPlugins.add(new EnhancedFeignPlugin() { + @Override + public EnhancedFeignPluginType getType() { + return EnhancedFeignPluginType.PRE; + } + + @Override + public void run(EnhancedFeignContext context) { + + } + + @Override + public void handlerThrowable(EnhancedFeignContext context, Throwable throwable) { + + } + + @Override + public int getOrder() { + return 0; + } + }); + + enhancedFeignPlugins.add(new EnhancedFeignPlugin() { + @Override + public EnhancedFeignPluginType getType() { + return EnhancedFeignPluginType.POST; + } + + @Override + public void run(EnhancedFeignContext context) { + + } + + @Override + public void handlerThrowable(EnhancedFeignContext context, Throwable throwable) { + + } + + @Override + public int getOrder() { + return 0; + } + }); + + enhancedFeignPlugins.add(new EnhancedFeignPlugin() { + @Override + public EnhancedFeignPluginType getType() { + return EnhancedFeignPluginType.EXCEPTION; + } + + @Override + public void run(EnhancedFeignContext context) { + + } + + @Override + public void handlerThrowable(EnhancedFeignContext context, Throwable throwable) { + + } + + @Override + public int getOrder() { + return 0; + } + }); + + enhancedFeignPlugins.add(new EnhancedFeignPlugin() { + @Override + public EnhancedFeignPluginType getType() { + return EnhancedFeignPluginType.FINALLY; + } + + @Override + public void run(EnhancedFeignContext context) { + + } + + @Override + public void handlerThrowable(EnhancedFeignContext context, Throwable throwable) { + + } + + @Override + public int getOrder() { + return 0; + } + }); + + return enhancedFeignPlugins; + + } + @SpringBootApplication protected static class TestApplication { diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/EnhancedFeignContextTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/EnhancedFeignContextTest.java new file mode 100644 index 000000000..0d3078a6c --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/EnhancedFeignContextTest.java @@ -0,0 +1,46 @@ +/* + * 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.feign.plugin; + +import feign.Request; +import feign.Response; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Test for {@link EnhancedFeignContext}. + * + * @author Haotian Zhang + */ +public class EnhancedFeignContextTest { + + @Test + public void testGetAndSet() { + EnhancedFeignContext enhancedFeignContext = new EnhancedFeignContext(); + enhancedFeignContext.setRequest(mock(Request.class)); + enhancedFeignContext.setOptions(mock(Request.Options.class)); + enhancedFeignContext.setResponse(mock(Response.class)); + enhancedFeignContext.setException(mock(Exception.class)); + assertThat(enhancedFeignContext.getRequest()).isNotNull(); + assertThat(enhancedFeignContext.getOptions()).isNotNull(); + assertThat(enhancedFeignContext.getResponse()).isNotNull(); + assertThat(enhancedFeignContext.getException()).isNotNull(); + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/ExceptionPolarisReporterTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/ExceptionPolarisReporterTest.java new file mode 100644 index 000000000..d47c7f2c5 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/ExceptionPolarisReporterTest.java @@ -0,0 +1,101 @@ +/* + * 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.feign.plugin.reporter; + +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext; +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType; +import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.polaris.api.pojo.RetStatus; +import feign.Request; +import feign.Response; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; + +/** + * Test for {@link ExceptionPolarisReporter}. + * + * @author Haotian Zhang + */ +@RunWith(MockitoJUnitRunner.class) +public class ExceptionPolarisReporterTest { + + private static MockedStatic mockedReporterUtils; + @Mock + private ConsumerAPI consumerAPI; + @InjectMocks + private ExceptionPolarisReporter exceptionPolarisReporter; + + @BeforeClass + public static void beforeClass() { + mockedReporterUtils = Mockito.mockStatic(ReporterUtils.class); + mockedReporterUtils.when(() -> ReporterUtils.createServiceCallResult(any(Request.class), any(RetStatus.class))) + .thenReturn(null); + } + + @AfterClass + public static void afterClass() { + mockedReporterUtils.close(); + } + + @Test + public void testGetName() { + assertThat(exceptionPolarisReporter.getName()).isEqualTo(ExceptionPolarisReporter.class.getName()); + } + + @Test + public void testType() { + assertThat(exceptionPolarisReporter.getType()).isEqualTo(EnhancedFeignPluginType.EXCEPTION); + } + + @Test + public void testRun() { + // mock request + Request request = mock(Request.class); + // mock response + Response response = mock(Response.class); + + EnhancedFeignContext context = new EnhancedFeignContext(); + context.setRequest(request); + context.setResponse(response); + exceptionPolarisReporter.run(context); + } + + @Test + public void testHandlerThrowable() { + // mock request + Request request = mock(Request.class); + // mock response + Response response = mock(Response.class); + + EnhancedFeignContext context = new EnhancedFeignContext(); + context.setRequest(request); + context.setResponse(response); + exceptionPolarisReporter.handlerThrowable(context, new RuntimeException("Mock exception.")); + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/ReporterUtilsTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/ReporterUtilsTest.java new file mode 100644 index 000000000..de60c99b8 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/ReporterUtilsTest.java @@ -0,0 +1,96 @@ +/* + * 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.feign.plugin.reporter; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.polaris.api.pojo.RetStatus; +import com.tencent.polaris.api.rpc.ServiceCallResult; +import feign.Request; +import feign.RequestTemplate; +import feign.Target; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST; +import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +/** + * Test for {@link ReporterUtils}. + * + * @author Haotian Zhang + */ +@RunWith(MockitoJUnitRunner.class) +public class ReporterUtilsTest { + + private static MockedStatic mockedApplicationContextAwareUtils; + + @BeforeClass + public static void beforeClass() { + mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn("unit-test"); + } + + @AfterClass + public static void afterClass() { + mockedApplicationContextAwareUtils.close(); + } + + @Before + public void setUp() { + MetadataContext.LOCAL_NAMESPACE = NAMESPACE_TEST; + MetadataContext.LOCAL_SERVICE = SERVICE_PROVIDER; + } + + @Test + public void testCreateServiceCallResult() { + // mock target + Target target = mock(Target.class); + doReturn(SERVICE_PROVIDER).when(target).name(); + + // mock RequestTemplate.class + RequestTemplate requestTemplate = new RequestTemplate(); + requestTemplate.feignTarget(target); + + // mock request + Request request = mock(Request.class); + doReturn(requestTemplate).when(request).requestTemplate(); + doReturn("http://1.1.1.1:2345/path").when(request).url(); + + ServiceCallResult serviceCallResult = ReporterUtils.createServiceCallResult(request, RetStatus.RetSuccess); + assertThat(serviceCallResult.getNamespace()).isEqualTo(NAMESPACE_TEST); + assertThat(serviceCallResult.getService()).isEqualTo(SERVICE_PROVIDER); + assertThat(serviceCallResult.getHost()).isEqualTo("1.1.1.1"); + assertThat(serviceCallResult.getPort()).isEqualTo(2345); + assertThat(serviceCallResult.getRetStatus()).isEqualTo(RetStatus.RetSuccess); + assertThat(serviceCallResult.getMethod()).isEqualTo("/path"); + assertThat(serviceCallResult.getCallerService().getNamespace()).isEqualTo(NAMESPACE_TEST); + assertThat(serviceCallResult.getCallerService().getService()).isEqualTo(SERVICE_PROVIDER); + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporterTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporterTest.java new file mode 100644 index 000000000..b3e28a5ca --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/feign/plugin/reporter/SuccessPolarisReporterTest.java @@ -0,0 +1,103 @@ +/* + * 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.feign.plugin.reporter; + +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignContext; +import com.tencent.cloud.rpc.enhancement.feign.plugin.EnhancedFeignPluginType; +import com.tencent.polaris.api.core.ConsumerAPI; +import com.tencent.polaris.api.pojo.RetStatus; +import feign.Request; +import feign.Response; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +/** + * Test for {@link SuccessPolarisReporter}. + * + * @author Haotian Zhang + */ +@RunWith(MockitoJUnitRunner.Silent.class) +public class SuccessPolarisReporterTest { + + private static MockedStatic mockedReporterUtils; + @Mock + private ConsumerAPI consumerAPI; + @InjectMocks + private SuccessPolarisReporter successPolarisReporter; + + @BeforeClass + public static void beforeClass() { + mockedReporterUtils = Mockito.mockStatic(ReporterUtils.class); + mockedReporterUtils.when(() -> ReporterUtils.createServiceCallResult(any(Request.class), any(RetStatus.class))) + .thenReturn(null); + } + + @AfterClass + public static void afterClass() { + mockedReporterUtils.close(); + } + + @Test + public void testGetName() { + assertThat(successPolarisReporter.getName()).isEqualTo(SuccessPolarisReporter.class.getName()); + } + + @Test + public void testType() { + assertThat(successPolarisReporter.getType()).isEqualTo(EnhancedFeignPluginType.POST); + } + + @Test + public void testRun() { + // mock request + Request request = mock(Request.class); + // mock response + Response response = mock(Response.class); + doReturn(502).when(response).status(); + + EnhancedFeignContext context = new EnhancedFeignContext(); + context.setRequest(request); + context.setResponse(response); + successPolarisReporter.run(context); + } + + @Test + public void testHandlerThrowable() { + // mock request + Request request = mock(Request.class); + // mock response + Response response = mock(Response.class); + + EnhancedFeignContext context = new EnhancedFeignContext(); + context.setRequest(request); + context.setResponse(response); + successPolarisReporter.handlerThrowable(context, new RuntimeException("Mock exception.")); + } +} diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateResponseErrorHandlerTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporterTest.java similarity index 79% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateResponseErrorHandlerTest.java rename to spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporterTest.java index 6cb630e37..7d54b6b8c 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateResponseErrorHandlerTest.java +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/EnhancedRestTemplateReporterTest.java @@ -15,13 +15,14 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.circuitbreaker.resttemplate; +package com.tencent.cloud.rpc.enhancement.resttemplate; import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; +import com.tencent.cloud.rpc.enhancement.config.RpcEnhancementReporterProperties; import com.tencent.polaris.api.core.ConsumerAPI; import org.junit.Test; import org.junit.runner.RunWith; @@ -35,19 +36,20 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** - * Test For {@link PolarisRestTemplateResponseErrorHandler}. + * Test For {@link EnhancedRestTemplateReporter}. * * @author wh 2022/6/22 */ @RunWith(SpringRunner.class) -@SpringBootTest(classes = PolarisRestTemplateResponseErrorHandlerTest.TestApplication.class, +@SpringBootTest(classes = EnhancedRestTemplateReporterTest.TestApplication.class, properties = {"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp"}) -public class PolarisRestTemplateResponseErrorHandlerTest { +public class EnhancedRestTemplateReporterTest { @Test public void handleError() throws Exception { ConsumerAPI consumerAPI = mock(ConsumerAPI.class); - PolarisRestTemplateResponseErrorHandler polarisRestTemplateResponseErrorHandler = new PolarisRestTemplateResponseErrorHandler(consumerAPI, null); + EnhancedRestTemplateReporter enhancedRestTemplateReporter = + new EnhancedRestTemplateReporter(mock(RpcEnhancementReporterProperties.class), consumerAPI, null); URI uri = mock(URI.class); when(uri.getPath()).thenReturn("/test"); when(uri.getHost()).thenReturn("host"); @@ -58,7 +60,7 @@ public class PolarisRestTemplateResponseErrorHandlerTest { when(url.getPort()).thenReturn(8080); when(httpURLConnection.getResponseCode()).thenReturn(200); SimpleClientHttpResponseTest clientHttpResponse = new SimpleClientHttpResponseTest(httpURLConnection); - polarisRestTemplateResponseErrorHandler.handleError(uri, HttpMethod.GET, clientHttpResponse); + enhancedRestTemplateReporter.handleError(uri, HttpMethod.GET, clientHttpResponse); when(consumerAPI.unWatchService(null)).thenReturn(true); } diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/SimpleClientHttpResponseTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/SimpleClientHttpResponseTest.java similarity index 97% rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/SimpleClientHttpResponseTest.java rename to spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/SimpleClientHttpResponseTest.java index d8ac018cf..0899da7a1 100644 --- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/SimpleClientHttpResponseTest.java +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/resttemplate/SimpleClientHttpResponseTest.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations under the License. */ -package com.tencent.cloud.polaris.circuitbreaker.resttemplate; +package com.tencent.cloud.rpc.enhancement.resttemplate; import java.io.IOException; import java.io.InputStream; diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfigurationTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfigurationTest.java new file mode 100644 index 000000000..c6c2ed132 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesAutoConfigurationTest.java @@ -0,0 +1,45 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.rpc.enhancement.stat.config; + +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link PolarisStatPropertiesAutoConfiguration}. + * + * @author Haotian Zhang + */ +public class PolarisStatPropertiesAutoConfigurationTest { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(PolarisStatPropertiesAutoConfiguration.class)); + + @Test + public void testDefaultInitialization() { + this.contextRunner.run(context -> { + assertThat(context).hasSingleBean(PolarisStatPropertiesAutoConfiguration.class); + assertThat(context).hasSingleBean(PolarisStatProperties.class); + assertThat(context).hasSingleBean(StatConfigModifier.class); + }); + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesBootstrapConfigurationTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesBootstrapConfigurationTest.java new file mode 100644 index 000000000..acb8420df --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesBootstrapConfigurationTest.java @@ -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.rpc.enhancement.stat.config; + +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link PolarisStatPropertiesBootstrapConfiguration}. + * + * @author Haotian Zhang + */ +public class PolarisStatPropertiesBootstrapConfigurationTest { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(PolarisStatPropertiesBootstrapConfiguration.class)) + .withPropertyValues("spring.cloud.polaris.enabled=true"); + + @Test + public void testDefaultInitialization() { + this.contextRunner.run(context -> { + assertThat(context).hasSingleBean(PolarisStatPropertiesBootstrapConfiguration.class); + assertThat(context).hasSingleBean(PolarisStatPropertiesAutoConfiguration.class); + assertThat(context).hasSingleBean(PolarisStatProperties.class); + assertThat(context).hasSingleBean(StatConfigModifier.class); + }); + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesTest.java b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesTest.java new file mode 100644 index 000000000..9adc4f65f --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/test/java/com/tencent/cloud/rpc/enhancement/stat/config/PolarisStatPropertiesTest.java @@ -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.rpc.enhancement.stat.config; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for {@link PolarisStatProperties}. + * + * @author Haotian Zhang + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = PolarisStatPropertiesTest.TestApplication.class) +@ActiveProfiles("test") +public class PolarisStatPropertiesTest { + + @Autowired + private PolarisStatProperties polarisStatProperties; + + @Test + public void testDefaultInitialization() { + assertThat(polarisStatProperties).isNotNull(); + assertThat(polarisStatProperties.isEnabled()).isTrue(); + assertThat(polarisStatProperties.getHost()).isNotBlank(); + assertThat(polarisStatProperties.getPort()).isEqualTo(20000); + assertThat(polarisStatProperties.getPath()).isEqualTo("/xxx"); + } + + @SpringBootApplication + protected static class TestApplication { + + } +} diff --git a/spring-cloud-tencent-rpc-enhancement/src/test/resources/application-test.properties b/spring-cloud-tencent-rpc-enhancement/src/test/resources/application-test.properties new file mode 100644 index 000000000..34e566e79 --- /dev/null +++ b/spring-cloud-tencent-rpc-enhancement/src/test/resources/application-test.properties @@ -0,0 +1,8 @@ +spring.cloud.polaris.stat.enabled=true +spring.cloud.polaris.stat.port=20000 +spring.cloud.polaris.stat.path=/xxx +spring.cloud.tencent.rpc-enhancement.reporter.ignore-internal-server-error=false +spring.cloud.tencent.rpc-enhancement.reporter.series[0]=CLIENT_ERROR +spring.cloud.tencent.rpc-enhancement.reporter.series[1]=SERVER_ERROR +spring.cloud.tencent.rpc-enhancement.reporter.statuses[0]=MULTIPLE_CHOICES +spring.cloud.tencent.rpc-enhancement.reporter.statuses[1]=MOVED_PERMANENTLY