Feature improvement, only register one url for port unification. (#12528)

This commit is contained in:
Ken Liu 2023-08-30 21:48:57 +08:00 committed by GitHub
parent 186ec674bf
commit 8e55dae8f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 262 additions and 92 deletions

View File

@ -641,7 +641,13 @@ public interface CommonConstants {
String REST_SERVICE_DEPLOYER_URL_ATTRIBUTE_KEY = "restServiceDeployerAttributeKey";
String SERVICE_DEPLOYER_ATTRIBUTE_KEY = "serviceDeployer"; String RESTEASY_NETTY_HTTP_REQUEST_ATTRIBUTE_KEY = "resteasyNettyHttpRequest";
String SERVICE_DEPLOYER_ATTRIBUTE_KEY = "serviceDeployer";
String RESTEASY_NETTY_HTTP_REQUEST_ATTRIBUTE_KEY = "resteasyNettyHttpRequest";
String DUBBO_MANUAL_REGISTER_KEY = "dubbo.application.manual-register";
String EXT_PROTOCOL = "ext.protocol";
String IS_EXTRA = "isExtra";
}

View File

@ -48,7 +48,9 @@ public interface ApplicationDeployer extends Deployer<ApplicationModel> {
/**
* Register application instance and start internal services
*/
void prepareApplicationInstance();
void prepareApplicationInstance(ModuleModel moduleModel);
void exportMetadataService();
/**
* Register application instance and start internal services

View File

@ -50,4 +50,8 @@ public interface ModuleDeployer extends Deployer<ModuleModel> {
* Whether start in background, do not await finish
*/
boolean isBackground();
boolean hasRegistryInteraction();
ApplicationDeployer getApplicationDeployer();
}

View File

@ -33,6 +33,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_PROTOCOL_KEY;
@ -82,6 +83,8 @@ public class ApplicationConfig extends AbstractConfig {
private static final long serialVersionUID = 5508512956753757169L;
private static final String DEFAULT_NAME_PREFIX = "DUBBO_APP_";
/**
* Application name
*/
@ -747,6 +750,12 @@ public class ApplicationConfig extends AbstractConfig {
public void refresh() {
super.refresh();
appendEnvironmentProperties();
if (StringUtils.isEmpty(getName())) {
String defaultName = DEFAULT_NAME_PREFIX + UUID.randomUUID();
this.setName(defaultName);
LOGGER.info("No application name was set, '" + defaultName + "' will be used as the default application name," +
" it's highly recommended to set a unique and customized name for it can be critical for some service governance features.");
}
}
private void appendEnvironmentProperties() {

View File

@ -76,6 +76,8 @@ import static org.apache.dubbo.common.constants.CommonConstants.DUBBO;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;
import static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_ISOLATION;
import static org.apache.dubbo.common.constants.CommonConstants.EXPORTER_LISTENER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.EXT_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.IS_EXTRA;
import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
@ -366,7 +368,17 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
mapServiceName(url, serviceNameMapping, scheduledExecutor);
}
});
onExported();
if (hasRegistrySpecified()) {
getScopeModel().getDeployer().getApplicationDeployer().exportMetadataService();
}
}
public boolean hasRegistrySpecified() {
return CollectionUtils.isNotEmpty(this.getRegistries())
|| CollectionUtils.isNotEmpty(getScopeModel().getApplicationModel().getApplicationConfigManager().getRegistries());
}
protected void mapServiceName(URL url, ServiceNameMapping serviceNameMapping, ScheduledExecutorService scheduledExecutor) {
@ -740,14 +752,13 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
// export to remote if the config is not local (export to local only when config is local)
if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
// export to extra protocol is used in remote export
String extProtocol = url.getParameter("ext.protocol", "");
String extProtocol = url.getParameter(EXT_PROTOCOL, "");
List<String> protocols = new ArrayList<>();
if (StringUtils.isNotBlank(extProtocol)) {
// export original url
url = URLBuilder.from(url).
addParameter(IS_PU_SERVER_KEY, Boolean.TRUE.toString()).
removeParameter("ext.protocol").
build();
}
@ -765,6 +776,8 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
if (StringUtils.isNotBlank(protocol)) {
URL localUrl = URLBuilder.from(url).
setProtocol(protocol).
addParameter(IS_EXTRA, Boolean.TRUE.toString()).
removeParameter(EXT_PROTOCOL).
build();
localUrl = exportRemote(localUrl, registryURLs, registerType);
if (!isGeneric(generic) && !getScopeModel().isInternal()) {

View File

@ -51,7 +51,7 @@ import static org.apache.dubbo.remoting.Constants.BIND_PORT_KEY;
public class InternalServiceConfigBuilder<T> {
private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass());
private static final Set<String> UNACCEPTABLE_PROTOCOL = Stream.of("rest", "grpc").collect(Collectors.toSet());
private static final Set<String> ACCEPTABLE_PROTOCOL = Stream.of("dubbo", "tri", "injvm").collect(Collectors.toSet());
private final ApplicationModel applicationModel;
private String protocol;
@ -112,19 +112,20 @@ public class InternalServiceConfigBuilder<T> {
*/
private String getRelatedOrDefaultProtocol() {
String protocol = "";
// <dubbo:consumer/>
List<ModuleModel> moduleModels = applicationModel.getPubModuleModels();
protocol = moduleModels.stream()
.map(ModuleModel::getConfigManager)
.map(ModuleConfigManager::getConsumers)
.filter(CollectionUtils::isNotEmpty)
.flatMap(Collection::stream)
.map(ConsumerConfig::getProtocol)
.filter(StringUtils::isNotEmpty)
.filter(p -> !UNACCEPTABLE_PROTOCOL.contains(p))
.findFirst()
.orElse("");
// <dubbo:protocol/>
if (StringUtils.isEmpty(protocol)) {
Collection<ProtocolConfig> protocols = applicationModel.getApplicationConfigManager().getProtocols();
if (CollectionUtils.isNotEmpty(protocols)) {
protocol = protocols.stream()
.map(ProtocolConfig::getName)
.filter(StringUtils::isNotEmpty)
.filter(p -> ACCEPTABLE_PROTOCOL.contains(p))
.findFirst()
.orElse("");
}
}
// <dubbo:provider/>
List<ModuleModel> moduleModels = applicationModel.getPubModuleModels();
if (StringUtils.isEmpty(protocol)) {
Stream<ProviderConfig> providerConfigStream = moduleModels.stream()
.map(ModuleModel::getConfigManager)
@ -145,22 +146,10 @@ public class InternalServiceConfigBuilder<T> {
}
})
.filter(StringUtils::isNotEmpty)
.filter(p -> !UNACCEPTABLE_PROTOCOL.contains(p))
.filter(p -> ACCEPTABLE_PROTOCOL.contains(p))
.findFirst()
.orElse("");
}
// <dubbo:protocol/>
if (StringUtils.isEmpty(protocol)) {
Collection<ProtocolConfig> protocols = applicationModel.getApplicationConfigManager().getProtocols();
if (CollectionUtils.isNotEmpty(protocols)) {
protocol = protocols.stream()
.map(ProtocolConfig::getName)
.filter(StringUtils::isNotEmpty)
.filter(p -> !UNACCEPTABLE_PROTOCOL.contains(p))
.findFirst()
.orElse("");
}
}
// <dubbo:application/>
if (StringUtils.isEmpty(protocol)) {
protocol = getApplicationConfig().getProtocol();
@ -171,7 +160,18 @@ public class InternalServiceConfigBuilder<T> {
}
}
}
return StringUtils.isNotEmpty(protocol) && !UNACCEPTABLE_PROTOCOL.contains(protocol) ? protocol : DUBBO_PROTOCOL;
// <dubbo:consumer/>
protocol = moduleModels.stream()
.map(ModuleModel::getConfigManager)
.map(ModuleConfigManager::getConsumers)
.filter(CollectionUtils::isNotEmpty)
.flatMap(Collection::stream)
.map(ConsumerConfig::getProtocol)
.filter(StringUtils::isNotEmpty)
.filter(p -> ACCEPTABLE_PROTOCOL.contains(p))
.findFirst()
.orElse("");
return StringUtils.isNotEmpty(protocol) && ACCEPTABLE_PROTOCOL.contains(protocol) ? protocol : DUBBO_PROTOCOL;
}
public InternalServiceConfigBuilder<T> protocol(String protocol) {
@ -254,7 +254,11 @@ public class InternalServiceConfigBuilder<T> {
logger.info("Using " + this.protocol + " protocol to export "+interfaceClass.getName()+" service on port " + protocolConfig.getPort());
applicationModel.getApplicationConfigManager().getProtocol(this.protocol)
.ifPresent(protocolConfig::mergeProtocol);
.ifPresent(p -> {
protocolConfig.mergeProtocol(p);
// clear extra protocols possibly merged from global ProtocolConfig
protocolConfig.setExtProtocol(null);
});
ApplicationConfig applicationConfig = getApplicationConfig();

View File

@ -183,13 +183,13 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
}
/**
* Close registration of instance for pure Consumer process by setting registerConsumer to 'false'
* by default is true.
* Enable registration of instance for pure Consumer process by setting registerConsumer to 'true'
* by default is false.
*/
private boolean isRegisterConsumerInstance() {
Boolean registerConsumer = getApplication().getRegisterConsumer();
if (registerConsumer == null) {
return true;
return false;
}
return Boolean.TRUE.equals(registerConsumer);
}
@ -746,7 +746,7 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
}
@Override
public void prepareApplicationInstance() {
public void prepareApplicationInstance(ModuleModel moduleModel) {
if (hasPreparedApplicationInstance.get()) {
return;
}
@ -754,8 +754,7 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
// export MetricsService
exportMetricsService();
if (isRegisterConsumerInstance()) {
exportMetadataService();
if (isRegisterConsumerInstance() || moduleModel.getDeployer().hasRegistryInteraction()) {
if (hasPreparedApplicationInstance.compareAndSet(false, true)) {
// register the local ServiceInstance if required
registerServiceInstance();
@ -763,6 +762,11 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
}
}
@Override
public synchronized void exportMetadataService() {
doExportMetadataService();
}
public void prepareInternalModule() {
if (hasPreparedInternalModule) {
return;
@ -1081,7 +1085,7 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
public void checkState(ModuleModel moduleModel, DeployState moduleState) {
synchronized (stateLock) {
if (!moduleModel.isInternal() && moduleState == DeployState.STARTED) {
prepareApplicationInstance();
prepareApplicationInstance(moduleModel);
}
DeployState newState = calculateState();
switch (newState) {
@ -1183,8 +1187,8 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
}
}
private void exportMetadataService() {
if (!isStarting()) {
private void doExportMetadataService() {
if (!isStarting() && !isStarted()) {
return;
}
for (DeployListener<ApplicationModel> listener : listeners) {

View File

@ -87,6 +87,9 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
private Boolean background;
private Boolean exportAsync;
private Boolean referAsync;
private boolean registryInteracted;
private CompletableFuture<?> exportFuture;
private CompletableFuture<?> referFuture;
@ -439,6 +442,10 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
exportedServices.add(sc);
}
}
if (serviceConfig.hasRegistrySpecified()) {
registryInteracted = true;
}
}
private void registerServiceInternal(ServiceConfigBase sc) {
@ -578,4 +585,13 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
this.initialize();
}
@Override
public boolean hasRegistryInteraction() {
return registryInteracted;
}
@Override
public ApplicationDeployer getApplicationDeployer() {
return applicationDeployer;
}
}

View File

@ -100,7 +100,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SE
import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_CLASS_NOT_FOUND;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_PARAMETER_FORMAT_ERROR;
import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_ALL;
import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_REGISTER_MODE_INSTANCE;
@ -464,7 +463,7 @@ public class ConfigValidationUtils {
try {
ClassUtils.forName("org.apache.dubbo.qos.protocol.QosProtocolWrapper");
} catch (ClassNotFoundException e) {
logger.warn(COMMON_CLASS_NOT_FOUND, "", "", "No QosProtocolWrapper class was found. Please check the dependency of dubbo-qos whether was imported correctly.", e);
logger.info("QosProtocolWrapper not found, qos will not be enabled, please check if 'dubbo-qos' dependency was imported correctly.");
}
}
}

View File

@ -37,7 +37,6 @@ import org.apache.dubbo.rpc.Protocol;
import org.apache.dubbo.rpc.ProxyFactory;
import org.apache.dubbo.rpc.cluster.filter.FilterChainBuilder;
import org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareClusterInvoker;
//import org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker;
import org.apache.dubbo.rpc.cluster.support.wrapper.ScopeClusterInvoker;
import org.apache.dubbo.rpc.listener.ListenerInvokerWrapper;
import org.apache.dubbo.rpc.model.ApplicationModel;
@ -1041,6 +1040,7 @@ class ReferenceConfigTest {
referenceConfig1.setRegistry(new RegistryConfig(zkUrl1));
referenceConfig1.setScopeModel(moduleModel);
referenceConfig1.setScope("remote");
referenceConfig1.setTimeout(30000);
Object object1 = referenceConfig1.get();
java.lang.reflect.Method callBean1 = object1.getClass().getDeclaredMethod("call", requestClazzOrigin);

View File

@ -186,8 +186,9 @@ class ServiceConfigTest {
assertThat(url.getParameters(), hasKey(METHODS_KEY));
assertThat(url.getParameters().get(METHODS_KEY), containsString("echo"));
assertThat(url.getParameters(), hasEntry(SIDE_KEY, PROVIDER));
// export MetadataService and DemoService in "mockprotocol2" protocol.
Mockito.verify(protocolDelegate, times(2)).export(Mockito.any(Invoker.class));
// export DemoService in "mockprotocol2" protocol.
Mockito.verify(protocolDelegate, times(1)).export(Mockito.any(Invoker.class));
// MetadataService will be exported on either dubbo or triple (the only two default acceptable protocol)
}
@Test
@ -351,8 +352,8 @@ class ServiceConfigTest {
assertThat(url.getParameters(), hasKey(METHODS_KEY));
assertThat(url.getParameters().get(METHODS_KEY), containsString("echo"));
assertThat(url.getParameters(), hasEntry(SIDE_KEY, PROVIDER));
// export MetadataService and DemoService in "mockprotocol2" protocol.
Mockito.verify(protocolDelegate, times(2)).export(Mockito.any(Invoker.class));
// export DemoService in "mockprotocol2" protocol (MetadataService will be not exported if no registry specified)
Mockito.verify(protocolDelegate, times(1)).export(Mockito.any(Invoker.class));
}
@Test

View File

@ -39,7 +39,6 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
@ -159,13 +158,9 @@ class MultipleRegistryCenterExportMetadataIntegrationTest implements Integration
// 1. Metadata Service exporter with Injvm protocol
// 2. MultipleRegistryCenterExportMetadataService exporter with Injvm protocol
Assertions.assertEquals(exporterListener.getExportedExporters().size(), 2);
List<Exporter<?>> injvmExporters = exporterListener.getExportedExporters()
.stream()
.filter(
exporter -> PROTOCOL_NAME.equalsIgnoreCase(exporter.getInvoker().getUrl().getProtocol())
).collect(Collectors.toList());
List<Exporter<?>> injvmExporters = exporterListener.getExportedExporters();
// Make sure there two injvmExporters
Assertions.assertEquals(injvmExporters.size(), 2);
Assertions.assertEquals(2, injvmExporters.size());
}
@AfterEach
@ -178,4 +173,4 @@ class MultipleRegistryCenterExportMetadataIntegrationTest implements Integration
serviceListener = null;
logger.info(getClass().getSimpleName() + " testcase is ending...");
}
}
}

View File

@ -39,7 +39,6 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
import static org.apache.dubbo.rpc.Constants.SCOPE_LOCAL;
@ -155,13 +154,9 @@ class SingleRegistryCenterExportMetadataIntegrationTest implements IntegrationTe
// 1. Metadata Service exporter with Injvm protocol
// 2. SingleRegistryCenterExportMetadataService exporter with Injvm protocol
Assertions.assertEquals(exporterListener.getExportedExporters().size(), 2);
List<Exporter<?>> injvmExporters = exporterListener.getExportedExporters()
.stream()
.filter(
exporter -> PROTOCOL_NAME.equalsIgnoreCase(exporter.getInvoker().getUrl().getProtocol())
).collect(Collectors.toList());
List<Exporter<?>> injvmExporters = exporterListener.getExportedExporters();
// Make sure there are 2 injvmExporters
Assertions.assertEquals(injvmExporters.size(), 2);
Assertions.assertEquals(2, injvmExporters.size());
}
@AfterEach
@ -174,4 +169,4 @@ class SingleRegistryCenterExportMetadataIntegrationTest implements IntegrationTe
serviceListener = null;
logger.info(getClass().getSimpleName() + " testcase is ending...");
}
}
}

View File

@ -69,7 +69,7 @@ class MetadataServiceURLParamsMetadataCustomizerTest {
}
@Test
void test() {
void test() throws InterruptedException {
DubboBootstrap providerBootstrap = DubboBootstrap.newInstance();
ServiceConfig<DemoService> serviceConfig = new ServiceConfig<>();
serviceConfig.setInterface(DemoService.class);
@ -90,8 +90,10 @@ class MetadataServiceURLParamsMetadataCustomizerTest {
ApplicationModel applicationModel = providerBootstrap.getApplicationModel();
MetadataServiceURLParamsMetadataCustomizer customizer = new MetadataServiceURLParamsMetadataCustomizer();
customizer.customize(instance, applicationModel);
Thread.sleep(5000);// wait for service delay export
customizer.customize(instance, applicationModel);
String val = instance.getMetadata().get(METADATA_SERVICE_URL_PARAMS_PROPERTY_NAME);
Assertions.assertNotNull(val);

View File

@ -30,9 +30,8 @@ import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.COMMON_CLASS_NOT_FOUND;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ -109,7 +108,7 @@ class ConfigValidationUtilsTest {
config.setQosEnable(true);
mock.validateApplicationConfig(config);
verify(loggerMock).warn(eq(COMMON_CLASS_NOT_FOUND), eq(""), eq(""), eq("No QosProtocolWrapper class was found. Please check the dependency of dubbo-qos whether was imported correctly."), any());
verify(loggerMock).info(anyString());
}
private void injectField(Field field, Object newValue) throws Exception {

View File

@ -32,7 +32,6 @@
<modules>
<module>dubbo-config-api</module>
<module>dubbo-config-spring</module>
<module>dubbo-config-spring6</module>
</modules>
<dependencies>
@ -49,4 +48,18 @@
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>spring6</id>
<activation>
<jdk>[17,)</jdk>
</activation>
<modules>
<module>dubbo-config-api</module>
<module>dubbo-config-spring</module>
<module>dubbo-config-spring6</module>
</modules>
</profile>
</profiles>
</project>

View File

@ -50,6 +50,7 @@ import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.CommonConstants.DOT_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_CHAR_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.IS_EXTRA;
import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
import static org.apache.dubbo.metadata.RevisionResolver.EMPTY_REVISION;
@ -240,7 +241,12 @@ public class MetadataInfo implements Serializable {
}
Set<ServiceInfo> subServices = subscribedServices.get(serviceKeyWithoutProtocol);
if (CollectionUtils.isNotEmpty(subServices)) {
return subServices.iterator().next();
List<ServiceInfo> validServices = subServices.stream().filter(serviceInfo -> StringUtils.isEmpty(serviceInfo.getParameter(IS_EXTRA))).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(validServices)) {
return validServices.iterator().next();
} else {
return subServices.iterator().next();
}
}
return null;
}

View File

@ -127,6 +127,7 @@ public class ServiceDiscoveryRegistry extends FailbackRegistry {
return factory.getServiceDiscovery(registryURL);
}
@Override
protected boolean shouldRegister(URL providerURL) {
String side = providerURL.getSide();

View File

@ -31,6 +31,7 @@ import org.apache.dubbo.common.utils.Assert;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.ConcurrentHashMapUtils;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.metadata.MetadataInfo;
import org.apache.dubbo.registry.AddressListener;
import org.apache.dubbo.registry.Constants;
@ -70,6 +71,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DISABLED_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INSTANCE_REGISTER_MODE;
import static org.apache.dubbo.common.constants.CommonConstants.IS_EXTRA;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_DESTROY_INVOKER;
@ -389,6 +391,14 @@ public class ServiceDiscoveryRegistryDirectory<T> extends DynamicDirectory<T> {
.getMatchedServiceInfos(consumerProtocolServiceKey)
.stream()
.filter(serviceInfo -> serviceInfo.getPort() <= 0 || serviceInfo.getPort() == port)
// special filter for extra protocols.
.filter(serviceInfo -> {
if (StringUtils.isNotEmpty(consumerProtocolServiceKey.getProtocol())) {// if consumer side protocol is specified, use all the protocols we got in hand now directly
return true;
} else {// if consumer side protocol is not specified, remove all extra protocols
return StringUtils.isEmpty(serviceInfo.getParameter(IS_EXTRA));
}
})
.map(MetadataInfo.ServiceInfo::getProtocolServiceKey)
.collect(Collectors.toList());

View File

@ -21,6 +21,7 @@ import org.apache.dubbo.common.constants.RegistryConstants;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.JsonUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.metadata.MetadataInfo;
@ -203,19 +204,21 @@ public class ServiceInstanceMetadataUtils {
}
public static void registerMetadataAndInstance(ApplicationModel applicationModel) {
LOGGER.info("Start registering instance address to registry.");
RegistryManager registryManager = applicationModel.getBeanFactory().getBean(RegistryManager.class);
// register service instance
List<ServiceDiscovery> serviceDiscoveries = registryManager.getServiceDiscoveries();
for (ServiceDiscovery serviceDiscovery : serviceDiscoveries) {
MetricsEventBus.post(RegistryEvent.toRegisterEvent(applicationModel,
Collections.singletonList(getServiceDiscoveryName(serviceDiscovery))),
() -> {
// register service instance
serviceDiscoveries.forEach(ServiceDiscovery::register);
return null;
}
);
if (CollectionUtils.isNotEmpty(registryManager.getServiceDiscoveries())) {
LOGGER.info("Start registering instance address to registry.");
List<ServiceDiscovery> serviceDiscoveries = registryManager.getServiceDiscoveries();
for (ServiceDiscovery serviceDiscovery : serviceDiscoveries) {
MetricsEventBus.post(RegistryEvent.toRegisterEvent(applicationModel,
Collections.singletonList(getServiceDiscoveryName(serviceDiscovery))),
() -> {
// register service instance
serviceDiscoveries.forEach(ServiceDiscovery::register);
return null;
}
);
}
}
}

View File

@ -61,10 +61,12 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.DISABLED_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_REGISTER_MODE;
import static org.apache.dubbo.common.constants.CommonConstants.EXT_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.PROTOCOL_FAILED_INIT_SERIALIZATION_OPTIMIZER;
@ -413,6 +415,11 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> {
}
URL url = mergeUrl(providerUrl);
// get the effective protocol that this consumer should consume based on consumer side protocol configuration and available protocols in address pool.
String effectiveProtocol = getEffectiveProtocol(queryProtocols, url);
if (!effectiveProtocol.equals(url.getProtocol())) {
url = url.setProtocol(effectiveProtocol);
}
// Cache key is url that does not merge with consumer side parameters,
// regardless of how the consumer combines parameters,
@ -453,6 +460,36 @@ public class RegistryDirectory<T> extends DynamicDirectory<T> {
return newUrlInvokerMap;
}
/**
* Get the protocol to consume by matching the consumer acceptable protocols and the available provider protocols.
* <p>
* Only one protocol will be used if consumer set to accept multiple protocols, for example, dubbo.consumer.protocol='tri,rest'.
*
* @param queryProtocols consumer side protocols.
* @param url provider url that have extra protocols specified.
* @return the protocol to consume.
*/
private String getEffectiveProtocol(String queryProtocols, URL url) {
String protocol = url.getProtocol();
if (StringUtils.isNotEmpty(queryProtocols)) {
String[] acceptProtocols = queryProtocols.split(COMMA_SEPARATOR);
String acceptedProtocol = acceptProtocols[0];
if (!acceptedProtocol.equals(url.getProtocol())) {
String extProtocols = url.getParameter(EXT_PROTOCOL);
if (StringUtils.isNotEmpty(extProtocols)) {
String[] extProtocolsArr = extProtocols.split(COMMA_SEPARATOR);
for (String p : extProtocolsArr) {
if (p.equalsIgnoreCase(acceptedProtocol)) {
protocol = acceptedProtocol;
break;
}
}
}
}
}
return protocol;
}
private boolean checkProtocolValid(String queryProtocols, URL providerUrl) {
// If protocol is configured at the reference side, only the matching protocol is selected
if (queryProtocols != null && queryProtocols.length() > 0) {

View File

@ -36,8 +36,9 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_NOTIFY_EVENT;
import static org.apache.dubbo.common.constants.CommonConstants.IS_EXTRA;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_NOTIFY_EVENT;
import static org.apache.dubbo.registry.Constants.DEFAULT_REGISTRY_RETRY_PERIOD;
import static org.apache.dubbo.registry.Constants.REGISTRY_RETRY_PERIOD_KEY;
@ -195,8 +196,7 @@ public abstract class FailbackRegistry extends AbstractRegistry {
@Override
public void register(URL url) {
if (!acceptable(url)) {
logger.info("URL " + url + " will not be registered to Registry. Registry " + this.getUrl() + " does not accept service of this protocol type.");
if (!shouldRegister(url)) {
return;
}
super.register(url);
@ -227,6 +227,18 @@ public abstract class FailbackRegistry extends AbstractRegistry {
}
}
protected boolean shouldRegister(URL providerURL) {
// extra protocol url must not be registered for interface based service discovery
if (providerURL.getParameter(IS_EXTRA, false)) {
return false;
}
if (!acceptable(providerURL)) {
logger.info("URL " + providerURL + " will not be registered to Registry. Registry " + this.getUrl() + " does not accept service of this protocol type.");
return false;
}
return true;
}
@Override
public void reExportRegister(URL url) {
if (!acceptable(url)) {

View File

@ -17,15 +17,22 @@
package org.apache.dubbo.remoting.api.pu;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.remoting.ChannelHandler;
import org.apache.dubbo.remoting.RemotingException;
import org.apache.dubbo.remoting.api.WireProtocol;
import org.apache.dubbo.remoting.transport.AbstractServer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.EXT_PROTOCOL;
public abstract class AbstractPortUnificationServer extends AbstractServer {
private final List<WireProtocol> protocols;
@ -44,7 +51,18 @@ public abstract class AbstractPortUnificationServer extends AbstractServer {
public AbstractPortUnificationServer(URL url, ChannelHandler handler) throws RemotingException {
super(url, handler);
this.protocols = url.getOrDefaultFrameworkModel().getExtensionLoader(WireProtocol.class).getActivateExtension(url, new String[0]);
ExtensionLoader<WireProtocol> loader = url.getOrDefaultFrameworkModel().getExtensionLoader(WireProtocol.class);
List<WireProtocol> extProtocols = new ArrayList<>();
// load main protocol
extProtocols.add(loader.getExtension(url.getProtocol()));
// load extra protocols
String extraProtocols = url.getParameter(EXT_PROTOCOL);
if (StringUtils.isNotEmpty(extraProtocols)) {
Arrays.stream(extraProtocols.split(COMMA_SEPARATOR)).forEach(p -> {
extProtocols.add(loader.getExtension(p));
});
}
this.protocols = extProtocols;
}
public List<WireProtocol> getProtocols() {

View File

@ -18,25 +18,43 @@ package org.apache.dubbo.remoting.transport.netty4;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.ExtensionDirector;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.threadpool.manager.DefaultExecutorRepository;
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.config.context.ModuleConfigManager;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.RemotingException;
import org.apache.dubbo.remoting.api.ProtocolDetector;
import org.apache.dubbo.remoting.api.WireProtocol;
import org.apache.dubbo.remoting.api.pu.AbstractPortUnificationServer;
import org.apache.dubbo.remoting.api.pu.ChannelOperator;
import org.apache.dubbo.remoting.api.pu.DefaultPuHandler;
import org.apache.dubbo.remoting.api.ssl.ContextOperator;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.concurrent.Executors;
import static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_MANAGEMENT_MODE_DEFAULT;
import static org.apache.dubbo.common.constants.CommonConstants.EXT_PROTOCOL;
class PortUnificationServerTest {
@Test
void testBind() throws RemotingException {
int port = NetUtils.getAvailablePort();
URL url = URL.valueOf("empty://127.0.0.1:" + port + "?foo=bar");
URL url = URL.valueOf("empty://127.0.0.1:" + port + "?foo=bar&" + EXT_PROTOCOL + "=tri");
ApplicationModel applicationModel = ApplicationModel.defaultModel();
ApplicationConfig applicationConfig = new ApplicationConfig("provider-app");
applicationConfig.setExecutorManagementMode(EXECUTOR_MANAGEMENT_MODE_DEFAULT);
@ -52,6 +70,7 @@ class PortUnificationServerTest {
final NettyPortUnificationServer server = new NettyPortUnificationServer(url, new DefaultPuHandler());
server.bind();
Assertions.assertTrue(server.isBound());
Assertions.assertEquals(2, server.getProtocols().size());
server.close();
}
}

View File

@ -72,11 +72,11 @@
<artifactId>dubbo-config-spring</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config-spring6</artifactId>
<version>${project.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.apache.dubbo</groupId>-->
<!-- <artifactId>dubbo-config-spring6</artifactId>-->
<!-- <version>${project.version}</version>-->
<!-- </dependency>-->
<!-- config-center -->
<dependency>

View File

@ -51,6 +51,8 @@ class FileTest {
ignoredModules.add(Pattern.compile("dubbo-parent"));
ignoredModules.add(Pattern.compile("dubbo-core-spi"));
ignoredModules.add(Pattern.compile("dubbo-demo.*"));
ignoredModules.add(Pattern.compile("dubbo-annotation-processor"));
ignoredModules.add(Pattern.compile("dubbo-config-spring6"));
ignoredArtifacts.add(Pattern.compile("dubbo-demo.*"));
ignoredArtifacts.add(Pattern.compile("dubbo-test.*"));