Merge branch 'apache-3.2' into apache-3.3

# Conflicts:
#	dubbo-common/src/main/java/org/apache/dubbo/common/utils/JsonUtils.java
#	dubbo-dependencies-bom/pom.xml
#	dubbo-dependencies/dubbo-dependencies-zookeeper-curator5/pom.xml
#	dubbo-dependencies/dubbo-dependencies-zookeeper/pom.xml
This commit is contained in:
Albumen Kevin 2023-04-13 20:32:44 +08:00
commit fe55491d4a
630 changed files with 17421 additions and 5568 deletions

107
.artifacts Normal file
View File

@ -0,0 +1,107 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Please add new modules to the end of the list.
dubbo
dubbo-auth
dubbo-apache-release
dubbo-bom
dubbo-build-tools
dubbo-cluster
dubbo-common
dubbo-compatible
dubbo-compiler
dubbo-config
dubbo-config-api
dubbo-config-spring
dubbo-configcenter
dubbo-configcenter-apollo
dubbo-configcenter-nacos
dubbo-configcenter-zookeeper
dubbo-container
dubbo-container-api
dubbo-container-spring
dubbo-core-spi
dubbo-dependencies
dubbo-dependencies-all
dubbo-dependencies-bom
dubbo-dependencies-zookeeper
dubbo-dependencies-zookeeper-curator5
dubbo-distribution
dubbo-filter
dubbo-filter-cache
dubbo-filter-validation
dubbo-kubernetes
dubbo-maven-plugin
dubbo-metadata
dubbo-metadata-api
dubbo-metadata-definition-protobuf
dubbo-metadata-processor
dubbo-metadata-report-nacos
dubbo-metadata-report-redis
dubbo-metadata-report-zookeeper
dubbo-metrics
dubbo-metrics-api
dubbo-metrics-default
dubbo-metrics-metadata
dubbo-metrics-prometheus
dubbo-metrics-registry
dubbo-monitor
dubbo-monitor-api
dubbo-monitor-default
dubbo-native
dubbo-native-plugin
dubbo-parent
dubbo-plugin
dubbo-qos
dubbo-qos-api
dubbo-reactive
dubbo-registry
dubbo-registry-api
dubbo-registry-multicast
dubbo-registry-multiple
dubbo-registry-nacos
dubbo-registry-zookeeper
dubbo-remoting
dubbo-remoting-api
dubbo-remoting-http
dubbo-remoting-netty
dubbo-remoting-netty4
dubbo-remoting-zookeeper
dubbo-remoting-zookeeper-curator5
dubbo-rpc
dubbo-rpc-api
dubbo-rpc-dubbo
dubbo-rpc-injvm
dubbo-rpc-rest
dubbo-rpc-triple
dubbo-security
dubbo-serialization
dubbo-serialization-api
dubbo-serialization-fastjson2
dubbo-serialization-hessian2
dubbo-serialization-jdk
dubbo-spring-boot
dubbo-spring-boot-actuator
dubbo-spring-boot-actuator-compatible
dubbo-spring-boot-autoconfigure
dubbo-spring-boot-autoconfigure-compatible
dubbo-spring-boot-compatible
dubbo-spring-boot-observability-starter
dubbo-spring-boot-starter
dubbo-spring-security
dubbo-xds

View File

@ -73,7 +73,9 @@ jobs:
cd ./dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean source:jar install -Pjacoco,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Pack class result"
run: 7z a ${{ github.workspace }}/class.zip */target/classes/* -r
run: |
shopt -s globstar
zip ${{ github.workspace }}/class.zip **/target/classes/* -r
- name: "Upload class result"
uses: actions/upload-artifact@v3
with:
@ -81,7 +83,7 @@ jobs:
path: ${{ github.workspace }}/class.zip
- name: "Pack checkstyle file if failure"
if: failure()
run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r
run: zip ${{ github.workspace }}/checkstyle.zip *checkstyle* -r
- name: "Upload checkstyle file if failure"
if: failure()
uses: actions/upload-artifact@v3

View File

@ -396,7 +396,7 @@ jobs:
run: |
cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider
${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile
nohup ./target/dubbo-demo-native-provider &
nohup ./target/demo-native-provider &
cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer
${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile
./target/dubbo-demo-native-consumer
./target/demo-native-consumer

View File

@ -80,5 +80,16 @@
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-metrics-default</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-integration-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -23,6 +23,7 @@ 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.ConfiguratorConfig;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
@ -68,7 +69,7 @@ public class ConfigParser {
private static List<URL> parseJsonArray(String rawConfig) {
List<URL> urls = new ArrayList<>();
try {
List<String> list = JsonUtils.getJson().toJavaList(rawConfig, String.class);
List<String> list = JsonUtils.toJavaList(rawConfig, String.class);
if (!CollectionUtils.isEmpty(list)) {
list.forEach(u -> urls.add(URL.valueOf(u)));
}
@ -79,7 +80,7 @@ public class ConfigParser {
}
private static ConfiguratorConfig parseObject(String rawConfig) {
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
Map<String, Object> map = yaml.load(rawConfig);
return ConfiguratorConfig.parseFromMap(map);
}

View File

@ -27,9 +27,9 @@ import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;
import org.apache.dubbo.common.utils.ConcurrentHashSet;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster;
import org.apache.dubbo.metrics.event.MetricsEvent;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.registry.event.RegistryEvent;
import org.apache.dubbo.metrics.registry.event.type.ServiceType;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcContext;
@ -45,6 +45,7 @@ import org.apache.dubbo.rpc.model.ApplicationModel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@ -131,8 +132,6 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
*/
private final int reconnectTaskPeriod;
private final GlobalMetricsEventMulticaster eventMulticaster;
private ApplicationModel applicationModel;
public AbstractDirectory(URL url) {
@ -187,7 +186,6 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
this.reconnectTaskPeriod = configuration.getInt(RECONNECT_TASK_PERIOD, DEFAULT_RECONNECT_TASK_PERIOD);
setRouterChain(routerChain);
eventMulticaster = applicationModel.getBeanFactory().getBean(GlobalMetricsEventMulticaster.class);
}
@Override
@ -354,6 +352,7 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
}
}, reconnectTaskPeriod, TimeUnit.MILLISECONDS);
}
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary()));
}
/**
@ -367,6 +366,7 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
if (invokersInitialized) {
refreshInvokerInternal();
}
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary()));
}
private synchronized void refreshInvokerInternal() {
@ -388,25 +388,18 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
invokersToRemove.removeAll(needToRemove);
}
private void publishMetricsEvent(MetricsEvent event) {
if (eventMulticaster != null) {
eventMulticaster.publishEvent(event);
}
}
@Override
public void addDisabledInvoker(Invoker<T> invoker) {
publishMetricsEvent(new RegistryEvent.MetricsDirectoryEvent(applicationModel, RegistryEvent.ApplicationType.D_DISABLE));
if (invokers.contains(invoker)) {
disabledInvokers.add(invoker);
removeValidInvoker(invoker);
logger.info("Disable service address: " + invoker.getUrl() + ".");
}
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary()));
}
@Override
public void recoverDisabledInvoker(Invoker<T> invoker) {
publishMetricsEvent(new RegistryEvent.MetricsDirectoryEvent(applicationModel, RegistryEvent.ApplicationType.D_RECOVER_DISABLE));
if (disabledInvokers.remove(invoker)) {
try {
addValidInvoker(invoker);
@ -415,6 +408,7 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
}
}
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary()));
}
protected final void refreshRouter(BitList<Invoker<T>> newlyInvokers, Runnable switchAction) {
@ -470,7 +464,8 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
this.invokers = invokers;
refreshInvokerInternal();
this.invokersInitialized = true;
publishMetricsEvent(new RegistryEvent.MetricsDirectoryEvent(applicationModel, RegistryEvent.ApplicationType.D_CURRENT, invokers.size()));
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary()));
}
protected void destroyInvokers() {
@ -481,14 +476,12 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
}
private boolean addValidInvoker(Invoker<T> invoker) {
publishMetricsEvent(new RegistryEvent.MetricsDirectoryEvent(applicationModel, RegistryEvent.ApplicationType.D_VALID));
synchronized (this.validInvokers) {
return this.validInvokers.add(invoker);
}
}
private boolean removeValidInvoker(Invoker<T> invoker) {
publishMetricsEvent(new RegistryEvent.MetricsDirectoryEvent(applicationModel, RegistryEvent.ApplicationType.D_UN_VALID));
synchronized (this.validInvokers) {
return this.validInvokers.remove(invoker);
}
@ -508,4 +501,29 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
.map(URL::getAddress)
.collect(Collectors.joining(","));
}
private Map<ServiceType, Map<String, Integer>> getSummary() {
Map<ServiceType, Map<String, Integer>> summaryMap = new HashMap<>();
summaryMap.put(ServiceType.D_VALID, groupByServiceKey(getValidInvokers()));
summaryMap.put(ServiceType.D_DISABLE, groupByServiceKey(getDisabledInvokers()));
summaryMap.put(ServiceType.D_TO_RECONNECT, groupByServiceKey(getInvokersToReconnect()));
summaryMap.put(ServiceType.D_ALL, groupByServiceKey(getInvokers()));
return summaryMap;
}
private Map<String, Integer> groupByServiceKey(Collection<Invoker<T>> invokers) {
Map<String, Integer> serviceNumMap = new HashMap<>();
for (Invoker<T> invoker : invokers) {
if (invoker.getClass().getSimpleName().contains("Mockito")) {
return serviceNumMap;
}
}
if (invokers.size() > 0) {
serviceNumMap = invokers.stream().filter(invoker -> invoker.getInterface() != null).collect(Collectors.groupingBy(invoker -> invoker.getInterface().getName(), Collectors.reducing(0, e -> 1, Integer::sum)));
}
return serviceNumMap;
}
}

View File

@ -16,8 +16,6 @@
*/
package org.apache.dubbo.rpc.cluster.directory;
import java.util.List;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
@ -29,6 +27,8 @@ import org.apache.dubbo.rpc.cluster.RouterChain;
import org.apache.dubbo.rpc.cluster.SingleRouterChain;
import org.apache.dubbo.rpc.cluster.router.state.BitList;
import java.util.List;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_SITE_SELECTION;
/**
@ -75,6 +75,8 @@ public class StaticDirectory<T> extends AbstractDirectory<T> {
for (Invoker<T> invoker : getValidInvokers()) {
if (invoker.isAvailable()) {
return true;
} else {
addInvalidateInvoker(invoker);
}
}
return false;

View File

@ -15,7 +15,8 @@
* limitations under the License.
*/
package org.apache.dubbo.metrics.filter;
package org.apache.dubbo.rpc.cluster.filter.support;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
@ -29,12 +30,13 @@ import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ScopeModelAware;
import java.util.Optional;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
@Activate(group = CONSUMER)
@Activate(group = CONSUMER,onClass = "org.apache.dubbo.metrics.collector.DefaultMetricsCollector")
public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener, ScopeModelAware {
private DefaultMetricsCollector collector;

View File

@ -14,12 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.metrics.observation;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
package org.apache.dubbo.rpc.cluster.filter.support;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.metrics.observation.DefaultDubboClientObservationConvention;
import org.apache.dubbo.metrics.observation.DubboClientContext;
import org.apache.dubbo.metrics.observation.DubboClientObservationConvention;
import org.apache.dubbo.metrics.observation.DubboObservationDocumentation;
import org.apache.dubbo.rpc.BaseFilter;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
@ -30,6 +31,9 @@ import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ScopeModelAware;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
/**
@ -38,13 +42,17 @@ import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
@Activate(group = CONSUMER, order = -1, onClass = "io.micrometer.observation.NoopObservationRegistry")
public class ObservationSenderFilter implements ClusterFilter, BaseFilter.Listener, ScopeModelAware {
private final ObservationRegistry observationRegistry;
private ObservationRegistry observationRegistry;
private final DubboClientObservationConvention clientObservationConvention;
private DubboClientObservationConvention clientObservationConvention;
public ObservationSenderFilter(ApplicationModel applicationModel) {
observationRegistry = applicationModel.getBeanFactory().getBean(ObservationRegistry.class);
clientObservationConvention = applicationModel.getBeanFactory().getBean(DubboClientObservationConvention.class);
applicationModel.getApplicationConfigManager().getTracing().ifPresent(cfg -> {
if (Boolean.TRUE.equals(cfg.getEnabled())) {
observationRegistry = applicationModel.getBeanFactory().getBean(ObservationRegistry.class);
clientObservationConvention = applicationModel.getBeanFactory().getBean(DubboClientObservationConvention.class);
}
});
}
@Override
@ -52,15 +60,18 @@ public class ObservationSenderFilter implements ClusterFilter, BaseFilter.Listen
if (observationRegistry == null) {
return invoker.invoke(invocation);
}
DubboClientContext senderContext = new DubboClientContext(invoker, invocation);
Observation observation = DubboObservation.CLIENT.observation(this.clientObservationConvention, DefaultDubboClientObservationConvention.INSTANCE, () -> senderContext, observationRegistry);
final DubboClientContext senderContext = new DubboClientContext(invoker, invocation);
final Observation observation = DubboObservationDocumentation.CLIENT.observation(
this.clientObservationConvention,
DefaultDubboClientObservationConvention.getInstance(),
() -> senderContext, observationRegistry);
invocation.put(Observation.class, observation.start());
return observation.scoped(() -> invoker.invoke(invocation));
}
@Override
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
Observation observation = (Observation) invocation.get(Observation.class);
final Observation observation = getObservation(invocation);
if (observation == null) {
return;
}
@ -69,11 +80,15 @@ public class ObservationSenderFilter implements ClusterFilter, BaseFilter.Listen
@Override
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
Observation observation = (Observation) invocation.get(Observation.class);
final Observation observation = getObservation(invocation);
if (observation == null) {
return;
}
observation.error(t);
observation.stop();
}
private Observation getObservation(Invocation invocation) {
return (Observation) invocation.get(Observation.class);
}
}

View File

@ -22,6 +22,7 @@ import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.cluster.ClusterInvoker;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
@ -79,10 +80,23 @@ public class RandomLoadBalance extends AbstractLoadBalance {
// 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);
// Return an invoker based on the random value.
for (int i = 0; i < length; i++) {
if (offset < weights[i]) {
return invokers.get(i);
if (length <= 4) {
for (int i = 0; i < length; i++) {
if (offset < weights[i]) {
return invokers.get(i);
}
}
} else {
int i = Arrays.binarySearch(weights, offset);
if (i < 0) {
i = -i - 1;
} else {
while (weights[i+1] == offset) {
i++;
}
i++;
}
return invokers.get(i);
}
}
// If all invokers have the same weight value or totalWeight=0, return evenly.

View File

@ -18,6 +18,7 @@ package org.apache.dubbo.rpc.cluster.router.condition.config.model;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
@ -40,7 +41,7 @@ import java.util.Map;
public class ConditionRuleParser {
public static ConditionRouterRule parse(String rawRule) {
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
Map<String, Object> map = yaml.load(rawRule);
ConditionRouterRule rule = ConditionRouterRule.parseFromMap(map);
rule.setRawRule(rawRule);

View File

@ -26,6 +26,8 @@ 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.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;
@ -66,9 +68,9 @@ public class MeshAppRuleListener implements ConfigurationListener {
try {
Map<String, List<Map<String, Object>>> groupMap = new HashMap<>();
Representer representer = new Representer();
Representer representer = new Representer(new DumperOptions());
representer.getPropertyUtils().setSkipMissingProperties(true);
Yaml yaml = new Yaml(new SafeConstructor(), representer);
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()), representer);
Iterable<Object> yamlIterator = yaml.loadAll(configInfo);
for (Object obj : yamlIterator) {

View File

@ -18,6 +18,7 @@ package org.apache.dubbo.rpc.cluster.router.script.config.model;
import org.apache.dubbo.rpc.cluster.router.AbstractRouterRule;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
@ -30,7 +31,7 @@ public class ScriptRule extends AbstractRouterRule {
private String script;
public static ScriptRule parse(String rawRule) {
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
Map<String, Object> map = yaml.load(rawRule);
ScriptRule rule = new ScriptRule();

View File

@ -18,6 +18,7 @@ package org.apache.dubbo.rpc.cluster.router.tag.model;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
@ -29,7 +30,7 @@ import java.util.Map;
public class TagRuleParser {
public static TagRouterRule parse(String rawRule) {
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
Map<String, Object> map = yaml.load(rawRule);
TagRouterRule rule = TagRouterRule.parseFromMap(map);
rule.setRawRule(rawRule);

View File

@ -39,7 +39,6 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
import static org.apache.dubbo.rpc.Constants.LOCAL_KEY;
import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
import static org.apache.dubbo.rpc.Constants.SCOPE_KEY;
import static org.apache.dubbo.rpc.Constants.SCOPE_REMOTE;
@ -47,24 +46,23 @@ import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
import static org.apache.dubbo.rpc.cluster.Constants.PEER_KEY;
/**
* A ClusterInvoker that selects between local and remote invokers at runtime.
* ScopeClusterInvoker is a cluster invoker which handles the invocation logic of a single service in a specific scope.
* <p>
* It selects between local and remote invoker at runtime.
*
* @param <T> the type of service interface
*/
public class ScopeClusterInvoker<T> implements ClusterInvoker<T>, ExporterChangeListener {
private final Object createLock = new Object();
private Protocol protocolSPI;
private final Directory<T> directory;
private final Invoker<T> invoker;
private final AtomicBoolean isExported;
private volatile Invoker<T> injvmInvoker;
private volatile InjvmExporterListener injvmExporterListener;
private boolean peerFlag;
private boolean injvmFlag;
private final Object createLock = new Object();
public ScopeClusterInvoker(Directory<T> directory, Invoker<T> invoker) {
this.directory = directory;
this.invoker = invoker;
@ -72,30 +70,6 @@ public class ScopeClusterInvoker<T> implements ClusterInvoker<T>, ExporterChange
init();
}
private void init() {
Boolean peer = (Boolean) getUrl().getAttribute(PEER_KEY);
String isInjvm = getUrl().getParameter(LOCAL_PROTOCOL);
if (peer != null && peer) {
peerFlag = true;
return;
}
if (injvmInvoker == null && LOCAL_PROTOCOL.equalsIgnoreCase(getRegistryUrl().getProtocol())) {
injvmInvoker = invoker;
isExported.compareAndSet(false, true);
injvmFlag = true;
return;
}
if (Boolean.TRUE.toString().equalsIgnoreCase(isInjvm) || LOCAL_KEY.equalsIgnoreCase(getUrl().getParameter(SCOPE_KEY))) {
injvmFlag = true;
} else if (isInjvm == null) {
injvmFlag = isNotRemoteOrGeneric();
}
protocolSPI = getUrl().getApplicationModel().getExtensionLoader(Protocol.class).getAdaptiveExtension();
injvmExporterListener = getUrl().getOrDefaultFrameworkModel().getBeanFactory().getBean(InjvmExporterListener.class);
injvmExporterListener.addExporterChangeListener(this, getUrl().getServiceKey());
}
@Override
public URL getUrl() {
return directory.getConsumerUrl();
@ -135,62 +109,28 @@ public class ScopeClusterInvoker<T> implements ClusterInvoker<T>, ExporterChange
return directory.getInterface();
}
/**
* Checks if the current ScopeClusterInvoker is exported to the local JVM and invokes the corresponding Invoker.
* If it's not exported locally, then it delegates the invocation to the original Invoker.
*
* @param invocation the invocation to be performed
* @return the result of the invocation
* @throws RpcException if there was an error during the invocation
*/
@Override
public Result invoke(Invocation invocation) throws RpcException {
if (peerFlag) {
// If it's a point-to-point direct connection, invoke the original Invoker
return invoker.invoke(invocation);
}
if (isInjvmExported()) {
// If it's exported to the local JVM, invoke the corresponding Invoker
return injvmInvoker.invoke(invocation);
}
// Otherwise, delegate the invocation to the original Invoker
return invoker.invoke(invocation);
}
private boolean isNotRemoteOrGeneric() {
return !SCOPE_REMOTE.equalsIgnoreCase(getUrl().getParameter(SCOPE_KEY)) &&
!getUrl().getParameter(GENERIC_KEY, false);
}
private boolean isInjvmExported() {
Boolean localInvoke = RpcContext.getServiceContext().getLocalInvoke();
boolean isExportedValue = isExported.get();
boolean local = (localInvoke != null && localInvoke);
// Determine whether this call is local
if (isExportedValue && local) {
return true;
}
// Determine whether this call is remote
if (localInvoke != null && !localInvoke) {
return false;
}
// When calling locally, determine whether it does not meet the requirements
if (!isExportedValue && (SCOPE_LOCAL.equalsIgnoreCase(getUrl().getParameter(SCOPE_KEY)) ||
Boolean.TRUE.toString().equalsIgnoreCase(getUrl().getParameter(LOCAL_PROTOCOL))|| local)) {
throw new RpcException("Local service has not been exposed yet!");
}
return isExportedValue && injvmFlag;
}
private void createInjvmInvoker() {
if (injvmInvoker == null) {
synchronized (createLock) {
if (injvmInvoker == null) {
URL url = new ServiceConfigURL(LOCAL_PROTOCOL, NetUtils.getLocalHost(), getUrl().getPort(), getInterface().getName(), getUrl().getParameters());
url = url.setScopeModel(getUrl().getScopeModel());
url = url.setServiceModel(getUrl().getServiceModel());
Invoker<?> invoker = protocolSPI.refer(getInterface(), url);
List<Invoker<?>> invokers = new ArrayList<>();
invokers.add(invoker);
injvmInvoker = Cluster.getCluster(url.getScopeModel(), Cluster.DEFAULT, false).join(new StaticDirectory(url, invokers), true);
}
}
}
}
@Override
public void onExporterChangeExport(Exporter<?> exporter) {
if (isExported.get()) {
@ -212,6 +152,103 @@ public class ScopeClusterInvoker<T> implements ClusterInvoker<T>, ExporterChange
}
}
public Invoker<?> getInvoker() {
return invoker;
}
/**
* Initializes the ScopeClusterInvoker instance.
*/
private void init() {
Boolean peer = (Boolean) getUrl().getAttribute(PEER_KEY);
String isInjvm = getUrl().getParameter(LOCAL_PROTOCOL);
// When the point-to-point direct connection is directly connected,
// the initialization is directly ended
if (peer != null && peer) {
peerFlag = true;
return;
}
// Check if the service has been exported through Injvm protocol
if (injvmInvoker == null && LOCAL_PROTOCOL.equalsIgnoreCase(getRegistryUrl().getProtocol())) {
injvmInvoker = invoker;
isExported.compareAndSet(false, true);
injvmFlag = true;
return;
}
// Check if the service has been exported through Injvm protocol or the SCOPE_LOCAL parameter is set
if (Boolean.TRUE.toString().equalsIgnoreCase(isInjvm) || SCOPE_LOCAL.equalsIgnoreCase(getUrl().getParameter(SCOPE_KEY))) {
injvmFlag = true;
} else if (isInjvm == null) {
injvmFlag = isNotRemoteOrGeneric();
}
protocolSPI = getUrl().getApplicationModel().getExtensionLoader(Protocol.class).getAdaptiveExtension();
injvmExporterListener = getUrl().getOrDefaultFrameworkModel().getBeanFactory().getBean(InjvmExporterListener.class);
injvmExporterListener.addExporterChangeListener(this, getUrl().getServiceKey());
}
/**
* Check if the service is a generalized call or the SCOPE_REMOTE parameter is set
*
* @return boolean
*/
private boolean isNotRemoteOrGeneric() {
return !SCOPE_REMOTE.equalsIgnoreCase(getUrl().getParameter(SCOPE_KEY)) &&
!getUrl().getParameter(GENERIC_KEY, false);
}
/**
* Checks whether the current ScopeClusterInvoker is exported to the local JVM and returns a boolean value.
*
* @return true if the ScopeClusterInvoker is exported to the local JVM, false otherwise
* @throws RpcException if there was an error during the invocation
*/
private boolean isInjvmExported() {
Boolean localInvoke = RpcContext.getServiceContext().getLocalInvoke();
boolean isExportedValue = isExported.get();
boolean local = (localInvoke != null && localInvoke);
// Determine whether this call is local
if (isExportedValue && local) {
return true;
}
// Determine whether this call is remote
if (localInvoke != null && !localInvoke) {
return false;
}
// When calling locally, determine whether it does not meet the requirements
if (!isExportedValue && (SCOPE_LOCAL.equalsIgnoreCase(getUrl().getParameter(SCOPE_KEY)) ||
Boolean.TRUE.toString().equalsIgnoreCase(getUrl().getParameter(LOCAL_PROTOCOL)) || local)) {
// If it's supposed to be exported to the local JVM ,but it's not, throw an exception
throw new RpcException("Local service for " + getUrl().getServiceInterface() + " has not been exposed yet!");
}
return isExportedValue && injvmFlag;
}
/**
* Creates a new Invoker for the current ScopeClusterInvoker and exports it to the local JVM.
*/
private void createInjvmInvoker() {
if (injvmInvoker == null) {
synchronized (createLock) {
if (injvmInvoker == null) {
URL url = new ServiceConfigURL(LOCAL_PROTOCOL, NetUtils.getLocalHost(), getUrl().getPort(), getInterface().getName(), getUrl().getParameters());
url = url.setScopeModel(getUrl().getScopeModel());
url = url.setServiceModel(getUrl().getServiceModel());
Invoker<?> invoker = protocolSPI.refer(getInterface(), url);
List<Invoker<?>> invokers = new ArrayList<>();
invokers.add(invoker);
injvmInvoker = Cluster.getCluster(url.getScopeModel(), Cluster.DEFAULT, false).join(new StaticDirectory(url, invokers), true);
}
}
}
}
/**
* Destroy the existing InjvmInvoker.
*/
private void destroyInjvmInvoker() {
if (injvmInvoker != null) {
injvmInvoker.destroy();
@ -219,7 +256,4 @@ public class ScopeClusterInvoker<T> implements ClusterInvoker<T>, ExporterChange
}
}
public Invoker<?> getInvoker() {
return invoker;
}
}

View File

@ -8,4 +8,4 @@ forking=org.apache.dubbo.rpc.cluster.support.ForkingCluster
available=org.apache.dubbo.rpc.cluster.support.AvailableCluster
mergeable=org.apache.dubbo.rpc.cluster.support.MergeableCluster
broadcast=org.apache.dubbo.rpc.cluster.support.BroadcastCluster
zone-aware=org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster
zone-aware=org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster

View File

@ -1,3 +1,5 @@
consumercontext=org.apache.dubbo.rpc.cluster.filter.support.ConsumerContextFilter
consumer-classloader=org.apache.dubbo.rpc.cluster.filter.support.ConsumerClassLoaderFilter
router-snapshot=org.apache.dubbo.rpc.cluster.router.RouterSnapshotFilter
observationsender=org.apache.dubbo.rpc.cluster.filter.support.ObservationSenderFilter
metricsClusterFilter=org.apache.dubbo.rpc.cluster.filter.support.MetricsClusterFilter

View File

@ -22,6 +22,7 @@ import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
@ -50,7 +51,7 @@ class ConfigParserTest {
@Test
void snakeYamlBasicTest() throws IOException {
try (InputStream yamlStream = this.getClass().getResourceAsStream("/ServiceNoApp.yml")) {
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
Map<String, Object> map = yaml.load(yamlStream);
ConfiguratorConfig config = ConfiguratorConfig.parseFromMap(map);
Assertions.assertNotNull(config);

View File

@ -19,15 +19,15 @@ package org.apache.dubbo.rpc.cluster.directory;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.Holder;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.router.MockInvoker;
import org.apache.dubbo.rpc.cluster.router.condition.ConditionStateRouterFactory;
import org.apache.dubbo.rpc.cluster.router.state.BitList;
import org.apache.dubbo.rpc.cluster.router.state.StateRouter;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@ -52,9 +52,9 @@ class StaticDirectoryTest {
List<StateRouter> routers = new ArrayList<StateRouter>();
routers.add(router);
List<Invoker<String>> originInvokers = new ArrayList<Invoker<String>>();
Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService"));
Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService"), true);
Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"), true);
Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"), true);
originInvokers.add(invoker1);
originInvokers.add(invoker2);
originInvokers.add(invoker3);
@ -62,10 +62,10 @@ class StaticDirectoryTest {
List<Invoker<String>> filteredInvokers = router.route(invokers.clone(), URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation(), false, new Holder<>());
ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class);
ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);
StaticDirectory<String> staticDirectory = new StaticDirectory<>(filteredInvokers);
boolean isAvailable = staticDirectory.isAvailable();
Assertions.assertTrue(!isAvailable);
Assertions.assertTrue(isAvailable);
List<Invoker<String>> newInvokers = staticDirectory.list(new MockDirInvocation());
Assertions.assertTrue(newInvokers.size() > 0);
staticDirectory.destroy();

View File

@ -0,0 +1,83 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.rpc.cluster.filter;
import io.micrometer.tracing.test.SampleTestRunner;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.TracingConfig;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.BaseFilter;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.junit.jupiter.api.AfterEach;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
abstract class AbstractObservationFilterTest extends SampleTestRunner {
ApplicationModel applicationModel;
RpcInvocation invocation;
BaseFilter filter;
Invoker<?> invoker = mock(Invoker.class);
static final String INTERFACE_NAME = "org.apache.dubbo.MockInterface";
static final String METHOD_NAME = "mockMethod";
static final String GROUP = "mockGroup";
static final String VERSION = "1.0.0";
@AfterEach
public void teardown() {
if (applicationModel != null) {
applicationModel.destroy();
}
}
abstract BaseFilter createFilter(ApplicationModel applicationModel);
void setupConfig() {
ApplicationConfig config = new ApplicationConfig();
config.setName("MockObservations");
applicationModel = ApplicationModel.defaultModel();
applicationModel.getApplicationConfigManager().setApplication(config);
invocation = new RpcInvocation(new MockInvocation());
invocation.addInvokedInvoker(invoker);
applicationModel.getBeanFactory().registerBean(getObservationRegistry());
TracingConfig tracingConfig = new TracingConfig();
tracingConfig.setEnabled(true);
applicationModel.getApplicationConfigManager().setTracing(tracingConfig);
filter = createFilter(applicationModel);
given(invoker.invoke(invocation)).willReturn(new AppResponse("success"));
initParam();
}
private void initParam() {
invocation.setTargetServiceUniqueName(GROUP + "/" + INTERFACE_NAME + ":" + VERSION);
invocation.setMethodName(METHOD_NAME);
invocation.setParameterTypes(new Class[] {String.class});
}
}

View File

@ -49,7 +49,6 @@ class DefaultFilterChainBuilderTest {
};
Invoker<?> invokerAfterBuild = defaultFilterChainBuilder.buildInvokerChain(invokerWithoutFilter, REFERENCE_FILTER_KEY, CONSUMER);
Assertions.assertTrue(invokerAfterBuild instanceof AbstractInvoker);
// verify that if LogFilter is configured, LogFilter should exist in the filter chain
URL urlWithFilter = URL.valueOf("injvm://127.0.0.1/DemoService")
@ -64,8 +63,6 @@ class DefaultFilterChainBuilderTest {
};
invokerAfterBuild = defaultFilterChainBuilder.buildInvokerChain(invokerWithFilter, REFERENCE_FILTER_KEY, CONSUMER);
Assertions.assertTrue(invokerAfterBuild instanceof FilterChainBuilder.CallbackRegistrationInvoker);
Assertions.assertEquals(1, ((FilterChainBuilder.CallbackRegistrationInvoker<?, ?>) invokerAfterBuild).filters.size());
}
@Test
@ -84,7 +81,7 @@ class DefaultFilterChainBuilderTest {
};
Invoker<?> invokerAfterBuild = defaultFilterChainBuilder.buildInvokerChain(invokerWithoutFilter, REFERENCE_FILTER_KEY, CONSUMER);
Assertions.assertTrue(invokerAfterBuild instanceof AbstractInvoker);
// Assertions.assertTrue(invokerAfterBuild instanceof AbstractInvoker);
// verify that if LogFilter is configured, LogFilter should exist in the filter chain
URL urlWithFilter = URL.valueOf("dubbo://127.0.0.1:20880/DemoService")

View File

@ -0,0 +1,183 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.rpc.cluster.filter;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.filter.MetricsFilter;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.filter.support.MetricsClusterFilter;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.stream.Collectors;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
class MetricsClusterFilterTest {
private ApplicationModel applicationModel;
private MetricsFilter filter;
private MetricsClusterFilter metricsClusterFilter;
private DefaultMetricsCollector collector;
private RpcInvocation invocation;
private final Invoker<?> invoker = mock(Invoker.class);
private static final String INTERFACE_NAME = "org.apache.dubbo.MockInterface";
private static final String METHOD_NAME = "mockMethod";
private static final String GROUP = "mockGroup";
private static final String VERSION = "1.0.0";
private String side;
private AtomicBoolean initApplication = new AtomicBoolean(false);
@BeforeEach
public void setup() {
ApplicationConfig config = new ApplicationConfig();
config.setName("MockMetrics");
//RpcContext.getContext().setAttachment("MockMetrics","MockMetrics");
applicationModel = ApplicationModel.defaultModel();
applicationModel.getApplicationConfigManager().setApplication(config);
invocation = new RpcInvocation();
filter = new MetricsFilter();
collector = applicationModel.getBeanFactory().getOrRegisterBean(DefaultMetricsCollector.class);
if(!initApplication.get()) {
collector.collectApplication(applicationModel);
initApplication.set(true);
}
filter.setApplicationModel(applicationModel);
side = CommonConstants.CONSUMER;
invocation.setInvoker(new TestMetricsInvoker(side));
RpcContext.getServiceContext().setUrl(URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&side=" + side));
metricsClusterFilter = new MetricsClusterFilter();
metricsClusterFilter.setApplicationModel(applicationModel);
}
@AfterEach
public void teardown() {
applicationModel.destroy();
}
@Test
public void testNoProvider(){
testClusterFilterError(RpcException.FORBIDDEN_EXCEPTION,
MetricsKey.METRIC_REQUESTS_SERVICE_UNAVAILABLE_FAILED.getNameByType(CommonConstants.CONSUMER));
}
private void testClusterFilterError(int errorCode,String name){
collector.setCollectEnabled(true);
given(invoker.invoke(invocation)).willThrow(new RpcException(errorCode));
initParam();
Long count = 1L;
for (int i = 0; i < count; i++) {
try {
metricsClusterFilter.invoke(invoker, invocation);
} catch (Exception e) {
Assertions.assertTrue(e instanceof RpcException);
metricsClusterFilter.onError(e, invoker, invocation);
}
}
Map<String, MetricSample> metricsMap = getMetricsMap();
Assertions.assertTrue(metricsMap.containsKey(name));
MetricSample sample = metricsMap.get(name);
Assertions.assertSame(((CounterMetricSample) sample).getValue().longValue(), count);
teardown();
}
private void initParam() {
invocation.setTargetServiceUniqueName(GROUP + "/" + INTERFACE_NAME + ":" + VERSION);
invocation.setMethodName(METHOD_NAME);
invocation.setParameterTypes(new Class[]{String.class});
}
private Map<String, MetricSample> getMetricsMap() {
List<MetricSample> samples = collector.collect();
List<MetricSample> samples1 = new ArrayList<>();
for (MetricSample sample : samples) {
if (sample.getName().contains("dubbo.thread.pool")) {
continue;
}
samples1.add(sample);
}
return samples1.stream().collect(Collectors.toMap(MetricSample::getName, Function.identity()));
}
public class TestMetricsInvoker implements Invoker {
private String side;
public TestMetricsInvoker(String side) {
this.side = side;
}
@Override
public Class getInterface() {
return null;
}
@Override
public Result invoke(Invocation invocation) throws RpcException {
return null;
}
@Override
public URL getUrl() {
return URL.valueOf("test://test:11/test?accesslog=true&group=dubbo&version=1.1&side="+side);
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public void destroy() {
}
}
}

View File

@ -0,0 +1,168 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.rpc.cluster.filter;
import org.apache.dubbo.rpc.AttachmentsAdapter;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.model.ServiceModel;
import java.util.HashMap;
import java.util.Map;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
/**
* MockInvocation.java
*/
public class MockInvocation extends RpcInvocation {
private Map<String, Object> attachments;
public MockInvocation() {
attachments = new HashMap<>();
attachments.put(PATH_KEY, "dubbo");
attachments.put(GROUP_KEY, "dubbo");
attachments.put(VERSION_KEY, "1.0.0");
attachments.put(DUBBO_VERSION_KEY, "1.0.0");
attachments.put(TOKEN_KEY, "sfag");
attachments.put(TIMEOUT_KEY, "1000");
}
@Override
public String getTargetServiceUniqueName() {
return null;
}
@Override
public String getProtocolServiceKey() {
return null;
}
public String getMethodName() {
return "echo";
}
@Override
public String getServiceName() {
return "DemoService";
}
public Class<?>[] getParameterTypes() {
return new Class[] {String.class};
}
public Object[] getArguments() {
return new Object[] {"aa"};
}
public Map<String, String> getAttachments() {
return new AttachmentsAdapter.ObjectToStringMap(attachments);
}
@Override
public Map<String, Object> getObjectAttachments() {
return attachments;
}
@Override
public void setAttachment(String key, String value) {
setObjectAttachment(key, value);
}
@Override
public void setAttachment(String key, Object value) {
setObjectAttachment(key, value);
}
@Override
public void setObjectAttachment(String key, Object value) {
attachments.put(key, value);
}
@Override
public void setAttachmentIfAbsent(String key, String value) {
setObjectAttachmentIfAbsent(key, value);
}
@Override
public void setAttachmentIfAbsent(String key, Object value) {
setObjectAttachmentIfAbsent(key, value);
}
@Override
public void setObjectAttachmentIfAbsent(String key, Object value) {
attachments.put(key, value);
}
public Invoker<?> getInvoker() {
return null;
}
@Override
public void setServiceModel(ServiceModel serviceModel) {
}
@Override
public ServiceModel getServiceModel() {
return null;
}
@Override
public Object put(Object key, Object value) {
return null;
}
@Override
public Object get(Object key) {
return null;
}
@Override
public Map<Object, Object> getAttributes() {
return null;
}
public String getAttachment(String key) {
return (String) getObjectAttachments().get(key);
}
@Override
public Object getObjectAttachment(String key) {
return attachments.get(key);
}
public String getAttachment(String key, String defaultValue) {
return (String) getObjectAttachments().get(key);
}
@Override
public Object getObjectAttachment(String key, Object defaultValue) {
Object result = attachments.get(key);
if (result == null) {
return defaultValue;
}
return result;
}
}

View File

@ -15,21 +15,22 @@
* limitations under the License.
*/
package org.apache.dubbo.metrics.observation;
package org.apache.dubbo.rpc.cluster.filter;
import io.micrometer.common.KeyValues;
import io.micrometer.core.tck.MeterRegistryAssert;
import io.micrometer.tracing.test.SampleTestRunner;
import io.micrometer.tracing.test.simple.SpansAssert;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
import org.apache.dubbo.rpc.cluster.filter.support.ObservationSenderFilter;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.assertj.core.api.BDDAssertions;
class ObservationSenderFilterTest extends AbstractObservationFilterTest {
@Override
public SampleTestRunnerConsumer yourCode() {
public SampleTestRunner.SampleTestRunnerConsumer yourCode() {
return (buildingBlocks, meterRegistry) -> {
setupConfig();
setupAttachments();

View File

@ -224,7 +224,7 @@ class LoadBalanceBaseTest {
@Override
public String toString() {
return JsonUtils.getJson().toJson(this);
return JsonUtils.toJson(this);
}
}

View File

@ -18,7 +18,7 @@ package org.apache.dubbo.rpc.cluster.router.file;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
@ -61,7 +61,7 @@ class FileRouterEngineTest {
@BeforeAll
public static void setUpBeforeClass() throws Exception {
ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class);
ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);
System.setProperty(ENABLE_CONNECTIVITY_VALIDATION, "false");
}

View File

@ -27,6 +27,7 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
@ -132,7 +133,7 @@ class MeshAppRuleListenerTest {
List<Map<String, Object>> rulesReceived = ruleCaptor.getValue();
assertEquals(2, rulesReceived.size());
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
Assertions.assertTrue(rulesReceived.contains(yaml.load(rule1)));
Assertions.assertTrue(rulesReceived.contains(yaml.load(rule2)));
@ -163,7 +164,7 @@ class MeshAppRuleListenerTest {
List<Map<String, Object>> rulesReceived = ruleCaptor.getValue();
assertEquals(2, rulesReceived.size());
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
Assertions.assertTrue(rulesReceived.contains(yaml.load(rule1)));
Assertions.assertTrue(rulesReceived.contains(yaml.load(rule2)));
@ -219,7 +220,7 @@ class MeshAppRuleListenerTest {
List<Map<String, Object>> rulesReceived = ruleCaptor.getValue();
assertEquals(2, rulesReceived.size());
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
Assertions.assertTrue(rulesReceived.contains(yaml.load(rule1)));
Assertions.assertTrue(rulesReceived.contains(yaml.load(rule2)));
@ -258,7 +259,7 @@ class MeshAppRuleListenerTest {
List<Map<String, Object>> rulesReceived = ruleCaptor.getValue();
assertEquals(1, rulesReceived.size());
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
Assertions.assertTrue(rulesReceived.contains(yaml.load(rule2)));
meshAppRuleListener.receiveConfigInfo(rule1 + "---\n" + rule4);
@ -282,7 +283,7 @@ class MeshAppRuleListenerTest {
@Override
public void onRuleChange(String appName, List<Map<String, Object>> rules) {
Assertions.assertEquals("demo-route", appName);
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
Assertions.assertTrue(rules.contains(yaml.load(rule5)));
Assertions.assertTrue(rules.contains(yaml.load(rule6)));
count.incrementAndGet();
@ -303,7 +304,7 @@ class MeshAppRuleListenerTest {
@Override
public void onRuleChange(String appName, List<Map<String, Object>> rules) {
Assertions.assertEquals("demo-route", appName);
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
Assertions.assertTrue(rules.contains(yaml.load(rule7)));
Assertions.assertTrue(rules.contains(yaml.load(rule8)));
count.incrementAndGet();
@ -353,7 +354,7 @@ class MeshAppRuleListenerTest {
List<Map<String, Object>> rulesReceived = ruleCaptor.getValue();
assertEquals(2, rulesReceived.size());
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
Assertions.assertTrue(rulesReceived.contains(yaml.load(rule1)));
Assertions.assertTrue(rulesReceived.contains(yaml.load(rule2)));

View File

@ -27,6 +27,7 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
@ -166,7 +167,7 @@ class MeshRuleManagerTest {
@Override
public void onRuleChange(String appName, List<Map<String, Object>> rules) {
assertEquals("dubbo-demo", appName);
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
assertTrue(rules.contains(yaml.load(rule1)));
assertTrue(rules.contains(yaml.load(rule2)));

View File

@ -33,6 +33,7 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
@ -239,7 +240,7 @@ class MeshRuleRouterTest {
void testRuleChange() {
StandardMeshRuleRouter<Object> meshRuleRouter = new StandardMeshRuleRouter<>(url);
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
List<Map<String, Object>> rules = new LinkedList<>();
rules.add(yaml.load(rule1));
@ -275,7 +276,7 @@ class MeshRuleRouterTest {
void testRoute2() {
StandardMeshRuleRouter<Object> meshRuleRouter = new StandardMeshRuleRouter<>(url);
Yaml yaml = new Yaml(new SafeConstructor());
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
List<Map<String, Object>> rules = new LinkedList<>();
rules.add(yaml.load(rule1));
rules.add(yaml.load(rule2));

View File

@ -20,7 +20,7 @@ import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
@ -107,7 +107,7 @@ class AbstractClusterInvokerTest {
@SuppressWarnings({"unchecked"})
@BeforeEach
public void setUp() throws Exception {
ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class);
ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);
Map<String, Object> attributes = new HashMap<>();
attributes.put("application", "abstractClusterInvokerTest");
url = url.putAttribute(REFER_KEY, attributes);

View File

@ -19,7 +19,7 @@ package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
@ -72,7 +72,7 @@ class ConnectivityValidationTest {
@BeforeEach
public void setup() {
ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class);
ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);
invoker1 = Mockito.mock(Invoker.class);
invoker2 = Mockito.mock(Invoker.class);
invoker3 = Mockito.mock(Invoker.class);

View File

@ -17,7 +17,7 @@
package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.Invocation;
@ -67,7 +67,7 @@ class FailoverClusterInvokerTest {
@BeforeEach
public void setUp() throws Exception {
ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class);
ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);
dic = mock(Directory.class);
given(dic.getUrl()).willReturn(url);

View File

@ -18,7 +18,7 @@ package org.apache.dubbo.rpc.cluster.support.wrapper;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
@ -51,7 +51,7 @@ class MockClusterInvokerTest {
@BeforeEach
public void beforeMethod() {
ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class);
ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);
invokers.clear();
}

View File

@ -18,7 +18,7 @@ package org.apache.dubbo.rpc.cluster.support.wrapper;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.ProxyFactory;
@ -48,7 +48,7 @@ class MockProviderRpcExceptionTest {
@BeforeEach
public void beforeMethod() {
ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class);
ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);
invokers.clear();
}

View File

@ -20,13 +20,14 @@ package org.apache.dubbo.rpc.cluster.support.wrapper;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.metrics.event.GlobalMetricsEventMulticaster;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.rpc.Exporter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.ProxyFactory;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.LoadBalance;
@ -41,7 +42,9 @@ import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.apache.dubbo.common.constants.CommonConstants.EXPORTER_LISTENER_KEY;
@ -50,6 +53,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
import static org.apache.dubbo.rpc.cluster.Constants.PEER_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.SCOPE_KEY;
@ -64,7 +68,7 @@ class ScopeClusterInvokerTest {
@BeforeEach
void beforeMonth() {
ApplicationModel.defaultModel().getBeanFactory().registerBean(GlobalMetricsEventMulticaster.class);
ApplicationModel.defaultModel().getBeanFactory().registerBean(MetricsDispatcher.class);
}
@AfterEach
@ -75,6 +79,9 @@ class ScopeClusterInvokerTest {
exporters.clear();
for (Invoker<DemoService> invoker : invokers) {
invoker.destroy();
if (invoker instanceof ScopeClusterInvoker) {
Assertions.assertTrue(((ScopeClusterInvoker) invoker).isDestroyed());
}
}
invokers.clear();
}
@ -104,7 +111,7 @@ class ScopeClusterInvokerTest {
url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());
URL injvmUrl = URL.valueOf("injvm://127.0.0.1/TestService")
.addParameter(INTERFACE_KEY, DemoService.class.getName()).setScopeModel(ApplicationModel.defaultModel().getDefaultModule()) ;
.addParameter(INTERFACE_KEY, DemoService.class.getName()).setScopeModel(ApplicationModel.defaultModel().getDefaultModule());
Exporter<?> exporter = protocol.export(proxy.getInvoker(new DemoServiceImpl(), DemoService.class, injvmUrl));
exporters.add(exporter);
@ -152,12 +159,6 @@ class ScopeClusterInvokerTest {
url = url.addParameter(SCOPE_KEY, SCOPE_LOCAL);
url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());
URL injvmUrl = URL.valueOf("injvm://127.0.0.1/TestService")
.addParameter(INTERFACE_KEY, DemoService.class.getName());
injvmUrl = injvmUrl.addParameter(EXPORTER_LISTENER_KEY, LOCAL_PROTOCOL).setScopeModel(ApplicationModel.defaultModel().getDefaultModule());
Exporter<?> exporter = protocol.export(proxy.getInvoker(new DemoServiceImpl(), DemoService.class, injvmUrl));
exporters.add(exporter);
Invoker<DemoService> cluster = getClusterInvoker(url);
invokers.add(cluster);
@ -165,8 +166,22 @@ class ScopeClusterInvokerTest {
invocation.setMethodName("doSomething4");
invocation.setParameterTypes(new Class[]{});
Assertions.assertTrue(cluster.isAvailable(), "");
Result ret = cluster.invoke(invocation);
Assertions.assertEquals("doSomething4", ret.getValue());
RpcInvocation finalInvocation = invocation;
Assertions.assertThrows(RpcException.class, () -> cluster.invoke(finalInvocation));
URL injvmUrl = URL.valueOf("injvm://127.0.0.1/TestService")
.addParameter(INTERFACE_KEY, DemoService.class.getName());
injvmUrl = injvmUrl.addParameter(EXPORTER_LISTENER_KEY, LOCAL_PROTOCOL).setScopeModel(ApplicationModel.defaultModel().getDefaultModule());
Exporter<?> exporter = protocol.export(proxy.getInvoker(new DemoServiceImpl(), DemoService.class, injvmUrl));
exporters.add(exporter);
invocation = new RpcInvocation();
invocation.setMethodName("doSomething4");
invocation.setParameterTypes(new Class[]{});
Assertions.assertTrue(cluster.isAvailable(), "");
Result ret2 = cluster.invoke(invocation);
Assertions.assertEquals("doSomething4", ret2.getValue());
}
@Test
@ -184,13 +199,12 @@ class ScopeClusterInvokerTest {
Invoker<DemoService> cluster = getClusterInvoker(url);
invokers.add(cluster);
//Configured with mock
RpcInvocation invocation = new RpcInvocation();
invocation.setMethodName("doSomething4");
invocation.setMethodName("doSomething5");
invocation.setParameterTypes(new Class[]{});
Assertions.assertTrue(cluster.isAvailable(), "");
Result ret = cluster.invoke(invocation);
Assertions.assertEquals("doSomething4", ret.getValue());
Assertions.assertEquals("doSomething5", ret.getValue());
}
@Test
@ -221,6 +235,91 @@ class ScopeClusterInvokerTest {
Assertions.assertFalse(((AtomicBoolean) isExported.get(cluster)).get());
}
@Test
void testPeerInvoke() {
URL url = URL.valueOf("remote://1.2.3.4/" + DemoService.class.getName());
url = url.addParameter(REFER_KEY,
URL.encode(PATH_KEY + "=" + DemoService.class.getName()));
Map<String, Object> peer = new HashMap<>();
peer.put(PEER_KEY, true);
url = url.addAttributes(peer);
url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());
Invoker<DemoService> cluster = getClusterInvoker(url);
invokers.add(cluster);
//Configured with mock
RpcInvocation invocation = new RpcInvocation();
invocation.setMethodName("doSomething6");
invocation.setParameterTypes(new Class[]{});
Result ret = cluster.invoke(invocation);
Assertions.assertEquals("doSomething6", ret.getValue());
}
@Test
void testInjvmUrlInvoke() {
URL url = URL.valueOf("injvm://1.2.3.4/" + DemoService.class.getName());
url = url.addParameter(REFER_KEY,
URL.encode(PATH_KEY + "=" + DemoService.class.getName()));
url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());
Invoker<DemoService> cluster = getClusterInvoker(url);
invokers.add(cluster);
//Configured with mock
RpcInvocation invocation = new RpcInvocation();
invocation.setMethodName("doSomething7");
invocation.setParameterTypes(new Class[]{});
Result ret = cluster.invoke(invocation);
Assertions.assertEquals("doSomething7", ret.getValue());
}
@Test
void testDynamicInvoke() {
URL url = URL.valueOf("remote://1.2.3.4/" + DemoService.class.getName());
url = url.addParameter(REFER_KEY,
URL.encode(PATH_KEY + "=" + DemoService.class.getName()));
url = url.setScopeModel(ApplicationModel.defaultModel().getDefaultModule());
Invoker<DemoService> cluster = getClusterInvoker(url);
invokers.add(cluster);
RpcInvocation invocation = new RpcInvocation();
invocation.setMethodName("doSomething8");
invocation.setParameterTypes(new Class[]{});
Result ret1 = cluster.invoke(invocation);
Assertions.assertEquals("doSomething8", ret1.getValue());
RpcContext.getServiceContext().setLocalInvoke(true);
invocation = new RpcInvocation();
invocation.setMethodName("doSomething8");
invocation.setParameterTypes(new Class[]{});
RpcInvocation finalInvocation = invocation;
Assertions.assertThrows(RpcException.class, () -> cluster.invoke(finalInvocation));
URL injvmUrl = URL.valueOf("injvm://127.0.0.1/TestService")
.addParameter(INTERFACE_KEY, DemoService.class.getName()).setScopeModel(ApplicationModel.defaultModel().getDefaultModule());
Exporter<?> exporter = protocol.export(proxy.getInvoker(new DemoServiceImpl(), DemoService.class, injvmUrl));
exporters.add(exporter);
invocation = new RpcInvocation();
invocation.setMethodName("doSomething8");
invocation.setParameterTypes(new Class[]{});
Result ret2 = cluster.invoke(invocation);
Assertions.assertEquals("doSomething8", ret2.getValue());
RpcContext.getServiceContext().setLocalInvoke(false);
invocation = new RpcInvocation();
invocation.setMethodName("doSomething8");
invocation.setParameterTypes(new Class[]{});
Result ret3 = cluster.invoke(invocation);
Assertions.assertEquals("doSomething8", ret3.getValue());
}
private Invoker<DemoService> getClusterInvoker(URL url) {
final URL durl = url.addParameter("proxy", "jdk");
invokers.clear();
@ -241,7 +340,10 @@ class ScopeClusterInvokerTest {
}
}
};
return new ScopeClusterInvoker<>(dic, cluster);
ScopeClusterInvoker<DemoService> demoServiceScopeClusterInvoker = new ScopeClusterInvoker<>(dic, cluster);
Assertions.assertNotNull(demoServiceScopeClusterInvoker.getDirectory());
Assertions.assertNotNull(demoServiceScopeClusterInvoker.getInvoker());
return demoServiceScopeClusterInvoker;
}
public static interface DemoService {
@ -252,6 +354,14 @@ class ScopeClusterInvokerTest {
String doSomething3();
String doSomething4();
String doSomething5();
String doSomething6();
String doSomething7();
String doSomething8();
}
public static class DemoServiceImpl implements DemoService {
@ -276,6 +386,26 @@ class ScopeClusterInvokerTest {
public String doSomething4() {
return "doSomething4";
}
@Override
public String doSomething5() {
return "doSomething5";
}
@Override
public String doSomething6() {
return "doSomething6";
}
@Override
public String doSomething7() {
return "doSomething7";
}
@Override
public String doSomething8() {
return "doSomething8";
}
}
}

View File

@ -101,37 +101,4 @@
<artifactId>javax.annotation-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>get-version-infos</id>
<phase>compile</phase>
<configuration>
<failOnError>true</failOnError>
<target>
<property name="version_file"
value="${project.build.outputDirectory}/META-INF/version"/>
<!-- get the current version of dubbo -->
<echo message="revision=${revision}${line.separator}" file="${version_file}"/>
<echo message="git.commit.id=" file="${version_file}" append="true"/>
<!-- get the latest commit id -->
<exec executable="git" output="${version_file}" error=".git.exec.error" append="true"
timeout="3000" failifexecutionfails="false">
<arg line="rev-parse HEAD"/>
</exec>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -62,7 +62,7 @@ public class BatchExecutorQueue<T> {
boolean flushedOnce = false;
while ((item = snapshot.poll()) != null) {
if (snapshot.size() == 0) {
i = 0;
flushedOnce = false;
break;
}
if (i == chunkSize) {
@ -74,7 +74,7 @@ public class BatchExecutorQueue<T> {
i++;
}
}
if ((i != 0 || !flushedOnce) && item != null) {
if (!flushedOnce && item != null) {
flush(item);
}
} finally {

View File

@ -18,20 +18,18 @@ package org.apache.dubbo.common;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.ConfigUtils;
import org.apache.dubbo.common.utils.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.CodeSource;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -64,25 +62,38 @@ public final class Version {
private static final Map<String, Integer> VERSION2INT = new HashMap<String, Integer>();
static {
// check if there's duplicated jar
Version.checkDuplicate(Version.class);
// get dubbo version and last commit id
try {
Properties properties =
ConfigUtils.loadProperties(Collections.emptySet(), "META-INF/version");
VERSION = Optional.ofNullable(properties.getProperty("revision"))
.filter(StringUtils::isNotBlank)
.orElseGet(() -> getVersion(Version.class, ""));
LATEST_COMMIT_ID = Optional.ofNullable(properties.getProperty("git.commit.id")).orElse("");
tryLoadVersionFromResource();
checkDuplicate();
} catch (Throwable e) {
logger.warn(COMMON_UNEXPECTED_EXCEPTION, "", "", "continue the old logic, ignore exception " + e.getMessage(), e);
}
if (StringUtils.isEmpty(VERSION)) {
VERSION = getVersion(Version.class, "");
}
if (StringUtils.isEmpty(LATEST_COMMIT_ID)) {
LATEST_COMMIT_ID = "";
}
}
private static void tryLoadVersionFromResource() throws IOException {
Enumeration<URL> configLoader = Version.class.getClassLoader().getResources("META-INF/versions/dubbo-common");
if (configLoader.hasMoreElements()) {
URL url = configLoader.nextElement();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("revision=")) {
VERSION = line.substring("revision=".length());
} else if (line.startsWith("git.commit.id=")) {
LATEST_COMMIT_ID = line.substring("git.commit.id=".length());
}
}
}
}
}
private Version() {
}
@ -266,48 +277,75 @@ public final class Version {
return file;
}
public static void checkDuplicate(Class<?> cls, boolean failOnError) {
checkDuplicate(cls.getName().replace('.', '/') + ".class", failOnError);
}
public static void checkDuplicate(Class<?> cls) {
checkDuplicate(cls, false);
}
public static void checkDuplicate(String path, boolean failOnError) {
private static void checkDuplicate() {
try {
// search in caller's classloader
Set<String> files = getResources(path);
// duplicated jar is found
if (files.size() > 1) {
String error = "Duplicate class " + path + " in " + files.size() + " jar " + files;
if (failOnError) {
throw new IllegalStateException(error);
} else {
logger.error(COMMON_UNEXPECTED_EXCEPTION, "", "", error);
}
}
checkArtifacts(loadArtifactIds());
} catch (Throwable e) {
logger.error(COMMON_UNEXPECTED_EXCEPTION, "", "", e.getMessage(), e);
}
}
/**
* search resources in caller's classloader
*/
private static Set<String> getResources(String path) throws IOException {
Enumeration<URL> urls = ClassUtils.getCallerClassLoader(Version.class).getResources(path);
Set<String> files = new HashSet<String>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
if (url != null) {
String file = url.getFile();
if (StringUtils.isNotEmpty(file)) {
files.add(file);
private static void checkArtifacts(Set<String> artifactIds) throws IOException {
if (!artifactIds.isEmpty()) {
for (String artifactId : artifactIds) {
checkArtifact(artifactId);
}
}
}
private static void checkArtifact(String artifactId) throws IOException {
Enumeration<URL> artifactEnumeration = Version.class.getClassLoader().getResources("META-INF/versions/" + artifactId);
while (artifactEnumeration.hasMoreElements()) {
URL url = artifactEnumeration.nextElement();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("#")) {
continue;
}
String[] artifactInfo = line.split("=");
if (artifactInfo.length == 2) {
String key = artifactInfo[0];
String value = artifactInfo[1];
checkVersion(artifactId, url, key, value);
}
}
}
}
return files;
}
private static void checkVersion(String artifactId, URL url, String key, String value) {
if ("revision".equals(key) && !value.equals(VERSION)) {
String error = "Inconsistent version " + value + " found in " + artifactId + " from " + url.getPath() + ", " +
"expected dubbo-common version is " + VERSION;
logger.error(COMMON_UNEXPECTED_EXCEPTION, "", "", error);
}
if ("git.commit.id".equals(key) && !value.equals(LATEST_COMMIT_ID)) {
String error = "Inconsistent git build commit id " + value + " found in " + artifactId + " from " + url.getPath() + ", " +
"expected dubbo-common version is " + LATEST_COMMIT_ID;
logger.error(COMMON_UNEXPECTED_EXCEPTION, "", "", error);
}
}
private static Set<String> loadArtifactIds() throws IOException {
Enumeration<URL> artifactsEnumeration = Version.class.getClassLoader().getResources("META-INF/versions/.artifacts");
Set<String> artifactIds = new HashSet<>();
while (artifactsEnumeration.hasMoreElements()) {
URL url = artifactsEnumeration.nextElement();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("#")) {
continue;
}
if (StringUtils.isEmpty(line)) {
continue;
}
artifactIds.add(line);
}
}
}
return artifactIds;
}
}

View File

@ -268,6 +268,10 @@ public class ScopeBeanFactory {
}
}
public boolean isDestroyed() {
return destroyed.get();
}
private void checkDestroyed() {
if (destroyed.get()) {
throw new IllegalStateException("ScopeBeanFactory is destroyed");

View File

@ -118,8 +118,6 @@ public interface CommonConstants {
String CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY = "CONSUMER_SHARED_SERVICE_EXECUTOR";
String INTERNAL_EXECUTOR_SERVICE_COMPONENT_KEY = "INTERNAL_SERVICE_EXECUTOR";
String THREADPOOL_KEY = "threadpool";
String THREAD_NAME_KEY = "threadname";
@ -620,5 +618,14 @@ public interface CommonConstants {
String ENCODE_IN_IO_THREAD_KEY = "encode.in.io";
boolean DEFAULT_ENCODE_IN_IO_THREAD = false;
/**
* @since 3.2.0
*/
String BYTE_ACCESSOR_KEY = "byte.accessor";
String PAYLOAD = "payload";
String DUBBO_METRICS_CONFIGCENTER_ENABLE = "dubbo.metrics.configcenter.enable";
Integer TRI_EXCEPTION_CODE_NOT_EXISTS = 0;
}

View File

@ -196,6 +196,8 @@ public interface LoggerCodeConstants {
String REGISTRY_ISTIO_EXCEPTION = "1-41";
String REGISTRY_NACOS_SUB_LEGACY = "1-42";
// Cluster module 2-x
String CLUSTER_FAILED_SITE_SELECTION = "2-1";

View File

@ -37,8 +37,14 @@ public interface MetricsConstants {
String TAG_VERSION_KEY = "version";
String TAG_APPLICATION_VERSION_KEY = "application.version";
String TAG_KEY_KEY = "key";
String TAG_CONFIG_CENTER = "config.center";
String TAG_CHANGE_TYPE = "change.type";
String ENABLE_JVM_METRICS_KEY = "enable.jvm.metrics";
String ENABLE_JVM_METRICS_KEY = "enable.jvm";
String AGGREGATION_COLLECTOR_KEY = "aggregation";
@ -48,6 +54,8 @@ public interface MetricsConstants {
String AGGREGATION_TIME_WINDOW_SECONDS_KEY = "aggregation.time.window.seconds";
String HISTOGRAM_ENABLED_KEY = "histogram.enabled";
String PROMETHEUS_EXPORTER_ENABLED_KEY = "prometheus.exporter.enabled";
String PROMETHEUS_EXPORTER_ENABLE_HTTP_SERVICE_DISCOVERY_KEY = "prometheus.exporter.enable.http.service.discovery";

View File

@ -25,6 +25,7 @@ import org.apache.dubbo.rpc.model.ApplicationModel;
*/
@SPI(scope = ExtensionScope.APPLICATION)
public interface ApplicationDeployListener extends DeployListener<ApplicationModel> {
default void onModuleStarted(ApplicationModel applicationModel) {
}

View File

@ -19,6 +19,10 @@ package org.apache.dubbo.common.deploy;
import org.apache.dubbo.rpc.model.ScopeModel;
public interface DeployListener<E extends ScopeModel> {
/**
* Useful to inject some configuration like MetricsConfig, RegistryConfig, etc.
*/
void onInitialize(E scopeModel);
void onStarting(E scopeModel);

View File

@ -19,6 +19,11 @@ package org.apache.dubbo.common.deploy;
import org.apache.dubbo.rpc.model.ScopeModel;
public class DeployListenerAdapter<E extends ScopeModel> implements DeployListener<E>{
@Override
public void onInitialize(E scopeModel) {
}
@Override
public void onStarting(E scopeModel) {
}

View File

@ -27,7 +27,7 @@ import java.lang.reflect.Type;
import java.util.List;
public class JacksonImpl extends AbstractJSONImpl {
private ObjectMapper objectMapper = new ObjectMapper();
private final ObjectMapper objectMapper = new ObjectMapper();
private volatile Object jacksonCache = null;

View File

@ -75,7 +75,7 @@ public class FrameworkStatusReportService implements ScopeModelAware {
HashMap<String, String> registration = new HashMap<>();
registration.put("application", applicationModel.getApplicationName());
registration.put("status", status);
return JsonUtils.getJson().toJson(registration);
return JsonUtils.toJson(registration);
}
public String createConsumptionReport(String interfaceName, String version, String group, String status) {
@ -86,7 +86,7 @@ public class FrameworkStatusReportService implements ScopeModelAware {
migrationStatus.put("version", version);
migrationStatus.put("group", group);
migrationStatus.put("status", status);
return JsonUtils.getJson().toJson(migrationStatus);
return JsonUtils.toJson(migrationStatus);
}
public String createMigrationStepReport(String interfaceName, String version, String group, String originStep, String newStep, String success) {
@ -99,6 +99,6 @@ public class FrameworkStatusReportService implements ScopeModelAware {
migrationStatus.put("originStep", originStep);
migrationStatus.put("newStep", newStep);
migrationStatus.put("success", success);
return JsonUtils.getJson().toJson(migrationStatus);
return JsonUtils.toJson(migrationStatus);
}
}

View File

@ -21,11 +21,12 @@ import org.apache.dubbo.common.logger.LoggerFactory;
import java.util.Collections;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
/**
* The most important difference between this Executor and other normal Executor is that this one doesn't manage
@ -38,78 +39,42 @@ import java.util.concurrent.TimeUnit;
public class ThreadlessExecutor extends AbstractExecutorService {
private static final Logger logger = LoggerFactory.getLogger(ThreadlessExecutor.class.getName());
private final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
private static final Object SHUTDOWN = new Object();
private CompletableFuture<?> waitingFuture;
private final Queue<Runnable> queue = new ConcurrentLinkedQueue<>();
private boolean finished = false;
private volatile boolean waiting = true;
private final Object lock = new Object();
public CompletableFuture<?> getWaitingFuture() {
return waitingFuture;
}
public void setWaitingFuture(CompletableFuture<?> waitingFuture) {
this.waitingFuture = waitingFuture;
}
private boolean isFinished() {
return finished;
}
private void setFinished(boolean finished) {
this.finished = finished;
}
public boolean isWaiting() {
return waiting;
}
private void setWaiting(boolean waiting) {
this.waiting = waiting;
}
/**
* Wait thread. It must be visible to other threads and does not need to be thread-safe
*/
private volatile Object waiter;
/**
* Waits until there is a task, executes the task and all queued tasks (if there're any). The task is either a normal
* response or a timeout response.
*/
public void waitAndDrain() throws InterruptedException {
/**
* Usually, {@link #waitAndDrain()} will only get called once. It blocks for the response for the first time,
* once the response (the task) reached and being executed waitAndDrain will return, the whole request process
* then finishes. Subsequent calls on {@link #waitAndDrain()} (if there're any) should return immediately.
*
* There's no need to worry that {@link #finished} is not thread-safe. Checking and updating of
* 'finished' only appear in waitAndDrain, since waitAndDrain is binding to one RPC call (one thread), the call
* of it is totally sequential.
*/
if (isFinished()) {
return;
throwIfInterrupted();
Runnable runnable = queue.poll();
if (runnable == null) {
waiter = Thread.currentThread();
try {
while ((runnable = queue.poll()) == null) {
LockSupport.park(this);
throwIfInterrupted();
}
} finally {
waiter = null;
}
}
Runnable runnable;
try {
runnable = queue.take();
} catch (InterruptedException e) {
setWaiting(false);
throw e;
}
synchronized (lock) {
setWaiting(false);
do {
runnable.run();
}
} while ((runnable = queue.poll()) != null);
}
runnable = queue.poll();
while (runnable != null) {
runnable.run();
runnable = queue.poll();
private static void throwIfInterrupted() throws InterruptedException {
if (Thread.interrupted()) {
throw new InterruptedException();
}
// mark the status of ThreadlessExecutor as finished.
setFinished(true);
}
/**
@ -120,26 +85,15 @@ public class ThreadlessExecutor extends AbstractExecutorService {
*/
@Override
public void execute(Runnable runnable) {
runnable = new RunnableWrapper(runnable);
synchronized (lock) {
if (!isWaiting()) {
runnable.run();
return;
}
queue.add(runnable);
RunnableWrapper run = new RunnableWrapper(runnable);
queue.add(run);
if (waiter != SHUTDOWN) {
LockSupport.unpark((Thread) waiter);
} else if (queue.remove(run)) {
throw new RejectedExecutionException();
}
}
/**
* tells the thread blocking on {@link #waitAndDrain()} to return, despite of the current status, to avoid endless waiting.
*/
public void notifyReturn(Throwable t) {
// an empty runnable task.
execute(() -> {
waitingFuture.completeExceptionally(t);
});
}
/**
* The following methods are still not supported
*/
@ -151,23 +105,26 @@ public class ThreadlessExecutor extends AbstractExecutorService {
@Override
public List<Runnable> shutdownNow() {
notifyReturn(new IllegalStateException("Consumer is shutting down and this call is going to be stopped without " +
"receiving any result, usually this is called by a slow provider instance or bad service implementation."));
waiter = SHUTDOWN;
Runnable runnable;
while ((runnable = queue.poll()) != null) {
runnable.run();
}
return Collections.emptyList();
}
@Override
public boolean isShutdown() {
return false;
return waiter == SHUTDOWN;
}
@Override
public boolean isTerminated() {
return false;
return isShutdown();
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
public boolean awaitTermination(long timeout, TimeUnit unit) {
return false;
}

View File

@ -30,11 +30,13 @@ import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.ConsumerConfig;
import org.apache.dubbo.config.ModuleConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.apache.dubbo.rpc.model.ServiceDescriptor;
import org.apache.dubbo.rpc.executor.DefaultExecutorSupport;
import org.apache.dubbo.rpc.executor.ExecutorSupport;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ConsumerModel;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.apache.dubbo.rpc.model.ProviderModel;
import org.apache.dubbo.rpc.model.ServiceModel;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -50,7 +52,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_EXPORT_T
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_REFER_THREAD_NUM;
import static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_SERVICE_COMPONENT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERNAL_EXECUTOR_SERVICE_COMPONENT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;
@ -64,6 +65,8 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_UNEXP
public class DefaultExecutorRepository implements ExecutorRepository, ExtensionAccessorAware {
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(DefaultExecutorRepository.class);
private static final String MAX_KEY = String.valueOf(Integer.MAX_VALUE);
private volatile ScheduledExecutorService serviceExportExecutor;
private volatile ExecutorService serviceReferExecutor;
@ -131,16 +134,34 @@ public class DefaultExecutorRepository implements ExecutorRepository, ExtensionA
}
}
private String getExecutorSecondKey(ServiceModel serviceModel, URL url) {
if (serviceModel instanceof ConsumerModel) {
return getConsumerKey(serviceModel);
} else {
return getProviderKey((ProviderModel) serviceModel, url);
}
}
private String getConsumerKey(URL url) {
// Consumer's executor is sharing globally, key=Integer.MAX_VALUE
return String.valueOf(Integer.MAX_VALUE);
}
private String getConsumerKey(ServiceModel serviceModel) {
// Consumer's executor is sharing globally, key=Integer.MAX_VALUE
return MAX_KEY;
}
protected String getProviderKey(URL url) {
// Provider's executor is sharing by protocol.
return String.valueOf(url.getPort());
}
protected String getProviderKey(ProviderModel providerModel, URL url) {
// Provider's executor is sharing by protocol.
return String.valueOf(url.getPort());
}
/**
* Return the executor key based on the type (internal or biz) of the current service.
*
@ -148,18 +169,18 @@ public class DefaultExecutorRepository implements ExecutorRepository, ExtensionA
* @return
*/
private String getExecutorKey(URL url) {
String executorKey = INTERNAL_EXECUTOR_SERVICE_COMPONENT_KEY;
ServiceDescriptor serviceDescriptor = applicationModel.getInternalModule().getServiceRepository().lookupService(url.getServiceInterface());
// if not found in internal service repository, then it's biz service defined by user.
if (serviceDescriptor == null) {
executorKey = EXECUTOR_SERVICE_COMPONENT_KEY;
}
if (CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(SIDE_KEY))) {
executorKey = CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY;
return CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY;
}
return EXECUTOR_SERVICE_COMPONENT_KEY;
}
private String getExecutorKey(ServiceModel serviceModel) {
if (serviceModel instanceof ProviderModel) {
return EXECUTOR_SERVICE_COMPONENT_KEY;
} else {
return CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY;
}
return executorKey;
}
protected ExecutorService createExecutor(URL url) {
@ -197,6 +218,37 @@ public class DefaultExecutorRepository implements ExecutorRepository, ExtensionA
}
}
@Override
public ExecutorService getExecutor(ServiceModel serviceModel, URL url) {
Map<String, ExecutorService> executors = data.get(getExecutorKey(serviceModel));
/*
* It's guaranteed that this method is called after {@link #createExecutorIfAbsent(URL)}, so data should already
* have Executor instances generated and stored.
*/
if (executors == null) {
logger.warn(COMMON_EXECUTORS_NO_FOUND, "", "", "No available executors, this is not expected, framework should call createExecutorIfAbsent first" +
"before coming to here.");
return null;
}
// Consumer's executor is sharing globally, key=Integer.MAX_VALUE. Provider's executor is sharing by protocol.
String executorCacheKey = getExecutorSecondKey(serviceModel, url);
ExecutorService executor = executors.get(executorCacheKey);
if (executor != null && (executor.isShutdown() || executor.isTerminated())) {
executors.remove(executorCacheKey);
// Does not re-create a shutdown executor, use SHARED_EXECUTOR for downgrade.
executor = null;
logger.info("Executor for " + url + " is shutdown.");
}
if (executor == null) {
return frameworkExecutorRepository.getSharedExecutor();
} else {
return executor;
}
}
@Override
public void updateThreadpool(URL url, ExecutorService executor) {
try {

View File

@ -22,19 +22,20 @@ import org.apache.dubbo.common.extension.ExtensionScope;
import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.executor.ExecutorSupport;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ServiceModel;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_DEFAULT;
import static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_ISOLATION;
/**
*
*/
@SPI(value = "default", scope = ExtensionScope.APPLICATION)
@SPI(value = "isolation", scope = ExtensionScope.APPLICATION)
public interface ExecutorRepository {
/**
@ -54,6 +55,8 @@ public interface ExecutorRepository {
*/
ExecutorService getExecutor(URL url);
ExecutorService getExecutor(ServiceModel serviceModel, URL url);
/**
@ -187,7 +190,7 @@ public interface ExecutorRepository {
static String getMode(ApplicationModel applicationModel) {
Optional<ApplicationConfig> optional = applicationModel.getApplicationConfigManager().getApplication();
return optional.map(ApplicationConfig::getExecutorManagementMode).orElse(EXECUTOR_MANAGEMENT_MODE_DEFAULT);
return optional.map(ApplicationConfig::getExecutorManagementMode).orElse(EXECUTOR_MANAGEMENT_MODE_ISOLATION);
}
}

View File

@ -27,6 +27,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@ -56,6 +57,8 @@ public class FrameworkExecutorRepository implements Disposable {
private final Ring<ExecutorService> executorServiceRing = new Ring<>();
private final ExecutorService internalServiceExecutor;
public FrameworkExecutorRepository() {
sharedExecutor = Executors.newCachedThreadPool(new NamedThreadFactory("Dubbo-framework-shared-handler", true));
sharedScheduledExecutor = Executors.newScheduledThreadPool(8, new NamedThreadFactory("Dubbo-framework-shared-scheduler", true));
@ -89,6 +92,9 @@ public class FrameworkExecutorRepository implements Disposable {
}
metadataRetryExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("Dubbo-framework-metadata-retry"));
internalServiceExecutor = new ThreadPoolExecutor(0, 100, 60L, TimeUnit.SECONDS,
new SynchronousQueue<>(), new NamedInternalThreadFactory("Dubbo-internal-service", true),
new ThreadPoolExecutor.AbortPolicy());
}
/**
@ -122,6 +128,10 @@ public class FrameworkExecutorRepository implements Disposable {
return metadataRetryExecutor;
}
public ExecutorService getInternalServiceExecutor() {
return internalServiceExecutor;
}
/**
* Get the default shared thread pool.
*
@ -177,6 +187,7 @@ public class FrameworkExecutorRepository implements Disposable {
logger.info("destroying framework executor repository ..");
shutdownExecutorService(poolRouterExecutor, "poolRouterExecutor");
shutdownExecutorService(metadataRetryExecutor, "metadataRetryExecutor");
shutdownExecutorService(internalServiceExecutor, "internalServiceExecutor");
// scheduledExecutors
shutdownExecutorServices(scheduledExecutors.listItems(), "scheduledExecutors");

View File

@ -20,6 +20,7 @@ import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.executor.ExecutorSupport;
import org.apache.dubbo.rpc.executor.IsolationExecutorSupportFactory;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ProviderModel;
import java.util.concurrent.ExecutorService;
@ -52,6 +53,15 @@ public class IsolationExecutorRepository extends DefaultExecutorRepository {
}
}
@Override
protected String getProviderKey(ProviderModel providerModel, URL url) {
if (url.getAttributes().containsKey(SERVICE_EXECUTOR)) {
return providerModel.getServiceKey();
} else {
return super.getProviderKey(url);
}
}
@Override
protected ExecutorService createExecutor(URL url) {
Object executor = url.getAttributes().get(SERVICE_EXECUTOR);

View File

@ -422,7 +422,7 @@ public class HashedWheelTimer implements Timer {
private static void reportTooManyInstances() {
String resourceType = ClassUtils.simpleClassName(HashedWheelTimer.class);
logger.error(COMMON_ERROR_TOO_MANY_INSTANCES, "", "", "You are creating too many " + resourceType + " instances. " +
resourceType + " is a shared resource that must be reused across the JVM," +
resourceType + " is a shared resource that must be reused across the JVM, " +
"so that only a few instances are created.");
}

View File

@ -994,7 +994,13 @@ public class URLParam {
Map<String, Map<String, String>> methodParameters = new HashMap<>(capacity);
for (Map.Entry<String, String> entry : params.entrySet()) {
addParameter(keyBit, valueMap, extraParam, methodParameters, entry.getKey(), entry.getValue(), false);
String key = entry.getKey();
String value = entry.getValue();
addParameter(keyBit, valueMap, extraParam, methodParameters, key, value, false);
// compatible with lower versions registering "default." keys
if (key.startsWith(DEFAULT_KEY_PREFIX)) {
addParameter(keyBit, valueMap, extraParam, methodParameters, key.substring(DEFAULT_KEY_PREFIX.length()), value, true);
}
}
return new URLParam(keyBit, valueMap, extraParam, methodParameters, rawParam);
} else {

View File

@ -74,20 +74,20 @@ public class ClassUtils {
* @since 2.7.6
*/
public static final Set<Class<?>> SIMPLE_TYPES = ofSet(
Void.class,
Boolean.class,
Character.class,
Byte.class,
Short.class,
Integer.class,
Long.class,
Float.class,
Double.class,
String.class,
BigDecimal.class,
BigInteger.class,
Date.class,
Object.class
Void.class,
Boolean.class,
Character.class,
Byte.class,
Short.class,
Integer.class,
Long.class,
Float.class,
Double.class,
String.class,
BigDecimal.class,
BigInteger.class,
Date.class,
Object.class
);
/**
* Prefix for internal array class names: "[L"
@ -118,8 +118,8 @@ public class ClassUtils {
Set<Class<?>> primitiveTypeNames = new HashSet<>(32);
primitiveTypeNames.addAll(PRIMITIVE_WRAPPER_TYPE_MAP.values());
primitiveTypeNames.addAll(Arrays
.asList(boolean[].class, byte[].class, char[].class, double[].class,
float[].class, int[].class, long[].class, short[].class));
.asList(boolean[].class, byte[].class, char[].class, double[].class,
float[].class, int[].class, long[].class, short[].class));
for (Class<?> primitiveTypeName : primitiveTypeNames) {
PRIMITIVE_TYPE_NAME_MAP.put(primitiveTypeName.getName(), primitiveTypeName);
}
@ -137,12 +137,12 @@ public class ClassUtils {
private static final char PACKAGE_SEPARATOR_CHAR = '.';
public static Class<?> forNameWithThreadContextClassLoader(String name)
throws ClassNotFoundException {
throws ClassNotFoundException {
return forName(name, Thread.currentThread().getContextClassLoader());
}
public static Class<?> forNameWithCallerClassLoader(String name, Class<?> caller)
throws ClassNotFoundException {
throws ClassNotFoundException {
return forName(name, caller.getClassLoader());
}
@ -224,7 +224,7 @@ public class ClassUtils {
* @see Class#forName(String, boolean, ClassLoader)
*/
public static Class<?> forName(String name, ClassLoader classLoader)
throws ClassNotFoundException, LinkageError {
throws ClassNotFoundException, LinkageError {
Class<?> clazz = resolvePrimitiveClassName(name);
if (clazz != null) {
@ -244,7 +244,7 @@ public class ClassUtils {
String elementClassName = null;
if (internalArrayMarker == 0) {
elementClassName = name
.substring(INTERNAL_ARRAY_PREFIX.length(), name.length() - 1);
.substring(INTERNAL_ARRAY_PREFIX.length(), name.length() - 1);
} else if (name.startsWith("[")) {
elementClassName = name.substring(1);
}
@ -354,7 +354,7 @@ public class ClassUtils {
*/
public static boolean isTypeMatch(Class<?> type, String value) {
if ((type == boolean.class || type == Boolean.class)
&& !("true".equals(value) || "false".equals(value))) {
&& !("true".equals(value) || "false".equals(value))) {
return false;
}
return true;
@ -408,18 +408,18 @@ public class ClassUtils {
if (isNotEmpty(interfaces)) {
// add current interfaces
Arrays.stream(interfaces)
.filter(resolved::add)
.forEach(cls -> {
allInterfaces.add(cls);
waitResolve.add(cls);
});
.filter(resolved::add)
.forEach(cls -> {
allInterfaces.add(cls);
waitResolve.add(cls);
});
}
// add all super classes to waitResolve
getAllSuperClasses(clazz)
.stream()
.filter(resolved::add)
.forEach(waitResolve::add);
.stream()
.filter(resolved::add)
.forEach(waitResolve::add);
clazz = waitResolve.poll();
}
@ -535,7 +535,7 @@ public class ClassUtils {
}
Method[] methods = Arrays.stream(tClass.getMethods())
.collect(Collectors.toList())
.toArray(new Method[] {});
.toArray(new Method[]{});
List<String> mns = new ArrayList<>(); // method names.
boolean hasMethod = hasMethods(methods);
if (hasMethod) {
@ -551,6 +551,44 @@ public class ClassUtils {
return mns.toArray(new String[0]);
}
public static boolean isMatch(Class<?> from, Class<?> to) {
if (from == to) {
return true;
}
boolean isMatch;
if (from.isPrimitive()) {
isMatch = matchPrimitive(from, to);
} else if (to.isPrimitive()) {
isMatch = matchPrimitive(to, from);
} else {
isMatch = to.isAssignableFrom(from);
}
return isMatch;
}
private static boolean matchPrimitive(Class<?> from, Class<?> to) {
if (from == boolean.class) {
return to == Boolean.class;
} else if (from == byte.class) {
return to == Byte.class;
} else if (from == char.class) {
return to == Character.class;
} else if (from == short.class) {
return to == Short.class;
} else if (from == int.class) {
return to == Integer.class;
} else if (from == long.class) {
return to == Long.class;
} else if (from == float.class) {
return to == Float.class;
} else if (from == double.class) {
return to == Double.class;
} else if (from == void.class) {
return to == Void.class;
}
return false;
}
/**
* get method name array.
*
@ -562,7 +600,7 @@ public class ClassUtils {
}
Method[] methods = Arrays.stream(tClass.getMethods())
.collect(Collectors.toList())
.toArray(new Method[] {});
.toArray(new Method[]{});
List<String> dmns = new ArrayList<>(); // method names.
boolean hasMethod = hasMethods(methods);
if (hasMethod) {

View File

@ -117,7 +117,7 @@ public enum JRE {
return OTHER;
}
} catch (Exception e) {
logger.debug("can't determine current JRE version, if JRE version is 8 but java.version is null", e);
logger.debug("Can't determine current JRE version (maybe java.version is null), assuming that JRE version is 8.", e);
}
// default java 8
return JAVA_8;

View File

@ -23,13 +23,16 @@ import org.apache.dubbo.common.json.impl.FastJsonImpl;
import org.apache.dubbo.common.json.impl.GsonImpl;
import org.apache.dubbo.common.json.impl.JacksonImpl;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class JsonUtils {
private static volatile JSON json;
public static JSON getJson() {
protected static JSON getJson() {
if (json == null) {
synchronized (JsonUtils.class) {
if (json == null) {
@ -86,4 +89,76 @@ public class JsonUtils {
return json;
}
/**
* @deprecated for uts only
*/
@Deprecated
protected static void setJson(JSON json) {
JsonUtils.json = json;
}
public static <T> T toJavaObject(String json, Type type) {
return getJson().toJavaObject(json, type);
}
public static <T> List<T> toJavaList(String json, Class<T> clazz) {
return getJson().toJavaList(json, clazz);
}
public static String toJson(Object obj) {
return getJson().toJson(obj);
}
public static List<?> getList(Map<String, ?> obj, String key) {
return getJson().getList(obj, key);
}
public static List<Map<String, ?>> getListOfObjects(Map<String, ?> obj, String key) {
return getJson().getListOfObjects(obj, key);
}
public static List<String> getListOfStrings(Map<String, ?> obj, String key) {
return getJson().getListOfStrings(obj, key);
}
public static Map<String, ?> getObject(Map<String, ?> obj, String key) {
return getJson().getObject(obj, key);
}
public static Double getNumberAsDouble(Map<String, ?> obj, String key) {
return getJson().getNumberAsDouble(obj, key);
}
public static Integer getNumberAsInteger(Map<String, ?> obj, String key) {
return getJson().getNumberAsInteger(obj, key);
}
public static Long getNumberAsLong(Map<String, ?> obj, String key) {
return getJson().getNumberAsLong(obj, key);
}
public static String getString(Map<String, ?> obj, String key) {
return getJson().getString(obj, key);
}
public static List<Map<String, ?>> checkObjectList(List<?> rawList) {
return getJson().checkObjectList(rawList);
}
public static List<String> checkStringList(List<?> rawList) {
return getJson().checkStringList(rawList);
}
}

View File

@ -23,7 +23,6 @@ import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.logger.support.FailsafeLogger;
import org.apache.dubbo.rpc.model.ScopeModel;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
@ -251,6 +250,8 @@ public final class NetUtils {
private static volatile String HOST_ADDRESS;
private static volatile String HOST_NAME;
private static volatile String HOST_ADDRESS_V6;
public static String getLocalHost() {
@ -585,11 +586,15 @@ public final class NetUtils {
}
public static String getLocalHostName() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
return getLocalAddress().getHostName();
if (HOST_NAME != null) {
return HOST_NAME;
}
try {
HOST_NAME= InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
HOST_NAME= Optional.ofNullable(getLocalAddress()).map(k->k.getHostName()).orElse(null);
}
return HOST_NAME;
}
/**

View File

@ -40,8 +40,8 @@ public interface PathUtils {
paths.addAll(asList(subPaths));
return normalize(paths.stream()
.filter(StringUtils::isNotEmpty)
.collect(Collectors.joining(SLASH)));
.filter(StringUtils::isNotEmpty)
.collect(Collectors.joining(SLASH)));
}
/**
@ -67,7 +67,6 @@ public interface PathUtils {
while (normalizedPath.contains("//")) {
normalizedPath = replace(normalizedPath, "//", "/");
}
return normalizedPath;
}

View File

@ -16,6 +16,12 @@
*/
package org.apache.dubbo.common.utils;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.rpc.model.ApplicationModel;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@ -53,11 +59,6 @@ import java.util.concurrent.ConcurrentSkipListMap;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_REFLECTIVE_OPERATION_FAILED;
import static org.apache.dubbo.common.utils.ClassUtils.isAssignableFrom;
@ -78,13 +79,15 @@ import static org.apache.dubbo.common.utils.ClassUtils.isAssignableFrom;
public class PojoUtils {
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(PojoUtils.class);
private static final ConcurrentMap<String, Method> NAME_METHODS_CACHE = new ConcurrentHashMap<String, Method>();
private static final ConcurrentMap<Class<?>, ConcurrentMap<String, Field>> CLASS_FIELD_CACHE = new ConcurrentHashMap<Class<?>, ConcurrentMap<String, Field>>();
private static final ConcurrentMap<String, Method> NAME_METHODS_CACHE = new ConcurrentHashMap<>();
private static final ConcurrentMap<Class<?>, ConcurrentMap<String, Field>> CLASS_FIELD_CACHE = new ConcurrentHashMap<>();
private static final ConcurrentMap<String, Object> CLASS_NOT_FOUND_CACHE = new ConcurrentHashMap<String, Object>();
private static final ConcurrentMap<String, Object> CLASS_NOT_FOUND_CACHE = new ConcurrentHashMap<>();
private static final Object NOT_FOUND_VALUE = new Object();
private static final boolean GENERIC_WITH_CLZ = Boolean.parseBoolean(ConfigurationUtils.getProperty(CommonConstants.GENERIC_WITH_CLZ_KEY, "true"));
private static final boolean GENERIC_WITH_CLZ = Boolean.parseBoolean(
ConfigurationUtils.getProperty(ApplicationModel.defaultModel(), CommonConstants.GENERIC_WITH_CLZ_KEY, "true"));
private static final List<Class<?>> CLASS_CAN_BE_STRING = Arrays.asList(Byte.class, Short.class, Integer.class,
Long.class, Float.class, Double.class, Boolean.class, Character.class);
@ -121,7 +124,7 @@ public class PojoUtils {
}
public static Object generalize(Object pojo) {
return generalize(pojo, new IdentityHashMap<Object, Object>());
return generalize(pojo, new IdentityHashMap<>());
}
@SuppressWarnings("unchecked")
@ -173,7 +176,7 @@ public class PojoUtils {
if (pojo instanceof Collection<?>) {
Collection<Object> src = (Collection<Object>) pojo;
int len = src.size();
Collection<Object> dest = (pojo instanceof List<?>) ? new ArrayList<Object>(len) : new HashSet<Object>(len);
Collection<Object> dest = (pojo instanceof List<?>) ? new ArrayList<>(len) : new HashSet<>(len);
history.put(pojo, dest);
for (Object obj : src) {
dest.add(generalize(obj, history));
@ -189,7 +192,7 @@ public class PojoUtils {
}
return dest;
}
Map<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap<>();
history.put(pojo, map);
if (GENERIC_WITH_CLZ) {
map.put("class", pojo.getClass().getName());
@ -228,16 +231,16 @@ public class PojoUtils {
}
public static Object realize(Object pojo, Class<?> type) {
return realize0(pojo, type, null, new IdentityHashMap<Object, Object>());
return realize0(pojo, type, null, new IdentityHashMap<>());
}
public static Object realize(Object pojo, Class<?> type, Type genericType) {
return realize0(pojo, type, genericType, new IdentityHashMap<Object, Object>());
return realize0(pojo, type, genericType, new IdentityHashMap<>());
}
private static class PojoInvocationHandler implements InvocationHandler {
private Map<Object, Object> map;
private final Map<Object, Object> map;
public PojoInvocationHandler(Map<Object, Object> map) {
this.map = map;
@ -259,7 +262,7 @@ public class PojoUtils {
value = map.get(methodName.substring(0, 1).toLowerCase() + methodName.substring(1));
}
if (value instanceof Map<?, ?> && !Map.class.isAssignableFrom(method.getReturnType())) {
value = realize0((Map<String, Object>) value, method.getReturnType(), null, new IdentityHashMap<Object, Object>());
value = realize0(value, method.getReturnType(), null, new IdentityHashMap<>());
}
return value;
}
@ -268,10 +271,10 @@ public class PojoUtils {
@SuppressWarnings("unchecked")
private static Collection<Object> createCollection(Class<?> type, int len) {
if (type.isAssignableFrom(ArrayList.class)) {
return new ArrayList<Object>(len);
return new ArrayList<>(len);
}
if (type.isAssignableFrom(HashSet.class)) {
return new HashSet<Object>(len);
return new HashSet<>(len);
}
if (!type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
try {
@ -280,7 +283,7 @@ public class PojoUtils {
// ignore
}
}
return new ArrayList<Object>();
return new ArrayList<>();
}
private static Map createMap(Map src) {
@ -318,7 +321,7 @@ public class PojoUtils {
}
if (result == null) {
result = new HashMap<Object, Object>();
result = new HashMap<>();
}
return result;
@ -326,6 +329,10 @@ public class PojoUtils {
@SuppressWarnings({"unchecked", "rawtypes"})
private static Object realize0(Object pojo, Class<?> type, Type genericType, final Map<Object, Object> history) {
return realize1(pojo, type, genericType, new HashMap<>(8), history);
}
private static Object realize1(Object pojo, Class<?> type, Type genericType, final Map<String, Type> mapParent, final Map<Object, Object> history) {
if (pojo == null) {
return null;
}
@ -349,6 +356,19 @@ public class PojoUtils {
history.put(pojo, pojo);
Map<String, Type> mapGeneric = new HashMap<>(8);
mapGeneric.putAll(mapParent);
TypeVariable<? extends Class<?>>[] typeParameters = type.getTypeParameters();
if(genericType instanceof ParameterizedType && typeParameters.length > 0) {
ParameterizedType parameterizedType = (ParameterizedType)genericType;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (int i = 0; i < typeParameters.length; i++) {
if(!(actualTypeArguments[i] instanceof TypeVariable)) {
mapGeneric.put(typeParameters[i].getTypeName(), actualTypeArguments[i]);
}
}
}
if (pojo.getClass().isArray()) {
if (Collection.class.isAssignableFrom(type)) {
Class<?> ctype = pojo.getClass().getComponentType();
@ -357,7 +377,7 @@ public class PojoUtils {
history.put(pojo, dest);
for (int i = 0; i < len; i++) {
Object obj = Array.get(pojo, i);
Object value = realize0(obj, ctype, null, history);
Object value = realize1(obj, ctype, null, mapGeneric, history);
dest.add(value);
}
return dest;
@ -368,7 +388,7 @@ public class PojoUtils {
history.put(pojo, dest);
for (int i = 0; i < len; i++) {
Object obj = Array.get(pojo, i);
Object value = realize0(obj, ctype, null, history);
Object value = realize1(obj, ctype, null, mapGeneric, history);
Array.set(dest, i, value);
}
return dest;
@ -384,7 +404,7 @@ public class PojoUtils {
history.put(pojo, dest);
int i = 0;
for (Object obj : src) {
Object value = realize0(obj, ctype, null, history);
Object value = realize1(obj, ctype, null, mapGeneric, history);
Array.set(dest, i, value);
i++;
}
@ -400,7 +420,7 @@ public class PojoUtils {
if (keyType instanceof Class) {
keyClazz = (Class<?>) keyType;
}
Object value = realize0(obj, keyClazz, keyType, history);
Object value = realize1(obj, keyClazz, keyType, mapGeneric, history);
dest.add(value);
}
return dest;
@ -483,8 +503,8 @@ public class PojoUtils {
valueClazz = entry.getValue() == null ? null : entry.getValue().getClass();
}
Object key = keyClazz == null ? entry.getKey() : realize0(entry.getKey(), keyClazz, keyType, history);
Object value = valueClazz == null ? entry.getValue() : realize0(entry.getValue(), valueClazz, valueType, history);
Object key = keyClazz == null ? entry.getKey() : realize1(entry.getKey(), keyClazz, keyType, mapGeneric, history);
Object value = valueClazz == null ? entry.getValue() : realize1(entry.getValue(), valueClazz, valueType, mapGeneric, history);
result.put(key, value);
}
return result;
@ -506,6 +526,7 @@ public class PojoUtils {
}
history.put(pojo, dest);
for (Map.Entry<Object, Object> entry : map.entrySet()) {
Object key = entry.getKey();
if (key instanceof String) {
@ -518,8 +539,24 @@ public class PojoUtils {
if (!method.isAccessible()) {
method.setAccessible(true);
}
Type ptype = method.getGenericParameterTypes()[0];
value = realize0(value, method.getParameterTypes()[0], ptype, history);
Type containType = mapGeneric.get(field.getGenericType().getTypeName());
if(containType != null) {
//is generic
if(containType instanceof ParameterizedType) {
value = realize1(value, (Class<?>) ((ParameterizedType)containType).getRawType(), containType, mapGeneric, history);
}
else if (containType instanceof Class){
value = realize1(value, (Class<?>) containType, containType, mapGeneric, history);
}
else {
Type ptype = method.getGenericParameterTypes()[0];
value = realize1(value, method.getParameterTypes()[0], ptype, mapGeneric, history);
}
}
else {
Type ptype = method.getGenericParameterTypes()[0];
value = realize1(value, method.getParameterTypes()[0], ptype, mapGeneric, history);
}
try {
method.invoke(dest, value);
} catch (Exception e) {
@ -529,7 +566,7 @@ public class PojoUtils {
throw new RuntimeException(exceptionDescription, e);
}
} else if (field != null) {
value = realize0(value, field.getType(), field.getGenericType(), history);
value = realize1(value, field.getType(), field.getGenericType(), mapGeneric, history);
try {
field.set(dest, value);
} catch (IllegalAccessException e) {
@ -672,10 +709,16 @@ public class PojoUtils {
if (CLASS_FIELD_CACHE.containsKey(cls) && CLASS_FIELD_CACHE.get(cls).containsKey(fieldName)) {
return CLASS_FIELD_CACHE.get(cls).get(fieldName);
}
try {
result = cls.getDeclaredField(fieldName);
result.setAccessible(true);
} catch (NoSuchFieldException e) {
for(Class<?> acls = cls; acls != null; acls = acls.getSuperclass()) {
try {
result = acls.getDeclaredField(fieldName);
if (!Modifier.isPublic(result.getModifiers())) {
result.setAccessible(true);
}
} catch (NoSuchFieldException e) {
}
}
if(result == null) {
for (Field field : cls.getFields()) {
if (fieldName.equals(field.getName()) && ReflectUtils.isPublicInstanceField(field)) {
result = field;
@ -683,6 +726,7 @@ public class PojoUtils {
}
}
}
if (result != null) {
ConcurrentMap<String, Field> fields = CLASS_FIELD_CACHE.computeIfAbsent(cls, k -> new ConcurrentHashMap<>());
fields.putIfAbsent(fieldName, result);

View File

@ -872,7 +872,7 @@ public final class ReflectUtils {
return EMPTY_CLASS_ARRAY;
}
List<Class<?>> cs = new ArrayList<Class<?>>();
List<Class<?>> cs = new ArrayList<>();
Matcher m = DESC_PATTERN.matcher(desc);
while (m.find()) {
cs.add(desc2class(cl, m.group()));
@ -900,7 +900,7 @@ public final class ReflectUtils {
}
Method method;
if (parameterTypes == null) {
List<Method> finded = new ArrayList<Method>();
List<Method> finded = new ArrayList<>();
for (Method m : clazz.getMethods()) {
if (m.getName().equals(methodName)) {
finded.add(m);
@ -1140,7 +1140,7 @@ public final class ReflectUtils {
}
public static Map<String, Field> getBeanPropertyFields(Class cl) {
Map<String, Field> properties = new HashMap<String, Field>();
Map<String, Field> properties = new HashMap<>();
for (; cl != null; cl = cl.getSuperclass()) {
Field[] fields = cl.getDeclaredFields();
for (Field field : fields) {
@ -1159,7 +1159,7 @@ public final class ReflectUtils {
}
public static Map<String, Method> getBeanPropertyReadMethods(Class cl) {
Map<String, Method> properties = new HashMap<String, Method>();
Map<String, Method> properties = new HashMap<>();
for (; cl != null; cl = cl.getSuperclass()) {
Method[] methods = cl.getDeclaredMethods();
for (Method method : methods) {

View File

@ -56,7 +56,7 @@ public class SerializeSecurityConfigurator implements ScopeClassLoaderListener<M
private volatile boolean autoTrustSerializeClass = true;
private volatile int trustSerializeClassLevel = 3;
private volatile int trustSerializeClassLevel = Integer.MAX_VALUE;
public SerializeSecurityConfigurator(ModuleModel moduleModel) {
this.moduleModel = moduleModel;

View File

@ -1030,7 +1030,7 @@ public final class StringUtils {
buf.append(arg);
} else {
try {
buf.append(JsonUtils.getJson().toJson(arg));
buf.append(JsonUtils.toJson(arg));
} catch (Exception e) {
logger.warn(COMMON_JSON_CONVERT_EXCEPTION, "", "", e.getMessage(), e);
buf.append(arg);

View File

@ -374,7 +374,7 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
}
private boolean verifyMethodConfig(MethodConfig methodConfig, Class<?> interfaceClass, boolean ignoreInvalidMethodConfig) {
protected boolean verifyMethodConfig(MethodConfig methodConfig, Class<?> interfaceClass, boolean ignoreInvalidMethodConfig) {
String methodName = methodConfig.getName();
if (StringUtils.isEmpty(methodName)) {
String msg = "<dubbo:method> name attribute is required! Please check: " +
@ -396,7 +396,12 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
logger.warn(CONFIG_NO_METHOD_FOUND, "", "", msg);
return false;
} else {
throw new IllegalStateException(msg);
if (!isNeedCheckMethod()) {
msg = "Generic call: " + msg;
logger.warn(CONFIG_NO_METHOD_FOUND, "", "", msg);
} else {
throw new IllegalStateException(msg);
}
}
}
return true;
@ -413,6 +418,11 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig {
return null;
}
@Transient
protected boolean isNeedCheckMethod() {
return true;
}
private boolean hasArgumentConfigProps(Map<String, String> configProperties, String methodName, int argIndex) {
String argPrefix = methodName + "." + argIndex + ".";
return ConfigurationUtils.hasSubProperties(configProperties, argPrefix);

View File

@ -183,6 +183,11 @@ public abstract class AbstractReferenceConfig extends AbstractInterfaceConfig {
}
}
@Override
protected boolean isNeedCheckMethod() {
return StringUtils.isEmpty(getGeneric());
}
/**
* @return
* @deprecated instead, use the parameter <b>scope</> to judge if it's in jvm, scope=local

View File

@ -16,14 +16,6 @@
*/
package org.apache.dubbo.config;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.dubbo.common.compiler.support.AdaptiveCompiler;
import org.apache.dubbo.common.infra.InfraAdapter;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
@ -33,6 +25,14 @@ import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.support.Parameter;
import org.apache.dubbo.rpc.model.ApplicationModel;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_VERSION_KEY;
@ -40,7 +40,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
import static org.apache.dubbo.common.constants.CommonConstants.DUMP_DIRECTORY;
import static org.apache.dubbo.common.constants.CommonConstants.DUMP_ENABLE;
import static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE;
import static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_DEFAULT;
import static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_ISOLATION;
import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.LIVENESS_PROBE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METADATA_KEY;
@ -274,7 +274,7 @@ public class ApplicationConfig extends AbstractConfig {
}
}
if (executorManagementMode == null) {
executorManagementMode = EXECUTOR_MANAGEMENT_MODE_DEFAULT;
executorManagementMode = EXECUTOR_MANAGEMENT_MODE_ISOLATION;
}
if (enableFileCache == null) {
enableFileCache = Boolean.TRUE;

View File

@ -20,6 +20,7 @@ import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.config.nested.AggregationConfig;
import org.apache.dubbo.config.nested.PrometheusConfig;
import org.apache.dubbo.config.nested.HistogramConfig;
import org.apache.dubbo.config.support.Nested;
import org.apache.dubbo.rpc.model.ApplicationModel;
@ -38,17 +39,22 @@ public class MetricsConfig extends AbstractConfig {
/**
* Enable jvm metrics when collecting.
*/
private Boolean enableJvmMetrics;
private Boolean enableJvm;
/**
* Enable threadpool metrics when collecting.
*/
private Boolean enableThreadpool;
/**
* Enable registry metrics.
*/
private Boolean enableRegistryMetrics;
private Boolean enableRegistry;
/**
* Enable metadata metrics.
*/
private Boolean enableMetadataMetrics;
private Boolean enableMetadata;
/**
* @deprecated After metrics config is refactored.
@ -69,6 +75,9 @@ public class MetricsConfig extends AbstractConfig {
@Nested
private AggregationConfig aggregation;
@Nested
private HistogramConfig histogram;
private String exportServiceProtocol;
private Integer exportServicePort;
@ -100,20 +109,20 @@ public class MetricsConfig extends AbstractConfig {
this.protocol = protocol;
}
public Boolean getEnableJvmMetrics() {
return enableJvmMetrics;
public Boolean getEnableJvm() {
return enableJvm;
}
public void setEnableJvmMetrics(Boolean enableJvmMetrics) {
this.enableJvmMetrics = enableJvmMetrics;
public void setEnableJvm(Boolean enableJvm) {
this.enableJvm = enableJvm;
}
public Boolean getEnableRegistryMetrics() {
return enableRegistryMetrics;
public Boolean getEnableRegistry() {
return enableRegistry;
}
public void setEnableRegistryMetrics(Boolean enableRegistryMetrics) {
this.enableRegistryMetrics = enableRegistryMetrics;
public void setEnableRegistry(Boolean enableRegistry) {
this.enableRegistry = enableRegistry;
}
public String getPort() {
@ -140,6 +149,14 @@ public class MetricsConfig extends AbstractConfig {
this.aggregation = aggregation;
}
public HistogramConfig getHistogram() {
return histogram;
}
public void setHistogram(HistogramConfig histogram) {
this.histogram = histogram;
}
public String getExportServiceProtocol() {
return exportServiceProtocol;
}
@ -156,12 +173,19 @@ public class MetricsConfig extends AbstractConfig {
this.exportServicePort = exportServicePort;
}
public Boolean getEnableMetadataMetrics() {
return enableMetadataMetrics;
public Boolean getEnableMetadata() {
return enableMetadata;
}
public void setEnableMetadataMetrics(Boolean enableMetadataMetrics) {
this.enableMetadataMetrics = enableMetadataMetrics;
public void setEnableMetadata(Boolean enableMetadata) {
this.enableMetadata = enableMetadata;
}
public Boolean getEnableThreadpool() {
return enableThreadpool;
}
public void setEnableThreadpool(Boolean enableThreadpool) {
this.enableThreadpool = enableThreadpool;
}
}

View File

@ -0,0 +1,90 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config;
import org.apache.dubbo.config.nested.BaggageConfig;
import org.apache.dubbo.config.nested.PropagationConfig;
import org.apache.dubbo.config.nested.SamplingConfig;
import org.apache.dubbo.config.support.Nested;
import org.apache.dubbo.rpc.model.ApplicationModel;
/**
* TracingConfig
*/
public class TracingConfig extends AbstractConfig {
private static final long serialVersionUID = -9089919311611546383L;
private Boolean enabled = false;
/**
* Sampling configuration.
*/
@Nested
private SamplingConfig sampling = new SamplingConfig();
/**
* Baggage configuration.
*/
@Nested
private BaggageConfig baggage = new BaggageConfig();
/**
* Propagation configuration.
*/
@Nested
private PropagationConfig propagation = new PropagationConfig();
public TracingConfig() {
}
public TracingConfig(ApplicationModel applicationModel) {
super(applicationModel);
}
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public SamplingConfig getSampling() {
return sampling;
}
public void setSampling(SamplingConfig sampling) {
this.sampling = sampling;
}
public BaggageConfig getBaggage() {
return baggage;
}
public void setBaggage(BaggageConfig baggage) {
this.baggage = baggage;
}
public PropagationConfig getPropagation() {
return propagation;
}
public void setPropagation(PropagationConfig propagation) {
this.propagation = propagation;
}
}

View File

@ -39,6 +39,7 @@ import org.apache.dubbo.config.ReferenceConfigBase;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfigBase;
import org.apache.dubbo.config.SslConfig;
import org.apache.dubbo.config.TracingConfig;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ScopeModel;
import org.apache.dubbo.rpc.model.ScopeModelUtil;
@ -92,6 +93,7 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
uniqueConfigTypes.add(ApplicationConfig.class);
uniqueConfigTypes.add(MonitorConfig.class);
uniqueConfigTypes.add(MetricsConfig.class);
uniqueConfigTypes.add(TracingConfig.class);
uniqueConfigTypes.add(SslConfig.class);
// unique config in each module
@ -127,7 +129,7 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
// dubbo.config.ignore-duplicated-interface
String ignoreDuplicatedInterfaceStr = (String) configuration
.getProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE);
.getProperty(ConfigKeys.DUBBO_CONFIG_IGNORE_DUPLICATED_INTERFACE);
if (ignoreDuplicatedInterfaceStr != null) {
this.ignoreDuplicatedInterface = Boolean.parseBoolean(ignoreDuplicatedInterfaceStr);
}
@ -192,7 +194,7 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
* @throws IllegalStateException
*/
private <C extends AbstractConfig> C addIfAbsent(C config, Map<String, C> configsMap)
throws IllegalStateException {
throws IllegalStateException {
if (config == null || configsMap == null) {
return config;
@ -216,8 +218,8 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
if (existedConfig != null && !isEquals(existedConfig, config)) {
String type = config.getClass().getSimpleName();
logger.warn(COMMON_UNEXPECTED_EXCEPTION, "", "", String.format("Duplicate %s found, there already has one default %s or more than two %ss have the same id, " +
"you can try to give each %s a different id, override previous config with later config. id: %s, prev: %s, later: %s",
type, type, type, type, key, existedConfig, config));
"you can try to give each %s a different id, override previous config with later config. id: %s, prev: %s, later: %s",
type, type, type, type, key, existedConfig, config));
}
// override existed config if any
@ -252,7 +254,7 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
return null;
} else if (size > 1) {
throw new IllegalStateException("Expected single instance of " + configType + ", but found " + size +
" instances, please remove redundant configs. instances: " + configsMap.values());
" instances, please remove redundant configs. instances: " + configsMap.values());
}
return (C) configsMap.values().iterator().next();
}
@ -335,11 +337,11 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
// try to find config by name
if (ReflectUtils.hasMethod(cls, CONFIG_NAME_READ_METHOD)) {
List<C> list = configsMap.values().stream()
.filter(cfg -> name.equals(getConfigName(cfg)))
.collect(Collectors.toList());
.filter(cfg -> name.equals(getConfigName(cfg)))
.collect(Collectors.toList());
if (list.size() > 1) {
throw new IllegalStateException("Found more than one config by name: " + name +
", instances: " + list + ". Please remove redundant configs or get config by id.");
", instances: " + list + ". Please remove redundant configs or get config by id.");
} else if (list.size() == 1) {
return list.get(0);
}
@ -364,8 +366,8 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
// 2. find equal config
prevConfig = values.stream()
.filter(val -> isEquals(val, config))
.findFirst();
.filter(val -> isEquals(val, config))
.findFirst();
return prevConfig;
}
@ -408,18 +410,18 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
static <C extends AbstractConfig> List<C> getDefaultConfigs(Map<String, C> configsMap) {
// find isDefault() == true
List<C> list = configsMap.values()
.stream()
.filter(c -> TRUE.equals(AbstractConfigManager.isDefaultConfig(c)))
.collect(Collectors.toList());
.stream()
.filter(c -> TRUE.equals(AbstractConfigManager.isDefaultConfig(c)))
.collect(Collectors.toList());
if (list.size() > 0) {
return list;
}
// find isDefault() == null
list = configsMap.values()
.stream()
.filter(c -> AbstractConfigManager.isDefaultConfig(c) == null)
.collect(Collectors.toList());
.stream()
.filter(c -> AbstractConfigManager.isDefaultConfig(c) == null)
.collect(Collectors.toList());
return list;
// exclude isDefault() == false
@ -430,7 +432,7 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
C oldOne = configsMap.values().iterator().next();
String configName = oldOne.getClass().getSimpleName();
String msgPrefix = "Duplicate Configs found for " + configName + ", only one unique " + configName +
" is allowed for one application. previous: " + oldOne + ", later: " + config + ". According to config mode [" + configMode + "], ";
" is allowed for one application. previous: " + oldOne + ", later: " + config + ". According to config mode [" + configMode + "], ";
switch (configMode) {
case STRICT: {
if (!isEquals(oldOne, config)) {
@ -625,9 +627,10 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
*/
protected <T extends AbstractConfig> boolean isRequired(Class<T> clazz) {
if (clazz == RegistryConfig.class ||
clazz == MetadataReportConfig.class ||
clazz == MonitorConfig.class ||
clazz == MetricsConfig.class) {
clazz == MetadataReportConfig.class ||
clazz == MonitorConfig.class ||
clazz == MetricsConfig.class ||
clazz == TracingConfig.class) {
return false;
}
return true;

View File

@ -32,6 +32,7 @@ import org.apache.dubbo.config.MonitorConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.SslConfig;
import org.apache.dubbo.config.TracingConfig;
import org.apache.dubbo.rpc.model.ApplicationModel;
import java.util.Arrays;
@ -59,8 +60,8 @@ public class ConfigManager extends AbstractConfigManager implements ApplicationE
public ConfigManager(ApplicationModel applicationModel) {
super(applicationModel, Arrays.asList(ApplicationConfig.class, MonitorConfig.class,
MetricsConfig.class, SslConfig.class, ProtocolConfig.class, RegistryConfig.class, ConfigCenterConfig.class,
MetadataReportConfig.class));
MetricsConfig.class, SslConfig.class, ProtocolConfig.class, RegistryConfig.class, ConfigCenterConfig.class,
MetadataReportConfig.class, TracingConfig.class));
}
@ -105,6 +106,15 @@ public class ConfigManager extends AbstractConfigManager implements ApplicationE
return ofNullable(getSingleConfig(getTagName(MetricsConfig.class)));
}
@DisableInject
public void setTracing(TracingConfig tracing) {
addConfig(tracing);
}
public Optional<TracingConfig> getTracing() {
return ofNullable(getSingleConfig(getTagName(TracingConfig.class)));
}
@DisableInject
public void setSsl(SslConfig sslConfig) {
addConfig(sslConfig);
@ -223,6 +233,7 @@ public class ConfigManager extends AbstractConfigManager implements ApplicationE
getApplication().ifPresent(ApplicationConfig::refresh);
getMonitor().ifPresent(MonitorConfig::refresh);
getMetrics().ifPresent(MetricsConfig::refresh);
getTracing().ifPresent(TracingConfig::refresh);
getSsl().ifPresent(SslConfig::refresh);
getProtocols().forEach(ProtocolConfig::refresh);
@ -243,6 +254,8 @@ public class ConfigManager extends AbstractConfigManager implements ApplicationE
// load dubbo.metrics.xxx
loadConfigsOfTypeFromProps(MetricsConfig.class);
loadConfigsOfTypeFromProps(TracingConfig.class);
// load multiple config types:
// load dubbo.protocols.xxx
loadConfigsOfTypeFromProps(ProtocolConfig.class);
@ -269,12 +282,13 @@ public class ConfigManager extends AbstractConfigManager implements ApplicationE
private void checkConfigs() {
// check config types (ignore metadata-center)
List<Class<? extends AbstractConfig>> multipleConfigTypes = Arrays.asList(
ApplicationConfig.class,
ProtocolConfig.class,
RegistryConfig.class,
MonitorConfig.class,
MetricsConfig.class,
SslConfig.class);
ApplicationConfig.class,
ProtocolConfig.class,
RegistryConfig.class,
MonitorConfig.class,
MetricsConfig.class,
TracingConfig.class,
SslConfig.class);
for (Class<? extends AbstractConfig> configType : multipleConfigTypes) {
checkDefaultAndValidateConfigs(configType);
@ -290,7 +304,7 @@ public class ConfigManager extends AbstractConfigManager implements ApplicationE
ProtocolConfig prevProtocol = protocolPortMap.get(port);
if (prevProtocol != null) {
throw new IllegalStateException("Duplicated port used by protocol configs, port: " + port +
", configs: " + Arrays.asList(prevProtocol, protocol));
", configs: " + Arrays.asList(prevProtocol, protocol));
}
protocolPortMap.put(port, protocol);
}

View File

@ -36,6 +36,7 @@ import org.apache.dubbo.config.ReferenceConfigBase;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfigBase;
import org.apache.dubbo.config.SslConfig;
import org.apache.dubbo.config.TracingConfig;
import org.apache.dubbo.rpc.model.ModuleModel;
import java.util.Arrays;
@ -352,6 +353,10 @@ public class ModuleConfigManager extends AbstractConfigManager implements Module
return applicationConfigManager.getMetrics();
}
public Optional<TracingConfig> getTracing() {
return applicationConfigManager.getTracing();
}
public Optional<SslConfig> getSsl() {
return applicationConfigManager.getSsl();
}

View File

@ -0,0 +1,96 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.nested;
import org.apache.dubbo.config.support.Nested;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class BaggageConfig implements Serializable {
private Boolean enabled = true;
/**
* Correlation configuration.
*/
@Nested
private Correlation correlation = new Correlation();
/**
* List of fields that are referenced the same in-process as it is on the wire.
* For example, the field "x-vcap-request-id" would be set as-is including the
* prefix.
*/
private List<String> remoteFields = new ArrayList<>();
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Correlation getCorrelation() {
return correlation;
}
public void setCorrelation(Correlation correlation) {
this.correlation = correlation;
}
public List<String> getRemoteFields() {
return remoteFields;
}
public void setRemoteFields(List<String> remoteFields) {
this.remoteFields = remoteFields;
}
public static class Correlation implements Serializable {
/**
* Whether to enable correlation of the baggage context with logging contexts.
*/
private boolean enabled = true;
/**
* List of fields that should be correlated with the logging context. That
* means that these fields would end up as key-value pairs in e.g. MDC.
*/
private List<String> fields = new ArrayList<>();
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public List<String> getFields() {
return this.fields;
}
public void setFields(List<String> fields) {
this.fields = fields;
}
}
}

View File

@ -0,0 +1,93 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.nested;
import java.io.Serializable;
public class HistogramConfig implements Serializable {
private Boolean enabled;
private Integer[] bucketsMs;
private Integer minExpectedMs;
private Integer maxExpectedMs;
private Boolean enabledPercentiles;
private double[] percentiles;
private Integer distributionStatisticExpiryMin;
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Integer[] getBucketsMs() {
return bucketsMs;
}
public void setBucketsMs(Integer[] bucketsMs) {
this.bucketsMs = bucketsMs;
}
public Integer getMinExpectedMs() {
return minExpectedMs;
}
public void setMinExpectedMs(Integer minExpectedMs) {
this.minExpectedMs = minExpectedMs;
}
public Integer getMaxExpectedMs() {
return maxExpectedMs;
}
public void setMaxExpectedMs(Integer maxExpectedMs) {
this.maxExpectedMs = maxExpectedMs;
}
public Boolean getEnabledPercentiles() {
return enabledPercentiles;
}
public void setEnabledPercentiles(Boolean enabledPercentiles) {
this.enabledPercentiles = enabledPercentiles;
}
public double[] getPercentiles() {
return percentiles;
}
public void setPercentiles(double[] percentiles) {
this.percentiles = percentiles;
}
public Integer getDistributionStatisticExpiryMin() {
return distributionStatisticExpiryMin;
}
public void setDistributionStatisticExpiryMin(Integer distributionStatisticExpiryMin) {
this.distributionStatisticExpiryMin = distributionStatisticExpiryMin;
}
}

View File

@ -14,27 +14,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.nested;
package org.apache.dubbo.metrics.event;
import java.io.Serializable;
/**
* RequestEvent.
*/
public class RequestEvent extends MetricsEvent {
private Type type;
public class PropagationConfig implements Serializable {
public RequestEvent(Object source, Type type) {
super(source);
this.type = type;
}
public static final String B3 = "B3";
public Type getType() {
public static final String W3C = "W3C";
/**
* Tracing context propagation type.
*/
private String type = W3C;
public String getType() {
return type;
}
public void setType(Type type) {
public void setType(String type) {
this.type = type;
}
}

View File

@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.nested;
import java.io.Serializable;
public class SamplingConfig implements Serializable {
/**
* Probability in the range from 0.0 to 1.0 that a trace will be sampled.
*/
private float probability = 0.10f;
public float getProbability() {
return this.probability;
}
public void setProbability(float probability) {
this.probability = probability;
}
}

View File

@ -114,7 +114,7 @@ public final class ServiceDefinitionBuilder {
*/
public static String schema(final Class<?> clazz) {
ServiceDefinition sd = build(clazz);
return JsonUtils.getJson().toJson(sd);
return JsonUtils.toJson(sd);
}
private ServiceDefinitionBuilder() {

View File

@ -50,15 +50,17 @@ public abstract class AbstractIsolationExecutorSupport implements ExecutorSuppor
for (URL serviceUrl : serviceUrls) {
if (serviceUrl.getProtocol().equals(url.getProtocol()) && serviceUrl.getPort() == url.getPort()) {
return executorRepository.getExecutor(serviceUrl);
return executorRepository.getExecutor(providerModel, serviceUrl);
}
}
return executorRepository.getExecutor(serviceUrls.get(0));
return executorRepository.getExecutor(providerModel, serviceUrls.get(0));
}
protected abstract ServiceKey getServiceKey(Object data);
protected ServiceKey getServiceKey(Object data) {
return null;
}
private ProviderModel getProviderModel(Object data) {
protected ProviderModel getProviderModel(Object data) {
ServiceKey serviceKey = getServiceKey(data);
if (serviceKey == null) {
return null;

View File

@ -0,0 +1,26 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.rpc.executor;
import org.apache.dubbo.common.URL;
public class DefaultIsolationExecutorSupportFactory implements IsolationExecutorSupportFactory {
@Override
public ExecutorSupport createIsolationExecutorSupport(URL url) {
return new DefaultExecutorSupport(url);
}
}

View File

@ -17,23 +17,19 @@
package org.apache.dubbo.rpc.executor;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.rpc.model.ApplicationModel;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
@SPI
@SPI("default")
public interface IsolationExecutorSupportFactory {
@Adaptive(PROTOCOL_KEY)
ExecutorSupport createIsolationExecutorSupport(URL url);
static ExecutorSupport getIsolationExecutorSupport(URL url) {
ApplicationModel applicationModel = url.getOrDefaultApplicationModel();
ExtensionLoader<IsolationExecutorSupportFactory> extensionLoader = applicationModel.getExtensionLoader(IsolationExecutorSupportFactory.class);
IsolationExecutorSupportFactory factory = extensionLoader.getAdaptiveExtension();
IsolationExecutorSupportFactory factory = extensionLoader.getOrDefaultExtension(url.getProtocol());
return factory.createIsolationExecutorSupport(url);
}

View File

@ -43,7 +43,7 @@ import java.util.concurrent.locks.Lock;
* returned from them are of process scope. If you want to support multiple dubbo servers in one
* single process, you may need to refactor those three classes.
* <p>
* Represent a application which is using Dubbo and store basic metadata info for using
* Represent an application which is using Dubbo and store basic metadata info for using
* during the processing of RPC invoking.
* <p>
* ApplicationModel includes many ProviderModel which is about published services

View File

@ -16,7 +16,6 @@
*/
package org.apache.dubbo.rpc.model;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.utils.ConcurrentHashMapUtils;
import org.apache.dubbo.common.utils.StringUtils;
@ -45,9 +44,6 @@ public class FrameworkServiceRepository {
// useful to find a provider model quickly with serviceInterfaceName:version
private final ConcurrentMap<String, List<ProviderModel>> providersWithoutGroup = new ConcurrentHashMap<>();
// useful to find a url quickly with serviceInterfaceName:version
private final ConcurrentMap<String, List<URL>> providerUrlsWithoutGroup = new ConcurrentHashMap<>();
public FrameworkServiceRepository(FrameworkModel frameworkModel) {
this.frameworkModel = frameworkModel;
}
@ -67,7 +63,6 @@ public class FrameworkServiceRepository {
providers.remove(providerModel.getServiceKey());
String keyWithoutGroup = keyWithoutGroup(providerModel.getServiceKey());
providersWithoutGroup.remove(keyWithoutGroup);
providerUrlsWithoutGroup.remove(keyWithoutGroup);
}
public ProviderModel lookupExportedServiceWithoutGroup(String key) {
@ -83,18 +78,10 @@ public class FrameworkServiceRepository {
return providersWithoutGroup.get(key);
}
public void registerProviderUrl(URL url) {
ConcurrentHashMapUtils.computeIfAbsent(providerUrlsWithoutGroup, keyWithoutGroup(url.getServiceKey()), (k) -> new CopyOnWriteArrayList<>()).add(url);
}
public ProviderModel lookupExportedService(String serviceKey) {
return providers.get(serviceKey);
}
public List<URL> lookupRegisteredProviderUrlsWithoutGroup(String key) {
return providerUrlsWithoutGroup.get(key);
}
public List<ProviderModel> allProviderModels() {
return Collections.unmodifiableList(new ArrayList<>(providers.values()));
}

View File

@ -35,6 +35,17 @@ public interface PackableMethod {
byte[] pack(Object obj) throws IOException;
}
interface WrapperUnPack extends UnPack {
default Object unpack(byte[] data) throws IOException, ClassNotFoundException {
return unpack(data, false);
}
Object unpack(byte[] data, boolean isReturnTriException) throws IOException, ClassNotFoundException;
}
interface UnPack {
/**
@ -44,6 +55,7 @@ public interface PackableMethod {
* @throws ClassNotFoundException when no class found
*/
Object unpack(byte[] data) throws IOException, ClassNotFoundException;
}
default Object parseRequest(byte[] data) throws IOException, ClassNotFoundException {
@ -51,7 +63,15 @@ public interface PackableMethod {
}
default Object parseResponse(byte[] data) throws IOException, ClassNotFoundException {
return getResponseUnpack().unpack(data);
return parseResponse(data, false);
}
default Object parseResponse(byte[] data, boolean isReturnTriException) throws IOException, ClassNotFoundException {
UnPack unPack = getResponseUnpack();
if (unPack instanceof WrapperUnPack) {
return ((WrapperUnPack) unPack).unpack(data, isReturnTriException);
}
return unPack.unpack(data);
}
default byte[] packRequest(Object request) throws IOException {

View File

@ -116,18 +116,18 @@ public class GenericException extends RuntimeException {
if(this.useCause) {
return getCause().getMessage();
}
return JsonUtils.getJson().toJson(GenericExceptionInfo.createNoStackTrace(genericExceptionInfo));
return JsonUtils.toJson(GenericExceptionInfo.createNoStackTrace(genericExceptionInfo));
}
public String getGenericException() {
if(this.useCause) {
return ((GenericException)getCause()).getGenericException();
}
return JsonUtils.getJson().toJson(genericExceptionInfo);
return JsonUtils.toJson(genericExceptionInfo);
}
public void setGenericException(String json) {
GenericExceptionInfo info = JsonUtils.getJson().toJavaObject(json, GenericExceptionInfo.class);
GenericExceptionInfo info = JsonUtils.toJavaObject(json, GenericExceptionInfo.class);
if(info == null) {
return;
}

View File

@ -0,0 +1 @@
default=org.apache.dubbo.rpc.executor.DefaultIsolationExecutorSupportFactory

View File

@ -125,6 +125,8 @@ java.util.TreeMap
java.util.TreeSet
java.util.UUID
java.util.WeakHashMap
org.apache.dubbo
com.alibaba.dubbo
org.apache.dubbo.metadata.MetadataInfo
com.alibaba.com.caucho.hessian.io
com.alibaba.dubbo.rpc.service.GenericException
org.apache.dubbo.rpc.service.GenericException
org.apache.dubbo.rpc.RpcException

View File

@ -16,6 +16,7 @@
*/
package org.apache.dubbo.common;
import org.apache.dubbo.common.url.component.ServiceConfigURL;
import org.apache.dubbo.common.utils.NetUtils;
import org.junit.jupiter.api.Test;
@ -47,6 +48,24 @@ class URLBuilderTest {
assertThat(url2.getVersion(), equalTo("1"));
}
@Test
void testDefault() {
ServiceConfigURL url1 = URLBuilder.from(URL.valueOf(""))
.addParameter("timeout", "1234")
.addParameter("default.timeout", "5678")
.build();
assertThat(url1.getParameter("timeout"), equalTo("1234"));
assertThat(url1.getParameter("default.timeout"), equalTo("5678"));
ServiceConfigURL url2 = URLBuilder.from(URL.valueOf(""))
.addParameter("default.timeout", "5678")
.build();
assertThat(url2.getParameter("timeout"), equalTo("5678"));
assertThat(url2.getParameter("default.timeout"), equalTo("5678"));
}
@Test
void shouldSet() {
URL url1 = URL.valueOf("dubbo://admin:hello1234@10.20.130.230:20880/context/path?version=1.0.0&application=morgan");
@ -145,4 +164,4 @@ class URLBuilderTest {
assertThat(url2.getParameter("version"), equalTo("1.0.0"));
assertThat(url2.getParameter("absentKey"), equalTo("absentValue"));
}
}
}

View File

@ -45,6 +45,8 @@ class URLStrParserTest {
testCases.add("dubbo://fe80:0:0:0:894:aeec:f37d:23e1%en0/path?abc=abc");
testCases.add("dubbo://[fe80:0:0:0:894:aeec:f37d:23e1]:20880/path?abc=abc");
testCases.add("nacos://192.168.1.1:8848?username=&password=");
testCases.add("dubbo://127.0.0.1?timeout=1234&default.timeout=5678");
testCases.add("dubbo://127.0.0.1?default.timeout=5678");
errorDecodedCases.add("dubbo:192.168.1.1");
errorDecodedCases.add("://192.168.1.1");
@ -81,4 +83,15 @@ class URLStrParserTest {
});
}
@Test
void testDefault() {
URL url1 = URLStrParser.parseEncodedStr(URL.encode("dubbo://127.0.0.1?timeout=1234&default.timeout=5678"));
assertThat(url1.getParameter("timeout"), equalTo("1234"));
assertThat(url1.getParameter("default.timeout"), equalTo("5678"));
URL url2 = URLStrParser.parseEncodedStr(URL.encode("dubbo://127.0.0.1?default.timeout=5678"));
assertThat(url2.getParameter("timeout"), equalTo("5678"));
assertThat(url2.getParameter("default.timeout"), equalTo("5678"));
}
}

View File

@ -59,6 +59,17 @@ class URLTest {
assertEquals("org.apache.dubbo.config.RegistryConfig#0", url.getParameter("id"));
}
@Test
void testDefault() {
URL url1 = URL.valueOf("dubbo://127.0.0.1:12345?timeout=1234&default.timeout=5678");
assertEquals(1234, url1.getParameter("timeout", 0));
assertEquals(5678, url1.getParameter("default.timeout", 0));
URL url2 = URL.valueOf("dubbo://127.0.0.1:12345?default.timeout=5678");
assertEquals(5678, url2.getParameter("timeout", 0));
assertEquals(5678, url2.getParameter("default.timeout", 0));
}
@Test
void test_valueOf_noProtocolAndHost() throws Exception {
URL url = URL.valueOf("/context/path?version=1.0.0&application=morgan");

View File

@ -60,22 +60,22 @@ class ClassUtilsTest {
@Test
void testForName2() {
ClassUtils.forName("boolean");
ClassUtils.forName("byte");
ClassUtils.forName("char");
ClassUtils.forName("short");
ClassUtils.forName("int");
ClassUtils.forName("long");
ClassUtils.forName("float");
ClassUtils.forName("double");
ClassUtils.forName("boolean[]");
ClassUtils.forName("byte[]");
ClassUtils.forName("char[]");
ClassUtils.forName("short[]");
ClassUtils.forName("int[]");
ClassUtils.forName("long[]");
ClassUtils.forName("float[]");
ClassUtils.forName("double[]");
Assertions.assertEquals(boolean.class, ClassUtils.forName("boolean"));
Assertions.assertEquals(byte.class, ClassUtils.forName("byte"));
Assertions.assertEquals(char.class, ClassUtils.forName("char"));
Assertions.assertEquals(short.class, ClassUtils.forName("short"));
Assertions.assertEquals(int.class, ClassUtils.forName("int"));
Assertions.assertEquals(long.class, ClassUtils.forName("long"));
Assertions.assertEquals(float.class, ClassUtils.forName("float"));
Assertions.assertEquals(double.class, ClassUtils.forName("double"));
Assertions.assertEquals(boolean[].class, ClassUtils.forName("boolean[]"));
Assertions.assertEquals(byte[].class, ClassUtils.forName("byte[]"));
Assertions.assertEquals(char[].class, ClassUtils.forName("char[]"));
Assertions.assertEquals(short[].class, ClassUtils.forName("short[]"));
Assertions.assertEquals(int[].class, ClassUtils.forName("int[]"));
Assertions.assertEquals(long[].class, ClassUtils.forName("long[]"));
Assertions.assertEquals(float[].class, ClassUtils.forName("float[]"));
Assertions.assertEquals(double[].class, ClassUtils.forName("double[]"));
}
@Test
@ -174,4 +174,4 @@ class ClassUtilsTest {
}
}
}
}

View File

@ -77,11 +77,11 @@ class EnvironmentTest {
// test getConfigurationMaps(AbstractConfig config, String prefix)
List<Map<String, String>> configurationMaps = environment.getConfigurationMaps(registryConfig, prefix);
Assertions.assertEquals(configurationMaps.size(), 7);
Assertions.assertEquals(7, configurationMaps.size());
// test getConfigurationMaps()
configurationMaps = environment.getConfigurationMaps();
Assertions.assertEquals(configurationMaps.size(), 6);
Assertions.assertEquals(6, configurationMaps.size());
CompositeConfiguration configuration1 = environment.getConfiguration();
CompositeConfiguration configuration2 = environment.getConfiguration();

View File

@ -17,10 +17,11 @@
package org.apache.dubbo.common.config.configcenter;
import org.apache.dubbo.common.config.configcenter.nop.NopDynamicConfigurationFactory;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.junit.jupiter.api.Test;
import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
@ -36,4 +37,8 @@ class DynamicConfigurationFactoryTest {
assertEquals(NopDynamicConfigurationFactory.class, factory.getClass());
assertEquals(NopDynamicConfigurationFactory.class, getExtensionLoader(DynamicConfigurationFactory.class).getExtension("nop").getClass());
}
}
private <T> ExtensionLoader<T> getExtensionLoader(Class<T> extClass) {
return ApplicationModel.defaultModel().getDefaultModule().getExtensionLoader(extClass);
}
}

View File

@ -16,13 +16,14 @@
*/
package org.apache.dubbo.common.convert;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.FrameworkModel;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
@ -60,4 +61,8 @@ class ConverterTest {
assertEquals(Boolean.FALSE, converterUtil.convertIfPossible("false", Boolean.class));
assertEquals(Double.valueOf(1), converterUtil.convertIfPossible("1", Double.class));
}
}
private <T> ExtensionLoader<T> getExtensionLoader(Class<T> extClass) {
return ApplicationModel.defaultModel().getDefaultModule().getExtensionLoader(extClass);
}
}

View File

@ -16,10 +16,12 @@
*/
package org.apache.dubbo.common.convert;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
@ -52,4 +54,8 @@ class StringToLongConverterTest {
converter.convert("ttt");
});
}
}
private <T> ExtensionLoader<T> getExtensionLoader(Class<T> extClass) {
return ApplicationModel.defaultModel().getDefaultModule().getExtensionLoader(extClass);
}
}

View File

@ -170,7 +170,7 @@ class ExtensionLoaderTest {
// get origin instance from wrapper
WrappedExt originImpl1 = impl1;
while (originImpl1 instanceof WrappedExtWrapper) {
originImpl1 = ((WrappedExtWrapper)originImpl1).getOrigin();
originImpl1 = ((WrappedExtWrapper) originImpl1).getOrigin();
}
// test unwrapped instance
@ -292,7 +292,7 @@ class ExtensionLoaderTest {
void test_getSupportedExtensions() {
Set<String> exts = getExtensionLoader(SimpleExt.class).getSupportedExtensions();
Set<String> expected = new HashSet<String>();
Set<String> expected = new HashSet<>();
expected.add("impl1");
expected.add("impl2");
expected.add("impl3");
@ -304,7 +304,7 @@ class ExtensionLoaderTest {
void test_getSupportedExtensions_wrapperIsNotExt() {
Set<String> exts = getExtensionLoader(WrappedExt.class).getSupportedExtensions();
Set<String> expected = new HashSet<String>();
Set<String> expected = new HashSet<>();
expected.add("impl1");
expected.add("impl2");
expected.add("impl3");
@ -720,7 +720,7 @@ class ExtensionLoaderTest {
void testDuplicatedImplWithoutOverriddenStrategy() {
List<LoadingStrategy> loadingStrategies = ExtensionLoader.getLoadingStrategies();
ExtensionLoader.setLoadingStrategies(new DubboExternalLoadingStrategyTest(false),
new DubboInternalLoadingStrategyTest(false));
new DubboInternalLoadingStrategyTest(false));
ExtensionLoader<DuplicatedWithoutOverriddenExt> extensionLoader = getExtensionLoader(DuplicatedWithoutOverriddenExt.class);
try {
extensionLoader.getExtension("duplicated");
@ -728,7 +728,7 @@ class ExtensionLoaderTest {
} catch (IllegalStateException expected) {
assertThat(expected.getMessage(), containsString("Failed to load extension class (interface: interface org.apache.dubbo.common.extension.duplicated.DuplicatedWithoutOverriddenExt"));
assertThat(expected.getMessage(), containsString("cause: Duplicate extension org.apache.dubbo.common.extension.duplicated.DuplicatedWithoutOverriddenExt name duplicated"));
}finally {
} finally {
//recover the loading strategies
ExtensionLoader.setLoadingStrategies(loadingStrategies.toArray(new LoadingStrategy[loadingStrategies.size()]));
}
@ -738,7 +738,7 @@ class ExtensionLoaderTest {
void testDuplicatedImplWithOverriddenStrategy() {
List<LoadingStrategy> loadingStrategies = ExtensionLoader.getLoadingStrategies();
ExtensionLoader.setLoadingStrategies(new DubboExternalLoadingStrategyTest(true),
new DubboInternalLoadingStrategyTest(true));
new DubboInternalLoadingStrategyTest(true));
ExtensionLoader<DuplicatedOverriddenExt> extensionLoader = getExtensionLoader(DuplicatedOverriddenExt.class);
DuplicatedOverriddenExt duplicatedOverriddenExt = extensionLoader.getExtension("duplicated");
assertEquals("DuplicatedOverriddenExt1", duplicatedOverriddenExt.echo());
@ -749,25 +749,25 @@ class ExtensionLoaderTest {
@Test
void testLoadByDubboInternalSPI() {
ExtensionLoader<SPI1> extensionLoader = getExtensionLoader(SPI1.class);
SPI1 spi1 = extensionLoader.getExtension("1",true);
SPI1 spi1 = extensionLoader.getExtension("1", true);
assertNotNull(spi1);
ExtensionLoader<SPI2> extensionLoader2 = getExtensionLoader(SPI2.class);
SPI2 spi2 = extensionLoader2.getExtension("2",true);
SPI2 spi2 = extensionLoader2.getExtension("2", true);
assertNotNull(spi2);
try {
ExtensionLoader<SPI3> extensionLoader3 = getExtensionLoader(SPI3.class);
SPI3 spi3 = extensionLoader3.getExtension("3",true);
SPI3 spi3 = extensionLoader3.getExtension("3", true);
assertNotNull(spi3);
}catch (IllegalStateException illegalStateException){
} catch (IllegalStateException illegalStateException) {
if (!illegalStateException.getMessage().contains("No such extension")) {
fail();
}
}
ExtensionLoader<SPI4> extensionLoader4 = getExtensionLoader(SPI4.class);
SPI4 spi4 = extensionLoader4.getExtension("4",true);
SPI4 spi4 = extensionLoader4.getExtension("4", true);
assertNotNull(spi4);
}
@ -780,7 +780,7 @@ class ExtensionLoaderTest {
}
/**
* The external {@link LoadingStrategy}, which can set if it support overridden
* The external {@link LoadingStrategy}, which can set if it supports overriding.
*/
private static class DubboExternalLoadingStrategyTest implements LoadingStrategy {
@ -832,4 +832,4 @@ class ExtensionLoaderTest {
return MAX_PRIORITY;
}
}
}
}

View File

@ -19,6 +19,8 @@ package org.apache.dubbo.common.extension;
import org.apache.dubbo.common.extension.compatible.CompatibleExt;
import org.apache.dubbo.common.extension.compatible.impl.CompatibleExtImpl1;
import org.apache.dubbo.common.extension.compatible.impl.CompatibleExtImpl2;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.junit.jupiter.api.Test;
@ -27,8 +29,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
class ExtensionLoader_Compatible_Test {
@Test
void test_getExtension() throws Exception {
assertTrue(ExtensionLoader.getExtensionLoader(CompatibleExt.class).getExtension("impl1") instanceof CompatibleExtImpl1);
assertTrue(ExtensionLoader.getExtensionLoader(CompatibleExt.class).getExtension("impl2") instanceof CompatibleExtImpl2);
void test_getExtension() {
ModuleModel moduleModel = ApplicationModel.defaultModel().getDefaultModule();
assertTrue(moduleModel.getExtensionLoader(CompatibleExt.class).getExtension("impl1") instanceof CompatibleExtImpl1);
assertTrue(moduleModel.getExtensionLoader(CompatibleExt.class).getExtension("impl2") instanceof CompatibleExtImpl2);
}
}
}

View File

@ -14,23 +14,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.model.person;
package org.apache.dubbo.metrics.event;
import java.io.Serializable;
public class ApplicationEvent extends MetricsEvent{
private ApplicationEvent.Type type;
public class Ageneric<T> implements Serializable {
public static String NAME = "A";
public ApplicationEvent(Object source, ApplicationEvent.Type type) {
super(source);
this.type = type;
private String name = NAME;
private T data;
public T getData() {
return data;
}
public ApplicationEvent.Type getType() {
return type;
public void setData(T data) {
this.data = data;
}
public void setType(ApplicationEvent.Type type) {
this.type = type;
public String getName() {
return name;
}
}

View File

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.model.person;
import java.io.Serializable;
public class Bgeneric<T> implements Serializable {
public static String NAME = "B";
private String name = NAME;
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getName() {
return name;
}
}

View File

@ -14,38 +14,43 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.rpc.protocol.rest.annotation.consumer;
package org.apache.dubbo.common.model.person;
import java.io.Serializable;
import org.apache.dubbo.common.serialize.Constants;
public class Cgeneric<T> implements Serializable {
public static String NAME = "C";
public class HttpConnectionConfig {
private String name = NAME;
private T data;
private Ageneric<T> a;
private Bgeneric<PersonInfo> b;
private int connectTimeout;
private int readTimeout;
private int chunkLength = 8196;
private byte serialization = Constants.FASTJSON2_SERIALIZATION_ID;
private int keepAlive = 60;
public int getConnectTimeout() {
return connectTimeout;
public T getData() {
return data;
}
public int getReadTimeout() {
return readTimeout;
public void setData(T data) {
this.data = data;
}
public int getChunkLength() {
return chunkLength;
public String getName() {
return name;
}
public byte getSerialization() {
return serialization;
public Ageneric<T> getA() {
return a;
}
public int getKeepAlive() {
return keepAlive;
public void setA(Ageneric<T> a) {
this.a = a;
}
public Bgeneric<PersonInfo> getB() {
return b;
}
public void setB(Bgeneric<PersonInfo> b) {
this.b = b;
}
}

View File

@ -0,0 +1,56 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.common.model.person;
import java.io.Serializable;
public class Dgeneric<T,Y,Z> implements Serializable {
public static String NAME = "D";
private String name = NAME;
private T t;
private Y y;
private Z z;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public Y getY() {
return y;
}
public void setY(Y y) {
this.y = y;
}
public Z getZ() {
return z;
}
public void setZ(Z z) {
this.z = z;
}
public String getName() {
return name;
}
}

View File

@ -75,13 +75,13 @@ class FrameworkStatusReportServiceTest {
// verify registrationStatus
Object registrationStatus = reportContent.get(REGISTRATION_STATUS);
Map<String, String> registrationMap = JsonUtils.getJson().toJavaObject(String.valueOf(registrationStatus), Map.class);
Map<String, String> registrationMap = JsonUtils.toJavaObject(String.valueOf(registrationStatus), Map.class);
Assertions.assertEquals(registrationMap.get("application"), "APP");
Assertions.assertEquals(registrationMap.get("status"), "instance");
// verify addressConsumptionStatus
Object addressConsumptionStatus = reportContent.get(ADDRESS_CONSUMPTION_STATUS);
Map<String, String> consumptionMap = JsonUtils.getJson().toJavaObject(String.valueOf(addressConsumptionStatus), Map.class);
Map<String, String> consumptionMap = JsonUtils.toJavaObject(String.valueOf(addressConsumptionStatus), Map.class);
Assertions.assertEquals(consumptionMap.get("application"), "APP");
Assertions.assertEquals(consumptionMap.get("service"), "Test");
Assertions.assertEquals(consumptionMap.get("status"), "status");
@ -91,7 +91,7 @@ class FrameworkStatusReportServiceTest {
// verify migrationStepStatus
Object migrationStepStatus = reportContent.get(MIGRATION_STEP_STATUS);
Map<String, String> migrationStepStatusMap = JsonUtils.getJson().toJavaObject(String.valueOf(migrationStepStatus), Map.class);
Map<String, String> migrationStepStatusMap = JsonUtils.toJavaObject(String.valueOf(migrationStepStatus), Map.class);
Assertions.assertEquals(migrationStepStatusMap.get("originStep"), "FORCE_INTERFACE");
Assertions.assertEquals(migrationStepStatusMap.get("application"), "APP");
Assertions.assertEquals(migrationStepStatusMap.get("service"), "Test");

Some files were not shown because too many files have changed in this diff Show More