[3.2]Use spotless to format the code (#13320)
* Use spotless to format the code Signed-off-by: crazyhzm <crazyhzm@gmail.com> * Support develop with JDK 21 Signed-off-by: crazyhzm <crazyhzm@gmail.com> --------- Signed-off-by: crazyhzm <crazyhzm@gmail.com>
This commit is contained in:
parent
04f134a168
commit
730695a7a2
|
|
@ -13,76 +13,77 @@
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<modelVersion>4.0.0</modelVersion>
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<artifactId>dubbo-build-tools</artifactId>
|
<artifactId>dubbo-build-tools</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.deploy.skip>true</maven.deploy.skip>
|
<maven.deploy.skip>true</maven.deploy.skip>
|
||||||
<spotless-maven-plugin.version>2.40.0</spotless-maven-plugin.version>
|
<spotless-maven-plugin.version>2.40.0</spotless-maven-plugin.version>
|
||||||
<spotless.action>check</spotless.action>
|
<spotless.action>check</spotless.action>
|
||||||
<dubbo-shared-resources.version>1.0.0</dubbo-shared-resources.version>
|
<dubbo-shared-resources.version>1.0.0</dubbo-shared-resources.version>
|
||||||
</properties>
|
<palantirJavaFormat.version>2.38.0</palantirJavaFormat.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
<profile>
|
<profile>
|
||||||
<id>java11+</id>
|
<id>java11+</id>
|
||||||
<activation>
|
<activation>
|
||||||
<jdk>[11,)</jdk>
|
<jdk>[11,)</jdk>
|
||||||
</activation>
|
</activation>
|
||||||
<build>
|
<build>
|
||||||
<!--- newer versions of plugins requires JDK 11 -->
|
<!--- newer versions of plugins requires JDK 11 -->
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>com.diffplug.spotless</groupId>
|
<groupId>com.diffplug.spotless</groupId>
|
||||||
<artifactId>spotless-maven-plugin</artifactId>
|
<artifactId>spotless-maven-plugin</artifactId>
|
||||||
<version>${spotless-maven-plugin.version}</version>
|
<version>${spotless-maven-plugin.version}</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<java>
|
<java>
|
||||||
<palantirJavaFormat />
|
<palantirJavaFormat>
|
||||||
<removeUnusedImports />
|
<version>${palantirJavaFormat.version}</version>
|
||||||
<importOrder>
|
</palantirJavaFormat>
|
||||||
<file>dubbo-importorder.txt</file>
|
<removeUnusedImports />
|
||||||
</importOrder>
|
<importOrder>
|
||||||
<licenseHeader>
|
<file>dubbo-importorder.txt</file>
|
||||||
<file>checkstyle-header.txt</file>
|
</importOrder>
|
||||||
</licenseHeader>
|
<licenseHeader>
|
||||||
</java>
|
<file>checkstyle-header.txt</file>
|
||||||
<pom>
|
</licenseHeader>
|
||||||
<sortPom>
|
</java>
|
||||||
<expandEmptyElements>false</expandEmptyElements>
|
<pom>
|
||||||
<spaceBeforeCloseEmptyElement>true</spaceBeforeCloseEmptyElement>
|
<sortPom>
|
||||||
</sortPom>
|
<expandEmptyElements>false</expandEmptyElements>
|
||||||
</pom>
|
<spaceBeforeCloseEmptyElement>true</spaceBeforeCloseEmptyElement>
|
||||||
<upToDateChecking>
|
</sortPom>
|
||||||
<enabled>true</enabled>
|
</pom>
|
||||||
</upToDateChecking>
|
<upToDateChecking>
|
||||||
</configuration>
|
<enabled>true</enabled>
|
||||||
<dependencies>
|
</upToDateChecking>
|
||||||
<dependency>
|
</configuration>
|
||||||
<groupId>com.alibaba</groupId>
|
<dependencies>
|
||||||
<artifactId>dubbo-shared-resources</artifactId>
|
<dependency>
|
||||||
<version>${dubbo-shared-resources.version}</version>
|
<groupId>com.alibaba</groupId>
|
||||||
</dependency>
|
<artifactId>dubbo-shared-resources</artifactId>
|
||||||
</dependencies>
|
<version>${dubbo-shared-resources.version}</version>
|
||||||
<executions>
|
</dependency>
|
||||||
<execution>
|
</dependencies>
|
||||||
<goals>
|
<executions>
|
||||||
<goal>${spotless.action}</goal>
|
<execution>
|
||||||
</goals>
|
<goals>
|
||||||
<phase>process-sources</phase>
|
<goal>${spotless.action}</goal>
|
||||||
</execution>
|
</goals>
|
||||||
</executions>
|
<phase>process-sources</phase>
|
||||||
</plugin>
|
</execution>
|
||||||
</plugins>
|
</executions>
|
||||||
</build>
|
</plugin>
|
||||||
</profile>
|
</plugins>
|
||||||
</profiles>
|
</build>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
contributor license agreements. See the NOTICE file distributed with
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
|
@ -14,105 +15,104 @@
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<parent>
|
||||||
<parent>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<artifactId>dubbo-parent</artifactId>
|
||||||
<artifactId>dubbo-parent</artifactId>
|
<version>${revision}</version>
|
||||||
<version>${revision}</version>
|
<relativePath>../pom.xml</relativePath>
|
||||||
<relativePath>../pom.xml</relativePath>
|
</parent>
|
||||||
</parent>
|
<artifactId>dubbo-cluster</artifactId>
|
||||||
<artifactId>dubbo-cluster</artifactId>
|
<packaging>jar</packaging>
|
||||||
<packaging>jar</packaging>
|
<name>${project.artifactId}</name>
|
||||||
<name>${project.artifactId}</name>
|
<description>The cluster module of dubbo project</description>
|
||||||
<description>The cluster module of dubbo project</description>
|
<properties>
|
||||||
<properties>
|
<skip_maven_deploy>false</skip_maven_deploy>
|
||||||
<skip_maven_deploy>false</skip_maven_deploy>
|
<nashorn-core.version>15.4</nashorn-core.version>
|
||||||
<nashorn-core.version>15.4</nashorn-core.version>
|
</properties>
|
||||||
</properties>
|
<dependencies>
|
||||||
<dependencies>
|
<dependency>
|
||||||
<dependency>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<artifactId>dubbo-rpc-api</artifactId>
|
||||||
<artifactId>dubbo-rpc-api</artifactId>
|
<version>${project.parent.version}</version>
|
||||||
<version>${project.parent.version}</version>
|
</dependency>
|
||||||
</dependency>
|
<dependency>
|
||||||
<dependency>
|
<groupId>org.yaml</groupId>
|
||||||
<groupId>org.yaml</groupId>
|
<artifactId>snakeyaml</artifactId>
|
||||||
<artifactId>snakeyaml</artifactId>
|
</dependency>
|
||||||
</dependency>
|
<dependency>
|
||||||
<dependency>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<artifactId>dubbo-rpc-injvm</artifactId>
|
||||||
<artifactId>dubbo-rpc-injvm</artifactId>
|
<version>${project.parent.version}</version>
|
||||||
<version>${project.parent.version}</version>
|
<scope>test</scope>
|
||||||
<scope>test</scope>
|
</dependency>
|
||||||
</dependency>
|
<dependency>
|
||||||
<dependency>
|
<groupId>org.apache.curator</groupId>
|
||||||
<groupId>org.apache.curator</groupId>
|
<artifactId>curator-framework</artifactId>
|
||||||
<artifactId>curator-framework</artifactId>
|
<scope>test</scope>
|
||||||
<scope>test</scope>
|
</dependency>
|
||||||
</dependency>
|
<dependency>
|
||||||
<dependency>
|
<groupId>org.apache.zookeeper</groupId>
|
||||||
<groupId>org.apache.zookeeper</groupId>
|
<artifactId>zookeeper</artifactId>
|
||||||
<artifactId>zookeeper</artifactId>
|
<scope>test</scope>
|
||||||
<scope>test</scope>
|
</dependency>
|
||||||
</dependency>
|
<dependency>
|
||||||
<dependency>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<artifactId>dubbo-serialization-hessian2</artifactId>
|
||||||
<artifactId>dubbo-serialization-hessian2</artifactId>
|
<version>${project.parent.version}</version>
|
||||||
<version>${project.parent.version}</version>
|
<scope>test</scope>
|
||||||
<scope>test</scope>
|
</dependency>
|
||||||
</dependency>
|
<dependency>
|
||||||
<dependency>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<artifactId>dubbo-serialization-fastjson2</artifactId>
|
||||||
<artifactId>dubbo-serialization-fastjson2</artifactId>
|
<version>${project.parent.version}</version>
|
||||||
<version>${project.parent.version}</version>
|
<scope>test</scope>
|
||||||
<scope>test</scope>
|
</dependency>
|
||||||
</dependency>
|
<dependency>
|
||||||
<dependency>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<artifactId>dubbo-test-check</artifactId>
|
||||||
<artifactId>dubbo-test-check</artifactId>
|
<version>${project.parent.version}</version>
|
||||||
<version>${project.parent.version}</version>
|
<scope>test</scope>
|
||||||
<scope>test</scope>
|
</dependency>
|
||||||
</dependency>
|
<dependency>
|
||||||
<dependency>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<artifactId>dubbo-metrics-registry</artifactId>
|
||||||
<artifactId>dubbo-metrics-registry</artifactId>
|
<version>${project.parent.version}</version>
|
||||||
<version>${project.parent.version}</version>
|
<scope>compile</scope>
|
||||||
<scope>compile</scope>
|
</dependency>
|
||||||
</dependency>
|
<dependency>
|
||||||
<dependency>
|
<groupId>org.apache.dubbo</groupId>
|
||||||
<groupId>org.apache.dubbo</groupId>
|
<artifactId>dubbo-metrics-default</artifactId>
|
||||||
<artifactId>dubbo-metrics-default</artifactId>
|
<version>${project.parent.version}</version>
|
||||||
<version>${project.parent.version}</version>
|
<optional>true</optional>
|
||||||
<optional>true</optional>
|
</dependency>
|
||||||
</dependency>
|
<dependency>
|
||||||
<dependency>
|
<groupId>io.micrometer</groupId>
|
||||||
<groupId>io.micrometer</groupId>
|
<artifactId>micrometer-tracing-integration-test</artifactId>
|
||||||
<artifactId>micrometer-tracing-integration-test</artifactId>
|
<scope>test</scope>
|
||||||
<scope>test</scope>
|
</dependency>
|
||||||
</dependency>
|
</dependencies>
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
<!--
|
<!--
|
||||||
https://github.com/openjdk/nashorn
|
https://github.com/openjdk/nashorn
|
||||||
Nashorn used to be part of the JDK until Java 14.
|
Nashorn used to be part of the JDK until Java 14.
|
||||||
This project provides a standalone version of Nashorn suitable for use with Java 11 and later.
|
This project provides a standalone version of Nashorn suitable for use with Java 11 and later.
|
||||||
-->
|
-->
|
||||||
<profile>
|
<profile>
|
||||||
<id>nashorn-jdk11</id>
|
<id>nashorn-jdk11</id>
|
||||||
<activation>
|
<activation>
|
||||||
<jdk>[11,)</jdk>
|
<jdk>[11,)</jdk>
|
||||||
</activation>
|
</activation>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openjdk.nashorn</groupId>
|
<groupId>org.openjdk.nashorn</groupId>
|
||||||
<artifactId>nashorn-core</artifactId>
|
<artifactId>nashorn-core</artifactId>
|
||||||
<version>${nashorn-core.version}</version>
|
<version>${nashorn-core.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</profile>
|
</profile>
|
||||||
</profiles>
|
</profiles>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,5 @@ public interface AddressListener {
|
||||||
*/
|
*/
|
||||||
List<URL> notify(List<URL> addresses, URL consumerUrl, Directory registryDirectory);
|
List<URL> notify(List<URL> addresses, URL consumerUrl, Directory registryDirectory);
|
||||||
|
|
||||||
default void destroy(URL consumerUrl, Directory registryDirectory) {
|
default void destroy(URL consumerUrl, Directory registryDirectory) {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,8 @@ public interface Cluster {
|
||||||
if (StringUtils.isEmpty(name)) {
|
if (StringUtils.isEmpty(name)) {
|
||||||
name = Cluster.DEFAULT;
|
name = Cluster.DEFAULT;
|
||||||
}
|
}
|
||||||
return ScopeModelUtil.getApplicationModel(scopeModel).getExtensionLoader(Cluster.class).getExtension(name, wrap);
|
return ScopeModelUtil.getApplicationModel(scopeModel)
|
||||||
|
.getExtensionLoader(Cluster.class)
|
||||||
|
.getExtension(name, wrap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ public interface Configurator extends Comparable<Configurator> {
|
||||||
*/
|
*/
|
||||||
URL configure(URL url);
|
URL configure(URL url);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert override urls to map for use when re-refer. Send all rules every time, the urls will be reassembled and
|
* Convert override urls to map for use when re-refer. Send all rules every time, the urls will be reassembled and
|
||||||
* calculated
|
* calculated
|
||||||
|
|
@ -73,7 +72,9 @@ public interface Configurator extends Comparable<Configurator> {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfiguratorFactory configuratorFactory = urls.get(0).getOrDefaultApplicationModel().getExtensionLoader(ConfiguratorFactory.class)
|
ConfiguratorFactory configuratorFactory = urls.get(0)
|
||||||
|
.getOrDefaultApplicationModel()
|
||||||
|
.getExtensionLoader(ConfiguratorFactory.class)
|
||||||
.getAdaptiveExtension();
|
.getAdaptiveExtension();
|
||||||
|
|
||||||
List<Configurator> configurators = new ArrayList<>(urls.size());
|
List<Configurator> configurators = new ArrayList<>(urls.size());
|
||||||
|
|
@ -83,7 +84,8 @@ public interface Configurator extends Comparable<Configurator> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Map<String, String> override = new HashMap<>(url.getParameters());
|
Map<String, String> override = new HashMap<>(url.getParameters());
|
||||||
//The anyhost parameter of override may be added automatically, it can't change the judgement of changing url
|
// The anyhost parameter of override may be added automatically, it can't change the judgement of changing
|
||||||
|
// url
|
||||||
override.remove(ANYHOST_KEY);
|
override.remove(ANYHOST_KEY);
|
||||||
if (CollectionUtils.isEmptyMap(override)) {
|
if (CollectionUtils.isEmptyMap(override)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -36,5 +36,4 @@ public interface ConfiguratorFactory {
|
||||||
*/
|
*/
|
||||||
@Adaptive(CommonConstants.PROTOCOL_KEY)
|
@Adaptive(CommonConstants.PROTOCOL_KEY)
|
||||||
Configurator getConfigurator(URL url);
|
Configurator getConfigurator(URL url);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,6 @@ public interface Constants {
|
||||||
|
|
||||||
String OVERRIDE_PROVIDERS_KEY = "providerAddresses";
|
String OVERRIDE_PROVIDERS_KEY = "providerAddresses";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* key for router type, for e.g., "script"/"file", corresponding to ScriptRouterFactory.NAME, FileRouterFactory.NAME
|
* key for router type, for e.g., "script"/"file", corresponding to ScriptRouterFactory.NAME, FileRouterFactory.NAME
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -46,5 +46,4 @@ public interface LoadBalance {
|
||||||
*/
|
*/
|
||||||
@Adaptive("loadbalance")
|
@Adaptive("loadbalance")
|
||||||
<T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
|
<T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,5 +22,4 @@ import org.apache.dubbo.common.extension.SPI;
|
||||||
public interface Merger<T> {
|
public interface Merger<T> {
|
||||||
|
|
||||||
T merge(T... items);
|
T merge(T... items);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,9 @@ public interface ProviderURLMergeProcessor {
|
||||||
*/
|
*/
|
||||||
URL mergeUrl(URL remoteUrl, Map<String, String> localParametersMap);
|
URL mergeUrl(URL remoteUrl, Map<String, String> localParametersMap);
|
||||||
|
|
||||||
default Map<String, String> mergeLocalParams(Map<String, String> localMap) { return localMap; }
|
default Map<String, String> mergeLocalParams(Map<String, String> localMap) {
|
||||||
|
return localMap;
|
||||||
|
}
|
||||||
|
|
||||||
default boolean accept(URL providerUrl, Map<String, String> localParametersMap) {
|
default boolean accept(URL providerUrl, Map<String, String> localParametersMap) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -68,8 +68,8 @@ public interface Router extends Comparable<Router> {
|
||||||
* @return state with route result
|
* @return state with route result
|
||||||
* @throws RpcException
|
* @throws RpcException
|
||||||
*/
|
*/
|
||||||
default <T> RouterResult<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation,
|
default <T> RouterResult<Invoker<T>> route(
|
||||||
boolean needToPrintMessage) throws RpcException {
|
List<Invoker<T>> invokers, URL url, Invocation invocation, boolean needToPrintMessage) throws RpcException {
|
||||||
return new RouterResult<>(route(invokers, url, invocation));
|
return new RouterResult<>(route(invokers, url, invocation));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,9 +80,7 @@ public interface Router extends Comparable<Router> {
|
||||||
* @param invokers invoker list
|
* @param invokers invoker list
|
||||||
* @param <T> invoker's type
|
* @param <T> invoker's type
|
||||||
*/
|
*/
|
||||||
default <T> void notify(List<Invoker<T>> invokers) {
|
default <T> void notify(List<Invoker<T>> invokers) {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To decide whether this router need to execute every time an RPC comes or should only execute when addresses or
|
* To decide whether this router need to execute every time an RPC comes or should only execute when addresses or
|
||||||
|
|
@ -109,7 +107,7 @@ public interface Router extends Comparable<Router> {
|
||||||
int getPriority();
|
int getPriority();
|
||||||
|
|
||||||
default void stop() {
|
default void stop() {
|
||||||
//do nothing by default
|
// do nothing by default
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,6 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.dubbo.rpc.cluster;
|
package org.apache.dubbo.rpc.cluster;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
import org.apache.dubbo.common.config.ConfigurationUtils;
|
import org.apache.dubbo.common.config.ConfigurationUtils;
|
||||||
import org.apache.dubbo.common.constants.LoggerCodeConstants;
|
import org.apache.dubbo.common.constants.LoggerCodeConstants;
|
||||||
|
|
@ -36,6 +30,12 @@ import org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;
|
||||||
import org.apache.dubbo.rpc.model.ModuleModel;
|
import org.apache.dubbo.rpc.model.ModuleModel;
|
||||||
import org.apache.dubbo.rpc.model.ScopeModelUtil;
|
import org.apache.dubbo.rpc.model.ScopeModelUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.apache.dubbo.rpc.cluster.Constants.ROUTER_KEY;
|
import static org.apache.dubbo.rpc.cluster.Constants.ROUTER_KEY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -52,31 +52,30 @@ public class RouterChain<T> {
|
||||||
public static <T> RouterChain<T> buildChain(Class<T> interfaceClass, URL url) {
|
public static <T> RouterChain<T> buildChain(Class<T> interfaceClass, URL url) {
|
||||||
SingleRouterChain<T> chain1 = buildSingleChain(interfaceClass, url);
|
SingleRouterChain<T> chain1 = buildSingleChain(interfaceClass, url);
|
||||||
SingleRouterChain<T> chain2 = buildSingleChain(interfaceClass, url);
|
SingleRouterChain<T> chain2 = buildSingleChain(interfaceClass, url);
|
||||||
return new RouterChain<>(new SingleRouterChain[]{chain1, chain2});
|
return new RouterChain<>(new SingleRouterChain[] {chain1, chain2});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> SingleRouterChain<T> buildSingleChain(Class<T> interfaceClass, URL url) {
|
public static <T> SingleRouterChain<T> buildSingleChain(Class<T> interfaceClass, URL url) {
|
||||||
ModuleModel moduleModel = url.getOrDefaultModuleModel();
|
ModuleModel moduleModel = url.getOrDefaultModuleModel();
|
||||||
|
|
||||||
List<RouterFactory> extensionFactories = moduleModel.getExtensionLoader(RouterFactory.class)
|
List<RouterFactory> extensionFactories =
|
||||||
.getActivateExtension(url, ROUTER_KEY);
|
moduleModel.getExtensionLoader(RouterFactory.class).getActivateExtension(url, ROUTER_KEY);
|
||||||
|
|
||||||
List<Router> routers = extensionFactories.stream()
|
List<Router> routers = extensionFactories.stream()
|
||||||
.map(factory -> factory.getRouter(url))
|
.map(factory -> factory.getRouter(url))
|
||||||
.sorted(Router::compareTo)
|
.sorted(Router::compareTo)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
List<StateRouter<T>> stateRouters = moduleModel
|
List<StateRouter<T>> stateRouters =
|
||||||
.getExtensionLoader(StateRouterFactory.class)
|
moduleModel.getExtensionLoader(StateRouterFactory.class).getActivateExtension(url, ROUTER_KEY).stream()
|
||||||
.getActivateExtension(url, ROUTER_KEY)
|
.map(factory -> factory.getRouter(interfaceClass, url))
|
||||||
.stream()
|
.collect(Collectors.toList());
|
||||||
.map(factory -> factory.getRouter(interfaceClass, url))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
|
boolean shouldFailFast = Boolean.parseBoolean(
|
||||||
|
ConfigurationUtils.getProperty(moduleModel, Constants.SHOULD_FAIL_FAST_KEY, "true"));
|
||||||
|
|
||||||
boolean shouldFailFast = Boolean.parseBoolean(ConfigurationUtils.getProperty(moduleModel, Constants.SHOULD_FAIL_FAST_KEY, "true"));
|
RouterSnapshotSwitcher routerSnapshotSwitcher =
|
||||||
|
ScopeModelUtil.getFrameworkModel(moduleModel).getBeanFactory().getBean(RouterSnapshotSwitcher.class);
|
||||||
RouterSnapshotSwitcher routerSnapshotSwitcher = ScopeModelUtil.getFrameworkModel(moduleModel).getBeanFactory().getBean(RouterSnapshotSwitcher.class);
|
|
||||||
|
|
||||||
return new SingleRouterChain<>(routers, stateRouters, shouldFailFast, routerSnapshotSwitcher);
|
return new SingleRouterChain<>(routers, stateRouters, shouldFailFast, routerSnapshotSwitcher);
|
||||||
}
|
}
|
||||||
|
|
@ -106,9 +105,9 @@ public class RouterChain<T> {
|
||||||
// If `availableInvokers` is created from origin invokers => use backup chain
|
// If `availableInvokers` is created from origin invokers => use backup chain
|
||||||
// If `availableInvokers` is created from newly invokers => use main chain
|
// If `availableInvokers` is created from newly invokers => use main chain
|
||||||
BitList<Invoker<T>> notifying = notifyingInvokers.get();
|
BitList<Invoker<T>> notifying = notifyingInvokers.get();
|
||||||
if (notifying != null &&
|
if (notifying != null
|
||||||
currentChain == backupChain &&
|
&& currentChain == backupChain
|
||||||
availableInvokers.getOriginList() == notifying.getOriginList()) {
|
&& availableInvokers.getOriginList() == notifying.getOriginList()) {
|
||||||
return mainChain;
|
return mainChain;
|
||||||
}
|
}
|
||||||
return currentChain;
|
return currentChain;
|
||||||
|
|
@ -140,7 +139,8 @@ public class RouterChain<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh main chain.
|
// Refresh main chain.
|
||||||
// No one can request to use main chain. `currentChain` is backup chain. `route` method cannot access main chain.
|
// No one can request to use main chain. `currentChain` is backup chain. `route` method cannot access main
|
||||||
|
// chain.
|
||||||
try {
|
try {
|
||||||
// Lock main chain to wait all invocation end
|
// Lock main chain to wait all invocation end
|
||||||
// To wait until no one is using main chain.
|
// To wait until no one is using main chain.
|
||||||
|
|
@ -157,26 +157,32 @@ public class RouterChain<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the reference of newly invokers to temp variable.
|
// Set the reference of newly invokers to temp variable.
|
||||||
// Reason: The next step will switch the invokers reference in directory, so we should check the `availableInvokers`
|
// Reason: The next step will switch the invokers reference in directory, so we should check the
|
||||||
// argument when `route`. If the current invocation use newly invokers, we should use main chain to route, and
|
// `availableInvokers`
|
||||||
|
// argument when `route`. If the current invocation use newly invokers, we should use main chain to
|
||||||
|
// route, and
|
||||||
// this can prevent use newly invokers to route backup chain, which can only route origin invokers now.
|
// this can prevent use newly invokers to route backup chain, which can only route origin invokers now.
|
||||||
notifyingInvokers.set(invokers);
|
notifyingInvokers.set(invokers);
|
||||||
|
|
||||||
// Switch the invokers reference in directory.
|
// Switch the invokers reference in directory.
|
||||||
// Cannot switch before update main chain or after backup chain update success. Or that will cause state inconsistent.
|
// Cannot switch before update main chain or after backup chain update success. Or that will cause state
|
||||||
|
// inconsistent.
|
||||||
switchAction.run();
|
switchAction.run();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Lock to prevent directory continue list
|
// Lock to prevent directory continue list
|
||||||
// The invokers reference in directory now should be the newly one and should always use the newly one once lock released.
|
// The invokers reference in directory now should be the newly one and should always use the newly one once
|
||||||
|
// lock released.
|
||||||
lock.writeLock().lock();
|
lock.writeLock().lock();
|
||||||
|
|
||||||
// Switch to main chain. Will update backup chain later.
|
// Switch to main chain. Will update backup chain later.
|
||||||
currentChain = mainChain;
|
currentChain = mainChain;
|
||||||
|
|
||||||
// Clean up temp variable.
|
// Clean up temp variable.
|
||||||
// `availableInvokers` check is useless now, because `route` method will no longer receive any `availableInvokers` related
|
// `availableInvokers` check is useless now, because `route` method will no longer receive any
|
||||||
// with the origin invokers. The getter of invokers reference in directory is locked now, and will return newly invokers
|
// `availableInvokers` related
|
||||||
|
// with the origin invokers. The getter of invokers reference in directory is locked now, and will return
|
||||||
|
// newly invokers
|
||||||
// once lock released.
|
// once lock released.
|
||||||
notifyingInvokers.set(null);
|
notifyingInvokers.set(null);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -186,7 +192,8 @@ public class RouterChain<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh main chain.
|
// Refresh main chain.
|
||||||
// No one can request to use main chain. `currentChain` is main chain. `route` method cannot access backup chain.
|
// No one can request to use main chain. `currentChain` is main chain. `route` method cannot access backup
|
||||||
|
// chain.
|
||||||
try {
|
try {
|
||||||
// Lock main chain to wait all invocation end
|
// Lock main chain to wait all invocation end
|
||||||
backupChain.getLock().writeLock().lock();
|
backupChain.getLock().writeLock().lock();
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster;
|
package org.apache.dubbo.rpc.cluster;
|
||||||
|
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
|
|
@ -26,5 +25,4 @@ import java.util.List;
|
||||||
public interface RuleConverter {
|
public interface RuleConverter {
|
||||||
|
|
||||||
List<URL> convert(URL subscribeUrl, Object source);
|
List<URL> convert(URL subscribeUrl, Object source);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,6 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.dubbo.rpc.cluster;
|
package org.apache.dubbo.rpc.cluster;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|
||||||
|
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
import org.apache.dubbo.common.Version;
|
import org.apache.dubbo.common.Version;
|
||||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||||
|
|
@ -40,6 +33,13 @@ import org.apache.dubbo.rpc.cluster.router.state.BitList;
|
||||||
import org.apache.dubbo.rpc.cluster.router.state.StateRouter;
|
import org.apache.dubbo.rpc.cluster.router.state.StateRouter;
|
||||||
import org.apache.dubbo.rpc.cluster.router.state.TailStateRouter;
|
import org.apache.dubbo.rpc.cluster.router.state.TailStateRouter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_STOP;
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_STOP;
|
||||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_NO_VALID_PROVIDER;
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_NO_VALID_PROVIDER;
|
||||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;
|
||||||
|
|
@ -79,7 +79,11 @@ public class SingleRouterChain<T> {
|
||||||
|
|
||||||
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||||
|
|
||||||
public SingleRouterChain(List<Router> routers, List<StateRouter<T>> stateRouters, boolean shouldFailFast, RouterSnapshotSwitcher routerSnapshotSwitcher) {
|
public SingleRouterChain(
|
||||||
|
List<Router> routers,
|
||||||
|
List<StateRouter<T>> stateRouters,
|
||||||
|
boolean shouldFailFast,
|
||||||
|
RouterSnapshotSwitcher routerSnapshotSwitcher) {
|
||||||
initWithRouters(routers);
|
initWithRouters(routers);
|
||||||
|
|
||||||
initWithStateRouters(stateRouters);
|
initWithStateRouters(stateRouters);
|
||||||
|
|
@ -134,9 +138,12 @@ public class SingleRouterChain<T> {
|
||||||
|
|
||||||
public List<Invoker<T>> route(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
|
public List<Invoker<T>> route(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
|
||||||
if (invokers.getOriginList() != availableInvokers.getOriginList()) {
|
if (invokers.getOriginList() != availableInvokers.getOriginList()) {
|
||||||
logger.error(INTERNAL_ERROR, "", "Router's invoker size: " + invokers.getOriginList().size() +
|
logger.error(
|
||||||
" Invocation's invoker size: " + availableInvokers.getOriginList().size(),
|
INTERNAL_ERROR,
|
||||||
"Reject to route, because the invokers has changed.");
|
"",
|
||||||
|
"Router's invoker size: " + invokers.getOriginList().size() + " Invocation's invoker size: "
|
||||||
|
+ availableInvokers.getOriginList().size(),
|
||||||
|
"Reject to route, because the invokers has changed.");
|
||||||
throw new IllegalStateException("reject to route, because the invokers has changed.");
|
throw new IllegalStateException("reject to route, because the invokers has changed.");
|
||||||
}
|
}
|
||||||
if (RpcContext.getServiceContext().isNeedPrintRouterSnapshot()) {
|
if (RpcContext.getServiceContext().isNeedPrintRouterSnapshot()) {
|
||||||
|
|
@ -202,7 +209,8 @@ public class SingleRouterChain<T> {
|
||||||
/**
|
/**
|
||||||
* Build each router's result
|
* Build each router's result
|
||||||
*/
|
*/
|
||||||
public RouterSnapshotNode<T> buildRouterSnapshot(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
|
public RouterSnapshotNode<T> buildRouterSnapshot(
|
||||||
|
URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
|
||||||
BitList<Invoker<T>> resultInvokers = availableInvokers.clone();
|
BitList<Invoker<T>> resultInvokers = availableInvokers.clone();
|
||||||
RouterSnapshotNode<T> parentNode = new RouterSnapshotNode<T>("Parent", resultInvokers.clone());
|
RouterSnapshotNode<T> parentNode = new RouterSnapshotNode<T>("Parent", resultInvokers.clone());
|
||||||
parentNode.setNodeOutputInvokers(resultInvokers.clone());
|
parentNode.setNodeOutputInvokers(resultInvokers.clone());
|
||||||
|
|
@ -228,7 +236,8 @@ public class SingleRouterChain<T> {
|
||||||
// Copy resultInvokers to a arrayList. BitList not support
|
// Copy resultInvokers to a arrayList. BitList not support
|
||||||
List<Invoker<T>> inputInvokers = new ArrayList<>(commonRouterResult);
|
List<Invoker<T>> inputInvokers = new ArrayList<>(commonRouterResult);
|
||||||
|
|
||||||
RouterSnapshotNode<T> currentNode = new RouterSnapshotNode<T>(router.getClass().getSimpleName(), inputInvokers);
|
RouterSnapshotNode<T> currentNode =
|
||||||
|
new RouterSnapshotNode<T>(router.getClass().getSimpleName(), inputInvokers);
|
||||||
|
|
||||||
// append to router node chain
|
// append to router node chain
|
||||||
commonRouterNode.appendNode(currentNode);
|
commonRouterNode.appendNode(currentNode);
|
||||||
|
|
@ -268,24 +277,27 @@ public class SingleRouterChain<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logRouterSnapshot(URL url, Invocation invocation, RouterSnapshotNode<T> snapshotNode) {
|
private void logRouterSnapshot(URL url, Invocation invocation, RouterSnapshotNode<T> snapshotNode) {
|
||||||
if (snapshotNode.getChainOutputInvokers() == null ||
|
if (snapshotNode.getChainOutputInvokers() == null
|
||||||
snapshotNode.getChainOutputInvokers().isEmpty()) {
|
|| snapshotNode.getChainOutputInvokers().isEmpty()) {
|
||||||
if (logger.isWarnEnabled()) {
|
if (logger.isWarnEnabled()) {
|
||||||
String message = "No provider available after route for the service " + url.getServiceKey()
|
String message = "No provider available after route for the service " + url.getServiceKey()
|
||||||
+ " from registry " + url.getAddress()
|
+ " from registry " + url.getAddress()
|
||||||
+ " on the consumer " + NetUtils.getLocalHost()
|
+ " on the consumer " + NetUtils.getLocalHost()
|
||||||
+ " using the dubbo version " + Version.getVersion() + ". Router snapshot is below: \n" + snapshotNode.toString();
|
+ " using the dubbo version " + Version.getVersion() + ". Router snapshot is below: \n"
|
||||||
|
+ snapshotNode.toString();
|
||||||
if (routerSnapshotSwitcher.isEnable()) {
|
if (routerSnapshotSwitcher.isEnable()) {
|
||||||
routerSnapshotSwitcher.setSnapshot(message);
|
routerSnapshotSwitcher.setSnapshot(message);
|
||||||
}
|
}
|
||||||
logger.warn(CLUSTER_NO_VALID_PROVIDER, "No provider available after route for the service", "", message);
|
logger.warn(
|
||||||
|
CLUSTER_NO_VALID_PROVIDER, "No provider available after route for the service", "", message);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (logger.isInfoEnabled()) {
|
if (logger.isInfoEnabled()) {
|
||||||
String message = "Router snapshot service " + url.getServiceKey()
|
String message = "Router snapshot service " + url.getServiceKey()
|
||||||
+ " from registry " + url.getAddress()
|
+ " from registry " + url.getAddress()
|
||||||
+ " on the consumer " + NetUtils.getLocalHost()
|
+ " on the consumer " + NetUtils.getLocalHost()
|
||||||
+ " using the dubbo version " + Version.getVersion() + " is below: \n" + snapshotNode.toString();
|
+ " using the dubbo version " + Version.getVersion() + " is below: \n"
|
||||||
|
+ snapshotNode.toString();
|
||||||
if (routerSnapshotSwitcher.isEnable()) {
|
if (routerSnapshotSwitcher.isEnable()) {
|
||||||
routerSnapshotSwitcher.setSnapshot(message);
|
routerSnapshotSwitcher.setSnapshot(message);
|
||||||
}
|
}
|
||||||
|
|
@ -330,7 +342,12 @@ public class SingleRouterChain<T> {
|
||||||
try {
|
try {
|
||||||
router.stop();
|
router.stop();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error(CLUSTER_FAILED_STOP, "route stop failed", "", "Error trying to stop router " + router.getClass(), e);
|
logger.error(
|
||||||
|
CLUSTER_FAILED_STOP,
|
||||||
|
"route stop failed",
|
||||||
|
"",
|
||||||
|
"Error trying to stop router " + router.getClass(),
|
||||||
|
e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
routers = Collections.emptyList();
|
routers = Collections.emptyList();
|
||||||
|
|
@ -340,7 +357,12 @@ public class SingleRouterChain<T> {
|
||||||
try {
|
try {
|
||||||
router.stop();
|
router.stop();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error(CLUSTER_FAILED_STOP, "StateRouter stop failed", "", "Error trying to stop StateRouter " + router.getClass(), e);
|
logger.error(
|
||||||
|
CLUSTER_FAILED_STOP,
|
||||||
|
"StateRouter stop failed",
|
||||||
|
"",
|
||||||
|
"Error trying to stop StateRouter " + router.getClass(),
|
||||||
|
e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stateRouters = Collections.emptyList();
|
stateRouters = Collections.emptyList();
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,10 @@ public abstract class AbstractConfigurator implements Configurator {
|
||||||
@Override
|
@Override
|
||||||
public URL configure(URL url) {
|
public URL configure(URL url) {
|
||||||
// If override url is not enabled or is invalid, just return.
|
// If override url is not enabled or is invalid, just return.
|
||||||
if (!configuratorUrl.getParameter(ENABLED_KEY, true) || configuratorUrl.getHost() == null || url == null || url.getHost() == null) {
|
if (!configuratorUrl.getParameter(ENABLED_KEY, true)
|
||||||
|
|| configuratorUrl.getHost() == null
|
||||||
|
|| url == null
|
||||||
|
|| url.getHost() == null) {
|
||||||
logger.info("Cannot apply configurator rule, the rule is disabled or is invalid: \n" + configuratorUrl);
|
logger.info("Cannot apply configurator rule, the rule is disabled or is invalid: \n" + configuratorUrl);
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +101,9 @@ public abstract class AbstractConfigurator implements Configurator {
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
private URL configureDeprecated(URL url) {
|
private URL configureDeprecated(URL url) {
|
||||||
// If override url has port, means it is a provider address. We want to control a specific provider with this override url, it may take effect on the specific provider instance or on consumers holding this provider instance.
|
// If override url has port, means it is a provider address. We want to control a specific provider with this
|
||||||
|
// override url, it may take effect on the specific provider instance or on consumers holding this provider
|
||||||
|
// instance.
|
||||||
if (configuratorUrl.getPort() != 0) {
|
if (configuratorUrl.getPort() != 0) {
|
||||||
if (url.getPort() == configuratorUrl.getPort()) {
|
if (url.getPort() == configuratorUrl.getPort()) {
|
||||||
return configureIfMatch(url.getHost(), url);
|
return configureIfMatch(url.getHost(), url);
|
||||||
|
|
@ -131,7 +136,8 @@ public abstract class AbstractConfigurator implements Configurator {
|
||||||
if (matcher.isMatch(host, url)) {
|
if (matcher.isMatch(host, url)) {
|
||||||
return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));
|
return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Cannot apply configurator rule, param mismatch, current params are " + url + ", params in rule is " + matcher);
|
logger.debug("Cannot apply configurator rule, param mismatch, current params are " + url
|
||||||
|
+ ", params in rule is " + matcher);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));
|
return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));
|
||||||
|
|
@ -141,7 +147,8 @@ public abstract class AbstractConfigurator implements Configurator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Cannot apply configurator rule, host mismatch, current host is " + host + ", host in rule is " + configuratorUrl.getHost());
|
logger.debug("Cannot apply configurator rule, host mismatch, current host is " + host + ", host in rule is "
|
||||||
|
+ configuratorUrl.getHost());
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
@ -159,15 +166,16 @@ public abstract class AbstractConfigurator implements Configurator {
|
||||||
String[] providerAddresses = providers.split(CommonConstants.COMMA_SEPARATOR);
|
String[] providerAddresses = providers.split(CommonConstants.COMMA_SEPARATOR);
|
||||||
for (String address : providerAddresses) {
|
for (String address : providerAddresses) {
|
||||||
if (address.equals(url.getAddress())
|
if (address.equals(url.getAddress())
|
||||||
|| address.equals(ANYHOST_VALUE)
|
|| address.equals(ANYHOST_VALUE)
|
||||||
|| address.equals(ANYHOST_VALUE + CommonConstants.GROUP_CHAR_SEPARATOR + ANY_VALUE)
|
|| address.equals(ANYHOST_VALUE + CommonConstants.GROUP_CHAR_SEPARATOR + ANY_VALUE)
|
||||||
|| address.equals(ANYHOST_VALUE + CommonConstants.GROUP_CHAR_SEPARATOR + url.getPort())
|
|| address.equals(ANYHOST_VALUE + CommonConstants.GROUP_CHAR_SEPARATOR + url.getPort())
|
||||||
|| address.equals(url.getHost())) {
|
|| address.equals(url.getHost())) {
|
||||||
match = true;
|
match = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!match) {
|
if (!match) {
|
||||||
logger.debug("Cannot apply configurator rule, provider address mismatch, current address " + url.getAddress() + ", address in rule is " + providers);
|
logger.debug("Cannot apply configurator rule, provider address mismatch, current address "
|
||||||
|
+ url.getAddress() + ", address in rule is " + providers);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -175,17 +183,18 @@ public abstract class AbstractConfigurator implements Configurator {
|
||||||
String configApplication = configuratorUrl.getApplication(configuratorUrl.getUsername());
|
String configApplication = configuratorUrl.getApplication(configuratorUrl.getUsername());
|
||||||
String currentApplication = url.getApplication(url.getUsername());
|
String currentApplication = url.getApplication(url.getUsername());
|
||||||
if (configApplication != null
|
if (configApplication != null
|
||||||
&& !ANY_VALUE.equals(configApplication)
|
&& !ANY_VALUE.equals(configApplication)
|
||||||
&& !configApplication.equals(currentApplication)) {
|
&& !configApplication.equals(currentApplication)) {
|
||||||
logger.debug("Cannot apply configurator rule, application name mismatch, current application is " + currentApplication + ", application in rule is " + configApplication);
|
logger.debug("Cannot apply configurator rule, application name mismatch, current application is "
|
||||||
|
+ currentApplication + ", application in rule is " + configApplication);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String configServiceKey = configuratorUrl.getServiceKey();
|
String configServiceKey = configuratorUrl.getServiceKey();
|
||||||
String currentServiceKey = url.getServiceKey();
|
String currentServiceKey = url.getServiceKey();
|
||||||
if (!ANY_VALUE.equals(configServiceKey)
|
if (!ANY_VALUE.equals(configServiceKey) && !configServiceKey.equals(currentServiceKey)) {
|
||||||
&& !configServiceKey.equals(currentServiceKey)) {
|
logger.debug("Cannot apply configurator rule, service mismatch, current service is " + currentServiceKey
|
||||||
logger.debug("Cannot apply configurator rule, service mismatch, current service is " + currentServiceKey + ", service in rule is " + configServiceKey);
|
+ ", service in rule is " + configServiceKey);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,8 +211,9 @@ public abstract class AbstractConfigurator implements Configurator {
|
||||||
if (startWithTilde) {
|
if (startWithTilde) {
|
||||||
conditionKeys.add(key);
|
conditionKeys.add(key);
|
||||||
}
|
}
|
||||||
if (value != null && !ANY_VALUE.equals(value)
|
if (value != null
|
||||||
&& !value.equals(url.getParameter(startWithTilde ? key.substring(1) : key))) {
|
&& !ANY_VALUE.equals(value)
|
||||||
|
&& !value.equals(url.getParameter(startWithTilde ? key.substring(1) : key))) {
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -233,5 +243,4 @@ public abstract class AbstractConfigurator implements Configurator {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract URL doConfigure(URL currentUrl, URL configUrl);
|
protected abstract URL doConfigure(URL currentUrl, URL configUrl);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,5 +32,4 @@ public class AbsentConfigurator extends AbstractConfigurator {
|
||||||
public URL doConfigure(URL currentUrl, URL configUrl) {
|
public URL doConfigure(URL currentUrl, URL configUrl) {
|
||||||
return currentUrl.addParametersIfAbsent(configUrl.getParameters());
|
return currentUrl.addParametersIfAbsent(configUrl.getParameters());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,5 +30,4 @@ public class AbsentConfiguratorFactory implements ConfiguratorFactory {
|
||||||
public Configurator getConfigurator(URL url) {
|
public Configurator getConfigurator(URL url) {
|
||||||
return new AbsentConfigurator(url);
|
return new AbsentConfigurator(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,5 +36,4 @@ public class OverrideConfigurator extends AbstractConfigurator {
|
||||||
logger.info("Start overriding url " + currentUrl + " with override url " + configUrl);
|
logger.info("Start overriding url " + currentUrl + " with override url " + configUrl);
|
||||||
return currentUrl.addParameters(configUrl.getParameters());
|
return currentUrl.addParameters(configUrl.getParameters());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,5 +30,4 @@ public class OverrideConfiguratorFactory implements ConfiguratorFactory {
|
||||||
public Configurator getConfigurator(URL url) {
|
public Configurator getConfigurator(URL url) {
|
||||||
return new OverrideConfigurator(url);
|
return new OverrideConfigurator(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,14 @@ import org.apache.dubbo.common.utils.StringUtils;
|
||||||
import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfigItem;
|
import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfigItem;
|
||||||
import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig;
|
import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig;
|
||||||
|
|
||||||
import org.yaml.snakeyaml.LoaderOptions;
|
|
||||||
import org.yaml.snakeyaml.Yaml;
|
|
||||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.yaml.snakeyaml.LoaderOptions;
|
||||||
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
|
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
|
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
|
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
|
||||||
import static org.apache.dubbo.common.constants.RegistryConstants.APP_DYNAMIC_CONFIGURATORS_CATEGORY;
|
import static org.apache.dubbo.common.constants.RegistryConstants.APP_DYNAMIC_CONFIGURATORS_CATEGORY;
|
||||||
|
|
@ -104,7 +104,12 @@ public class ConfigParser {
|
||||||
if (CollectionUtils.isNotEmpty(apps)) {
|
if (CollectionUtils.isNotEmpty(apps)) {
|
||||||
apps.forEach(app -> {
|
apps.forEach(app -> {
|
||||||
StringBuilder tmpUrlBuilder = new StringBuilder(urlBuilder);
|
StringBuilder tmpUrlBuilder = new StringBuilder(urlBuilder);
|
||||||
urls.add(appendMatchCondition(URL.valueOf(tmpUrlBuilder.append("&application=").append(app).toString()), item));
|
urls.add(appendMatchCondition(
|
||||||
|
URL.valueOf(tmpUrlBuilder
|
||||||
|
.append("&application=")
|
||||||
|
.append(app)
|
||||||
|
.toString()),
|
||||||
|
item));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
urls.add(appendMatchCondition(URL.valueOf(urlBuilder.toString()), item));
|
urls.add(appendMatchCondition(URL.valueOf(urlBuilder.toString()), item));
|
||||||
|
|
@ -155,8 +160,8 @@ public class ConfigParser {
|
||||||
}
|
}
|
||||||
Map<String, String> parameters = item.getParameters();
|
Map<String, String> parameters = item.getParameters();
|
||||||
if (CollectionUtils.isEmptyMap(parameters)) {
|
if (CollectionUtils.isEmptyMap(parameters)) {
|
||||||
throw new IllegalStateException("Invalid configurator rule, please specify at least one parameter " +
|
throw new IllegalStateException("Invalid configurator rule, please specify at least one parameter "
|
||||||
"you want to change in the rule.");
|
+ "you want to change in the rule.");
|
||||||
}
|
}
|
||||||
|
|
||||||
parameters.forEach((k, v) -> {
|
parameters.forEach((k, v) -> {
|
||||||
|
|
|
||||||
|
|
@ -101,12 +101,11 @@ public class ConditionMatch {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ConditionMatch{" +
|
return "ConditionMatch{" + "address='"
|
||||||
"address='" + address + '\'' +
|
+ address + '\'' + "providerAddress='"
|
||||||
"providerAddress='" + providerAddress + '\'' +
|
+ providerAddress + '\'' + ", service='"
|
||||||
", service='" + service + '\'' +
|
+ service + '\'' + ", app='"
|
||||||
", app='" + app + '\'' +
|
+ app + '\'' + ", param='"
|
||||||
", param='" + param + '\'' +
|
+ param + '\'' + '}';
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,32 +68,33 @@ public class ConfigItem {
|
||||||
|
|
||||||
Object addresses = map.get(ADDRESSES_KEY);
|
Object addresses = map.get(ADDRESSES_KEY);
|
||||||
if (addresses != null && List.class.isAssignableFrom(addresses.getClass())) {
|
if (addresses != null && List.class.isAssignableFrom(addresses.getClass())) {
|
||||||
configItem.setAddresses(((List<Object>) addresses).stream()
|
configItem.setAddresses(
|
||||||
.map(String::valueOf).collect(Collectors.toList()));
|
((List<Object>) addresses).stream().map(String::valueOf).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Object providerAddresses = map.get(PROVIDER_ADDRESSES_KEY);
|
Object providerAddresses = map.get(PROVIDER_ADDRESSES_KEY);
|
||||||
if (providerAddresses != null && List.class.isAssignableFrom(providerAddresses.getClass())) {
|
if (providerAddresses != null && List.class.isAssignableFrom(providerAddresses.getClass())) {
|
||||||
configItem.setProviderAddresses(((List<Object>) providerAddresses).stream()
|
configItem.setProviderAddresses(((List<Object>) providerAddresses)
|
||||||
.map(String::valueOf).collect(Collectors.toList()));
|
.stream().map(String::valueOf).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Object services = map.get(SERVICES_KEY);
|
Object services = map.get(SERVICES_KEY);
|
||||||
if (services != null && List.class.isAssignableFrom(services.getClass())) {
|
if (services != null && List.class.isAssignableFrom(services.getClass())) {
|
||||||
configItem.setServices(((List<Object>) services).stream()
|
configItem.setServices(
|
||||||
.map(String::valueOf).collect(Collectors.toList()));
|
((List<Object>) services).stream().map(String::valueOf).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Object applications = map.get(APPLICATIONS_KEY);
|
Object applications = map.get(APPLICATIONS_KEY);
|
||||||
if (applications != null && List.class.isAssignableFrom(applications.getClass())) {
|
if (applications != null && List.class.isAssignableFrom(applications.getClass())) {
|
||||||
configItem.setApplications(((List<Object>) applications).stream()
|
configItem.setApplications(
|
||||||
.map(String::valueOf).collect(Collectors.toList()));
|
((List<Object>) applications).stream().map(String::valueOf).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Object parameters = map.get(PARAMETERS_KEY);
|
Object parameters = map.get(PARAMETERS_KEY);
|
||||||
if (parameters != null && Map.class.isAssignableFrom(parameters.getClass())) {
|
if (parameters != null && Map.class.isAssignableFrom(parameters.getClass())) {
|
||||||
configItem.setParameters(((Map<String, Object>) parameters).entrySet()
|
configItem.setParameters(((Map<String, Object>) parameters)
|
||||||
.stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().toString())));
|
.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue()
|
||||||
|
.toString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -102,7 +103,12 @@ public class ConfigItem {
|
||||||
configItem.setMatch(PojoUtils.mapToPojo((Map<String, Object>) match, ConditionMatch.class));
|
configItem.setMatch(PojoUtils.mapToPojo((Map<String, Object>) match, ConditionMatch.class));
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
logger.error(CLUSTER_FAILED_RECEIVE_RULE, " Failed to parse dynamic configuration rule", String.valueOf(map.get(MATCH_KEY)), "Error occurred when parsing rule component.", t);
|
logger.error(
|
||||||
|
CLUSTER_FAILED_RECEIVE_RULE,
|
||||||
|
" Failed to parse dynamic configuration rule",
|
||||||
|
String.valueOf(map.get(MATCH_KEY)),
|
||||||
|
"Error occurred when parsing rule component.",
|
||||||
|
t);
|
||||||
}
|
}
|
||||||
|
|
||||||
configItem.setSide((String) map.get(SIDE_KEY));
|
configItem.setSide((String) map.get(SIDE_KEY));
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,8 @@ public class ConfiguratorConfig {
|
||||||
|
|
||||||
Object configs = map.get(CONFIGS_KEY);
|
Object configs = map.get(CONFIGS_KEY);
|
||||||
if (configs != null && List.class.isAssignableFrom(configs.getClass())) {
|
if (configs != null && List.class.isAssignableFrom(configs.getClass())) {
|
||||||
configuratorConfig.setConfigs(((List<Map<String, Object>>) configs).stream()
|
configuratorConfig.setConfigs(((List<Map<String, Object>>) configs)
|
||||||
.map(ConfigItem::parseFromMap).collect(Collectors.toList()));
|
.stream().map(ConfigItem::parseFromMap).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return configuratorConfig;
|
return configuratorConfig;
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,6 @@ public class ParamMatch {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ParamMatch{" +
|
return "ParamMatch{" + "key='" + key + '\'' + ", value='" + value + '\'' + '}';
|
||||||
"key='" + key + '\'' +
|
|
||||||
", value='" + value + '\'' +
|
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -160,18 +160,20 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
|
||||||
|
|
||||||
// remove some local only parameters
|
// remove some local only parameters
|
||||||
applicationModel = url.getOrDefaultApplicationModel();
|
applicationModel = url.getOrDefaultApplicationModel();
|
||||||
this.queryMap = applicationModel.getBeanFactory().getBean(ClusterUtils.class).mergeLocalParams(queryMap);
|
this.queryMap =
|
||||||
|
applicationModel.getBeanFactory().getBean(ClusterUtils.class).mergeLocalParams(queryMap);
|
||||||
|
|
||||||
if (consumerUrl == null) {
|
if (consumerUrl == null) {
|
||||||
String host = isNotEmpty(queryMap.get(REGISTER_IP_KEY)) ? queryMap.get(REGISTER_IP_KEY) : this.url.getHost();
|
String host =
|
||||||
|
isNotEmpty(queryMap.get(REGISTER_IP_KEY)) ? queryMap.get(REGISTER_IP_KEY) : this.url.getHost();
|
||||||
String path = isNotEmpty(queryMap.get(PATH_KEY)) ? queryMap.get(PATH_KEY) : queryMap.get(INTERFACE_KEY);
|
String path = isNotEmpty(queryMap.get(PATH_KEY)) ? queryMap.get(PATH_KEY) : queryMap.get(INTERFACE_KEY);
|
||||||
String consumedProtocol = isNotEmpty(queryMap.get(PROTOCOL_KEY)) ? queryMap.get(PROTOCOL_KEY) : CONSUMER;
|
String consumedProtocol = isNotEmpty(queryMap.get(PROTOCOL_KEY)) ? queryMap.get(PROTOCOL_KEY) : CONSUMER;
|
||||||
|
|
||||||
URL consumerUrlFrom = this.url
|
URL consumerUrlFrom = this.url
|
||||||
.setHost(host)
|
.setHost(host)
|
||||||
.setPort(0)
|
.setPort(0)
|
||||||
.setProtocol(consumedProtocol)
|
.setProtocol(consumedProtocol)
|
||||||
.setPath(path);
|
.setPath(path);
|
||||||
if (isUrlFromRegistry) {
|
if (isUrlFromRegistry) {
|
||||||
// reserve parameters if url is already a consumer url
|
// reserve parameters if url is already a consumer url
|
||||||
consumerUrlFrom = consumerUrlFrom.clearParameters();
|
consumerUrlFrom = consumerUrlFrom.clearParameters();
|
||||||
|
|
@ -179,19 +181,23 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
|
||||||
this.consumerUrl = consumerUrlFrom.addParameters(queryMap);
|
this.consumerUrl = consumerUrlFrom.addParameters(queryMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.connectivityExecutor = applicationModel.getFrameworkModel().getBeanFactory()
|
this.connectivityExecutor = applicationModel
|
||||||
.getBean(FrameworkExecutorRepository.class).getConnectivityScheduledExecutor();
|
.getFrameworkModel()
|
||||||
|
.getBeanFactory()
|
||||||
|
.getBean(FrameworkExecutorRepository.class)
|
||||||
|
.getConnectivityScheduledExecutor();
|
||||||
Configuration configuration = ConfigurationUtils.getGlobalConfiguration(url.getOrDefaultModuleModel());
|
Configuration configuration = ConfigurationUtils.getGlobalConfiguration(url.getOrDefaultModuleModel());
|
||||||
this.reconnectTaskTryCount = configuration.getInt(RECONNECT_TASK_TRY_COUNT, DEFAULT_RECONNECT_TASK_TRY_COUNT);
|
this.reconnectTaskTryCount = configuration.getInt(RECONNECT_TASK_TRY_COUNT, DEFAULT_RECONNECT_TASK_TRY_COUNT);
|
||||||
this.reconnectTaskPeriod = configuration.getInt(RECONNECT_TASK_PERIOD, DEFAULT_RECONNECT_TASK_PERIOD);
|
this.reconnectTaskPeriod = configuration.getInt(RECONNECT_TASK_PERIOD, DEFAULT_RECONNECT_TASK_PERIOD);
|
||||||
setRouterChain(routerChain);
|
setRouterChain(routerChain);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Invoker<T>> list(Invocation invocation) throws RpcException {
|
public List<Invoker<T>> list(Invocation invocation) throws RpcException {
|
||||||
if (destroyed) {
|
if (destroyed) {
|
||||||
throw new RpcException("Directory of type " + this.getClass().getSimpleName() + " already destroyed for service " + getConsumerUrl().getServiceKey() + " from registry " + getUrl());
|
throw new RpcException(
|
||||||
|
"Directory of type " + this.getClass().getSimpleName() + " already destroyed for service "
|
||||||
|
+ getConsumerUrl().getServiceKey() + " from registry " + getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
BitList<Invoker<T>> availableInvokers;
|
BitList<Invoker<T>> availableInvokers;
|
||||||
|
|
@ -222,12 +228,16 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
|
||||||
if (routedResult.isEmpty()) {
|
if (routedResult.isEmpty()) {
|
||||||
// 2-2 - No provider available.
|
// 2-2 - No provider available.
|
||||||
|
|
||||||
logger.warn(CLUSTER_NO_VALID_PROVIDER, "provider server or registry center crashed", "",
|
logger.warn(
|
||||||
"No provider available after connectivity filter for the service " + getConsumerUrl().getServiceKey()
|
CLUSTER_NO_VALID_PROVIDER,
|
||||||
+ " All routed invokers' size: " + routedResult.size()
|
"provider server or registry center crashed",
|
||||||
+ " from registry " + this
|
"",
|
||||||
+ " on the consumer " + NetUtils.getLocalHost()
|
"No provider available after connectivity filter for the service "
|
||||||
+ " using the dubbo version " + Version.getVersion() + ".");
|
+ getConsumerUrl().getServiceKey()
|
||||||
|
+ " All routed invokers' size: " + routedResult.size()
|
||||||
|
+ " from registry " + this
|
||||||
|
+ " on the consumer " + NetUtils.getLocalHost()
|
||||||
|
+ " using the dubbo version " + Version.getVersion() + ".");
|
||||||
}
|
}
|
||||||
return Collections.unmodifiableList(routedResult);
|
return Collections.unmodifiableList(routedResult);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -290,68 +300,78 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
|
||||||
// 3. try start check connectivity task
|
// 3. try start check connectivity task
|
||||||
checkConnectivity();
|
checkConnectivity();
|
||||||
|
|
||||||
logger.info("The invoker " + invoker.getUrl() + " has been added to invalidate list due to connectivity problem. " +
|
logger.info("The invoker " + invoker.getUrl()
|
||||||
"Will trying to reconnect to it in the background.");
|
+ " has been added to invalidate list due to connectivity problem. "
|
||||||
|
+ "Will trying to reconnect to it in the background.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkConnectivity() {
|
public void checkConnectivity() {
|
||||||
// try to submit task, to ensure there is only one task at most for each directory
|
// try to submit task, to ensure there is only one task at most for each directory
|
||||||
if (checkConnectivityPermit.tryAcquire()) {
|
if (checkConnectivityPermit.tryAcquire()) {
|
||||||
this.connectivityCheckFuture = connectivityExecutor.schedule(() -> {
|
this.connectivityCheckFuture = connectivityExecutor.schedule(
|
||||||
try {
|
() -> {
|
||||||
if (isDestroyed()) {
|
try {
|
||||||
return;
|
if (isDestroyed()) {
|
||||||
}
|
return;
|
||||||
RpcContext.getServiceContext().setConsumerUrl(getConsumerUrl());
|
|
||||||
List<Invoker<T>> needDeleteList = new ArrayList<>();
|
|
||||||
List<Invoker<T>> invokersToTry = new ArrayList<>();
|
|
||||||
|
|
||||||
// 1. pick invokers from invokersToReconnect
|
|
||||||
// limit max reconnectTaskTryCount, prevent this task hang up all the connectivityExecutor for long time
|
|
||||||
if (invokersToReconnect.size() < reconnectTaskTryCount) {
|
|
||||||
invokersToTry.addAll(invokersToReconnect);
|
|
||||||
} else {
|
|
||||||
for (int i = 0; i < reconnectTaskTryCount; i++) {
|
|
||||||
Invoker<T> tInvoker = invokersToReconnect.get(ThreadLocalRandom.current().nextInt(invokersToReconnect.size()));
|
|
||||||
if (!invokersToTry.contains(tInvoker)) {
|
|
||||||
// ignore if is selected, invokersToTry's size is always smaller than reconnectTaskTryCount + 1
|
|
||||||
invokersToTry.add(tInvoker);
|
|
||||||
}
|
}
|
||||||
}
|
RpcContext.getServiceContext().setConsumerUrl(getConsumerUrl());
|
||||||
}
|
List<Invoker<T>> needDeleteList = new ArrayList<>();
|
||||||
|
List<Invoker<T>> invokersToTry = new ArrayList<>();
|
||||||
|
|
||||||
// 2. try to check the invoker's status
|
// 1. pick invokers from invokersToReconnect
|
||||||
for (Invoker<T> invoker : invokersToTry) {
|
// limit max reconnectTaskTryCount, prevent this task hang up all the connectivityExecutor
|
||||||
if (invokers.contains(invoker)) {
|
// for long time
|
||||||
if (invoker.isAvailable()) {
|
if (invokersToReconnect.size() < reconnectTaskTryCount) {
|
||||||
needDeleteList.add(invoker);
|
invokersToTry.addAll(invokersToReconnect);
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < reconnectTaskTryCount; i++) {
|
||||||
|
Invoker<T> tInvoker = invokersToReconnect.get(
|
||||||
|
ThreadLocalRandom.current().nextInt(invokersToReconnect.size()));
|
||||||
|
if (!invokersToTry.contains(tInvoker)) {
|
||||||
|
// ignore if is selected, invokersToTry's size is always smaller than
|
||||||
|
// reconnectTaskTryCount + 1
|
||||||
|
invokersToTry.add(tInvoker);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
needDeleteList.add(invoker);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. recover valid invoker
|
// 2. try to check the invoker's status
|
||||||
for (Invoker<T> tInvoker : needDeleteList) {
|
for (Invoker<T> invoker : invokersToTry) {
|
||||||
if (invokers.contains(tInvoker)) {
|
if (invokers.contains(invoker)) {
|
||||||
addValidInvoker(tInvoker);
|
if (invoker.isAvailable()) {
|
||||||
logger.info("Recover service address: " + tInvoker.getUrl() + " from invalid list.");
|
needDeleteList.add(invoker);
|
||||||
}
|
}
|
||||||
invokersToReconnect.remove(tInvoker);
|
} else {
|
||||||
}
|
needDeleteList.add(invoker);
|
||||||
} finally {
|
}
|
||||||
checkConnectivityPermit.release();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 4. submit new task if it has more to recover
|
// 3. recover valid invoker
|
||||||
if (!invokersToReconnect.isEmpty()) {
|
for (Invoker<T> tInvoker : needDeleteList) {
|
||||||
checkConnectivity();
|
if (invokers.contains(tInvoker)) {
|
||||||
}
|
addValidInvoker(tInvoker);
|
||||||
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
logger.info(
|
||||||
}, reconnectTaskPeriod, TimeUnit.MILLISECONDS);
|
"Recover service address: " + tInvoker.getUrl() + " from invalid list.");
|
||||||
|
}
|
||||||
|
invokersToReconnect.remove(tInvoker);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
checkConnectivityPermit.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. submit new task if it has more to recover
|
||||||
|
if (!invokersToReconnect.isEmpty()) {
|
||||||
|
checkConnectivity();
|
||||||
|
}
|
||||||
|
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(
|
||||||
|
applicationModel, getSummary(), getDirectoryMeta()));
|
||||||
|
},
|
||||||
|
reconnectTaskPeriod,
|
||||||
|
TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
MetricsEventBus.publish(
|
||||||
|
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -365,7 +385,8 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
|
||||||
if (invokersInitialized) {
|
if (invokersInitialized) {
|
||||||
refreshInvokerInternal();
|
refreshInvokerInternal();
|
||||||
}
|
}
|
||||||
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
MetricsEventBus.publish(
|
||||||
|
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<String, String> getDirectoryMeta() {
|
protected Map<String, String> getDirectoryMeta() {
|
||||||
|
|
@ -398,7 +419,8 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
|
||||||
removeValidInvoker(invoker);
|
removeValidInvoker(invoker);
|
||||||
logger.info("Disable service address: " + invoker.getUrl() + ".");
|
logger.info("Disable service address: " + invoker.getUrl() + ".");
|
||||||
}
|
}
|
||||||
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
MetricsEventBus.publish(
|
||||||
|
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -411,19 +433,24 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
MetricsEventBus.publish(
|
||||||
|
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void refreshRouter(BitList<Invoker<T>> newlyInvokers, Runnable switchAction) {
|
protected final void refreshRouter(BitList<Invoker<T>> newlyInvokers, Runnable switchAction) {
|
||||||
try {
|
try {
|
||||||
routerChain.setInvokers(newlyInvokers.clone(), switchAction);
|
routerChain.setInvokers(newlyInvokers.clone(), switchAction);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
logger.error(LoggerCodeConstants.INTERNAL_ERROR, "", "", "Error occurred when refreshing router chain. " +
|
logger.error(
|
||||||
"The addresses from notification: " +
|
LoggerCodeConstants.INTERNAL_ERROR,
|
||||||
newlyInvokers.stream()
|
"",
|
||||||
.map(Invoker::getUrl)
|
"",
|
||||||
.map(URL::getAddress)
|
"Error occurred when refreshing router chain. " + "The addresses from notification: "
|
||||||
.collect(Collectors.joining(", ")), t);
|
+ newlyInvokers.stream()
|
||||||
|
.map(Invoker::getUrl)
|
||||||
|
.map(URL::getAddress)
|
||||||
|
.collect(Collectors.joining(", ")),
|
||||||
|
t);
|
||||||
|
|
||||||
throw t;
|
throw t;
|
||||||
}
|
}
|
||||||
|
|
@ -468,7 +495,8 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
|
||||||
refreshInvokerInternal();
|
refreshInvokerInternal();
|
||||||
this.invokersInitialized = true;
|
this.invokersInitialized = true;
|
||||||
|
|
||||||
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
MetricsEventBus.publish(
|
||||||
|
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void destroyInvokers() {
|
protected void destroyInvokers() {
|
||||||
|
|
@ -483,7 +511,8 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
|
||||||
synchronized (this.validInvokers) {
|
synchronized (this.validInvokers) {
|
||||||
result = this.validInvokers.add(invoker);
|
result = this.validInvokers.add(invoker);
|
||||||
}
|
}
|
||||||
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
MetricsEventBus.publish(
|
||||||
|
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -492,12 +521,14 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
|
||||||
synchronized (this.validInvokers) {
|
synchronized (this.validInvokers) {
|
||||||
result = this.validInvokers.remove(invoker);
|
result = this.validInvokers.remove(invoker);
|
||||||
}
|
}
|
||||||
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
MetricsEventBus.publish(
|
||||||
|
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract List<Invoker<T>> doList(SingleRouterChain<T> singleRouterChain,
|
protected abstract List<Invoker<T>> doList(
|
||||||
BitList<Invoker<T>> invokers, Invocation invocation) throws RpcException;
|
SingleRouterChain<T> singleRouterChain, BitList<Invoker<T>> invokers, Invocation invocation)
|
||||||
|
throws RpcException;
|
||||||
|
|
||||||
protected String joinValidInvokerAddresses() {
|
protected String joinValidInvokerAddresses() {
|
||||||
BitList<Invoker<T>> validInvokers = getValidInvokers().clone();
|
BitList<Invoker<T>> validInvokers = getValidInvokers().clone();
|
||||||
|
|
@ -505,10 +536,10 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
|
||||||
return "empty";
|
return "empty";
|
||||||
}
|
}
|
||||||
return validInvokers.stream()
|
return validInvokers.stream()
|
||||||
.limit(5)
|
.limit(5)
|
||||||
.map(Invoker::getUrl)
|
.map(Invoker::getUrl)
|
||||||
.map(URL::getAddress)
|
.map(URL::getAddress)
|
||||||
.collect(Collectors.joining(","));
|
.collect(Collectors.joining(","));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<MetricsKey, Map<String, Integer>> getSummary() {
|
private Map<MetricsKey, Map<String, Integer>> getSummary() {
|
||||||
|
|
@ -527,25 +558,27 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Directory(" +
|
return "Directory(" + "invokers: "
|
||||||
"invokers: " + invokers.size() + "[" +
|
+ invokers.size() + "["
|
||||||
invokers.stream()
|
+ invokers.stream()
|
||||||
.map(Invoker::getUrl)
|
.map(Invoker::getUrl)
|
||||||
.map(URL::getAddress)
|
.map(URL::getAddress)
|
||||||
.limit(3)
|
.limit(3)
|
||||||
.collect(Collectors.joining(", ")) + "]" +
|
.collect(Collectors.joining(", "))
|
||||||
", validInvokers: " + validInvokers.size() + "[" +
|
+ "]" + ", validInvokers: "
|
||||||
validInvokers.stream()
|
+ validInvokers.size() + "["
|
||||||
.map(Invoker::getUrl)
|
+ validInvokers.stream()
|
||||||
.map(URL::getAddress)
|
.map(Invoker::getUrl)
|
||||||
.limit(3)
|
.map(URL::getAddress)
|
||||||
.collect(Collectors.joining(", ")) + "]" +
|
.limit(3)
|
||||||
", invokersToReconnect: " + invokersToReconnect.size() + "[" +
|
.collect(Collectors.joining(", "))
|
||||||
invokersToReconnect.stream()
|
+ "]" + ", invokersToReconnect: "
|
||||||
.map(Invoker::getUrl)
|
+ invokersToReconnect.size() + "["
|
||||||
.map(URL::getAddress)
|
+ invokersToReconnect.stream()
|
||||||
.limit(3)
|
.map(Invoker::getUrl)
|
||||||
.collect(Collectors.joining(", ")) + "]" +
|
.map(URL::getAddress)
|
||||||
')';
|
.limit(3)
|
||||||
|
.collect(Collectors.joining(", "))
|
||||||
|
+ "]" + ')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,12 @@ public class StaticDirectory<T> extends AbstractDirectory<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public StaticDirectory(URL url, List<Invoker<T>> invokers, RouterChain<T> routerChain) {
|
public StaticDirectory(URL url, List<Invoker<T>> invokers, RouterChain<T> routerChain) {
|
||||||
super(url == null && CollectionUtils.isNotEmpty(invokers) ? invokers.get(0).getUrl() : url, routerChain, false);
|
super(
|
||||||
|
url == null && CollectionUtils.isNotEmpty(invokers)
|
||||||
|
? invokers.get(0).getUrl()
|
||||||
|
: url,
|
||||||
|
routerChain,
|
||||||
|
false);
|
||||||
if (CollectionUtils.isEmpty(invokers)) {
|
if (CollectionUtils.isEmpty(invokers)) {
|
||||||
throw new IllegalArgumentException("invokers == null");
|
throw new IllegalArgumentException("invokers == null");
|
||||||
}
|
}
|
||||||
|
|
@ -101,28 +106,34 @@ public class StaticDirectory<T> extends AbstractDirectory<T> {
|
||||||
|
|
||||||
public void buildRouterChain() {
|
public void buildRouterChain() {
|
||||||
RouterChain<T> routerChain = RouterChain.buildChain(getInterface(), getUrl());
|
RouterChain<T> routerChain = RouterChain.buildChain(getInterface(), getUrl());
|
||||||
routerChain.setInvokers(getInvokers(), () -> {
|
routerChain.setInvokers(getInvokers(), () -> {});
|
||||||
});
|
|
||||||
this.setRouterChain(routerChain);
|
this.setRouterChain(routerChain);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notify(List<Invoker<T>> invokers) {
|
public void notify(List<Invoker<T>> invokers) {
|
||||||
BitList<Invoker<T>> bitList = new BitList<>(invokers);
|
BitList<Invoker<T>> bitList = new BitList<>(invokers);
|
||||||
if (routerChain != null) {
|
if (routerChain != null) {
|
||||||
refreshRouter(bitList.clone(), () -> this.setInvokers(bitList));
|
refreshRouter(bitList.clone(), () -> this.setInvokers(bitList));
|
||||||
} else {
|
} else {
|
||||||
this.setInvokers(bitList);
|
this.setInvokers(bitList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<Invoker<T>> doList(SingleRouterChain<T> singleRouterChain, BitList<Invoker<T>> invokers, Invocation invocation) throws RpcException {
|
protected List<Invoker<T>> doList(
|
||||||
|
SingleRouterChain<T> singleRouterChain, BitList<Invoker<T>> invokers, Invocation invocation)
|
||||||
|
throws RpcException {
|
||||||
if (singleRouterChain != null) {
|
if (singleRouterChain != null) {
|
||||||
try {
|
try {
|
||||||
List<Invoker<T>> finalInvokers = singleRouterChain.route(getConsumerUrl(), invokers, invocation);
|
List<Invoker<T>> finalInvokers = singleRouterChain.route(getConsumerUrl(), invokers, invocation);
|
||||||
return finalInvokers == null ? BitList.emptyList() : finalInvokers;
|
return finalInvokers == null ? BitList.emptyList() : finalInvokers;
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
logger.error(CLUSTER_FAILED_SITE_SELECTION, "Failed to execute router", "", "Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
|
logger.error(
|
||||||
|
CLUSTER_FAILED_SITE_SELECTION,
|
||||||
|
"Failed to execute router",
|
||||||
|
"",
|
||||||
|
"Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(),
|
||||||
|
t);
|
||||||
return BitList.emptyList();
|
return BitList.emptyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,5 +21,4 @@ import org.apache.dubbo.common.extension.SPI;
|
||||||
import org.apache.dubbo.rpc.BaseFilter;
|
import org.apache.dubbo.rpc.BaseFilter;
|
||||||
|
|
||||||
@SPI(scope = ExtensionScope.MODULE)
|
@SPI(scope = ExtensionScope.MODULE)
|
||||||
public interface ClusterFilter extends BaseFilter {
|
public interface ClusterFilter extends BaseFilter {}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,14 @@ public class DefaultFilterChainBuilder implements FilterChainBuilder {
|
||||||
List<ModuleModel> moduleModels = getModuleModelsFromUrl(url);
|
List<ModuleModel> moduleModels = getModuleModelsFromUrl(url);
|
||||||
List<Filter> filters;
|
List<Filter> filters;
|
||||||
if (moduleModels != null && moduleModels.size() == 1) {
|
if (moduleModels != null && moduleModels.size() == 1) {
|
||||||
filters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModels.get(0)).getActivateExtension(url, key, group);
|
filters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModels.get(0))
|
||||||
|
.getActivateExtension(url, key, group);
|
||||||
} else if (moduleModels != null && moduleModels.size() > 1) {
|
} else if (moduleModels != null && moduleModels.size() > 1) {
|
||||||
filters = new ArrayList<>();
|
filters = new ArrayList<>();
|
||||||
List<ExtensionDirector> directors = new ArrayList<>();
|
List<ExtensionDirector> directors = new ArrayList<>();
|
||||||
for (ModuleModel moduleModel : moduleModels) {
|
for (ModuleModel moduleModel : moduleModels) {
|
||||||
List<Filter> tempFilters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModel).getActivateExtension(url, key, group);
|
List<Filter> tempFilters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModel)
|
||||||
|
.getActivateExtension(url, key, group);
|
||||||
filters.addAll(tempFilters);
|
filters.addAll(tempFilters);
|
||||||
directors.add(moduleModel.getExtensionDirector());
|
directors.add(moduleModel.getExtensionDirector());
|
||||||
}
|
}
|
||||||
|
|
@ -62,7 +64,6 @@ public class DefaultFilterChainBuilder implements FilterChainBuilder {
|
||||||
filters = ScopeModelUtil.getExtensionLoader(Filter.class, null).getActivateExtension(url, key, group);
|
filters = ScopeModelUtil.getExtensionLoader(Filter.class, null).getActivateExtension(url, key, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!CollectionUtils.isEmpty(filters)) {
|
if (!CollectionUtils.isEmpty(filters)) {
|
||||||
for (int i = filters.size() - 1; i >= 0; i--) {
|
for (int i = filters.size() - 1; i >= 0; i--) {
|
||||||
final Filter filter = filters.get(i);
|
final Filter filter = filters.get(i);
|
||||||
|
|
@ -79,25 +80,29 @@ public class DefaultFilterChainBuilder implements FilterChainBuilder {
|
||||||
* build consumer cluster filter chain
|
* build consumer cluster filter chain
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <T> ClusterInvoker<T> buildClusterInvokerChain(final ClusterInvoker<T> originalInvoker, String key, String group) {
|
public <T> ClusterInvoker<T> buildClusterInvokerChain(
|
||||||
|
final ClusterInvoker<T> originalInvoker, String key, String group) {
|
||||||
ClusterInvoker<T> last = originalInvoker;
|
ClusterInvoker<T> last = originalInvoker;
|
||||||
URL url = originalInvoker.getUrl();
|
URL url = originalInvoker.getUrl();
|
||||||
List<ModuleModel> moduleModels = getModuleModelsFromUrl(url);
|
List<ModuleModel> moduleModels = getModuleModelsFromUrl(url);
|
||||||
List<ClusterFilter> filters;
|
List<ClusterFilter> filters;
|
||||||
if (moduleModels != null && moduleModels.size() == 1) {
|
if (moduleModels != null && moduleModels.size() == 1) {
|
||||||
filters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, moduleModels.get(0)).getActivateExtension(url, key, group);
|
filters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, moduleModels.get(0))
|
||||||
|
.getActivateExtension(url, key, group);
|
||||||
} else if (moduleModels != null && moduleModels.size() > 1) {
|
} else if (moduleModels != null && moduleModels.size() > 1) {
|
||||||
filters = new ArrayList<>();
|
filters = new ArrayList<>();
|
||||||
List<ExtensionDirector> directors = new ArrayList<>();
|
List<ExtensionDirector> directors = new ArrayList<>();
|
||||||
for (ModuleModel moduleModel : moduleModels) {
|
for (ModuleModel moduleModel : moduleModels) {
|
||||||
List<ClusterFilter> tempFilters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, moduleModel).getActivateExtension(url, key, group);
|
List<ClusterFilter> tempFilters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, moduleModel)
|
||||||
|
.getActivateExtension(url, key, group);
|
||||||
filters.addAll(tempFilters);
|
filters.addAll(tempFilters);
|
||||||
directors.add(moduleModel.getExtensionDirector());
|
directors.add(moduleModel.getExtensionDirector());
|
||||||
}
|
}
|
||||||
filters = sortingAndDeduplication(filters, directors);
|
filters = sortingAndDeduplication(filters, directors);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
filters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, null).getActivateExtension(url, key, group);
|
filters =
|
||||||
|
ScopeModelUtil.getExtensionLoader(ClusterFilter.class, null).getActivateExtension(url, key, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CollectionUtils.isEmpty(filters)) {
|
if (!CollectionUtils.isEmpty(filters)) {
|
||||||
|
|
@ -141,5 +146,4 @@ public class DefaultFilterChainBuilder implements FilterChainBuilder {
|
||||||
}
|
}
|
||||||
return moduleModels;
|
return moduleModels;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,8 @@ public interface FilterChainBuilder {
|
||||||
public Result invoke(Invocation invocation) throws RpcException {
|
public Result invoke(Invocation invocation) throws RpcException {
|
||||||
Result asyncResult;
|
Result asyncResult;
|
||||||
try {
|
try {
|
||||||
InvocationProfilerUtils.enterDetailProfiler(invocation, () -> "Filter " + filter.getClass().getName() + " invoke.");
|
InvocationProfilerUtils.enterDetailProfiler(
|
||||||
|
invocation, () -> "Filter " + filter.getClass().getName() + " invoke.");
|
||||||
asyncResult = filter.invoke(nextNode, invocation);
|
asyncResult = filter.invoke(nextNode, invocation);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
InvocationProfilerUtils.releaseDetailProfiler(invocation);
|
InvocationProfilerUtils.releaseDetailProfiler(invocation);
|
||||||
|
|
@ -159,12 +160,11 @@ public interface FilterChainBuilder {
|
||||||
* @param <TYPE>
|
* @param <TYPE>
|
||||||
*/
|
*/
|
||||||
class ClusterFilterChainNode<T, TYPE extends ClusterInvoker<T>, FILTER extends BaseFilter>
|
class ClusterFilterChainNode<T, TYPE extends ClusterInvoker<T>, FILTER extends BaseFilter>
|
||||||
extends FilterChainNode<T, TYPE, FILTER> implements ClusterInvoker<T> {
|
extends FilterChainNode<T, TYPE, FILTER> implements ClusterInvoker<T> {
|
||||||
public ClusterFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) {
|
public ClusterFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) {
|
||||||
super(originalInvoker, nextNode, filter);
|
super(originalInvoker, nextNode, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URL getRegistryUrl() {
|
public URL getRegistryUrl() {
|
||||||
return getOriginalInvoker().getRegistryUrl();
|
return getOriginalInvoker().getRegistryUrl();
|
||||||
|
|
@ -182,7 +182,8 @@ public interface FilterChainBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
class CallbackRegistrationInvoker<T, FILTER extends BaseFilter> implements Invoker<T> {
|
class CallbackRegistrationInvoker<T, FILTER extends BaseFilter> implements Invoker<T> {
|
||||||
private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(CallbackRegistrationInvoker.class);
|
private static final ErrorTypeAwareLogger LOGGER =
|
||||||
|
LoggerFactory.getErrorTypeAwareLogger(CallbackRegistrationInvoker.class);
|
||||||
final Invoker<T> filterInvoker;
|
final Invoker<T> filterInvoker;
|
||||||
final List<FILTER> filters;
|
final List<FILTER> filters;
|
||||||
|
|
||||||
|
|
@ -223,9 +224,20 @@ public interface FilterChainBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (RuntimeException runtimeException) {
|
} catch (RuntimeException runtimeException) {
|
||||||
LOGGER.error(CLUSTER_EXECUTE_FILTER_EXCEPTION, "the custom filter is abnormal", "", String.format("Exception occurred while executing the %s filter named %s.", i, filter.getClass().getSimpleName()));
|
LOGGER.error(
|
||||||
|
CLUSTER_EXECUTE_FILTER_EXCEPTION,
|
||||||
|
"the custom filter is abnormal",
|
||||||
|
"",
|
||||||
|
String.format(
|
||||||
|
"Exception occurred while executing the %s filter named %s.",
|
||||||
|
i, filter.getClass().getSimpleName()));
|
||||||
if (LOGGER.isDebugEnabled()) {
|
if (LOGGER.isDebugEnabled()) {
|
||||||
LOGGER.debug(String.format("Whole filter list is: %s", filters.stream().map(tmpFilter -> tmpFilter.getClass().getSimpleName()).collect(Collectors.toList())));
|
LOGGER.debug(String.format(
|
||||||
|
"Whole filter list is: %s",
|
||||||
|
filters.stream()
|
||||||
|
.map(tmpFilter ->
|
||||||
|
tmpFilter.getClass().getSimpleName())
|
||||||
|
.collect(Collectors.toList())));
|
||||||
}
|
}
|
||||||
filterRuntimeException = runtimeException;
|
filterRuntimeException = runtimeException;
|
||||||
t = runtimeException;
|
t = runtimeException;
|
||||||
|
|
@ -264,11 +276,12 @@ public interface FilterChainBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ClusterCallbackRegistrationInvoker<T, FILTER extends BaseFilter> extends CallbackRegistrationInvoker<T, FILTER>
|
class ClusterCallbackRegistrationInvoker<T, FILTER extends BaseFilter>
|
||||||
implements ClusterInvoker<T> {
|
extends CallbackRegistrationInvoker<T, FILTER> implements ClusterInvoker<T> {
|
||||||
private ClusterInvoker<T> originalInvoker;
|
private ClusterInvoker<T> originalInvoker;
|
||||||
|
|
||||||
public ClusterCallbackRegistrationInvoker(ClusterInvoker<T> originalInvoker, Invoker<T> filterInvoker, List<FILTER> filters) {
|
public ClusterCallbackRegistrationInvoker(
|
||||||
|
ClusterInvoker<T> originalInvoker, Invoker<T> filterInvoker, List<FILTER> filters) {
|
||||||
super(filterInvoker, filters);
|
super(filterInvoker, filters);
|
||||||
this.originalInvoker = originalInvoker;
|
this.originalInvoker = originalInvoker;
|
||||||
}
|
}
|
||||||
|
|
@ -293,10 +306,11 @@ public interface FilterChainBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Experimental(
|
||||||
@Experimental("Works for the same purpose as FilterChainNode, replace FilterChainNode with this one when proved stable enough")
|
"Works for the same purpose as FilterChainNode, replace FilterChainNode with this one when proved stable enough")
|
||||||
class CopyOfFilterChainNode<T, TYPE extends Invoker<T>, FILTER extends BaseFilter> implements Invoker<T> {
|
class CopyOfFilterChainNode<T, TYPE extends Invoker<T>, FILTER extends BaseFilter> implements Invoker<T> {
|
||||||
private static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(CopyOfFilterChainNode.class);
|
private static final ErrorTypeAwareLogger LOGGER =
|
||||||
|
LoggerFactory.getErrorTypeAwareLogger(CopyOfFilterChainNode.class);
|
||||||
TYPE originalInvoker;
|
TYPE originalInvoker;
|
||||||
Invoker<T> nextNode;
|
Invoker<T> nextNode;
|
||||||
FILTER filter;
|
FILTER filter;
|
||||||
|
|
@ -330,11 +344,14 @@ public interface FilterChainBuilder {
|
||||||
public Result invoke(Invocation invocation) throws RpcException {
|
public Result invoke(Invocation invocation) throws RpcException {
|
||||||
Result asyncResult;
|
Result asyncResult;
|
||||||
try {
|
try {
|
||||||
InvocationProfilerUtils.enterDetailProfiler(invocation, () -> "Filter " + filter.getClass().getName() + " invoke.");
|
InvocationProfilerUtils.enterDetailProfiler(
|
||||||
|
invocation, () -> "Filter " + filter.getClass().getName() + " invoke.");
|
||||||
asyncResult = filter.invoke(nextNode, invocation);
|
asyncResult = filter.invoke(nextNode, invocation);
|
||||||
if (!(asyncResult instanceof AsyncRpcResult)) {
|
if (!(asyncResult instanceof AsyncRpcResult)) {
|
||||||
String msg = "The result of filter invocation must be AsyncRpcResult. (If you want to recreate a result, please use AsyncRpcResult.newDefaultAsyncResult.) " +
|
String msg =
|
||||||
"Filter class: " + filter.getClass().getName() + ". Result class: " + asyncResult.getClass().getName() + ".";
|
"The result of filter invocation must be AsyncRpcResult. (If you want to recreate a result, please use AsyncRpcResult.newDefaultAsyncResult.) "
|
||||||
|
+ "Filter class: " + filter.getClass().getName() + ". Result class: "
|
||||||
|
+ asyncResult.getClass().getName() + ".";
|
||||||
LOGGER.error(INTERNAL_ERROR, "", "", msg);
|
LOGGER.error(INTERNAL_ERROR, "", "", msg);
|
||||||
throw new RpcException(msg);
|
throw new RpcException(msg);
|
||||||
}
|
}
|
||||||
|
|
@ -372,14 +389,14 @@ public interface FilterChainBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Experimental("Works for the same purpose as ClusterFilterChainNode, replace ClusterFilterChainNode with this one when proved stable enough")
|
@Experimental(
|
||||||
|
"Works for the same purpose as ClusterFilterChainNode, replace ClusterFilterChainNode with this one when proved stable enough")
|
||||||
class CopyOfClusterFilterChainNode<T, TYPE extends ClusterInvoker<T>, FILTER extends BaseFilter>
|
class CopyOfClusterFilterChainNode<T, TYPE extends ClusterInvoker<T>, FILTER extends BaseFilter>
|
||||||
extends CopyOfFilterChainNode<T, TYPE, FILTER> implements ClusterInvoker<T> {
|
extends CopyOfFilterChainNode<T, TYPE, FILTER> implements ClusterInvoker<T> {
|
||||||
public CopyOfClusterFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) {
|
public CopyOfClusterFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) {
|
||||||
super(originalInvoker, nextNode, filter);
|
super(originalInvoker, nextNode, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URL getRegistryUrl() {
|
public URL getRegistryUrl() {
|
||||||
return getOriginalInvoker().getRegistryUrl();
|
return getOriginalInvoker().getRegistryUrl();
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,8 @@ public class ProtocolFilterWrapper implements Protocol {
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> FilterChainBuilder getFilterChainBuilder(URL url) {
|
private <T> FilterChainBuilder getFilterChainBuilder(URL url) {
|
||||||
return ScopeModelUtil.getExtensionLoader(FilterChainBuilder.class, url.getScopeModel()).getDefaultExtension();
|
return ScopeModelUtil.getExtensionLoader(FilterChainBuilder.class, url.getScopeModel())
|
||||||
|
.getDefaultExtension();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -83,5 +84,4 @@ public class ProtocolFilterWrapper implements Protocol {
|
||||||
public List<ProtocolServer> getServers() {
|
public List<ProtocolServer> getServers() {
|
||||||
return protocol.getServers();
|
return protocol.getServers();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ public class ConsumerClassLoaderFilter implements ClusterFilter {
|
||||||
ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();
|
ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();
|
||||||
try {
|
try {
|
||||||
Optional.ofNullable(invocation.getServiceModel())
|
Optional.ofNullable(invocation.getServiceModel())
|
||||||
.map(ServiceModel::getClassLoader)
|
.map(ServiceModel::getClassLoader)
|
||||||
.ifPresent(Thread.currentThread()::setContextClassLoader);
|
.ifPresent(Thread.currentThread()::setContextClassLoader);
|
||||||
return invoker.invoke(invocation);
|
return invoker.invoke(invocation);
|
||||||
} finally {
|
} finally {
|
||||||
Thread.currentThread().setContextClassLoader(originClassLoader);
|
Thread.currentThread().setContextClassLoader(originClassLoader);
|
||||||
|
|
|
||||||
|
|
@ -56,16 +56,17 @@ public class ConsumerContextFilter implements ClusterFilter, ClusterFilter.Liste
|
||||||
private Set<PenetrateAttachmentSelector> supportedSelectors;
|
private Set<PenetrateAttachmentSelector> supportedSelectors;
|
||||||
|
|
||||||
public ConsumerContextFilter(ApplicationModel applicationModel) {
|
public ConsumerContextFilter(ApplicationModel applicationModel) {
|
||||||
ExtensionLoader<PenetrateAttachmentSelector> selectorExtensionLoader = applicationModel.getExtensionLoader(PenetrateAttachmentSelector.class);
|
ExtensionLoader<PenetrateAttachmentSelector> selectorExtensionLoader =
|
||||||
|
applicationModel.getExtensionLoader(PenetrateAttachmentSelector.class);
|
||||||
supportedSelectors = selectorExtensionLoader.getSupportedExtensionInstances();
|
supportedSelectors = selectorExtensionLoader.getSupportedExtensionInstances();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||||
RpcContext.getServiceContext()
|
RpcContext.getServiceContext()
|
||||||
.setInvoker(invoker)
|
.setInvoker(invoker)
|
||||||
.setInvocation(invocation)
|
.setInvocation(invocation)
|
||||||
.setLocalAddress(NetUtils.getLocalHost(), 0);
|
.setLocalAddress(NetUtils.getLocalHost(), 0);
|
||||||
|
|
||||||
RpcContext context = RpcContext.getClientAttachment();
|
RpcContext context = RpcContext.getClientAttachment();
|
||||||
context.setAttachment(REMOTE_APPLICATION_KEY, invoker.getUrl().getApplication());
|
context.setAttachment(REMOTE_APPLICATION_KEY, invoker.getUrl().getApplication());
|
||||||
|
|
@ -75,15 +76,18 @@ public class ConsumerContextFilter implements ClusterFilter, ClusterFilter.Liste
|
||||||
|
|
||||||
if (CollectionUtils.isNotEmpty(supportedSelectors)) {
|
if (CollectionUtils.isNotEmpty(supportedSelectors)) {
|
||||||
for (PenetrateAttachmentSelector supportedSelector : supportedSelectors) {
|
for (PenetrateAttachmentSelector supportedSelector : supportedSelectors) {
|
||||||
Map<String, Object> selected = supportedSelector.select(invocation, RpcContext.getClientAttachment(), RpcContext.getServerAttachment());
|
Map<String, Object> selected = supportedSelector.select(
|
||||||
|
invocation, RpcContext.getClientAttachment(), RpcContext.getServerAttachment());
|
||||||
if (CollectionUtils.isNotEmptyMap(selected)) {
|
if (CollectionUtils.isNotEmptyMap(selected)) {
|
||||||
((RpcInvocation) invocation).addObjectAttachments(selected);
|
((RpcInvocation) invocation).addObjectAttachments(selected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
((RpcInvocation) invocation).addObjectAttachments(RpcContext.getServerAttachment().getObjectAttachments());
|
((RpcInvocation) invocation)
|
||||||
|
.addObjectAttachments(RpcContext.getServerAttachment().getObjectAttachments());
|
||||||
}
|
}
|
||||||
Map<String, Object> contextAttachments = RpcContext.getClientAttachment().getObjectAttachments();
|
Map<String, Object> contextAttachments =
|
||||||
|
RpcContext.getClientAttachment().getObjectAttachments();
|
||||||
if (CollectionUtils.isNotEmptyMap(contextAttachments)) {
|
if (CollectionUtils.isNotEmptyMap(contextAttachments)) {
|
||||||
/**
|
/**
|
||||||
* invocation.addAttachmentsIfAbsent(context){@link RpcInvocation#addAttachmentsIfAbsent(Map)}should not be used here,
|
* invocation.addAttachmentsIfAbsent(context){@link RpcInvocation#addAttachmentsIfAbsent(Map)}should not be used here,
|
||||||
|
|
@ -106,9 +110,12 @@ public class ConsumerContextFilter implements ClusterFilter, ClusterFilter.Liste
|
||||||
|
|
||||||
TimeoutCountDown timeoutCountDown = (TimeoutCountDown) countDown;
|
TimeoutCountDown timeoutCountDown = (TimeoutCountDown) countDown;
|
||||||
if (timeoutCountDown.isExpired()) {
|
if (timeoutCountDown.isExpired()) {
|
||||||
return AsyncRpcResult.newDefaultAsyncResult(new RpcException(RpcException.TIMEOUT_TERMINATE,
|
return AsyncRpcResult.newDefaultAsyncResult(
|
||||||
"No time left for making the following call: " + invocation.getServiceName() + "."
|
new RpcException(
|
||||||
+ RpcUtils.getMethodName(invocation) + ", terminate directly."), invocation);
|
RpcException.TIMEOUT_TERMINATE,
|
||||||
|
"No time left for making the following call: " + invocation.getServiceName() + "."
|
||||||
|
+ RpcUtils.getMethodName(invocation) + ", terminate directly."),
|
||||||
|
invocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -135,14 +142,15 @@ public class ConsumerContextFilter implements ClusterFilter, ClusterFilter.Liste
|
||||||
RpcInvocation rpcInvocation = (RpcInvocation) invocation;
|
RpcInvocation rpcInvocation = (RpcInvocation) invocation;
|
||||||
if (rpcInvocation.getInvokeMode() != null) {
|
if (rpcInvocation.getInvokeMode() != null) {
|
||||||
// clear service context if not in sync mode
|
// clear service context if not in sync mode
|
||||||
if (rpcInvocation.getInvokeMode() == InvokeMode.ASYNC || rpcInvocation.getInvokeMode() == InvokeMode.FUTURE) {
|
if (rpcInvocation.getInvokeMode() == InvokeMode.ASYNC
|
||||||
|
|| rpcInvocation.getInvokeMode() == InvokeMode.FUTURE) {
|
||||||
RpcContext.removeServiceContext();
|
RpcContext.removeServiceContext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// server context must not be removed because user might use it on callback.
|
// server context must not be removed because user might use it on callback.
|
||||||
// So the clear of is delayed til the start of the next rpc call, see RpcContext.removeServerContext(); in invoke() above
|
// So the clear of is delayed til the start of the next rpc call, see RpcContext.removeServerContext(); in
|
||||||
|
// invoke() above
|
||||||
// RpcContext.removeServerContext();
|
// RpcContext.removeServerContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,8 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.filter.support;
|
package org.apache.dubbo.rpc.cluster.filter.support;
|
||||||
|
|
||||||
|
|
||||||
import org.apache.dubbo.common.extension.Activate;
|
import org.apache.dubbo.common.extension.Activate;
|
||||||
import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
|
import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
|
||||||
import org.apache.dubbo.metrics.event.MetricsDispatcher;
|
import org.apache.dubbo.metrics.event.MetricsDispatcher;
|
||||||
|
|
@ -76,9 +74,15 @@ public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener,
|
||||||
if (t instanceof RpcException) {
|
if (t instanceof RpcException) {
|
||||||
RpcException e = (RpcException) t;
|
RpcException e = (RpcException) t;
|
||||||
if (e.isForbidden()) {
|
if (e.isForbidden()) {
|
||||||
MetricsEventBus.publish(RequestEvent.toRequestErrorEvent(applicationModel, appName, metricsDispatcher, invocation, CONSUMER_SIDE, e.getCode(), serviceLevel));
|
MetricsEventBus.publish(RequestEvent.toRequestErrorEvent(
|
||||||
|
applicationModel,
|
||||||
|
appName,
|
||||||
|
metricsDispatcher,
|
||||||
|
invocation,
|
||||||
|
CONSUMER_SIDE,
|
||||||
|
e.getCode(),
|
||||||
|
serviceLevel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,11 @@ import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
|
||||||
|
|
||||||
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
|
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
|
||||||
|
|
||||||
@Activate(group = {CONSUMER}, order = Integer.MIN_VALUE + 100)
|
@Activate(
|
||||||
|
group = {CONSUMER},
|
||||||
|
order = Integer.MIN_VALUE + 100)
|
||||||
public class MetricsConsumerFilter extends MetricsFilter implements ClusterFilter, BaseFilter.Listener {
|
public class MetricsConsumerFilter extends MetricsFilter implements ClusterFilter, BaseFilter.Listener {
|
||||||
public MetricsConsumerFilter() {
|
public MetricsConsumerFilter() {}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,8 @@ public class ObservationSenderFilter implements ClusterFilter, BaseFilter.Listen
|
||||||
applicationModel.getApplicationConfigManager().getTracing().ifPresent(cfg -> {
|
applicationModel.getApplicationConfigManager().getTracing().ifPresent(cfg -> {
|
||||||
if (Boolean.TRUE.equals(cfg.getEnabled())) {
|
if (Boolean.TRUE.equals(cfg.getEnabled())) {
|
||||||
observationRegistry = applicationModel.getBeanFactory().getBean(ObservationRegistry.class);
|
observationRegistry = applicationModel.getBeanFactory().getBean(ObservationRegistry.class);
|
||||||
clientObservationConvention = applicationModel.getBeanFactory().getBean(DubboClientObservationConvention.class);
|
clientObservationConvention =
|
||||||
|
applicationModel.getBeanFactory().getBean(DubboClientObservationConvention.class);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +65,8 @@ public class ObservationSenderFilter implements ClusterFilter, BaseFilter.Listen
|
||||||
final Observation observation = DubboObservationDocumentation.CLIENT.observation(
|
final Observation observation = DubboObservationDocumentation.CLIENT.observation(
|
||||||
this.clientObservationConvention,
|
this.clientObservationConvention,
|
||||||
DefaultDubboClientObservationConvention.getInstance(),
|
DefaultDubboClientObservationConvention.getInstance(),
|
||||||
() -> senderContext, observationRegistry);
|
() -> senderContext,
|
||||||
|
observationRegistry);
|
||||||
invocation.put(Observation.class, observation.start());
|
invocation.put(Observation.class, observation.start());
|
||||||
return observation.scoped(() -> invoker.invoke(invocation));
|
return observation.scoped(() -> invoker.invoke(invocation));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,5 +56,4 @@ public class DefaultGovernanceRuleRepositoryImpl implements GovernanceRuleReposi
|
||||||
private DynamicConfiguration getDynamicConfiguration() {
|
private DynamicConfiguration getDynamicConfiguration() {
|
||||||
return moduleModel.modelEnvironment().getDynamicConfiguration().orElse(null);
|
return moduleModel.modelEnvironment().getDynamicConfiguration().orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@ public interface GovernanceRuleRepository {
|
||||||
addListener(key, DEFAULT_GROUP, listener);
|
addListener(key, DEFAULT_GROUP, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link #removeListener(String, String, ConfigurationListener)}
|
* {@link #removeListener(String, String, ConfigurationListener)}
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public abstract class AbstractLoadBalance implements LoadBalance {
|
||||||
* @return weight which takes warmup into account
|
* @return weight which takes warmup into account
|
||||||
*/
|
*/
|
||||||
static int calculateWarmupWeight(int uptime, int warmup, int weight) {
|
static int calculateWarmupWeight(int uptime, int warmup, int weight) {
|
||||||
int ww = (int) ( uptime / ((float) warmup / weight));
|
int ww = (int) (uptime / ((float) warmup / weight));
|
||||||
return ww < 1 ? 1 : (Math.min(ww, weight));
|
return ww < 1 ? 1 : (Math.min(ww, weight));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,7 +64,6 @@ public abstract class AbstractLoadBalance implements LoadBalance {
|
||||||
|
|
||||||
protected abstract <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation);
|
protected abstract <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the weight of the invoker's invocation which takes warmup time into account
|
* Get the weight of the invoker's invocation which takes warmup time into account
|
||||||
* if the uptime is within the warmup time, the weight will be reduce proportionally
|
* if the uptime is within the warmup time, the weight will be reduce proportionally
|
||||||
|
|
@ -94,7 +93,7 @@ public abstract class AbstractLoadBalance implements LoadBalance {
|
||||||
}
|
}
|
||||||
int warmup = invoker.getUrl().getParameter(WARMUP_KEY, DEFAULT_WARMUP);
|
int warmup = invoker.getUrl().getParameter(WARMUP_KEY, DEFAULT_WARMUP);
|
||||||
if (uptime > 0 && uptime < warmup) {
|
if (uptime > 0 && uptime < warmup) {
|
||||||
weight = calculateWarmupWeight((int)uptime, warmup, weight);
|
weight = calculateWarmupWeight((int) uptime, warmup, weight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,36 +41,36 @@ public class AdaptiveLoadBalance extends AbstractLoadBalance {
|
||||||
|
|
||||||
public static final String NAME = "adaptive";
|
public static final String NAME = "adaptive";
|
||||||
|
|
||||||
//default key
|
// default key
|
||||||
private String attachmentKey = "mem,load";
|
private String attachmentKey = "mem,load";
|
||||||
|
|
||||||
private final AdaptiveMetrics adaptiveMetrics;
|
private final AdaptiveMetrics adaptiveMetrics;
|
||||||
|
|
||||||
public AdaptiveLoadBalance(ApplicationModel scopeModel){
|
public AdaptiveLoadBalance(ApplicationModel scopeModel) {
|
||||||
adaptiveMetrics = scopeModel.getBeanFactory().getBean(AdaptiveMetrics.class);
|
adaptiveMetrics = scopeModel.getBeanFactory().getBean(AdaptiveMetrics.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
|
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
|
||||||
Invoker<T> invoker = selectByP2C(invokers,invocation);
|
Invoker<T> invoker = selectByP2C(invokers, invocation);
|
||||||
invocation.setAttachment(Constants.ADAPTIVE_LOADBALANCE_ATTACHMENT_KEY,attachmentKey);
|
invocation.setAttachment(Constants.ADAPTIVE_LOADBALANCE_ATTACHMENT_KEY, attachmentKey);
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
invocation.getAttributes().put(Constants.ADAPTIVE_LOADBALANCE_START_TIME,startTime);
|
invocation.getAttributes().put(Constants.ADAPTIVE_LOADBALANCE_START_TIME, startTime);
|
||||||
invocation.getAttributes().put(LOADBALANCE_KEY,LoadbalanceRules.ADAPTIVE);
|
invocation.getAttributes().put(LOADBALANCE_KEY, LoadbalanceRules.ADAPTIVE);
|
||||||
adaptiveMetrics.addConsumerReq(getServiceKey(invoker,invocation));
|
adaptiveMetrics.addConsumerReq(getServiceKey(invoker, invocation));
|
||||||
adaptiveMetrics.setPickTime(getServiceKey(invoker,invocation),startTime);
|
adaptiveMetrics.setPickTime(getServiceKey(invoker, invocation), startTime);
|
||||||
|
|
||||||
return invoker;
|
return invoker;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> Invoker<T> selectByP2C(List<Invoker<T>> invokers, Invocation invocation){
|
private <T> Invoker<T> selectByP2C(List<Invoker<T>> invokers, Invocation invocation) {
|
||||||
int length = invokers.size();
|
int length = invokers.size();
|
||||||
if(length == 1) {
|
if (length == 1) {
|
||||||
return invokers.get(0);
|
return invokers.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(length == 2) {
|
if (length == 2) {
|
||||||
return chooseLowLoadInvoker(invokers.get(0),invokers.get(1),invocation);
|
return chooseLowLoadInvoker(invokers.get(0), invokers.get(1), invocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pos1 = ThreadLocalRandom.current().nextInt(length);
|
int pos1 = ThreadLocalRandom.current().nextInt(length);
|
||||||
|
|
@ -79,22 +79,22 @@ public class AdaptiveLoadBalance extends AbstractLoadBalance {
|
||||||
pos2 = pos2 + 1;
|
pos2 = pos2 + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return chooseLowLoadInvoker(invokers.get(pos1),invokers.get(pos2),invocation);
|
return chooseLowLoadInvoker(invokers.get(pos1), invokers.get(pos2), invocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getServiceKey(Invoker<?> invoker,Invocation invocation){
|
private String getServiceKey(Invoker<?> invoker, Invocation invocation) {
|
||||||
|
|
||||||
String key = (String) invocation.getAttributes().get(invoker);
|
String key = (String) invocation.getAttributes().get(invoker);
|
||||||
if (StringUtils.isNotEmpty(key)){
|
if (StringUtils.isNotEmpty(key)) {
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
key = buildServiceKey(invoker,invocation);
|
key = buildServiceKey(invoker, invocation);
|
||||||
invocation.getAttributes().put(invoker,key);
|
invocation.getAttributes().put(invoker, key);
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildServiceKey(Invoker<?> invoker,Invocation invocation){
|
private String buildServiceKey(Invoker<?> invoker, Invocation invocation) {
|
||||||
URL url = invoker.getUrl();
|
URL url = invoker.getUrl();
|
||||||
StringBuilder sb = new StringBuilder(128);
|
StringBuilder sb = new StringBuilder(128);
|
||||||
sb.append(url.getAddress()).append(":").append(invocation.getProtocolServiceKey());
|
sb.append(url.getAddress()).append(":").append(invocation.getProtocolServiceKey());
|
||||||
|
|
@ -104,16 +104,19 @@ public class AdaptiveLoadBalance extends AbstractLoadBalance {
|
||||||
private int getTimeout(Invoker<?> invoker, Invocation invocation) {
|
private int getTimeout(Invoker<?> invoker, Invocation invocation) {
|
||||||
URL url = invoker.getUrl();
|
URL url = invoker.getUrl();
|
||||||
String methodName = RpcUtils.getMethodName(invocation);
|
String methodName = RpcUtils.getMethodName(invocation);
|
||||||
return (int) RpcUtils.getTimeout(url,methodName, RpcContext.getClientAttachment(),invocation, DEFAULT_TIMEOUT);
|
return (int)
|
||||||
|
RpcUtils.getTimeout(url, methodName, RpcContext.getClientAttachment(), invocation, DEFAULT_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> Invoker<T> chooseLowLoadInvoker(Invoker<T> invoker1,Invoker<T> invoker2,Invocation invocation){
|
private <T> Invoker<T> chooseLowLoadInvoker(Invoker<T> invoker1, Invoker<T> invoker2, Invocation invocation) {
|
||||||
int weight1 = getWeight(invoker1, invocation);
|
int weight1 = getWeight(invoker1, invocation);
|
||||||
int weight2 = getWeight(invoker2, invocation);
|
int weight2 = getWeight(invoker2, invocation);
|
||||||
int timeout1 = getTimeout(invoker1, invocation);
|
int timeout1 = getTimeout(invoker1, invocation);
|
||||||
int timeout2 = getTimeout(invoker2, invocation);
|
int timeout2 = getTimeout(invoker2, invocation);
|
||||||
long load1 = Double.doubleToLongBits(adaptiveMetrics.getLoad(getServiceKey(invoker1,invocation),weight1,timeout1 ));
|
long load1 = Double.doubleToLongBits(
|
||||||
long load2 = Double.doubleToLongBits(adaptiveMetrics.getLoad(getServiceKey(invoker2,invocation),weight2,timeout2 ));
|
adaptiveMetrics.getLoad(getServiceKey(invoker1, invocation), weight1, timeout1));
|
||||||
|
long load2 = Double.doubleToLongBits(
|
||||||
|
adaptiveMetrics.getLoad(getServiceKey(invoker2, invocation), weight2, timeout2));
|
||||||
|
|
||||||
if (load1 == load2) {
|
if (load1 == load2) {
|
||||||
// The sum of weights
|
// The sum of weights
|
||||||
|
|
@ -129,5 +132,4 @@ public class AdaptiveLoadBalance extends AbstractLoadBalance {
|
||||||
}
|
}
|
||||||
return load1 > load2 ? invoker2 : invoker1;
|
return load1 > load2 ? invoker2 : invoker1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,8 @@ public class ConsistentHashLoadBalance extends AbstractLoadBalance {
|
||||||
*/
|
*/
|
||||||
public static final String HASH_ARGUMENTS = "hash.arguments";
|
public static final String HASH_ARGUMENTS = "hash.arguments";
|
||||||
|
|
||||||
private final ConcurrentMap<String, ConsistentHashSelector<?>> selectors = new ConcurrentHashMap<String, ConsistentHashSelector<?>>();
|
private final ConcurrentMap<String, ConsistentHashSelector<?>> selectors =
|
||||||
|
new ConcurrentHashMap<String, ConsistentHashSelector<?>>();
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -124,11 +125,10 @@ public class ConsistentHashLoadBalance extends AbstractLoadBalance {
|
||||||
|
|
||||||
private long hash(byte[] digest, int number) {
|
private long hash(byte[] digest, int number) {
|
||||||
return (((long) (digest[3 + number * 4] & 0xFF) << 24)
|
return (((long) (digest[3 + number * 4] & 0xFF) << 24)
|
||||||
| ((long) (digest[2 + number * 4] & 0xFF) << 16)
|
| ((long) (digest[2 + number * 4] & 0xFF) << 16)
|
||||||
| ((long) (digest[1 + number * 4] & 0xFF) << 8)
|
| ((long) (digest[1 + number * 4] & 0xFF) << 8)
|
||||||
| (digest[number * 4] & 0xFF))
|
| (digest[number * 4] & 0xFF))
|
||||||
& 0xFFFFFFFFL;
|
& 0xFFFFFFFFL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,17 +56,18 @@ public class LeastActiveLoadBalance extends AbstractLoadBalance {
|
||||||
// Every least active invoker has the same weight value?
|
// Every least active invoker has the same weight value?
|
||||||
boolean sameWeight = true;
|
boolean sameWeight = true;
|
||||||
|
|
||||||
|
|
||||||
// Filter out all the least active invokers
|
// Filter out all the least active invokers
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
Invoker<T> invoker = invokers.get(i);
|
Invoker<T> invoker = invokers.get(i);
|
||||||
// Get the active number of the invoker
|
// Get the active number of the invoker
|
||||||
int active = RpcStatus.getStatus(invoker.getUrl(), RpcUtils.getMethodName(invocation)).getActive();
|
int active = RpcStatus.getStatus(invoker.getUrl(), RpcUtils.getMethodName(invocation))
|
||||||
|
.getActive();
|
||||||
// Get the weight of the invoker's configuration. The default value is 100.
|
// Get the weight of the invoker's configuration. The default value is 100.
|
||||||
int afterWarmup = getWeight(invoker, invocation);
|
int afterWarmup = getWeight(invoker, invocation);
|
||||||
// save for later use
|
// save for later use
|
||||||
weights[i] = afterWarmup;
|
weights[i] = afterWarmup;
|
||||||
// If it is the first invoker or the active number of the invoker is less than the current least active number
|
// If it is the first invoker or the active number of the invoker is less than the current least active
|
||||||
|
// number
|
||||||
if (leastActive == -1 || active < leastActive) {
|
if (leastActive == -1 || active < leastActive) {
|
||||||
// Reset the active number of the current invoker to the least active number
|
// Reset the active number of the current invoker to the least active number
|
||||||
leastActive = active;
|
leastActive = active;
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,8 @@ public class RandomLoadBalance extends AbstractLoadBalance {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (totalWeight > 0 && !sameWeight) {
|
if (totalWeight > 0 && !sameWeight) {
|
||||||
// If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on totalWeight.
|
// If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on
|
||||||
|
// totalWeight.
|
||||||
int offset = ThreadLocalRandom.current().nextInt(totalWeight);
|
int offset = ThreadLocalRandom.current().nextInt(totalWeight);
|
||||||
// Return an invoker based on the random value.
|
// Return an invoker based on the random value.
|
||||||
if (length <= 4) {
|
if (length <= 4) {
|
||||||
|
|
@ -92,7 +93,7 @@ public class RandomLoadBalance extends AbstractLoadBalance {
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
i = -i - 1;
|
i = -i - 1;
|
||||||
} else {
|
} else {
|
||||||
while (weights[i+1] == offset) {
|
while (weights[i + 1] == offset) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,8 @@ public class RoundRobinLoadBalance extends AbstractLoadBalance {
|
||||||
|
|
||||||
private static final int RECYCLE_PERIOD = 60000;
|
private static final int RECYCLE_PERIOD = 60000;
|
||||||
|
|
||||||
private final ConcurrentMap<String, ConcurrentMap<String, WeightedRoundRobin>> methodWeightMap = new ConcurrentHashMap<>();
|
private final ConcurrentMap<String, ConcurrentMap<String, WeightedRoundRobin>> methodWeightMap =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
|
|
||||||
protected static class WeightedRoundRobin {
|
protected static class WeightedRoundRobin {
|
||||||
private int weight;
|
private int weight;
|
||||||
|
|
@ -91,7 +92,8 @@ public class RoundRobinLoadBalance extends AbstractLoadBalance {
|
||||||
@Override
|
@Override
|
||||||
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
|
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
|
||||||
String key = invokers.get(0).getUrl().getServiceKey() + "." + RpcUtils.getMethodName(invocation);
|
String key = invokers.get(0).getUrl().getServiceKey() + "." + RpcUtils.getMethodName(invocation);
|
||||||
ConcurrentMap<String, WeightedRoundRobin> map = ConcurrentHashMapUtils.computeIfAbsent(methodWeightMap, key, k -> new ConcurrentHashMap<>());
|
ConcurrentMap<String, WeightedRoundRobin> map =
|
||||||
|
ConcurrentHashMapUtils.computeIfAbsent(methodWeightMap, key, k -> new ConcurrentHashMap<>());
|
||||||
int totalWeight = 0;
|
int totalWeight = 0;
|
||||||
long maxCurrent = Long.MIN_VALUE;
|
long maxCurrent = Long.MIN_VALUE;
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
|
@ -107,7 +109,7 @@ public class RoundRobinLoadBalance extends AbstractLoadBalance {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (weight != weightedRoundRobin.getWeight()) {
|
if (weight != weightedRoundRobin.getWeight()) {
|
||||||
//weight changed
|
// weight changed
|
||||||
weightedRoundRobin.setWeight(weight);
|
weightedRoundRobin.setWeight(weight);
|
||||||
}
|
}
|
||||||
long cur = weightedRoundRobin.increaseCurrent();
|
long cur = weightedRoundRobin.increaseCurrent();
|
||||||
|
|
@ -129,5 +131,4 @@ public class RoundRobinLoadBalance extends AbstractLoadBalance {
|
||||||
// should not happen here
|
// should not happen here
|
||||||
return invokers.get(0);
|
return invokers.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,15 @@ public class ShortestResponseLoadBalance extends AbstractLoadBalance implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setApplicationModel(ApplicationModel applicationModel) {
|
public void setApplicationModel(ApplicationModel applicationModel) {
|
||||||
slidePeriod = applicationModel.modelEnvironment().getConfiguration().getInt(Constants.SHORTEST_RESPONSE_SLIDE_PERIOD, 30_000);
|
slidePeriod = applicationModel
|
||||||
executorService = applicationModel.getFrameworkModel().getBeanFactory()
|
.modelEnvironment()
|
||||||
.getBean(FrameworkExecutorRepository.class).getSharedExecutor();
|
.getConfiguration()
|
||||||
|
.getInt(Constants.SHORTEST_RESPONSE_SLIDE_PERIOD, 30_000);
|
||||||
|
executorService = applicationModel
|
||||||
|
.getFrameworkModel()
|
||||||
|
.getBeanFactory()
|
||||||
|
.getBean(FrameworkExecutorRepository.class)
|
||||||
|
.getSharedExecutor();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class SlideWindowData {
|
protected static class SlideWindowData {
|
||||||
|
|
@ -118,9 +124,11 @@ public class ShortestResponseLoadBalance extends AbstractLoadBalance implements
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
Invoker<T> invoker = invokers.get(i);
|
Invoker<T> invoker = invokers.get(i);
|
||||||
RpcStatus rpcStatus = RpcStatus.getStatus(invoker.getUrl(), RpcUtils.getMethodName(invocation));
|
RpcStatus rpcStatus = RpcStatus.getStatus(invoker.getUrl(), RpcUtils.getMethodName(invocation));
|
||||||
SlideWindowData slideWindowData = ConcurrentHashMapUtils.computeIfAbsent(methodMap, rpcStatus, SlideWindowData::new);
|
SlideWindowData slideWindowData =
|
||||||
|
ConcurrentHashMapUtils.computeIfAbsent(methodMap, rpcStatus, SlideWindowData::new);
|
||||||
|
|
||||||
// Calculate the estimated response time from the product of active connections and succeeded average elapsed time.
|
// Calculate the estimated response time from the product of active connections and succeeded average
|
||||||
|
// elapsed time.
|
||||||
long estimateResponse = slideWindowData.getEstimateResponse();
|
long estimateResponse = slideWindowData.getEstimateResponse();
|
||||||
int afterWarmup = getWeight(invoker, invocation);
|
int afterWarmup = getWeight(invoker, invocation);
|
||||||
weights[i] = afterWarmup;
|
weights[i] = afterWarmup;
|
||||||
|
|
@ -135,16 +143,15 @@ public class ShortestResponseLoadBalance extends AbstractLoadBalance implements
|
||||||
} else if (estimateResponse == shortestResponse) {
|
} else if (estimateResponse == shortestResponse) {
|
||||||
shortestIndexes[shortestCount++] = i;
|
shortestIndexes[shortestCount++] = i;
|
||||||
totalWeight += afterWarmup;
|
totalWeight += afterWarmup;
|
||||||
if (sameWeight && i > 0
|
if (sameWeight && i > 0 && afterWarmup != firstWeight) {
|
||||||
&& afterWarmup != firstWeight) {
|
|
||||||
sameWeight = false;
|
sameWeight = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (System.currentTimeMillis() - lastUpdateTime > slidePeriod
|
if (System.currentTimeMillis() - lastUpdateTime > slidePeriod
|
||||||
&& onResetSlideWindow.compareAndSet(false, true)) {
|
&& onResetSlideWindow.compareAndSet(false, true)) {
|
||||||
//reset slideWindowData in async way
|
// reset slideWindowData in async way
|
||||||
executorService.execute(() -> {
|
executorService.execute(() -> {
|
||||||
methodMap.values().forEach(SlideWindowData::reset);
|
methodMap.values().forEach(SlideWindowData::reset);
|
||||||
lastUpdateTime = System.currentTimeMillis();
|
lastUpdateTime = System.currentTimeMillis();
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.merger;
|
package org.apache.dubbo.rpc.cluster.merger;
|
||||||
|
|
||||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||||
|
|
@ -43,5 +42,4 @@ public class BooleanArrayMerger implements Merger<boolean[]> {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.merger;
|
package org.apache.dubbo.rpc.cluster.merger;
|
||||||
|
|
||||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||||
|
|
@ -43,5 +42,4 @@ public class ByteArrayMerger implements Merger<byte[]> {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.merger;
|
package org.apache.dubbo.rpc.cluster.merger;
|
||||||
|
|
||||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.merger;
|
package org.apache.dubbo.rpc.cluster.merger;
|
||||||
|
|
||||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||||
|
|
@ -30,7 +29,8 @@ public class DoubleArrayMerger implements Merger<double[]> {
|
||||||
if (ArrayUtils.isEmpty(items)) {
|
if (ArrayUtils.isEmpty(items)) {
|
||||||
return new double[0];
|
return new double[0];
|
||||||
}
|
}
|
||||||
return Arrays.stream(items).filter(Objects::nonNull)
|
return Arrays.stream(items)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
.flatMapToDouble(Arrays::stream)
|
.flatMapToDouble(Arrays::stream)
|
||||||
.toArray();
|
.toArray();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.merger;
|
package org.apache.dubbo.rpc.cluster.merger;
|
||||||
|
|
||||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.merger;
|
package org.apache.dubbo.rpc.cluster.merger;
|
||||||
|
|
||||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||||
|
|
@ -30,9 +29,9 @@ public class IntArrayMerger implements Merger<int[]> {
|
||||||
if (ArrayUtils.isEmpty(items)) {
|
if (ArrayUtils.isEmpty(items)) {
|
||||||
return new int[0];
|
return new int[0];
|
||||||
}
|
}
|
||||||
return Arrays.stream(items).filter(Objects::nonNull)
|
return Arrays.stream(items)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
.flatMapToInt(Arrays::stream)
|
.flatMapToInt(Arrays::stream)
|
||||||
.toArray();
|
.toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.merger;
|
package org.apache.dubbo.rpc.cluster.merger;
|
||||||
|
|
||||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||||
|
|
@ -34,10 +33,9 @@ public class ListMerger implements Merger<List<?>> {
|
||||||
if (ArrayUtils.isEmpty(items)) {
|
if (ArrayUtils.isEmpty(items)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
return Stream.of(items).filter(Objects::nonNull)
|
return Stream.of(items)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
.flatMap(Collection::stream)
|
.flatMap(Collection::stream)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.merger;
|
package org.apache.dubbo.rpc.cluster.merger;
|
||||||
|
|
||||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||||
|
|
@ -30,7 +29,8 @@ public class LongArrayMerger implements Merger<long[]> {
|
||||||
if (ArrayUtils.isEmpty(items)) {
|
if (ArrayUtils.isEmpty(items)) {
|
||||||
return new long[0];
|
return new long[0];
|
||||||
}
|
}
|
||||||
return Arrays.stream(items).filter(Objects::nonNull)
|
return Arrays.stream(items)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
.flatMapToLong(Arrays::stream)
|
.flatMapToLong(Arrays::stream)
|
||||||
.toArray();
|
.toArray();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,5 +36,4 @@ public class MapMerger implements Merger<Map<?, ?>> {
|
||||||
Stream.of(items).filter(Objects::nonNull).forEach(result::putAll);
|
Stream.of(items).filter(Objects::nonNull).forEach(result::putAll);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.merger;
|
package org.apache.dubbo.rpc.cluster.merger;
|
||||||
|
|
||||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||||
|
|
@ -69,13 +68,17 @@ public class MergerFactory implements ScopeModelAware {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadMergers() {
|
private void loadMergers() {
|
||||||
Set<String> names = scopeModel.getExtensionLoader(Merger.class)
|
Set<String> names = scopeModel.getExtensionLoader(Merger.class).getSupportedExtensions();
|
||||||
.getSupportedExtensions();
|
|
||||||
for (String name : names) {
|
for (String name : names) {
|
||||||
Merger m = scopeModel.getExtensionLoader(Merger.class).getExtension(name);
|
Merger m = scopeModel.getExtensionLoader(Merger.class).getExtension(name);
|
||||||
Class<?> actualTypeArg = getActualTypeArgument(m.getClass());
|
Class<?> actualTypeArg = getActualTypeArgument(m.getClass());
|
||||||
if (actualTypeArg == null) {
|
if (actualTypeArg == null) {
|
||||||
logger.warn(CLUSTER_FAILED_LOAD_MERGER,"load merger config failed","","Failed to get actual type argument from merger " + m.getClass().getName());
|
logger.warn(
|
||||||
|
CLUSTER_FAILED_LOAD_MERGER,
|
||||||
|
"load merger config failed",
|
||||||
|
"",
|
||||||
|
"Failed to get actual type argument from merger "
|
||||||
|
+ m.getClass().getName());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
MERGER_CACHE.putIfAbsent(actualTypeArg, m);
|
MERGER_CACHE.putIfAbsent(actualTypeArg, m);
|
||||||
|
|
@ -94,7 +97,7 @@ public class MergerFactory implements ScopeModelAware {
|
||||||
ParameterizedType mergerType;
|
ParameterizedType mergerType;
|
||||||
for (Type it : interfaceTypes) {
|
for (Type it : interfaceTypes) {
|
||||||
if (it instanceof ParameterizedType
|
if (it instanceof ParameterizedType
|
||||||
&& (mergerType = ((ParameterizedType) it)).getRawType() == Merger.class) {
|
&& (mergerType = ((ParameterizedType) it)).getRawType() == Merger.class) {
|
||||||
Type typeArg = mergerType.getActualTypeArguments()[0];
|
Type typeArg = mergerType.getActualTypeArguments()[0];
|
||||||
return TypeUtils.getRawClass(typeArg);
|
return TypeUtils.getRawClass(typeArg);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.merger;
|
package org.apache.dubbo.rpc.cluster.merger;
|
||||||
|
|
||||||
import org.apache.dubbo.common.utils.ArrayUtils;
|
import org.apache.dubbo.common.utils.ArrayUtils;
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,13 @@ public abstract class AbstractRouter implements Router {
|
||||||
private GovernanceRuleRepository ruleRepository;
|
private GovernanceRuleRepository ruleRepository;
|
||||||
|
|
||||||
public AbstractRouter(URL url) {
|
public AbstractRouter(URL url) {
|
||||||
this.ruleRepository = url.getOrDefaultModuleModel().getExtensionLoader(GovernanceRuleRepository.class).getDefaultExtension();
|
this.ruleRepository = url.getOrDefaultModuleModel()
|
||||||
|
.getExtensionLoader(GovernanceRuleRepository.class)
|
||||||
|
.getDefaultExtension();
|
||||||
this.url = url;
|
this.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AbstractRouter() {
|
public AbstractRouter() {}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URL getUrl() {
|
public URL getUrl() {
|
||||||
|
|
@ -67,8 +68,7 @@ public abstract class AbstractRouter implements Router {
|
||||||
this.priority = priority;
|
this.priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GovernanceRuleRepository getRuleRepository(){
|
public GovernanceRuleRepository getRuleRepository() {
|
||||||
return this.ruleRepository;
|
return this.ruleRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
|
||||||
public class RouterSnapshotFilter implements ClusterFilter, BaseFilter.Listener {
|
public class RouterSnapshotFilter implements ClusterFilter, BaseFilter.Listener {
|
||||||
|
|
||||||
private final RouterSnapshotSwitcher switcher;
|
private final RouterSnapshotSwitcher switcher;
|
||||||
private final static Logger logger = LoggerFactory.getLogger(RouterSnapshotFilter.class);
|
private static final Logger logger = LoggerFactory.getLogger(RouterSnapshotFilter.class);
|
||||||
|
|
||||||
public RouterSnapshotFilter(FrameworkModel frameworkModel) {
|
public RouterSnapshotFilter(FrameworkModel frameworkModel) {
|
||||||
this.switcher = frameworkModel.getBeanFactory().getBean(RouterSnapshotSwitcher.class);
|
this.switcher = frameworkModel.getBeanFactory().getBean(RouterSnapshotSwitcher.class);
|
||||||
|
|
|
||||||
|
|
@ -114,43 +114,55 @@ public class RouterSnapshotNode<T> {
|
||||||
|
|
||||||
public String toString(int level) {
|
public String toString(int level) {
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
stringBuilder.append("[ ")
|
stringBuilder
|
||||||
.append(name)
|
.append("[ ")
|
||||||
.append(' ')
|
.append(name)
|
||||||
.append("(Input: ").append(beforeSize).append(") ")
|
.append(' ')
|
||||||
.append("(Current Node Output: ").append(nodeOutputSize).append(") ")
|
.append("(Input: ")
|
||||||
.append("(Chain Node Output: ").append(chainOutputSize).append(')')
|
.append(beforeSize)
|
||||||
.append(routerMessage == null ? "" : " Router message: ")
|
.append(") ")
|
||||||
.append(routerMessage == null ? "" : routerMessage)
|
.append("(Current Node Output: ")
|
||||||
.append(" ] ");
|
.append(nodeOutputSize)
|
||||||
|
.append(") ")
|
||||||
|
.append("(Chain Node Output: ")
|
||||||
|
.append(chainOutputSize)
|
||||||
|
.append(')')
|
||||||
|
.append(routerMessage == null ? "" : " Router message: ")
|
||||||
|
.append(routerMessage == null ? "" : routerMessage)
|
||||||
|
.append(" ] ");
|
||||||
if (level == 1) {
|
if (level == 1) {
|
||||||
stringBuilder.append("Input: ")
|
stringBuilder
|
||||||
.append(CollectionUtils.isEmpty(inputInvokers) ? "Empty" :
|
.append("Input: ")
|
||||||
inputInvokers.subList(0, Math.min(5, inputInvokers.size()))
|
.append(
|
||||||
.stream()
|
CollectionUtils.isEmpty(inputInvokers)
|
||||||
.map(Invoker::getUrl)
|
? "Empty"
|
||||||
.map(URL::getAddress)
|
: inputInvokers.subList(0, Math.min(5, inputInvokers.size())).stream()
|
||||||
.collect(Collectors.joining(",")))
|
.map(Invoker::getUrl)
|
||||||
.append(" -> ");
|
.map(URL::getAddress)
|
||||||
|
.collect(Collectors.joining(",")))
|
||||||
|
.append(" -> ");
|
||||||
|
|
||||||
stringBuilder.append("Chain Node Output: ")
|
stringBuilder
|
||||||
.append(CollectionUtils.isEmpty(chainOutputInvokers) ? "Empty" :
|
.append("Chain Node Output: ")
|
||||||
chainOutputInvokers.subList(0, Math.min(5, chainOutputInvokers.size()))
|
.append(
|
||||||
.stream()
|
CollectionUtils.isEmpty(chainOutputInvokers)
|
||||||
.map(Invoker::getUrl)
|
? "Empty"
|
||||||
.map(URL::getAddress)
|
: chainOutputInvokers.subList(0, Math.min(5, chainOutputInvokers.size())).stream()
|
||||||
.collect(Collectors.joining(",")));
|
.map(Invoker::getUrl)
|
||||||
|
.map(URL::getAddress)
|
||||||
|
.collect(Collectors.joining(",")));
|
||||||
} else {
|
} else {
|
||||||
stringBuilder.append("Current Node Output: ")
|
stringBuilder
|
||||||
.append(CollectionUtils.isEmpty(nodeOutputInvokers) ? "Empty" :
|
.append("Current Node Output: ")
|
||||||
nodeOutputInvokers.subList(0, Math.min(5, nodeOutputInvokers.size()))
|
.append(
|
||||||
.stream()
|
CollectionUtils.isEmpty(nodeOutputInvokers)
|
||||||
.map(Invoker::getUrl)
|
? "Empty"
|
||||||
.map(URL::getAddress)
|
: nodeOutputInvokers.subList(0, Math.min(5, nodeOutputInvokers.size())).stream()
|
||||||
.collect(Collectors.joining(",")));
|
.map(Invoker::getUrl)
|
||||||
|
.map(URL::getAddress)
|
||||||
|
.collect(Collectors.joining(",")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (nodeOutputInvokers != null && nodeOutputInvokers.size() > 5) {
|
if (nodeOutputInvokers != null && nodeOutputInvokers.size() > 5) {
|
||||||
stringBuilder.append("...");
|
stringBuilder.append("...");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ public class RouterSnapshotSwitcher {
|
||||||
private volatile boolean enable;
|
private volatile boolean enable;
|
||||||
private final Set<String> enabledService = new ConcurrentHashSet<>();
|
private final Set<String> enabledService = new ConcurrentHashSet<>();
|
||||||
|
|
||||||
private final static int MAX_LENGTH = 1 << 5; // 2 ^ 5 = 31
|
private static final int MAX_LENGTH = 1 << 5; // 2 ^ 5 = 31
|
||||||
|
|
||||||
private final AtomicInteger offset = new AtomicInteger(0);
|
private final AtomicInteger offset = new AtomicInteger(0);
|
||||||
private volatile String[] recentSnapshot = new String[MAX_LENGTH];
|
private volatile String[] recentSnapshot = new String[MAX_LENGTH];
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,8 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
|
||||||
super(url);
|
super(url);
|
||||||
this.setForce(force);
|
this.setForce(force);
|
||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
matcherFactories = moduleModel.getExtensionLoader(ConditionMatcherFactory.class).getActivateExtensions();
|
matcherFactories =
|
||||||
|
moduleModel.getExtensionLoader(ConditionMatcherFactory.class).getActivateExtensions();
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
this.init(rule);
|
this.init(rule);
|
||||||
}
|
}
|
||||||
|
|
@ -94,7 +95,8 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
|
||||||
super(url);
|
super(url);
|
||||||
this.setUrl(url);
|
this.setUrl(url);
|
||||||
this.setForce(url.getParameter(FORCE_KEY, false));
|
this.setForce(url.getParameter(FORCE_KEY, false));
|
||||||
matcherFactories = moduleModel.getExtensionLoader(ConditionMatcherFactory.class).getActivateExtensions();
|
matcherFactories =
|
||||||
|
moduleModel.getExtensionLoader(ConditionMatcherFactory.class).getActivateExtensions();
|
||||||
this.enabled = url.getParameter(ENABLED_KEY, true);
|
this.enabled = url.getParameter(ENABLED_KEY, true);
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
init(url.getParameterAndDecoded(RULE_KEY));
|
init(url.getParameterAndDecoded(RULE_KEY));
|
||||||
|
|
@ -110,8 +112,10 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
|
||||||
int i = rule.indexOf("=>");
|
int i = rule.indexOf("=>");
|
||||||
String whenRule = i < 0 ? null : rule.substring(0, i).trim();
|
String whenRule = i < 0 ? null : rule.substring(0, i).trim();
|
||||||
String thenRule = i < 0 ? rule.trim() : rule.substring(i + 2).trim();
|
String thenRule = i < 0 ? rule.trim() : rule.substring(i + 2).trim();
|
||||||
Map<String, ConditionMatcher> when = StringUtils.isBlank(whenRule) || "true".equals(whenRule) ? new HashMap<>() : parseRule(whenRule);
|
Map<String, ConditionMatcher> when =
|
||||||
Map<String, ConditionMatcher> then = StringUtils.isBlank(thenRule) || "false".equals(thenRule) ? null : parseRule(thenRule);
|
StringUtils.isBlank(whenRule) || "true".equals(whenRule) ? new HashMap<>() : parseRule(whenRule);
|
||||||
|
Map<String, ConditionMatcher> then =
|
||||||
|
StringUtils.isBlank(thenRule) || "false".equals(thenRule) ? null : parseRule(thenRule);
|
||||||
// NOTE: It should be determined on the business level whether the `When condition` can be empty or not.
|
// NOTE: It should be determined on the business level whether the `When condition` can be empty or not.
|
||||||
this.whenCondition = when;
|
this.whenCondition = when;
|
||||||
this.thenCondition = then;
|
this.thenCondition = then;
|
||||||
|
|
@ -120,8 +124,7 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, ConditionMatcher> parseRule(String rule)
|
private Map<String, ConditionMatcher> parseRule(String rule) throws ParseException {
|
||||||
throws ParseException {
|
|
||||||
Map<String, ConditionMatcher> condition = new HashMap<>();
|
Map<String, ConditionMatcher> condition = new HashMap<>();
|
||||||
if (StringUtils.isBlank(rule)) {
|
if (StringUtils.isBlank(rule)) {
|
||||||
return condition;
|
return condition;
|
||||||
|
|
@ -151,10 +154,12 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
|
||||||
// The Value in the KV part.
|
// The Value in the KV part.
|
||||||
else if ("=".equals(separator)) {
|
else if ("=".equals(separator)) {
|
||||||
if (matcherPair == null) {
|
if (matcherPair == null) {
|
||||||
throw new ParseException("Illegal route rule \""
|
throw new ParseException(
|
||||||
+ rule + "\", The error char '" + separator
|
"Illegal route rule \""
|
||||||
+ "' at index " + matcher.start() + " before \""
|
+ rule + "\", The error char '" + separator
|
||||||
+ content + "\".", matcher.start());
|
+ "' at index " + matcher.start() + " before \""
|
||||||
|
+ content + "\".",
|
||||||
|
matcher.start());
|
||||||
}
|
}
|
||||||
|
|
||||||
values = matcherPair.getMatches();
|
values = matcherPair.getMatches();
|
||||||
|
|
@ -163,10 +168,12 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
|
||||||
// The Value in the KV part.
|
// The Value in the KV part.
|
||||||
else if ("!=".equals(separator)) {
|
else if ("!=".equals(separator)) {
|
||||||
if (matcherPair == null) {
|
if (matcherPair == null) {
|
||||||
throw new ParseException("Illegal route rule \""
|
throw new ParseException(
|
||||||
+ rule + "\", The error char '" + separator
|
"Illegal route rule \""
|
||||||
+ "' at index " + matcher.start() + " before \""
|
+ rule + "\", The error char '" + separator
|
||||||
+ content + "\".", matcher.start());
|
+ "' at index " + matcher.start() + " before \""
|
||||||
|
+ content + "\".",
|
||||||
|
matcher.start());
|
||||||
}
|
}
|
||||||
|
|
||||||
values = matcherPair.getMismatches();
|
values = matcherPair.getMismatches();
|
||||||
|
|
@ -175,25 +182,34 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
|
||||||
// The Value in the KV part, if Value have more than one items.
|
// The Value in the KV part, if Value have more than one items.
|
||||||
else if (",".equals(separator)) { // Should be separated by ','
|
else if (",".equals(separator)) { // Should be separated by ','
|
||||||
if (values == null || values.isEmpty()) {
|
if (values == null || values.isEmpty()) {
|
||||||
throw new ParseException("Illegal route rule \""
|
throw new ParseException(
|
||||||
+ rule + "\", The error char '" + separator
|
"Illegal route rule \""
|
||||||
+ "' at index " + matcher.start() + " before \""
|
+ rule + "\", The error char '" + separator
|
||||||
+ content + "\".", matcher.start());
|
+ "' at index " + matcher.start() + " before \""
|
||||||
|
+ content + "\".",
|
||||||
|
matcher.start());
|
||||||
}
|
}
|
||||||
values.add(content);
|
values.add(content);
|
||||||
} else {
|
} else {
|
||||||
throw new ParseException("Illegal route rule \"" + rule
|
throw new ParseException(
|
||||||
+ "\", The error char '" + separator + "' at index "
|
"Illegal route rule \"" + rule
|
||||||
+ matcher.start() + " before \"" + content + "\".", matcher.start());
|
+ "\", The error char '" + separator + "' at index "
|
||||||
|
+ matcher.start() + " before \"" + content + "\".",
|
||||||
|
matcher.start());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return condition;
|
return condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BitList<Invoker<T>> doRoute(BitList<Invoker<T>> invokers, URL url, Invocation invocation,
|
protected BitList<Invoker<T>> doRoute(
|
||||||
boolean needToPrintMessage, Holder<RouterSnapshotNode<T>> nodeHolder,
|
BitList<Invoker<T>> invokers,
|
||||||
Holder<String> messageHolder) throws RpcException {
|
URL url,
|
||||||
|
Invocation invocation,
|
||||||
|
boolean needToPrintMessage,
|
||||||
|
Holder<RouterSnapshotNode<T>> nodeHolder,
|
||||||
|
Holder<String> messageHolder)
|
||||||
|
throws RpcException {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
if (needToPrintMessage) {
|
if (needToPrintMessage) {
|
||||||
messageHolder.set("Directly return. Reason: ConditionRouter disabled.");
|
messageHolder.set("Directly return. Reason: ConditionRouter disabled.");
|
||||||
|
|
@ -215,7 +231,13 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
|
||||||
return invokers;
|
return invokers;
|
||||||
}
|
}
|
||||||
if (thenCondition == null) {
|
if (thenCondition == null) {
|
||||||
logger.warn(CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY,"condition state router thenCondition is empty","","The current consumer in the service blacklist. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey()); if (needToPrintMessage) {
|
logger.warn(
|
||||||
|
CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY,
|
||||||
|
"condition state router thenCondition is empty",
|
||||||
|
"",
|
||||||
|
"The current consumer in the service blacklist. consumer: " + NetUtils.getLocalHost()
|
||||||
|
+ ", service: " + url.getServiceKey());
|
||||||
|
if (needToPrintMessage) {
|
||||||
messageHolder.set("Empty return. Reason: ThenCondition is empty.");
|
messageHolder.set("Empty return. Reason: ThenCondition is empty.");
|
||||||
}
|
}
|
||||||
return BitList.emptyList();
|
return BitList.emptyList();
|
||||||
|
|
@ -229,14 +251,26 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} else if (this.isForce()) {
|
} else if (this.isForce()) {
|
||||||
logger.warn(CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY,"execute condition state router result list is empty. and force=true","","The route result is empty and force execute. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey() + ", router: " + url.getParameterAndDecoded(RULE_KEY));
|
logger.warn(
|
||||||
|
CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY,
|
||||||
|
"execute condition state router result list is empty. and force=true",
|
||||||
|
"",
|
||||||
|
"The route result is empty and force execute. consumer: " + NetUtils.getLocalHost()
|
||||||
|
+ ", service: " + url.getServiceKey() + ", router: "
|
||||||
|
+ url.getParameterAndDecoded(RULE_KEY));
|
||||||
if (needToPrintMessage) {
|
if (needToPrintMessage) {
|
||||||
messageHolder.set("Empty return. Reason: Empty result from condition and condition is force.");
|
messageHolder.set("Empty return. Reason: Empty result from condition and condition is force.");
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
logger.error(CLUSTER_FAILED_EXEC_CONDITION_ROUTER,"execute condition state router exception","","Failed to execute condition router rule: " + getUrl() + ", invokers: " + invokers + ", cause: " + t.getMessage(),t);
|
logger.error(
|
||||||
|
CLUSTER_FAILED_EXEC_CONDITION_ROUTER,
|
||||||
|
"execute condition state router exception",
|
||||||
|
"",
|
||||||
|
"Failed to execute condition router rule: " + getUrl() + ", invokers: " + invokers + ", cause: "
|
||||||
|
+ t.getMessage(),
|
||||||
|
t);
|
||||||
}
|
}
|
||||||
if (needToPrintMessage) {
|
if (needToPrintMessage) {
|
||||||
messageHolder.set("Directly return. Reason: Error occurred ( or result is empty ).");
|
messageHolder.set("Directly return. Reason: Error occurred ( or result is empty ).");
|
||||||
|
|
@ -247,7 +281,7 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
|
||||||
@Override
|
@Override
|
||||||
public boolean isRuntime() {
|
public boolean isRuntime() {
|
||||||
// We always return true for previously defined Router, that is, old Router doesn't support cache anymore.
|
// We always return true for previously defined Router, that is, old Router doesn't support cache anymore.
|
||||||
// return true;
|
// return true;
|
||||||
return this.getUrl().getParameter(RUNTIME_KEY, false);
|
return this.getUrl().getParameter(RUNTIME_KEY, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,7 +291,10 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
|
||||||
return factory.createMatcher(key, moduleModel);
|
return factory.createMatcher(key, moduleModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return moduleModel.getExtensionLoader(ConditionMatcherFactory.class).getExtension("param").createMatcher(key, moduleModel);
|
return moduleModel
|
||||||
|
.getExtensionLoader(ConditionMatcherFactory.class)
|
||||||
|
.getExtension("param")
|
||||||
|
.createMatcher(key, moduleModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean matchWhen(URL url, Invocation invocation) {
|
boolean matchWhen(URL url, Invocation invocation) {
|
||||||
|
|
@ -276,7 +313,12 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
|
||||||
return doMatch(url, param, null, thenCondition, false);
|
return doMatch(url, param, null, thenCondition, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean doMatch(URL url, URL param, Invocation invocation, Map<String, ConditionMatcher> conditions, boolean isWhenCondition) {
|
private boolean doMatch(
|
||||||
|
URL url,
|
||||||
|
URL param,
|
||||||
|
Invocation invocation,
|
||||||
|
Map<String, ConditionMatcher> conditions,
|
||||||
|
boolean isWhenCondition) {
|
||||||
Map<String, String> sample = url.toOriginalMap();
|
Map<String, String> sample = url.toOriginalMap();
|
||||||
for (Map.Entry<String, ConditionMatcher> entry : conditions.entrySet()) {
|
for (Map.Entry<String, ConditionMatcher> entry : conditions.entrySet()) {
|
||||||
ConditionMatcher matchPair = entry.getValue();
|
ConditionMatcher matchPair = entry.getValue();
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,8 @@ public abstract class ListenableStateRouter<T> extends AbstractStateRouter<T> im
|
||||||
public static final String NAME = "LISTENABLE_ROUTER";
|
public static final String NAME = "LISTENABLE_ROUTER";
|
||||||
public static final String RULE_SUFFIX = ".condition-router";
|
public static final String RULE_SUFFIX = ".condition-router";
|
||||||
|
|
||||||
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ListenableStateRouter.class);
|
private static final ErrorTypeAwareLogger logger =
|
||||||
|
LoggerFactory.getErrorTypeAwareLogger(ListenableStateRouter.class);
|
||||||
private volatile ConditionRouterRule routerRule;
|
private volatile ConditionRouterRule routerRule;
|
||||||
private volatile List<ConditionStateRouter<T>> conditionRouters = Collections.emptyList();
|
private volatile List<ConditionStateRouter<T>> conditionRouters = Collections.emptyList();
|
||||||
private final String ruleKey;
|
private final String ruleKey;
|
||||||
|
|
@ -65,8 +66,8 @@ public abstract class ListenableStateRouter<T> extends AbstractStateRouter<T> im
|
||||||
@Override
|
@Override
|
||||||
public synchronized void process(ConfigChangedEvent event) {
|
public synchronized void process(ConfigChangedEvent event) {
|
||||||
if (logger.isInfoEnabled()) {
|
if (logger.isInfoEnabled()) {
|
||||||
logger.info("Notification of condition rule, change type is: " + event.getChangeType() +
|
logger.info("Notification of condition rule, change type is: " + event.getChangeType() + ", raw rule is:\n "
|
||||||
", raw rule is:\n " + event.getContent());
|
+ event.getContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.getChangeType().equals(ConfigChangeType.DELETED)) {
|
if (event.getChangeType().equals(ConfigChangeType.DELETED)) {
|
||||||
|
|
@ -77,18 +78,31 @@ public abstract class ListenableStateRouter<T> extends AbstractStateRouter<T> im
|
||||||
routerRule = ConditionRuleParser.parse(event.getContent());
|
routerRule = ConditionRuleParser.parse(event.getContent());
|
||||||
generateConditions(routerRule);
|
generateConditions(routerRule);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error(CLUSTER_FAILED_RULE_PARSING,"Failed to parse the raw condition rule","","Failed to parse the raw condition rule and it will not take effect, please check " +
|
logger.error(
|
||||||
"if the condition rule matches with the template, the raw rule is:\n " + event.getContent(),e);
|
CLUSTER_FAILED_RULE_PARSING,
|
||||||
|
"Failed to parse the raw condition rule",
|
||||||
|
"",
|
||||||
|
"Failed to parse the raw condition rule and it will not take effect, please check "
|
||||||
|
+ "if the condition rule matches with the template, the raw rule is:\n "
|
||||||
|
+ event.getContent(),
|
||||||
|
e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BitList<Invoker<T>> doRoute(BitList<Invoker<T>> invokers, URL url, Invocation invocation,
|
public BitList<Invoker<T>> doRoute(
|
||||||
boolean needToPrintMessage, Holder<RouterSnapshotNode<T>> nodeHolder, Holder<String> messageHolder) throws RpcException {
|
BitList<Invoker<T>> invokers,
|
||||||
|
URL url,
|
||||||
|
Invocation invocation,
|
||||||
|
boolean needToPrintMessage,
|
||||||
|
Holder<RouterSnapshotNode<T>> nodeHolder,
|
||||||
|
Holder<String> messageHolder)
|
||||||
|
throws RpcException {
|
||||||
if (CollectionUtils.isEmpty(invokers) || conditionRouters.size() == 0) {
|
if (CollectionUtils.isEmpty(invokers) || conditionRouters.size() == 0) {
|
||||||
if (needToPrintMessage) {
|
if (needToPrintMessage) {
|
||||||
messageHolder.set("Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty.");
|
messageHolder.set(
|
||||||
|
"Directly return. Reason: Invokers from previous router is empty or conditionRouters is empty.");
|
||||||
}
|
}
|
||||||
return invokers;
|
return invokers;
|
||||||
}
|
}
|
||||||
|
|
@ -123,9 +137,9 @@ public abstract class ListenableStateRouter<T> extends AbstractStateRouter<T> im
|
||||||
|
|
||||||
private void generateConditions(ConditionRouterRule rule) {
|
private void generateConditions(ConditionRouterRule rule) {
|
||||||
if (rule != null && rule.isValid()) {
|
if (rule != null && rule.isValid()) {
|
||||||
this.conditionRouters = rule.getConditions()
|
this.conditionRouters = rule.getConditions().stream()
|
||||||
.stream()
|
.map(condition ->
|
||||||
.map(condition -> new ConditionStateRouter<T>(getUrl(), condition, rule.isForce(), rule.isEnabled()))
|
new ConditionStateRouter<T>(getUrl(), condition, rule.isForce(), rule.isEnabled()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
for (ConditionStateRouter<T> conditionRouter : this.conditionRouters) {
|
for (ConditionStateRouter<T> conditionRouter : this.conditionRouters) {
|
||||||
conditionRouter.setNextRouter(TailStateRouter.getInstance());
|
conditionRouter.setNextRouter(TailStateRouter.getInstance());
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,8 @@ import static org.apache.dubbo.common.utils.StringUtils.isEmpty;
|
||||||
* Application level router, "application.condition-router"
|
* Application level router, "application.condition-router"
|
||||||
*/
|
*/
|
||||||
public class ProviderAppStateRouter<T> extends ListenableStateRouter<T> {
|
public class ProviderAppStateRouter<T> extends ListenableStateRouter<T> {
|
||||||
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ListenableStateRouter.class);
|
private static final ErrorTypeAwareLogger logger =
|
||||||
|
LoggerFactory.getErrorTypeAwareLogger(ListenableStateRouter.class);
|
||||||
public static final String NAME = "PROVIDER_APP_ROUTER";
|
public static final String NAME = "PROVIDER_APP_ROUTER";
|
||||||
private String application;
|
private String application;
|
||||||
private final String currentApplication;
|
private final String currentApplication;
|
||||||
|
|
@ -55,7 +56,11 @@ public class ProviderAppStateRouter<T> extends ListenableStateRouter<T> {
|
||||||
|
|
||||||
// provider application is empty or equals with the current application
|
// provider application is empty or equals with the current application
|
||||||
if (isEmpty(providerApplication)) {
|
if (isEmpty(providerApplication)) {
|
||||||
logger.warn(CLUSTER_TAG_ROUTE_EMPTY, "condition router get providerApplication is empty, will not subscribe to provider app rules.", "", "");
|
logger.warn(
|
||||||
|
CLUSTER_TAG_ROUTE_EMPTY,
|
||||||
|
"condition router get providerApplication is empty, will not subscribe to provider app rules.",
|
||||||
|
"",
|
||||||
|
"");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (providerApplication.equals(currentApplication)) {
|
if (providerApplication.equals(currentApplication)) {
|
||||||
|
|
|
||||||
|
|
@ -34,5 +34,4 @@ public class ServiceStateRouterFactory extends CacheableStateRouterFactory {
|
||||||
protected <T> StateRouter<T> createRouter(Class<T> interfaceClass, URL url) {
|
protected <T> StateRouter<T> createRouter(Class<T> interfaceClass, URL url) {
|
||||||
return new ServiceStateRouter<T>(url);
|
return new ServiceStateRouter<T>(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,15 +34,14 @@ public class ConditionRouterRule extends AbstractRouterRule {
|
||||||
|
|
||||||
Object conditions = map.get(CONDITIONS_KEY);
|
Object conditions = map.get(CONDITIONS_KEY);
|
||||||
if (conditions != null && List.class.isAssignableFrom(conditions.getClass())) {
|
if (conditions != null && List.class.isAssignableFrom(conditions.getClass())) {
|
||||||
conditionRouterRule.setConditions(((List<Object>) conditions).stream()
|
conditionRouterRule.setConditions(
|
||||||
.map(String::valueOf).collect(Collectors.toList()));
|
((List<Object>) conditions).stream().map(String::valueOf).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return conditionRouterRule;
|
return conditionRouterRule;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConditionRouterRule() {
|
public ConditionRouterRule() {}
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getConditions() {
|
public List<String> getConditions() {
|
||||||
return conditions;
|
return conditions;
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@ package org.apache.dubbo.rpc.cluster.router.condition.config.model;
|
||||||
|
|
||||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.yaml.snakeyaml.LoaderOptions;
|
import org.yaml.snakeyaml.LoaderOptions;
|
||||||
import org.yaml.snakeyaml.Yaml;
|
import org.yaml.snakeyaml.Yaml;
|
||||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* %YAML1.2
|
* %YAML1.2
|
||||||
*
|
*
|
||||||
|
|
@ -51,5 +51,4 @@ public class ConditionRuleParser {
|
||||||
|
|
||||||
return rule;
|
return rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAIL
|
||||||
* provides the common match logics.
|
* provides the common match logics.
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractConditionMatcher implements ConditionMatcher {
|
public abstract class AbstractConditionMatcher implements ConditionMatcher {
|
||||||
public static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractConditionMatcher.class);
|
public static final ErrorTypeAwareLogger logger =
|
||||||
|
LoggerFactory.getErrorTypeAwareLogger(AbstractConditionMatcher.class);
|
||||||
public static final String DOES_NOT_FOUND_VALUE = "dubbo_internal_not_found_argument_condition_value";
|
public static final String DOES_NOT_FOUND_VALUE = "dubbo_internal_not_found_argument_condition_value";
|
||||||
final Set<String> matches = new HashSet<>();
|
final Set<String> matches = new HashSet<>();
|
||||||
final Set<String> mismatches = new HashSet<>();
|
final Set<String> mismatches = new HashSet<>();
|
||||||
|
|
@ -52,9 +53,10 @@ public abstract class AbstractConditionMatcher implements ConditionMatcher {
|
||||||
this.valueMatchers = model.getExtensionLoader(ValuePattern.class).getActivateExtensions();
|
this.valueMatchers = model.getExtensionLoader(ValuePattern.class).getActivateExtensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getSampleValueFromUrl(String conditionKey, Map<String, String> sample, URL param, Invocation invocation) {
|
public static String getSampleValueFromUrl(
|
||||||
|
String conditionKey, Map<String, String> sample, URL param, Invocation invocation) {
|
||||||
String sampleValue;
|
String sampleValue;
|
||||||
//get real invoked method name from invocation
|
// get real invoked method name from invocation
|
||||||
if (invocation != null && (METHOD_KEY.equals(conditionKey) || METHODS_KEY.equals(conditionKey))) {
|
if (invocation != null && (METHOD_KEY.equals(conditionKey) || METHODS_KEY.equals(conditionKey))) {
|
||||||
sampleValue = RpcUtils.getMethodName(invocation);
|
sampleValue = RpcUtils.getMethodName(invocation);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -67,7 +69,8 @@ public abstract class AbstractConditionMatcher implements ConditionMatcher {
|
||||||
public boolean isMatch(Map<String, String> sample, URL param, Invocation invocation, boolean isWhenCondition) {
|
public boolean isMatch(Map<String, String> sample, URL param, Invocation invocation, boolean isWhenCondition) {
|
||||||
String value = getValue(sample, param, invocation);
|
String value = getValue(sample, param, invocation);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
// if key does not present in whichever of url, invocation or attachment based on the matcher type, then return false.
|
// if key does not present in whichever of url, invocation or attachment based on the matcher type, then
|
||||||
|
// return false.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,7 +93,7 @@ public abstract class AbstractConditionMatcher implements ConditionMatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!matches.isEmpty() && !mismatches.isEmpty()) {
|
if (!matches.isEmpty() && !mismatches.isEmpty()) {
|
||||||
//when both mismatches and matches contain the same value, then using mismatches first
|
// when both mismatches and matches contain the same value, then using mismatches first
|
||||||
for (String mismatch : mismatches) {
|
for (String mismatch : mismatches) {
|
||||||
if (doPatternMatch(mismatch, value, param, invocation, isWhenCondition)) {
|
if (doPatternMatch(mismatch, value, param, invocation, isWhenCondition)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -117,16 +120,23 @@ public abstract class AbstractConditionMatcher implements ConditionMatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
// range, equal or other methods
|
// range, equal or other methods
|
||||||
protected boolean doPatternMatch(String pattern, String value, URL url, Invocation invocation, boolean isWhenCondition) {
|
protected boolean doPatternMatch(
|
||||||
|
String pattern, String value, URL url, Invocation invocation, boolean isWhenCondition) {
|
||||||
for (ValuePattern valueMatcher : valueMatchers) {
|
for (ValuePattern valueMatcher : valueMatchers) {
|
||||||
if (valueMatcher.shouldMatch(pattern)) {
|
if (valueMatcher.shouldMatch(pattern)) {
|
||||||
return valueMatcher.match(pattern, value, url, invocation, isWhenCondition);
|
return valueMatcher.match(pattern, value, url, invocation, isWhenCondition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// this should never happen.
|
// this should never happen.
|
||||||
logger.error(CLUSTER_FAILED_EXEC_CONDITION_ROUTER, "Executing condition rule value match expression error.", "pattern is " + pattern + ", value is " + value + ", condition type " + (isWhenCondition ? "when" : "then"), "There should at least has one ValueMatcher instance that applies to all patterns, will force to use wildcard matcher now.");
|
logger.error(
|
||||||
|
CLUSTER_FAILED_EXEC_CONDITION_ROUTER,
|
||||||
|
"Executing condition rule value match expression error.",
|
||||||
|
"pattern is " + pattern + ", value is " + value + ", condition type "
|
||||||
|
+ (isWhenCondition ? "when" : "then"),
|
||||||
|
"There should at least has one ValueMatcher instance that applies to all patterns, will force to use wildcard matcher now.");
|
||||||
|
|
||||||
ValuePattern paramValueMatcher = model.getExtensionLoader(ValuePattern.class).getExtension("wildcard");
|
ValuePattern paramValueMatcher =
|
||||||
|
model.getExtensionLoader(ValuePattern.class).getExtension("wildcard");
|
||||||
return paramValueMatcher.match(pattern, value, url, invocation, isWhenCondition);
|
return paramValueMatcher.match(pattern, value, url, invocation, isWhenCondition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,5 +145,4 @@ public abstract class AbstractConditionMatcher implements ConditionMatcher {
|
||||||
* This makes condition rule possible to check values in any place of a request.
|
* This makes condition rule possible to check values in any place of a request.
|
||||||
*/
|
*/
|
||||||
protected abstract String getValue(Map<String, String> sample, URL url, Invocation invocation);
|
protected abstract String getValue(Map<String, String> sample, URL url, Invocation invocation);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAIL
|
||||||
*/
|
*/
|
||||||
@Activate
|
@Activate
|
||||||
public class ArgumentConditionMatcher extends AbstractConditionMatcher {
|
public class ArgumentConditionMatcher extends AbstractConditionMatcher {
|
||||||
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ArgumentConditionMatcher.class);
|
private static final ErrorTypeAwareLogger logger =
|
||||||
|
LoggerFactory.getErrorTypeAwareLogger(ArgumentConditionMatcher.class);
|
||||||
private static final Pattern ARGUMENTS_PATTERN = Pattern.compile("arguments\\[([0-9]+)\\]");
|
private static final Pattern ARGUMENTS_PATTERN = Pattern.compile("arguments\\[([0-9]+)\\]");
|
||||||
|
|
||||||
public ArgumentConditionMatcher(String key, ModuleModel model) {
|
public ArgumentConditionMatcher(String key, ModuleModel model) {
|
||||||
|
|
@ -56,16 +57,21 @@ public class ArgumentConditionMatcher extends AbstractConditionMatcher {
|
||||||
return DOES_NOT_FOUND_VALUE;
|
return DOES_NOT_FOUND_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//extract the argument index
|
// extract the argument index
|
||||||
int index = Integer.parseInt(matcher.group(1));
|
int index = Integer.parseInt(matcher.group(1));
|
||||||
if (index < 0 || index > invocation.getArguments().length) {
|
if (index < 0 || index > invocation.getArguments().length) {
|
||||||
return DOES_NOT_FOUND_VALUE;
|
return DOES_NOT_FOUND_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//extract the argument value
|
// extract the argument value
|
||||||
return String.valueOf(invocation.getArguments()[index]);
|
return String.valueOf(invocation.getArguments()[index]);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warn(CLUSTER_FAILED_EXEC_CONDITION_ROUTER, "Parse argument match condition failed", "", "Invalid , will ignore., ", e);
|
logger.warn(
|
||||||
|
CLUSTER_FAILED_EXEC_CONDITION_ROUTER,
|
||||||
|
"Parse argument match condition failed",
|
||||||
|
"",
|
||||||
|
"Invalid , will ignore., ",
|
||||||
|
e);
|
||||||
}
|
}
|
||||||
return DOES_NOT_FOUND_VALUE;
|
return DOES_NOT_FOUND_VALUE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAIL
|
||||||
*/
|
*/
|
||||||
@Activate
|
@Activate
|
||||||
public class AttachmentConditionMatcher extends AbstractConditionMatcher {
|
public class AttachmentConditionMatcher extends AbstractConditionMatcher {
|
||||||
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AttachmentConditionMatcher.class);
|
private static final ErrorTypeAwareLogger logger =
|
||||||
|
LoggerFactory.getErrorTypeAwareLogger(AttachmentConditionMatcher.class);
|
||||||
private static final Pattern ATTACHMENTS_PATTERN = Pattern.compile("attachments\\[(.+)\\]");
|
private static final Pattern ATTACHMENTS_PATTERN = Pattern.compile("attachments\\[(.+)\\]");
|
||||||
|
|
||||||
public AttachmentConditionMatcher(String key, ModuleModel model) {
|
public AttachmentConditionMatcher(String key, ModuleModel model) {
|
||||||
|
|
@ -56,20 +57,21 @@ public class AttachmentConditionMatcher extends AbstractConditionMatcher {
|
||||||
return DOES_NOT_FOUND_VALUE;
|
return DOES_NOT_FOUND_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//extract the argument index
|
// extract the argument index
|
||||||
String attachmentKey = matcher.group(1);
|
String attachmentKey = matcher.group(1);
|
||||||
if (StringUtils.isEmpty(attachmentKey)) {
|
if (StringUtils.isEmpty(attachmentKey)) {
|
||||||
return DOES_NOT_FOUND_VALUE;
|
return DOES_NOT_FOUND_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//extract the argument value
|
// extract the argument value
|
||||||
return invocation.getAttachment(attachmentKey);
|
return invocation.getAttachment(attachmentKey);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warn(CLUSTER_FAILED_EXEC_CONDITION_ROUTER,
|
logger.warn(
|
||||||
"condition state router attachment match failed",
|
CLUSTER_FAILED_EXEC_CONDITION_ROUTER,
|
||||||
"",
|
"condition state router attachment match failed",
|
||||||
"Invalid match condition: " + key,
|
"",
|
||||||
e);
|
"Invalid match condition: " + key,
|
||||||
|
e);
|
||||||
}
|
}
|
||||||
return DOES_NOT_FOUND_VALUE;
|
return DOES_NOT_FOUND_VALUE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,5 +37,4 @@ public class UrlParamConditionMatcher extends AbstractConditionMatcher {
|
||||||
protected String getValue(Map<String, String> sample, URL url, Invocation invocation) {
|
protected String getValue(Map<String, String> sample, URL url, Invocation invocation) {
|
||||||
return getSampleValueFromUrl(key, sample, url, invocation);
|
return getSampleValueFromUrl(key, sample, url, invocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,11 @@ public class RangeValuePattern implements ValuePattern {
|
||||||
|
|
||||||
String[] arr = pattern.split("~");
|
String[] arr = pattern.split("~");
|
||||||
if (arr.length < 2) {
|
if (arr.length < 2) {
|
||||||
logger.error(CLUSTER_FAILED_EXEC_CONDITION_ROUTER, "", "", "Invalid condition rule " + pattern + " or value " + value + ", will ignore.");
|
logger.error(
|
||||||
|
CLUSTER_FAILED_EXEC_CONDITION_ROUTER,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"Invalid condition rule " + pattern + " or value " + value + ", will ignore.");
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,7 +79,12 @@ public class RangeValuePattern implements ValuePattern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error(CLUSTER_FAILED_EXEC_CONDITION_ROUTER, "Parse integer error", "", "Invalid condition rule " + pattern + " or value " + value + ", will ignore.", e);
|
logger.error(
|
||||||
|
CLUSTER_FAILED_EXEC_CONDITION_ROUTER,
|
||||||
|
"Parse integer error",
|
||||||
|
"",
|
||||||
|
"Invalid condition rule " + pattern + " or value " + value + ", will ignore.",
|
||||||
|
e);
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,9 @@ public class FileStateRouterFactory implements StateRouterFactory {
|
||||||
try {
|
try {
|
||||||
// Transform File URL into Script Route URL, and Load
|
// Transform File URL into Script Route URL, and Load
|
||||||
// file:///d:/path/to/route.js?router=script ==> script:///d:/path/to/route.js?type=js&rule=<file-content>
|
// file:///d:/path/to/route.js?router=script ==> script:///d:/path/to/route.js?type=js&rule=<file-content>
|
||||||
String protocol = url.getParameter(ROUTER_KEY, ScriptStateRouterFactory.NAME); // Replace original protocol (maybe 'file') with 'script'
|
String protocol = url.getParameter(
|
||||||
|
ROUTER_KEY,
|
||||||
|
ScriptStateRouterFactory.NAME); // Replace original protocol (maybe 'file') with 'script'
|
||||||
String type = null; // Use file suffix to config script type, e.g., js, groovy ...
|
String type = null; // Use file suffix to config script type, e.g., js, groovy ...
|
||||||
String path = url.getPath();
|
String path = url.getPath();
|
||||||
if (path != null) {
|
if (path != null) {
|
||||||
|
|
@ -71,5 +73,4 @@ public class FileStateRouterFactory implements StateRouterFactory {
|
||||||
throw new IllegalStateException(e.getMessage(), e);
|
throw new IllegalStateException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.route;
|
package org.apache.dubbo.rpc.cluster.router.mesh.route;
|
||||||
|
|
||||||
import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
|
import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
|
||||||
|
|
@ -26,24 +25,23 @@ import org.apache.dubbo.common.utils.CollectionUtils;
|
||||||
import org.apache.dubbo.rpc.cluster.router.mesh.util.MeshRuleDispatcher;
|
import org.apache.dubbo.rpc.cluster.router.mesh.util.MeshRuleDispatcher;
|
||||||
import org.apache.dubbo.rpc.cluster.router.mesh.util.MeshRuleListener;
|
import org.apache.dubbo.rpc.cluster.router.mesh.util.MeshRuleListener;
|
||||||
|
|
||||||
import org.yaml.snakeyaml.DumperOptions;
|
|
||||||
import org.yaml.snakeyaml.LoaderOptions;
|
|
||||||
import org.yaml.snakeyaml.Yaml;
|
|
||||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|
||||||
import org.yaml.snakeyaml.representer.Representer;
|
|
||||||
|
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.yaml.snakeyaml.DumperOptions;
|
||||||
|
import org.yaml.snakeyaml.LoaderOptions;
|
||||||
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||||
|
import org.yaml.snakeyaml.representer.Representer;
|
||||||
|
|
||||||
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_RECEIVE_RULE;
|
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_RECEIVE_RULE;
|
||||||
import static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.METADATA_KEY;
|
import static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.METADATA_KEY;
|
||||||
import static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.NAME_KEY;
|
import static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.NAME_KEY;
|
||||||
import static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.STANDARD_ROUTER_KEY;
|
import static org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleConstants.STANDARD_ROUTER_KEY;
|
||||||
|
|
||||||
|
|
||||||
public class MeshAppRuleListener implements ConfigurationListener {
|
public class MeshAppRuleListener implements ConfigurationListener {
|
||||||
|
|
||||||
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MeshAppRuleListener.class);
|
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MeshAppRuleListener.class);
|
||||||
|
|
@ -62,8 +60,7 @@ public class MeshAppRuleListener implements ConfigurationListener {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void receiveConfigInfo(String configInfo) {
|
public void receiveConfigInfo(String configInfo) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(MessageFormat.format("[MeshAppRule] Received rule for app [{0}]: {1}.",
|
logger.debug(MessageFormat.format("[MeshAppRule] Received rule for app [{0}]: {1}.", appName, configInfo));
|
||||||
appName, configInfo));
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Map<String, List<Map<String, Object>>> groupMap = new HashMap<>();
|
Map<String, List<Map<String, Object>>> groupMap = new HashMap<>();
|
||||||
|
|
@ -79,19 +76,34 @@ public class MeshAppRuleListener implements ConfigurationListener {
|
||||||
|
|
||||||
String ruleType = computeRuleType(resultMap);
|
String ruleType = computeRuleType(resultMap);
|
||||||
if (ruleType != null) {
|
if (ruleType != null) {
|
||||||
groupMap.computeIfAbsent(ruleType, (k)-> new LinkedList<>()).add(resultMap);
|
groupMap.computeIfAbsent(ruleType, (k) -> new LinkedList<>())
|
||||||
|
.add(resultMap);
|
||||||
} else {
|
} else {
|
||||||
logger.error(CLUSTER_FAILED_RECEIVE_RULE,"receive mesh app route rule is invalid","","Unable to get rule type from raw rule. " +
|
logger.error(
|
||||||
"Probably the metadata.name is absent. App Name: " + appName + " RawRule: " + configInfo);
|
CLUSTER_FAILED_RECEIVE_RULE,
|
||||||
|
"receive mesh app route rule is invalid",
|
||||||
|
"",
|
||||||
|
"Unable to get rule type from raw rule. "
|
||||||
|
+ "Probably the metadata.name is absent. App Name: " + appName + " RawRule: "
|
||||||
|
+ configInfo);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.error(CLUSTER_FAILED_RECEIVE_RULE,"receive mesh app route rule is invalid","","Rule format is unacceptable. App Name: " + appName + " RawRule: " + configInfo);
|
logger.error(
|
||||||
|
CLUSTER_FAILED_RECEIVE_RULE,
|
||||||
|
"receive mesh app route rule is invalid",
|
||||||
|
"",
|
||||||
|
"Rule format is unacceptable. App Name: " + appName + " RawRule: " + configInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleMapHolder = groupMap;
|
ruleMapHolder = groupMap;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error(CLUSTER_FAILED_RECEIVE_RULE,"failed to receive mesh app route rule","","[MeshAppRule] parse failed: " + configInfo,e);
|
logger.error(
|
||||||
|
CLUSTER_FAILED_RECEIVE_RULE,
|
||||||
|
"failed to receive mesh app route rule",
|
||||||
|
"",
|
||||||
|
"[MeshAppRule] parse failed: " + configInfo,
|
||||||
|
e);
|
||||||
}
|
}
|
||||||
if (ruleMapHolder != null) {
|
if (ruleMapHolder != null) {
|
||||||
meshRuleDispatcher.post(ruleMapHolder);
|
meshRuleDispatcher.post(ruleMapHolder);
|
||||||
|
|
@ -123,7 +135,6 @@ public class MeshAppRuleListener implements ConfigurationListener {
|
||||||
meshRuleDispatcher.register(subscriber);
|
meshRuleDispatcher.register(subscriber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public <T> void unregister(MeshRuleListener subscriber) {
|
public <T> void unregister(MeshRuleListener subscriber) {
|
||||||
meshRuleDispatcher.unregister(subscriber);
|
meshRuleDispatcher.unregister(subscriber);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.route;
|
package org.apache.dubbo.rpc.cluster.router.mesh.route;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,11 @@ public class MeshRuleCache<T> {
|
||||||
private final Map<String, Map<String, BitList<Invoker<T>>>> totalSubsetMap;
|
private final Map<String, Map<String, BitList<Invoker<T>>>> totalSubsetMap;
|
||||||
private final BitList<Invoker<T>> unmatchedInvokers;
|
private final BitList<Invoker<T>> unmatchedInvokers;
|
||||||
|
|
||||||
private MeshRuleCache(List<String> appList, Map<String, VsDestinationGroup> appToVDGroup, Map<String, Map<String, BitList<Invoker<T>>>> totalSubsetMap, BitList<Invoker<T>> unmatchedInvokers) {
|
private MeshRuleCache(
|
||||||
|
List<String> appList,
|
||||||
|
Map<String, VsDestinationGroup> appToVDGroup,
|
||||||
|
Map<String, Map<String, BitList<Invoker<T>>>> totalSubsetMap,
|
||||||
|
BitList<Invoker<T>> unmatchedInvokers) {
|
||||||
this.appList = appList;
|
this.appList = appList;
|
||||||
this.appToVDGroup = appToVDGroup;
|
this.appToVDGroup = appToVDGroup;
|
||||||
this.totalSubsetMap = totalSubsetMap;
|
this.totalSubsetMap = totalSubsetMap;
|
||||||
|
|
@ -83,7 +87,10 @@ public class MeshRuleCache<T> {
|
||||||
return !totalSubsetMap.isEmpty();
|
return !totalSubsetMap.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> MeshRuleCache<T> build(String protocolServiceKey, BitList<Invoker<T>> invokers, Map<String, VsDestinationGroup> vsDestinationGroupMap) {
|
public static <T> MeshRuleCache<T> build(
|
||||||
|
String protocolServiceKey,
|
||||||
|
BitList<Invoker<T>> invokers,
|
||||||
|
Map<String, VsDestinationGroup> vsDestinationGroupMap) {
|
||||||
if (CollectionUtils.isNotEmptyMap(vsDestinationGroupMap)) {
|
if (CollectionUtils.isNotEmptyMap(vsDestinationGroupMap)) {
|
||||||
BitList<Invoker<T>> unmatchedInvokers = new BitList<>(invokers.getOriginList(), true);
|
BitList<Invoker<T>> unmatchedInvokers = new BitList<>(invokers.getOriginList(), true);
|
||||||
Map<String, Map<String, BitList<Invoker<T>>>> totalSubsetMap = new HashMap<>();
|
Map<String, Map<String, BitList<Invoker<T>>>> totalSubsetMap = new HashMap<>();
|
||||||
|
|
@ -99,7 +106,8 @@ public class MeshRuleCache<T> {
|
||||||
unmatchedInvokers.add(invoker);
|
unmatchedInvokers.add(invoker);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Map<String, BitList<Invoker<T>>> subsetMap = totalSubsetMap.computeIfAbsent(remoteApplication, (k) -> new HashMap<>());
|
Map<String, BitList<Invoker<T>>> subsetMap =
|
||||||
|
totalSubsetMap.computeIfAbsent(remoteApplication, (k) -> new HashMap<>());
|
||||||
|
|
||||||
boolean matched = false;
|
boolean matched = false;
|
||||||
for (DestinationRule destinationRule : vsDestinationGroup.getDestinationRuleList()) {
|
for (DestinationRule destinationRule : vsDestinationGroup.getDestinationRuleList()) {
|
||||||
|
|
@ -107,7 +115,8 @@ public class MeshRuleCache<T> {
|
||||||
List<Subset> subsetList = destinationRuleSpec.getSubsets();
|
List<Subset> subsetList = destinationRuleSpec.getSubsets();
|
||||||
for (Subset subset : subsetList) {
|
for (Subset subset : subsetList) {
|
||||||
String subsetName = subset.getName();
|
String subsetName = subset.getName();
|
||||||
List<Invoker<T>> subsetInvokers = subsetMap.computeIfAbsent(subsetName, (k) -> new BitList<>(invokers.getOriginList(), true));
|
List<Invoker<T>> subsetInvokers = subsetMap.computeIfAbsent(
|
||||||
|
subsetName, (k) -> new BitList<>(invokers.getOriginList(), true));
|
||||||
|
|
||||||
Map<String, String> labels = subset.getLabels();
|
Map<String, String> labels = subset.getLabels();
|
||||||
if (isLabelMatch(invoker.getUrl(), protocolServiceKey, labels)) {
|
if (isLabelMatch(invoker.getUrl(), protocolServiceKey, labels)) {
|
||||||
|
|
@ -121,17 +130,20 @@ public class MeshRuleCache<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MeshRuleCache<>(new LinkedList<>(vsDestinationGroupMap.keySet()),
|
return new MeshRuleCache<>(
|
||||||
Collections.unmodifiableMap(vsDestinationGroupMap),
|
new LinkedList<>(vsDestinationGroupMap.keySet()),
|
||||||
Collections.unmodifiableMap(totalSubsetMap),
|
Collections.unmodifiableMap(vsDestinationGroupMap),
|
||||||
unmatchedInvokers);
|
Collections.unmodifiableMap(totalSubsetMap),
|
||||||
|
unmatchedInvokers);
|
||||||
} else {
|
} else {
|
||||||
return new MeshRuleCache<T>(Collections.emptyList(), Collections.emptyMap(), Collections.emptyMap(), invokers);
|
return new MeshRuleCache<T>(
|
||||||
|
Collections.emptyList(), Collections.emptyMap(), Collections.emptyMap(), invokers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> MeshRuleCache<T> emptyCache() {
|
public static <T> MeshRuleCache<T> emptyCache() {
|
||||||
return new MeshRuleCache<>(Collections.emptyList(), Collections.emptyMap(), Collections.emptyMap(), BitList.emptyList());
|
return new MeshRuleCache<>(
|
||||||
|
Collections.emptyList(), Collections.emptyMap(), Collections.emptyMap(), BitList.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static boolean isLabelMatch(URL url, String protocolServiceKey, Map<String, String> inputMap) {
|
protected static boolean isLabelMatch(URL url, String protocolServiceKey, Map<String, String> inputMap) {
|
||||||
|
|
@ -161,7 +173,10 @@ public class MeshRuleCache<T> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MeshRuleCache<?> ruleCache = (MeshRuleCache<?>) o;
|
MeshRuleCache<?> ruleCache = (MeshRuleCache<?>) o;
|
||||||
return Objects.equals(appList, ruleCache.appList) && Objects.equals(appToVDGroup, ruleCache.appToVDGroup) && Objects.equals(totalSubsetMap, ruleCache.totalSubsetMap) && Objects.equals(unmatchedInvokers, ruleCache.unmatchedInvokers);
|
return Objects.equals(appList, ruleCache.appList)
|
||||||
|
&& Objects.equals(appToVDGroup, ruleCache.appToVDGroup)
|
||||||
|
&& Objects.equals(totalSubsetMap, ruleCache.totalSubsetMap)
|
||||||
|
&& Objects.equals(unmatchedInvokers, ruleCache.unmatchedInvokers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.route;
|
package org.apache.dubbo.rpc.cluster.router.mesh.route;
|
||||||
|
|
||||||
import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
|
import org.apache.dubbo.common.config.configcenter.DynamicConfiguration;
|
||||||
|
|
@ -44,11 +43,12 @@ public class MeshRuleManager {
|
||||||
|
|
||||||
public MeshRuleManager(ModuleModel moduleModel) {
|
public MeshRuleManager(ModuleModel moduleModel) {
|
||||||
this.ruleRepository = moduleModel.getDefaultExtension(GovernanceRuleRepository.class);
|
this.ruleRepository = moduleModel.getDefaultExtension(GovernanceRuleRepository.class);
|
||||||
Set<MeshEnvListenerFactory> envListenerFactories = moduleModel.getExtensionLoader(MeshEnvListenerFactory.class).getSupportedExtensionInstances();
|
Set<MeshEnvListenerFactory> envListenerFactories =
|
||||||
|
moduleModel.getExtensionLoader(MeshEnvListenerFactory.class).getSupportedExtensionInstances();
|
||||||
this.envListeners = envListenerFactories.stream()
|
this.envListeners = envListenerFactories.stream()
|
||||||
.map(MeshEnvListenerFactory::getListener)
|
.map(MeshEnvListenerFactory::getListener)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized MeshAppRuleListener subscribeAppRule(String app) {
|
private synchronized MeshAppRuleListener subscribeAppRule(String app) {
|
||||||
|
|
@ -64,7 +64,12 @@ public class MeshRuleManager {
|
||||||
meshAppRuleListener.receiveConfigInfo(rawConfig);
|
meshAppRuleListener.receiveConfigInfo(rawConfig);
|
||||||
}
|
}
|
||||||
} catch (Throwable throwable) {
|
} catch (Throwable throwable) {
|
||||||
logger.error(CLUSTER_FAILED_RECEIVE_RULE,"failed to get mesh app route rule","","get MeshRuleManager app rule failed.",throwable);
|
logger.error(
|
||||||
|
CLUSTER_FAILED_RECEIVE_RULE,
|
||||||
|
"failed to get mesh app route rule",
|
||||||
|
"",
|
||||||
|
"get MeshRuleManager app rule failed.",
|
||||||
|
throwable);
|
||||||
}
|
}
|
||||||
|
|
||||||
ruleRepository.addListener(appRuleDataId, DynamicConfiguration.DEFAULT_GROUP, meshAppRuleListener);
|
ruleRepository.addListener(appRuleDataId, DynamicConfiguration.DEFAULT_GROUP, meshAppRuleListener);
|
||||||
|
|
@ -93,7 +98,6 @@ public class MeshRuleManager {
|
||||||
envListener.onUnSubscribe(app);
|
envListener.onUnSubscribe(app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized <T> void register(String app, MeshRuleListener subscriber) {
|
public synchronized <T> void register(String app, MeshRuleListener subscriber) {
|
||||||
|
|
|
||||||
|
|
@ -74,13 +74,20 @@ public abstract class MeshRuleRouter<T> extends AbstractStateRouter<T> implement
|
||||||
super(url);
|
super(url);
|
||||||
sourcesLabels = Collections.unmodifiableMap(new HashMap<>(url.getParameters()));
|
sourcesLabels = Collections.unmodifiableMap(new HashMap<>(url.getParameters()));
|
||||||
this.meshRuleManager = url.getOrDefaultModuleModel().getBeanFactory().getBean(MeshRuleManager.class);
|
this.meshRuleManager = url.getOrDefaultModuleModel().getBeanFactory().getBean(MeshRuleManager.class);
|
||||||
this.tracingContextProviders = url.getOrDefaultModuleModel().getExtensionLoader(TracingContextProvider.class).getSupportedExtensionInstances();
|
this.tracingContextProviders = url.getOrDefaultModuleModel()
|
||||||
|
.getExtensionLoader(TracingContextProvider.class)
|
||||||
|
.getSupportedExtensionInstances();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BitList<Invoker<T>> doRoute(BitList<Invoker<T>> invokers, URL url, Invocation invocation,
|
protected BitList<Invoker<T>> doRoute(
|
||||||
boolean needToPrintMessage, Holder<RouterSnapshotNode<T>> nodeHolder,
|
BitList<Invoker<T>> invokers,
|
||||||
Holder<String> messageHolder) throws RpcException {
|
URL url,
|
||||||
|
Invocation invocation,
|
||||||
|
boolean needToPrintMessage,
|
||||||
|
Holder<RouterSnapshotNode<T>> nodeHolder,
|
||||||
|
Holder<String> messageHolder)
|
||||||
|
throws RpcException {
|
||||||
MeshRuleCache<T> ruleCache = this.meshRuleCache;
|
MeshRuleCache<T> ruleCache = this.meshRuleCache;
|
||||||
if (!ruleCache.containsRule()) {
|
if (!ruleCache.containsRule()) {
|
||||||
if (needToPrintMessage) {
|
if (needToPrintMessage) {
|
||||||
|
|
@ -96,7 +103,8 @@ public abstract class MeshRuleRouter<T> extends AbstractStateRouter<T> implement
|
||||||
// loop each application
|
// loop each application
|
||||||
for (String appName : ruleCache.getAppList()) {
|
for (String appName : ruleCache.getAppList()) {
|
||||||
// find destination by invocation
|
// find destination by invocation
|
||||||
List<DubboRouteDestination> routeDestination = getDubboRouteDestination(ruleCache.getVsDestinationGroup(appName), invocation);
|
List<DubboRouteDestination> routeDestination =
|
||||||
|
getDubboRouteDestination(ruleCache.getVsDestinationGroup(appName), invocation);
|
||||||
if (routeDestination != null) {
|
if (routeDestination != null) {
|
||||||
// aggregate target invokers
|
// aggregate target invokers
|
||||||
String subset = randomSelectDestination(ruleCache, appName, routeDestination, invokers);
|
String subset = randomSelectDestination(ruleCache, appName, routeDestination, invokers);
|
||||||
|
|
@ -104,7 +112,12 @@ public abstract class MeshRuleRouter<T> extends AbstractStateRouter<T> implement
|
||||||
BitList<Invoker<T>> destination = meshRuleCache.getSubsetInvokers(appName, subset);
|
BitList<Invoker<T>> destination = meshRuleCache.getSubsetInvokers(appName, subset);
|
||||||
result = result.or(destination);
|
result = result.or(destination);
|
||||||
if (stringBuilder != null) {
|
if (stringBuilder != null) {
|
||||||
stringBuilder.append("Match App: ").append(appName).append(" Subset: ").append(subset).append(' ');
|
stringBuilder
|
||||||
|
.append("Match App: ")
|
||||||
|
.append(appName)
|
||||||
|
.append(" Subset: ")
|
||||||
|
.append(subset)
|
||||||
|
.append(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -129,7 +142,8 @@ public abstract class MeshRuleRouter<T> extends AbstractStateRouter<T> implement
|
||||||
/**
|
/**
|
||||||
* Select RouteDestination by Invocation
|
* Select RouteDestination by Invocation
|
||||||
*/
|
*/
|
||||||
protected List<DubboRouteDestination> getDubboRouteDestination(VsDestinationGroup vsDestinationGroup, Invocation invocation) {
|
protected List<DubboRouteDestination> getDubboRouteDestination(
|
||||||
|
VsDestinationGroup vsDestinationGroup, Invocation invocation) {
|
||||||
if (vsDestinationGroup != null) {
|
if (vsDestinationGroup != null) {
|
||||||
List<VirtualServiceRule> virtualServiceRuleList = vsDestinationGroup.getVirtualServiceRuleList();
|
List<VirtualServiceRule> virtualServiceRuleList = vsDestinationGroup.getVirtualServiceRuleList();
|
||||||
if (CollectionUtils.isNotEmpty(virtualServiceRuleList)) {
|
if (CollectionUtils.isNotEmpty(virtualServiceRuleList)) {
|
||||||
|
|
@ -182,8 +196,8 @@ public abstract class MeshRuleRouter<T> extends AbstractStateRouter<T> implement
|
||||||
return dubboRouteDetail.getRoute();
|
return dubboRouteDetail.getRoute();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchRequestList.stream().allMatch(
|
if (matchRequestList.stream()
|
||||||
request -> request.isMatch(invocation, sourcesLabels, tracingContextProviders))) {
|
.allMatch(request -> request.isMatch(invocation, sourcesLabels, tracingContextProviders))) {
|
||||||
return dubboRouteDetail.getRoute();
|
return dubboRouteDetail.getRoute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -195,7 +209,12 @@ public abstract class MeshRuleRouter<T> extends AbstractStateRouter<T> implement
|
||||||
/**
|
/**
|
||||||
* Find out target invokers from RouteDestination
|
* Find out target invokers from RouteDestination
|
||||||
*/
|
*/
|
||||||
protected String randomSelectDestination(MeshRuleCache<T> meshRuleCache, String appName, List<DubboRouteDestination> routeDestination, BitList<Invoker<T>> availableInvokers) throws RpcException {
|
protected String randomSelectDestination(
|
||||||
|
MeshRuleCache<T> meshRuleCache,
|
||||||
|
String appName,
|
||||||
|
List<DubboRouteDestination> routeDestination,
|
||||||
|
BitList<Invoker<T>> availableInvokers)
|
||||||
|
throws RpcException {
|
||||||
// randomly select one DubboRouteDestination from list by weight
|
// randomly select one DubboRouteDestination from list by weight
|
||||||
int totalWeight = 0;
|
int totalWeight = 0;
|
||||||
for (DubboRouteDestination dubboRouteDestination : routeDestination) {
|
for (DubboRouteDestination dubboRouteDestination : routeDestination) {
|
||||||
|
|
@ -206,7 +225,8 @@ public abstract class MeshRuleRouter<T> extends AbstractStateRouter<T> implement
|
||||||
target -= Math.max(destination.getWeight(), 1);
|
target -= Math.max(destination.getWeight(), 1);
|
||||||
if (target <= 0) {
|
if (target <= 0) {
|
||||||
// match weight
|
// match weight
|
||||||
String result = computeDestination(meshRuleCache, appName, destination.getDestination(), availableInvokers);
|
String result =
|
||||||
|
computeDestination(meshRuleCache, appName, destination.getDestination(), availableInvokers);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -226,13 +246,19 @@ public abstract class MeshRuleRouter<T> extends AbstractStateRouter<T> implement
|
||||||
/**
|
/**
|
||||||
* Compute Destination Subset
|
* Compute Destination Subset
|
||||||
*/
|
*/
|
||||||
protected String computeDestination(MeshRuleCache<T> meshRuleCache, String appName, DubboDestination dubboDestination, BitList<Invoker<T>> availableInvokers) throws RpcException {
|
protected String computeDestination(
|
||||||
|
MeshRuleCache<T> meshRuleCache,
|
||||||
|
String appName,
|
||||||
|
DubboDestination dubboDestination,
|
||||||
|
BitList<Invoker<T>> availableInvokers)
|
||||||
|
throws RpcException {
|
||||||
String subset = dubboDestination.getSubset();
|
String subset = dubboDestination.getSubset();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
BitList<Invoker<T>> result = meshRuleCache.getSubsetInvokers(appName, subset);
|
BitList<Invoker<T>> result = meshRuleCache.getSubsetInvokers(appName, subset);
|
||||||
|
|
||||||
if (CollectionUtils.isNotEmpty(result) && !availableInvokers.clone().and(result).isEmpty()) {
|
if (CollectionUtils.isNotEmpty(result)
|
||||||
|
&& !availableInvokers.clone().and(result).isEmpty()) {
|
||||||
return subset;
|
return subset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,7 +335,12 @@ public abstract class MeshRuleRouter<T> extends AbstractStateRouter<T> implement
|
||||||
appToVDGroup.put(appName, vsDestinationGroup);
|
appToVDGroup.put(appName, vsDestinationGroup);
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
logger.error(CLUSTER_FAILED_RECEIVE_RULE,"failed to parse mesh route rule","","Error occurred when parsing rule component.",t);
|
logger.error(
|
||||||
|
CLUSTER_FAILED_RECEIVE_RULE,
|
||||||
|
"failed to parse mesh route rule",
|
||||||
|
"",
|
||||||
|
"Error occurred when parsing rule component.",
|
||||||
|
t);
|
||||||
}
|
}
|
||||||
|
|
||||||
computeSubset(appToVDGroup);
|
computeSubset(appToVDGroup);
|
||||||
|
|
@ -323,7 +354,8 @@ public abstract class MeshRuleRouter<T> extends AbstractStateRouter<T> implement
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void computeSubset(Map<String, VsDestinationGroup> vsDestinationGroupMap) {
|
protected void computeSubset(Map<String, VsDestinationGroup> vsDestinationGroupMap) {
|
||||||
this.meshRuleCache = MeshRuleCache.build(getUrl().getProtocolServiceKey(), this.invokerList, vsDestinationGroupMap);
|
this.meshRuleCache =
|
||||||
|
MeshRuleCache.build(getUrl().getProtocolServiceKey(), this.invokerList, vsDestinationGroupMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.route;
|
package org.apache.dubbo.rpc.cluster.router.mesh.route;
|
||||||
|
|
||||||
import org.apache.dubbo.common.URL;
|
import org.apache.dubbo.common.URL;
|
||||||
|
|
@ -22,7 +21,6 @@ import org.apache.dubbo.common.extension.Activate;
|
||||||
import org.apache.dubbo.rpc.cluster.router.state.StateRouter;
|
import org.apache.dubbo.rpc.cluster.router.state.StateRouter;
|
||||||
import org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;
|
import org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;
|
||||||
|
|
||||||
|
|
||||||
@Activate(order = -50)
|
@Activate(order = -50)
|
||||||
public class StandardMeshRuleRouterFactory implements StateRouterFactory {
|
public class StandardMeshRuleRouterFactory implements StateRouterFactory {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,10 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
public class BaseRule {
|
public class BaseRule {
|
||||||
private String apiVersion;
|
private String apiVersion;
|
||||||
private String kind;
|
private String kind;
|
||||||
|
|
@ -51,10 +49,9 @@ public class BaseRule {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "BaseRule{" +
|
return "BaseRule{" + "apiVersion='"
|
||||||
"apiVersion='" + apiVersion + '\'' +
|
+ apiVersion + '\'' + ", kind='"
|
||||||
", kind='" + kind + '\'' +
|
+ kind + '\'' + ", metadata="
|
||||||
", metadata=" + metadata +
|
+ metadata + '}';
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.DestinationRule;
|
import org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.DestinationRule;
|
||||||
|
|
@ -23,7 +22,6 @@ import org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.VirtualServi
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class VsDestinationGroup {
|
public class VsDestinationGroup {
|
||||||
private String appName;
|
private String appName;
|
||||||
private List<VirtualServiceRule> virtualServiceRuleList = new LinkedList<>();
|
private List<VirtualServiceRule> virtualServiceRuleList = new LinkedList<>();
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
||||||
|
|
||||||
|
public class ConnectionPoolSettings {}
|
||||||
public class ConnectionPoolSettings {
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,10 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.cluster.router.mesh.rule.BaseRule;
|
import org.apache.dubbo.rpc.cluster.router.mesh.rule.BaseRule;
|
||||||
|
|
||||||
|
|
||||||
public class DestinationRule extends BaseRule {
|
public class DestinationRule extends BaseRule {
|
||||||
private DestinationRuleSpec spec;
|
private DestinationRuleSpec spec;
|
||||||
|
|
||||||
|
|
@ -33,9 +31,6 @@ public class DestinationRule extends BaseRule {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "DestinationRule{" +
|
return "DestinationRule{" + "base=" + super.toString() + ", spec=" + spec + '}';
|
||||||
"base=" + super.toString() +
|
|
||||||
", spec=" + spec +
|
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,10 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class DestinationRuleSpec {
|
public class DestinationRuleSpec {
|
||||||
private String host;
|
private String host;
|
||||||
private List<Subset> subsets;
|
private List<Subset> subsets;
|
||||||
|
|
@ -51,10 +49,9 @@ public class DestinationRuleSpec {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "DestinationRuleSpec{" +
|
return "DestinationRuleSpec{" + "host='"
|
||||||
"host='" + host + '\'' +
|
+ host + '\'' + ", subsets="
|
||||||
", subsets=" + subsets +
|
+ subsets + ", trafficPolicy="
|
||||||
", trafficPolicy=" + trafficPolicy +
|
+ trafficPolicy + '}';
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,10 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
public class Subset {
|
public class Subset {
|
||||||
private String name;
|
private String name;
|
||||||
private Map<String, String> labels;
|
private Map<String, String> labels;
|
||||||
|
|
@ -42,9 +40,6 @@ public class Subset {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Subset{" +
|
return "Subset{" + "name='" + name + '\'' + ", labels=" + labels + '}';
|
||||||
"name='" + name + '\'' +
|
|
||||||
", labels=" + labels +
|
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,8 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
||||||
|
|
||||||
|
|
||||||
public class TCPSettings {
|
public class TCPSettings {
|
||||||
private int maxConnections;
|
private int maxConnections;
|
||||||
private int connectTimeout;
|
private int connectTimeout;
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,10 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
||||||
|
|
||||||
|
|
||||||
public class TcpKeepalive {
|
public class TcpKeepalive {
|
||||||
private int probes;
|
private int probes;
|
||||||
private int time;
|
private int time;
|
||||||
private int interval;
|
private int interval;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,10 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.loadbalance.LoadBalancerSettings;
|
import org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.loadbalance.LoadBalancerSettings;
|
||||||
|
|
||||||
|
|
||||||
public class TrafficPolicy {
|
public class TrafficPolicy {
|
||||||
private LoadBalancerSettings loadBalancer;
|
private LoadBalancerSettings loadBalancer;
|
||||||
|
|
||||||
|
|
@ -33,8 +31,6 @@ public class TrafficPolicy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TrafficPolicy{" +
|
return "TrafficPolicy{" + "loadBalancer=" + loadBalancer + '}';
|
||||||
"loadBalancer=" + loadBalancer +
|
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.loadbalance;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.loadbalance;
|
||||||
|
|
||||||
|
public class ConsistentHashLB {}
|
||||||
public class ConsistentHashLB {
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,8 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.loadbalance;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.loadbalance;
|
||||||
|
|
||||||
|
|
||||||
public class LoadBalancerSettings {
|
public class LoadBalancerSettings {
|
||||||
private SimpleLB simple;
|
private SimpleLB simple;
|
||||||
private ConsistentHashLB consistentHash;
|
private ConsistentHashLB consistentHash;
|
||||||
|
|
@ -40,9 +38,6 @@ public class LoadBalancerSettings {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "LoadBalancerSettings{" +
|
return "LoadBalancerSettings{" + "simple=" + simple + ", consistentHash=" + consistentHash + '}';
|
||||||
"simple=" + simple +
|
|
||||||
", consistentHash=" + consistentHash +
|
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,8 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.loadbalance;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.destination.loadbalance;
|
||||||
|
|
||||||
|
|
||||||
public enum SimpleLB {
|
public enum SimpleLB {
|
||||||
ROUND_ROBIN,
|
ROUND_ROBIN,
|
||||||
LEAST_CONN,
|
LEAST_CONN,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.Invocation;
|
import org.apache.dubbo.rpc.Invocation;
|
||||||
|
|
@ -26,7 +25,6 @@ import org.apache.dubbo.rpc.cluster.router.mesh.util.TracingContextProvider;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
public class DubboMatchRequest {
|
public class DubboMatchRequest {
|
||||||
private String name;
|
private String name;
|
||||||
private DubboMethodMatch method;
|
private DubboMethodMatch method;
|
||||||
|
|
@ -76,16 +74,16 @@ public class DubboMatchRequest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "DubboMatchRequest{" +
|
return "DubboMatchRequest{" + "name='"
|
||||||
"name='" + name + '\'' +
|
+ name + '\'' + ", method="
|
||||||
", method=" + method +
|
+ method + ", sourceLabels="
|
||||||
", sourceLabels=" + sourceLabels +
|
+ sourceLabels + ", attachments="
|
||||||
", attachments=" + attachments +
|
+ attachments + ", headers="
|
||||||
", headers=" + headers +
|
+ headers + '}';
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMatch(Invocation invocation, Map<String, String> sourceLabels, Set<TracingContextProvider> contextProviders) {
|
public boolean isMatch(
|
||||||
|
Invocation invocation, Map<String, String> sourceLabels, Set<TracingContextProvider> contextProviders) {
|
||||||
// Match method
|
// Match method
|
||||||
if (getMethod() != null) {
|
if (getMethod() != null) {
|
||||||
if (!getMethod().isMatch(invocation)) {
|
if (!getMethod().isMatch(invocation)) {
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,12 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.StringMatch;
|
import org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.StringMatch;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class DubboRoute {
|
public class DubboRoute {
|
||||||
private String name;
|
private String name;
|
||||||
private List<StringMatch> services;
|
private List<StringMatch> services;
|
||||||
|
|
@ -53,10 +51,6 @@ public class DubboRoute {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "DubboRoute{" +
|
return "DubboRoute{" + "name='" + name + '\'' + ", services=" + services + ", routedetail=" + routedetail + '}';
|
||||||
"name='" + name + '\'' +
|
|
||||||
", services=" + services +
|
|
||||||
", routedetail=" + routedetail +
|
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,12 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.destination.DubboRouteDestination;
|
import org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.destination.DubboRouteDestination;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class DubboRouteDetail {
|
public class DubboRouteDetail {
|
||||||
private String name;
|
private String name;
|
||||||
private List<DubboMatchRequest> match;
|
private List<DubboMatchRequest> match;
|
||||||
|
|
@ -53,10 +51,6 @@ public class DubboRouteDetail {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "DubboRouteDetail{" +
|
return "DubboRouteDetail{" + "name='" + name + '\'' + ", match=" + match + ", route=" + route + '}';
|
||||||
"name='" + name + '\'' +
|
|
||||||
", match=" + match +
|
|
||||||
", route=" + route +
|
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,10 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;
|
||||||
|
|
||||||
import org.apache.dubbo.rpc.cluster.router.mesh.rule.BaseRule;
|
import org.apache.dubbo.rpc.cluster.router.mesh.rule.BaseRule;
|
||||||
|
|
||||||
|
|
||||||
public class VirtualServiceRule extends BaseRule {
|
public class VirtualServiceRule extends BaseRule {
|
||||||
private VirtualServiceSpec spec;
|
private VirtualServiceSpec spec;
|
||||||
|
|
||||||
|
|
@ -33,9 +31,6 @@ public class VirtualServiceRule extends BaseRule {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "VirtualServiceRule{" +
|
return "VirtualServiceRule{" + "base=" + super.toString() + ", spec=" + spec + '}';
|
||||||
"base=" + super.toString() +
|
|
||||||
", spec=" + spec +
|
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,10 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class VirtualServiceSpec {
|
public class VirtualServiceSpec {
|
||||||
private List<String> hosts;
|
private List<String> hosts;
|
||||||
private List<DubboRoute> dubbo;
|
private List<DubboRoute> dubbo;
|
||||||
|
|
@ -42,9 +40,6 @@ public class VirtualServiceSpec {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "VirtualServiceSpec{" +
|
return "VirtualServiceSpec{" + "hosts=" + hosts + ", dubbo=" + dubbo + '}';
|
||||||
"hosts=" + hosts +
|
|
||||||
", dubbo=" + dubbo +
|
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,17 +14,14 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.destination;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.destination;
|
||||||
|
|
||||||
|
|
||||||
public class DubboDestination {
|
public class DubboDestination {
|
||||||
private String host;
|
private String host;
|
||||||
private String subset;
|
private String subset;
|
||||||
private int port;
|
private int port;
|
||||||
private DubboRouteDestination fallback;
|
private DubboRouteDestination fallback;
|
||||||
|
|
||||||
|
|
||||||
public String getHost() {
|
public String getHost() {
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,8 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.destination;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.destination;
|
||||||
|
|
||||||
|
|
||||||
public class DubboRouteDestination {
|
public class DubboRouteDestination {
|
||||||
private DubboDestination destination;
|
private DubboDestination destination;
|
||||||
private int weight;
|
private int weight;
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,14 @@ public class AddressMatch {
|
||||||
try {
|
try {
|
||||||
return input.equals(getCird()) || matchIpExpression(getCird(), input);
|
return input.equals(getCird()) || matchIpExpression(getCird(), input);
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
logger.error(CLUSTER_FAILED_EXEC_CONDITION_ROUTER, "Executing routing rule match expression error.", "", String.format("Error trying to match cird formatted address %s with input %s in AddressMatch.", getCird(), input), e);
|
logger.error(
|
||||||
|
CLUSTER_FAILED_EXEC_CONDITION_ROUTER,
|
||||||
|
"Executing routing rule match expression error.",
|
||||||
|
"",
|
||||||
|
String.format(
|
||||||
|
"Error trying to match cird formatted address %s with input %s in AddressMatch.",
|
||||||
|
getCird(), input),
|
||||||
|
e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (getWildcard() != null && input != null) {
|
if (getWildcard() != null && input != null) {
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,8 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;
|
||||||
|
|
||||||
|
|
||||||
public class BoolMatch {
|
public class BoolMatch {
|
||||||
private Boolean exact;
|
private Boolean exact;
|
||||||
|
|
||||||
|
|
@ -29,8 +27,8 @@ public class BoolMatch {
|
||||||
this.exact = exact;
|
this.exact = exact;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMatch(boolean input){
|
public boolean isMatch(boolean input) {
|
||||||
if (exact != null){
|
if (exact != null) {
|
||||||
return input == exact;
|
return input == exact;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,8 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;
|
||||||
|
|
||||||
|
|
||||||
public class DoubleMatch {
|
public class DoubleMatch {
|
||||||
private Double exact;
|
private Double exact;
|
||||||
private DoubleRangeMatch range;
|
private DoubleRangeMatch range;
|
||||||
|
|
@ -47,7 +45,6 @@ public class DoubleMatch {
|
||||||
this.mod = mod;
|
this.mod = mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean isMatch(Double input) {
|
public boolean isMatch(Double input) {
|
||||||
if (exact != null && mod == null) {
|
if (exact != null && mod == null) {
|
||||||
return input.equals(exact);
|
return input.equals(exact);
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,8 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;
|
package org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match;
|
||||||
|
|
||||||
|
|
||||||
public class DoubleRangeMatch {
|
public class DoubleRangeMatch {
|
||||||
private Double start;
|
private Double start;
|
||||||
private Double end;
|
private Double end;
|
||||||
|
|
@ -38,7 +36,6 @@ public class DoubleRangeMatch {
|
||||||
this.end = end;
|
this.end = end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean isMatch(Double input) {
|
public boolean isMatch(Double input) {
|
||||||
if (start != null && end != null) {
|
if (start != null && end != null) {
|
||||||
return input.compareTo(start) >= 0 && input.compareTo(end) < 0;
|
return input.compareTo(start) >= 0 && input.compareTo(end) < 0;
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue