Introduce new Service Discovery model (#4223)

This commit is contained in:
Mercy Ma 2019-06-17 11:12:47 +08:00 committed by ken.lj
parent 7f7a289878
commit 5fb8dc07a8
195 changed files with 14261 additions and 3109 deletions

View File

@ -507,6 +507,23 @@
<optional>true</optional>
</dependency>
<!-- 2.7.3 new modules -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-event</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-metadata</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- Transitive dependencies -->
<dependency>
<groupId>org.springframework</groupId>
@ -639,6 +656,10 @@
<include>org.apache.dubbo:dubbo-metadata-report-nacos</include>
<include>org.apache.dubbo:dubbo-serialization-native-hession</include>
<include>org.apache.dubbo:dubbo-rpc-native-thrift</include>
<!-- 2.7.3 new modules -->
<include>org.apache.dubbo:dubbo-event</include>
<include>org.apache.dubbo:dubbo-metadata</include>
</includes>
</artifactSet>
<transformers>
@ -764,6 +785,19 @@
<resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.store.MetadataReportFactory
</resource>
</transformer>
<!-- @since 2.7.3 -->
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/dubbo/internal/org.apache.dubbo.event.EventDispatcher
</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.MetadataServiceExporter
</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/dubbo/internal/org.apache.dubbo.metadata.LocalMetadataService
</resource>
</transformer>
</transformers>
<filters>
<filter>

94
dubbo-bootstrap/pom.xml Normal file
View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-parent</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-bootstrap</artifactId>
<packaging>jar</packaging>
<name>dubbo-bootstrap</name>
<description>The bootstrap module of Dubbo project</description>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
<!-- Test dependencies -->
<!-- Zookeeper dependencies for testing -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-configcenter-zookeeper</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<!-- Nacos dependencies for testing -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-configcenter-nacos</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-dubbo</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-remoting-netty4</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-hessian2</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,36 @@
/*
* 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.bootstrap;
/**
* Abstract {@link Settings}
*
* @since 2.7.3
*/
public class AbstractSettings implements Settings {
private final DubboBootstrap dubboBootstrap;
public AbstractSettings(DubboBootstrap dubboBootstrap) {
this.dubboBootstrap = dubboBootstrap;
}
@Override
public DubboBootstrap next() {
return dubboBootstrap;
}
}

View File

@ -0,0 +1,127 @@
/*
* 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.bootstrap;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.MonitorConfig;
import org.apache.dubbo.config.builders.ApplicationBuilder;
import java.util.Map;
/**
* {@link ApplicationConfig Application} settings
*
* @since 2.7.3
*/
public class ApplicationSettings extends AbstractSettings {
private final ApplicationBuilder builder;
public ApplicationSettings(ApplicationBuilder builder, DubboBootstrap dubboBootstrap) {
super(dubboBootstrap);
this.builder = builder;
}
public ApplicationSettings version(String version) {
builder.version(version);
return this;
}
public ApplicationSettings owner(String owner) {
builder.owner(owner);
return this;
}
public ApplicationSettings organization(String organization) {
builder.organization(organization);
return this;
}
public ApplicationSettings architecture(String architecture) {
builder.architecture(architecture);
return this;
}
public ApplicationSettings environment(String environment) {
builder.environment(environment);
return this;
}
public ApplicationSettings compiler(String compiler) {
builder.compiler(compiler);
return this;
}
public ApplicationSettings logger(String logger) {
builder.logger(logger);
return this;
}
public ApplicationSettings monitor(MonitorConfig monitor) {
builder.monitor(monitor);
return this;
}
public ApplicationSettings monitor(String monitor) {
builder.monitor(monitor);
return this;
}
public ApplicationSettings isDefault(Boolean isDefault) {
builder.isDefault(isDefault);
return this;
}
public ApplicationSettings dumpDirectory(String dumpDirectory) {
builder.dumpDirectory(dumpDirectory);
return this;
}
public ApplicationSettings qosEnable(Boolean qosEnable) {
builder.qosEnable(qosEnable);
return this;
}
public ApplicationSettings qosPort(Integer qosPort) {
builder.qosPort(qosPort);
return this;
}
public ApplicationSettings qosAcceptForeignIp(Boolean qosAcceptForeignIp) {
builder.qosAcceptForeignIp(qosAcceptForeignIp);
return this;
}
public ApplicationSettings shutwait(String shutwait) {
builder.shutwait(shutwait);
return this;
}
public ApplicationSettings appendParameter(String key, String value) {
builder.appendParameter(key, value);
return this;
}
public ApplicationSettings appendParameters(Map<String, String> appendParameters) {
builder.appendParameters(appendParameters);
return this;
}
ApplicationConfig build() {
return builder.build();
}
}

View File

@ -0,0 +1,644 @@
/*
* 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.bootstrap;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.config.AbstractConfig;
import org.apache.dubbo.config.AbstractInterfaceConfig;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.config.builders.AbstractBuilder;
import org.apache.dubbo.config.builders.ApplicationBuilder;
import org.apache.dubbo.config.builders.ProtocolBuilder;
import org.apache.dubbo.config.builders.ReferenceBuilder;
import org.apache.dubbo.config.builders.RegistryBuilder;
import org.apache.dubbo.config.builders.ServiceBuilder;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.config.metadata.ConfigurableMetadataServiceExporter;
import org.apache.dubbo.event.EventDispatcher;
import org.apache.dubbo.event.EventListener;
import org.apache.dubbo.metadata.MetadataServiceExporter;
import org.apache.dubbo.registry.client.DefaultServiceInstance;
import org.apache.dubbo.registry.client.ServiceDiscovery;
import org.apache.dubbo.registry.client.ServiceInstance;
import org.apache.dubbo.registry.support.ServiceOrientedRegistry;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static java.util.Collections.emptyMap;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.utils.StringUtils.isBlank;
import static org.apache.dubbo.common.utils.StringUtils.split;
import static org.apache.dubbo.common.utils.StringUtils.trim;
import static org.apache.dubbo.registry.support.AbstractRegistryFactory.getRegistries;
/**
* The bootstrap class of Dubbo
*
* @since 2.7.3
*/
public class DubboBootstrap {
public static final String DEFAULT_REGISTRY_ID = "REGISTRY#DEFAULT";
public static final String DEFAULT_PROTOCOL_ID = "PROTOCOL#DEFAULT";
public static final String DEFAULT_SERVICE_ID = "SERVICE#DEFAULT";
public static final String DEFAULT_REFERENCE_ID = "REFERENCE#DEFAULT";
private static final String NAME = DubboBootstrap.class.getSimpleName();
private final Logger logger = LoggerFactory.getLogger(getClass());
private final MetadataServiceExporter metadataServiceExporter = new ConfigurableMetadataServiceExporter();
private final AtomicBoolean awaited = new AtomicBoolean(false);
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private final ExecutorService executorService = newSingleThreadExecutor();
private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
/**
* Is provider or not
*/
private boolean isProvider;
private boolean initialized = false;
private boolean started = false;
/**
* Only Provider Register
*/
private boolean onlyRegisterProvider = false;
private ServiceInstance serviceInstance;
private ApplicationBuilder applicationBuilder;
private Map<String, RegistryBuilder> registryBuilders = new HashMap<>();
private Map<String, ProtocolBuilder> protocolBuilders = new HashMap<>();
private Map<String, ServiceBuilder<?>> serviceBuilders = new HashMap<>();
private Map<String, ReferenceBuilder<?>> referenceBuilders = new HashMap<>();
/**
* The global {@link ApplicationConfig}
*/
private ApplicationConfig applicationConfig;
/**
* the global {@link RegistryConfig registries}
*/
private Map<String, RegistryConfig> registryConfigs = emptyMap();
/**
* the global {@link RegistryConfig registries}
*/
private Map<String, ProtocolConfig> protocolConfigs = emptyMap();
/**
* the global {@link ServiceConfig services}
*/
private Map<String, ServiceConfig<?>> serviceConfigs = emptyMap();
/**
* the global {@link ReferenceConfig references}
*/
private Map<String, ReferenceConfig<?>> referenceConfigs = new HashMap<>();
public ApplicationSettings application(String name) {
return new ApplicationSettings(initApplicationBuilder(name), this);
}
public RegistrySettings registry() {
return registry(DEFAULT_REGISTRY_ID);
}
public RegistrySettings registry(String id) {
return new RegistrySettings(initRegistryBuilder(id), this);
}
public ProtocolSettings protocol() {
return protocol(DEFAULT_PROTOCOL_ID);
}
public ProtocolSettings protocol(String id) {
return new ProtocolSettings(initProtocolBuilder(id), this);
}
public <S> ServiceSettings<S> service(String id) {
return new ServiceSettings(initServiceBuilder(id), this);
}
public <S> ReferenceSettings<S> reference(String id) {
return new ReferenceSettings<>(initReferenceBuilder(id), this);
}
/**
* Set only register provider or not
*
* @param onlyRegisterProvider if <code>true</code>, only register the provider and reduce the registries' load.
* @return {@link DubboBootstrap}
*/
public DubboBootstrap onlyRegisterProvider(boolean onlyRegisterProvider) {
this.onlyRegisterProvider = onlyRegisterProvider;
return this;
}
public DubboBootstrap application(String name, Consumer<ApplicationBuilder> builder) {
initApplicationBuilder(name);
builder.accept(applicationBuilder);
return this;
}
public DubboBootstrap registry(String id, Consumer<RegistryBuilder> builder) {
builder.accept(initRegistryBuilder(id));
return this;
}
public DubboBootstrap protocol(String id, Consumer<ProtocolBuilder> builder) {
builder.accept(initProtocolBuilder(id));
return this;
}
public <S> DubboBootstrap service(String id, Consumer<ServiceBuilder<S>> builder) {
builder.accept(initServiceBuilder(id));
return this;
}
public <S> DubboBootstrap reference(String id, Consumer<ReferenceBuilder<S>> builder) {
builder.accept(initReferenceBuilder(id));
return this;
}
/**
* Initialize
*/
public void init() {
if (isInitialized()) {
return;
}
initApplicationConfig();
initRegistryConfigs();
initProtocolConfigs();
initServiceConfigs();
initReferenceConfigs();
clearBuilders();
initialized = true;
if (logger.isInfoEnabled()) {
logger.info(NAME + " has been initialized!");
}
}
/**
* Get the {@link ServiceConfig} by specified id
*
* @param id The {@link ServiceConfig#getId() id} of {@link ServiceConfig}
* @param <S> the type of service interface
* @return <code>null</code> if not found
*/
public <S> ServiceConfig<S> serviceConfig(String id) {
return (ServiceConfig<S>) serviceConfigs.get(id);
}
/**
* Get the {@link ReferenceConfig} by specified id
*
* @param id The {@link ReferenceConfig#getId() id} of {@link ReferenceConfig}
* @param <S> the type of service interface
* @return <code>null</code> if not found
*/
public <S> ReferenceConfig<S> referenceConfig(String id) {
return (ReferenceConfig<S>) referenceConfigs.get(id);
}
private List<ServiceDiscovery> getServiceDiscoveries() {
return getRegistries()
.stream()
.filter(registry -> ServiceOrientedRegistry.class.isInstance(registry))
.map(registry -> ServiceOrientedRegistry.class.cast(registry))
.map(ServiceOrientedRegistry::getServiceDiscovery)
.collect(Collectors.toList());
}
/**
* Start the bootstrap
*/
public DubboBootstrap start() {
if (!isStarted()) {
if (!isInitialized()) {
init();
}
exportServices();
// Not only provider register and some services are exported
if (!onlyRegisterProvider && !serviceConfigs.isEmpty()) {
/**
* export {@link MetadataService}
*/
List<URL> exportedURLs = exportMetadataService(applicationConfig, registryConfigs, protocolConfigs);
/**
* Register the local {@link ServiceInstance}
*/
registerServiceInstance(exportedURLs);
}
started = true;
if (logger.isInfoEnabled()) {
logger.info(NAME + " is starting...");
}
}
return this;
}
/**
* Block current thread to be await.
*
* @return {@link DubboBootstrap}
*/
public DubboBootstrap await() {
// has been waited, return immediately
if (!awaited.get()) {
if (!executorService.isShutdown()) {
executorService.execute(() -> executeMutually(() -> {
while (!awaited.get()) {
if (logger.isInfoEnabled()) {
logger.info(NAME + " is awaiting...");
}
try {
condition.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}));
}
}
return this;
}
/**
* Stop the bootstrap
*/
public void stop() {
if (!isInitialized() || !isStarted()) {
return;
}
unregisterServiceInstance();
destroy();
clear();
release();
shutdown();
}
public boolean isInitialized() {
return initialized;
}
public boolean isStarted() {
return started;
}
private ApplicationBuilder initApplicationBuilder(String name) {
applicationBuilder = new ApplicationBuilder().name(name);
return applicationBuilder;
}
private RegistryBuilder createRegistryBuilder(String id) {
return new RegistryBuilder().id(id);
}
private ProtocolBuilder createProtocolBuilder(String id) {
return new ProtocolBuilder().id(id);
}
private ServiceBuilder createServiceBuilder(String id) {
return new ServiceBuilder().id(id);
}
private ReferenceBuilder createReferenceBuilder(String id) {
return new ReferenceBuilder().id(id);
}
private RegistryBuilder initRegistryBuilder(String id) {
return registryBuilders.computeIfAbsent(id, this::createRegistryBuilder);
}
private ProtocolBuilder initProtocolBuilder(String id) {
return protocolBuilders.computeIfAbsent(id, this::createProtocolBuilder);
}
private ServiceBuilder initServiceBuilder(String id) {
return serviceBuilders.computeIfAbsent(id, this::createServiceBuilder);
}
private ReferenceBuilder initReferenceBuilder(String id) {
return referenceBuilders.computeIfAbsent(id, this::createReferenceBuilder);
}
private void initApplicationConfig() {
this.applicationConfig = buildApplicationConfig();
}
private void initRegistryConfigs() {
this.registryConfigs = buildRegistryConfigs();
}
private void initProtocolConfigs() {
this.protocolConfigs = buildProtocolConfigs();
}
private void initReferenceConfigs() {
this.referenceConfigs = buildReferenceConfigs();
this.referenceConfigs.values().forEach(this::initReferenceConfig);
}
/**
* Add an instance of {@link EventListener}
*
* @param listener {@link EventListener}
* @return {@link DubboBootstrap}
*/
public DubboBootstrap addEventListener(EventListener<?> listener) {
eventDispatcher.addEventListener(listener);
return this;
}
private void initServiceConfigs() {
this.serviceConfigs = buildServiceConfigs();
this.serviceConfigs.values().forEach(this::initServiceConfig);
}
private List<URL> exportMetadataService(ApplicationConfig applicationConfig,
Map<String, RegistryConfig> globalRegistryConfigs,
Map<String, ProtocolConfig> globalProtocolConfigs) {
ConfigurableMetadataServiceExporter exporter = new ConfigurableMetadataServiceExporter();
exporter.setApplicationConfig(applicationConfig);
exporter.setRegistries(globalRegistryConfigs.values());
exporter.setProtocols(globalProtocolConfigs.values());
return exporter.export();
}
private ApplicationConfig buildApplicationConfig() {
return applicationBuilder.build();
}
private Map<String, ProtocolConfig> buildProtocolConfigs() {
return buildConfigs(protocolBuilders);
}
private Map<String, RegistryConfig> buildRegistryConfigs() {
return buildConfigs(registryBuilders);
}
private Map<String, ServiceConfig<?>> buildServiceConfigs() {
return buildConfigs(serviceBuilders);
}
private Map<String, ReferenceConfig<?>> buildReferenceConfigs() {
return buildConfigs(referenceBuilders);
}
private void exportServices() {
serviceConfigs.values().forEach(this::exportServiceConfig);
}
private void initServiceConfig(ServiceConfig<?> serviceConfig) {
initConfig(serviceConfig);
initProtocols(serviceConfig);
}
private void initReferenceConfig(ReferenceConfig<?> referenceConfig) {
initConfig(referenceConfig);
}
private void initConfig(AbstractInterfaceConfig config) {
initApplication(config);
initRegistries(config);
}
private void initApplication(AbstractInterfaceConfig config) {
if (config.getApplication() == null) {
config.setApplication(applicationConfig);
}
}
private void initRegistries(AbstractInterfaceConfig config) {
List<RegistryConfig> registries = config.getRegistries();
if (CollectionUtils.isEmpty(registries)) { // If no registry present
registries = new LinkedList<>();
String registerIds = config.getRegistryIds();
if (!isBlank(registerIds)) {
for (String id : split(registerIds, ',')) {
RegistryConfig registryConfig = registryConfigs.get(trim(id));
registries.add(registryConfig);
}
}
if (registries.isEmpty()) { // If empty, add all global registries
registries.addAll(registryConfigs.values());
}
config.setRegistries(registries);
}
}
private void initProtocols(ServiceConfig<?> serviceConfig) {
List<ProtocolConfig> protocols = serviceConfig.getProtocols();
if (CollectionUtils.isEmpty(protocols)) { // If no protocols present
protocols = new LinkedList<>();
String protocolIds = serviceConfig.getProtocolIds();
if (!isBlank(protocolIds)) {
for (String id : split(protocolIds, ',')) {
ProtocolConfig protocol = protocolConfigs.get(trim(id));
protocols.add(protocol);
}
}
if (protocols.isEmpty()) { // If empty, add all global protocols
protocols.addAll(protocolConfigs.values());
}
serviceConfig.setProtocols(protocols);
}
}
private void exportServiceConfig(ServiceConfig<?> serviceConfig) {
serviceConfig.export();
}
private void registerServiceInstance(List<URL> exportedURLs) {
exportedURLs
.stream()
.findFirst()
.ifPresent(url -> {
String serviceName = url.getParameter(APPLICATION_KEY);
String host = url.getHost();
int port = url.getPort();
ServiceInstance serviceInstance = initServiceInstance(serviceName, host, port);
getServiceDiscoveries().forEach(serviceDiscovery -> serviceDiscovery.register(serviceInstance));
});
}
private void unregisterServiceInstance() {
if (serviceInstance != null) {
getServiceDiscoveries().forEach(serviceDiscovery -> {
serviceDiscovery.unregister(serviceInstance);
});
}
}
private ServiceInstance initServiceInstance(String serviceName, String host, int port) {
this.serviceInstance = new DefaultServiceInstance(serviceName, host, port);
return this.serviceInstance;
}
private void destroy() {
destroyProtocolConfigs();
destroyReferenceConfigs();
}
private void destroyProtocolConfigs() {
protocolConfigs.values().forEach(ProtocolConfig::destroy);
if (logger.isDebugEnabled()) {
logger.debug(NAME + "'s all ProtocolConfigs have been destroyed.");
}
}
private void destroyReferenceConfigs() {
referenceConfigs.values().forEach(ReferenceConfig::destroy);
if (logger.isDebugEnabled()) {
logger.debug(NAME + "'s all ReferenceConfigs have been destroyed.");
}
}
private void clear() {
clearBuilders();
clearConfigs();
ConfigManager.getInstance().clear();
}
private void clearConfigs() {
this.applicationConfig = null;
this.registryConfigs.clear();
this.protocolConfigs.clear();
this.serviceConfigs.clear();
this.referenceConfigs.clear();
if (logger.isDebugEnabled()) {
logger.debug(NAME + "'s configs have been clear.");
}
}
private void clearBuilders() {
this.applicationBuilder = null;
this.registryBuilders.clear();
this.protocolBuilders.clear();
this.serviceBuilders.clear();
this.referenceBuilders.clear();
if (logger.isDebugEnabled()) {
logger.debug(NAME + "'s builders have been clear.");
}
}
private void release() {
executeMutually(() -> {
while (awaited.compareAndSet(false, true)) {
if (logger.isInfoEnabled()) {
logger.info(NAME + " is about to shutdown...");
}
condition.signalAll();
}
});
}
private void shutdown() {
if (!executorService.isShutdown()) {
// Shutdown executorService
executorService.shutdown();
}
}
private void executeMutually(Runnable runnable) {
try {
lock.lock();
runnable.run();
} finally {
lock.unlock();
}
}
private static <C extends AbstractConfig, B extends AbstractBuilder> Map<String, C> buildConfigs(Map<String, B> map) {
Map<String, C> configs = new HashMap<>();
map.entrySet().forEach(entry -> {
configs.put(entry.getKey(), (C) entry.getValue().build());
});
return configs;
}
}

View File

@ -0,0 +1,215 @@
/*
* 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.bootstrap;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.builders.ProtocolBuilder;
import java.util.Map;
/**
* The settings of {@link ProtocolConfig protcol}
*
* @see ProtocolBuilder
* @since 2.7.3
*/
public class ProtocolSettings extends AbstractSettings {
private final ProtocolBuilder builder;
public ProtocolSettings(ProtocolBuilder builder, DubboBootstrap dubboBootstrap) {
super(dubboBootstrap);
this.builder = builder;
}
public ProtocolSettings name(String name) {
builder.name(name);
return this;
}
public ProtocolSettings host(String host) {
builder.host(host);
return this;
}
public ProtocolSettings port(Integer port) {
builder.port(port);
return this;
}
public ProtocolSettings contextpath(String contextpath) {
builder.contextpath(contextpath);
return this;
}
@Deprecated
public ProtocolSettings path(String path) {
builder.path(path);
return this;
}
public ProtocolSettings threadpool(String threadpool) {
builder.threadpool(threadpool);
return this;
}
public ProtocolSettings corethreads(Integer corethreads) {
builder.corethreads(corethreads);
return this;
}
public ProtocolSettings threads(Integer threads) {
builder.threads(threads);
return this;
}
public ProtocolSettings iothreads(Integer iothreads) {
builder.iothreads(iothreads);
return this;
}
public ProtocolSettings queues(Integer queues) {
builder.queues(queues);
return this;
}
public ProtocolSettings accepts(Integer accepts) {
builder.accepts(accepts);
return this;
}
public ProtocolSettings codec(String codec) {
builder.codec(codec);
return this;
}
public ProtocolSettings serialization(String serialization) {
builder.serialization(serialization);
return this;
}
public ProtocolSettings charset(String charset) {
builder.charset(charset);
return this;
}
public ProtocolSettings payload(Integer payload) {
builder.payload(payload);
return this;
}
public ProtocolSettings buffer(Integer buffer) {
builder.buffer(buffer);
return this;
}
public ProtocolSettings heartbeat(Integer heartbeat) {
builder.heartbeat(heartbeat);
return this;
}
public ProtocolSettings accesslog(String accesslog) {
builder.accesslog(accesslog);
return this;
}
public ProtocolSettings transporter(String transporter) {
builder.transporter(transporter);
return this;
}
public ProtocolSettings exchanger(String exchanger) {
builder.exchanger(exchanger);
return this;
}
public ProtocolSettings dispatcher(String dispatcher) {
builder.dispatcher(dispatcher);
return this;
}
@Deprecated
public ProtocolSettings dispather(String dispather) {
builder.dispather(dispather);
return this;
}
public ProtocolSettings networker(String networker) {
builder.networker(networker);
return this;
}
public ProtocolSettings server(String server) {
builder.server(server);
return this;
}
public ProtocolSettings client(String client) {
builder.client(client);
return this;
}
public ProtocolSettings telnet(String telnet) {
builder.telnet(telnet);
return this;
}
public ProtocolSettings prompt(String prompt) {
builder.prompt(prompt);
return this;
}
public ProtocolSettings status(String status) {
builder.status(status);
return this;
}
public ProtocolSettings register(Boolean register) {
builder.register(register);
return this;
}
public ProtocolSettings keepAlive(Boolean keepAlive) {
builder.keepAlive(keepAlive);
return this;
}
public ProtocolSettings optimizer(String optimizer) {
builder.optimizer(optimizer);
return this;
}
public ProtocolSettings extension(String extension) {
builder.extension(extension);
return this;
}
public ProtocolSettings appendParameter(String key, String value) {
builder.appendParameter(key, value);
return this;
}
public ProtocolSettings appendParameters(Map<String, String> appendParameters) {
builder.appendParameters(appendParameters);
return this;
}
public ProtocolSettings isDefault(Boolean isDefault) {
builder.isDefault(isDefault);
return this;
}
}

View File

@ -0,0 +1,334 @@
/*
* 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.bootstrap;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ConfigCenterConfig;
import org.apache.dubbo.config.ConsumerConfig;
import org.apache.dubbo.config.MetadataReportConfig;
import org.apache.dubbo.config.MethodConfig;
import org.apache.dubbo.config.ModuleConfig;
import org.apache.dubbo.config.MonitorConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.builders.ReferenceBuilder;
import java.util.List;
import java.util.Map;
/**
* The settings of {@link ReferenceConfig}
*
* @since 2.7.3
*/
public class ReferenceSettings<S> extends AbstractSettings {
private final ReferenceBuilder<S> builder;
public ReferenceSettings(ReferenceBuilder<S> builder, DubboBootstrap dubboBootstrap) {
super(dubboBootstrap);
this.builder = builder;
}
public ReferenceSettings<S> interfaceName(String interfaceName) {
builder.interfaceName(interfaceName);
return this;
}
public ReferenceSettings<S> interfaceClass(Class<?> interfaceClass) {
builder.interfaceClass(interfaceClass);
return this;
}
public ReferenceSettings<S> client(String client) {
builder.client(client);
return this;
}
public ReferenceSettings<S> url(String url) {
builder.url(url);
return this;
}
public ReferenceSettings<S> addMethods(List<MethodConfig> methods) {
builder.addMethods(methods);
return this;
}
public ReferenceSettings<S> addMethod(MethodConfig method) {
builder.addMethod(method);
return this;
}
public ReferenceSettings<S> consumer(ConsumerConfig consumer) {
builder.consumer(consumer);
return this;
}
public ReferenceSettings<S> protocol(String protocol) {
builder.protocol(protocol);
return this;
}
public ReferenceSettings<S> check(Boolean check) {
builder.check(check);
return this;
}
public ReferenceSettings<S> init(Boolean init) {
builder.init(init);
return this;
}
public ReferenceSettings<S> generic(String generic) {
builder.generic(generic);
return this;
}
public ReferenceSettings<S> generic(Boolean generic) {
builder.generic(generic);
return this;
}
@Deprecated
public ReferenceSettings<S> injvm(Boolean injvm) {
builder.injvm(injvm);
return this;
}
public ReferenceSettings<S> lazy(Boolean lazy) {
builder.lazy(lazy);
return this;
}
public ReferenceSettings<S> reconnect(String reconnect) {
builder.reconnect(reconnect);
return this;
}
public ReferenceSettings<S> sticky(Boolean sticky) {
builder.sticky(sticky);
return this;
}
public ReferenceSettings<S> version(String version) {
builder.version(version);
return this;
}
public ReferenceSettings<S> group(String group) {
builder.group(group);
return this;
}
@Deprecated
public ReferenceSettings<S> local(String local) {
builder.local(local);
return this;
}
@Deprecated
public ReferenceSettings<S> local(Boolean local) {
builder.local(local);
return this;
}
public ReferenceSettings<S> stub(String stub) {
builder.stub(stub);
return this;
}
public ReferenceSettings<S> stub(Boolean stub) {
builder.stub(stub);
return this;
}
public ReferenceSettings<S> monitor(MonitorConfig monitor) {
builder.monitor(monitor);
return this;
}
public ReferenceSettings<S> monitor(String monitor) {
builder.monitor(monitor);
return this;
}
public ReferenceSettings<S> proxy(String proxy) {
builder.proxy(proxy);
return this;
}
public ReferenceSettings<S> cluster(String cluster) {
builder.cluster(cluster);
return this;
}
public ReferenceSettings<S> filter(String filter) {
builder.filter(filter);
return this;
}
public ReferenceSettings<S> listener(String listener) {
builder.listener(listener);
return this;
}
public ReferenceSettings<S> owner(String owner) {
builder.owner(owner);
return this;
}
public ReferenceSettings<S> connections(Integer connections) {
builder.connections(connections);
return this;
}
public ReferenceSettings<S> layer(String layer) {
builder.layer(layer);
return this;
}
public ReferenceSettings<S> application(ApplicationConfig application) {
builder.application(application);
return this;
}
public ReferenceSettings<S> module(ModuleConfig module) {
builder.module(module);
return this;
}
public ReferenceSettings<S> addRegistries(List<RegistryConfig> registries) {
builder.addRegistries(registries);
return this;
}
public ReferenceSettings<S> addRegistry(RegistryConfig registry) {
builder.addRegistry(registry);
return this;
}
public ReferenceSettings<S> registryIds(String registryIds) {
builder.registryIds(registryIds);
return this;
}
public ReferenceSettings<S> onconnect(String onconnect) {
builder.onconnect(onconnect);
return this;
}
public ReferenceSettings<S> ondisconnect(String ondisconnect) {
builder.ondisconnect(ondisconnect);
return this;
}
public ReferenceSettings<S> metadataReportConfig(MetadataReportConfig metadataReportConfig) {
builder.metadataReportConfig(metadataReportConfig);
return this;
}
public ReferenceSettings<S> configCenter(ConfigCenterConfig configCenter) {
builder.configCenter(configCenter);
return this;
}
public ReferenceSettings<S> callbacks(Integer callbacks) {
builder.callbacks(callbacks);
return this;
}
public ReferenceSettings<S> scope(String scope) {
builder.scope(scope);
return this;
}
public ReferenceSettings<S> tag(String tag) {
builder.tag(tag);
return this;
}
public ReferenceSettings<S> timeout(Integer timeout) {
builder.timeout(timeout);
return this;
}
public ReferenceSettings<S> retries(Integer retries) {
builder.retries(retries);
return this;
}
public ReferenceSettings<S> actives(Integer actives) {
builder.actives(actives);
return this;
}
public ReferenceSettings<S> loadbalance(String loadbalance) {
builder.loadbalance(loadbalance);
return this;
}
public ReferenceSettings<S> async(Boolean async) {
builder.async(async);
return this;
}
public ReferenceSettings<S> sent(Boolean sent) {
builder.sent(sent);
return this;
}
public ReferenceSettings<S> mock(String mock) {
builder.mock(mock);
return this;
}
public ReferenceSettings<S> mock(Boolean mock) {
builder.mock(mock);
return this;
}
public ReferenceSettings<S> merger(String merger) {
builder.merger(merger);
return this;
}
public ReferenceSettings<S> cache(String cache) {
builder.cache(cache);
return this;
}
public ReferenceSettings<S> validation(String validation) {
builder.validation(validation);
return this;
}
public ReferenceSettings<S> appendParameters(Map<String, String> appendParameters) {
builder.appendParameters(appendParameters);
return this;
}
public ReferenceSettings<S> appendParameter(String key, String value) {
builder.appendParameter(key, value);
return this;
}
public ReferenceSettings<S> forks(Integer forks) {
builder.forks(forks);
return this;
}
}

View File

@ -0,0 +1,164 @@
/*
* 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.bootstrap;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.builders.RegistryBuilder;
import java.util.Map;
/**
* The settings of {@link RegistryConfig}
*
* @since 2.7.3
*/
public class RegistrySettings extends AbstractSettings {
private final RegistryBuilder builder;
public RegistrySettings(RegistryBuilder builder, DubboBootstrap dubboBootstrap) {
super(dubboBootstrap);
this.builder = builder;
}
public RegistrySettings address(String address) {
builder.address(address);
return this;
}
public RegistrySettings username(String username) {
builder.username(username);
return this;
}
public RegistrySettings password(String password) {
builder.password(password);
return this;
}
public RegistrySettings port(Integer port) {
builder.port(port);
return this;
}
public RegistrySettings protocol(String protocol) {
builder.protocol(protocol);
return this;
}
public RegistrySettings transporter(String transporter) {
builder.transporter(transporter);
return this;
}
@Deprecated
public RegistrySettings transport(String transport) {
builder.transport(transport);
return this;
}
public RegistrySettings server(String server) {
builder.server(server);
return this;
}
public RegistrySettings client(String client) {
builder.client(client);
return this;
}
public RegistrySettings cluster(String cluster) {
builder.cluster(cluster);
return this;
}
public RegistrySettings group(String group) {
builder.group(group);
return this;
}
public RegistrySettings version(String version) {
builder.version(version);
return this;
}
public RegistrySettings timeout(Integer timeout) {
builder.timeout(timeout);
return this;
}
public RegistrySettings session(Integer session) {
builder.session(session);
return this;
}
public RegistrySettings file(String file) {
builder.file(file);
return this;
}
@Deprecated
public RegistrySettings wait(Integer wait) {
builder.wait(wait);
return this;
}
public RegistrySettings isCheck(Boolean check) {
builder.isCheck(check);
return this;
}
public RegistrySettings isDynamic(Boolean dynamic) {
builder.isDynamic(dynamic);
return this;
}
public RegistrySettings register(Boolean register) {
builder.register(register);
return this;
}
public RegistrySettings subscribe(Boolean subscribe) {
builder.subscribe(subscribe);
return this;
}
public RegistrySettings appendParameter(String key, String value) {
builder.appendParameter(key, value);
return this;
}
public RegistrySettings appendParameters(Map<String, String> appendParameters) {
builder.appendParameters(appendParameters);
return this;
}
public RegistrySettings isDefault(Boolean isDefault) {
builder.isDefault(isDefault);
return this;
}
public RegistrySettings simplified(Boolean simplified) {
builder.simplified(simplified);
return this;
}
public RegistrySettings extraKeys(String extraKeys) {
builder.extraKeys(extraKeys);
return this;
}
}

View File

@ -0,0 +1,384 @@
/*
* 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.bootstrap;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ConfigCenterConfig;
import org.apache.dubbo.config.MetadataReportConfig;
import org.apache.dubbo.config.MethodConfig;
import org.apache.dubbo.config.ModuleConfig;
import org.apache.dubbo.config.MonitorConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.config.builders.ServiceBuilder;
import java.util.List;
import java.util.Map;
/**
* The settings of {@link ServiceConfig Dubbo service}
*
* @since 2.7.3
*/
public class ServiceSettings<S> extends AbstractSettings {
private final ServiceBuilder<S> builder;
public ServiceSettings(ServiceBuilder<S> builder, DubboBootstrap dubboBootstrap) {
super(dubboBootstrap);
this.builder = builder;
}
public ServiceSettings<S> interfaceName(String interfaceName) {
builder.interfaceName(interfaceName);
return this;
}
public ServiceSettings<S> interfaceClass(Class<?> interfaceClass) {
builder.interfaceClass(interfaceClass);
return this;
}
public ServiceSettings<S> ref(S ref) {
builder.ref(ref);
return this;
}
public ServiceSettings<S> path(String path) {
builder.path(path);
return this;
}
public ServiceSettings<S> addMethod(MethodConfig method) {
builder.addMethod(method);
return this;
}
public ServiceSettings<S> addMethods(List<? extends MethodConfig> methods) {
builder.addMethods(methods);
return this;
}
public ServiceSettings<S> provider(ProviderConfig provider) {
builder.provider(provider);
return this;
}
public ServiceSettings<S> providerIds(String providerIds) {
builder.providerIds(providerIds);
return this;
}
public ServiceSettings<S> generic(String generic) {
builder.generic(generic);
return this;
}
public ServiceSettings<S> mock(String mock) {
builder.mock(mock);
return this;
}
public ServiceSettings<S> mock(Boolean mock) {
builder.mock(mock);
return this;
}
public ServiceSettings<S> version(String version) {
builder.version(version);
return this;
}
public ServiceSettings<S> group(String group) {
builder.group(group);
return this;
}
public ServiceSettings<S> deprecated(Boolean deprecated) {
builder.deprecated(deprecated);
return this;
}
public ServiceSettings<S> delay(Integer delay) {
builder.delay(delay);
return this;
}
public ServiceSettings<S> export(Boolean export) {
builder.export(export);
return this;
}
public ServiceSettings<S> weight(Integer weight) {
builder.weight(weight);
return this;
}
public ServiceSettings<S> document(String document) {
builder.document(document);
return this;
}
public ServiceSettings<S> dynamic(Boolean dynamic) {
builder.dynamic(dynamic);
return this;
}
public ServiceSettings<S> token(String token) {
builder.token(token);
return this;
}
public ServiceSettings<S> token(Boolean token) {
builder.token(token);
return this;
}
public ServiceSettings<S> accesslog(String accesslog) {
builder.accesslog(accesslog);
return this;
}
public ServiceSettings<S> accesslog(Boolean accesslog) {
builder.accesslog(accesslog);
return this;
}
public ServiceSettings<S> addProtocols(List<ProtocolConfig> protocols) {
builder.addProtocols(protocols);
return this;
}
public ServiceSettings<S> addProtocol(ProtocolConfig protocol) {
builder.addProtocol(protocol);
return this;
}
public ServiceSettings<S> protocolIds(String protocolIds) {
builder.protocolIds(protocolIds);
return this;
}
public ServiceSettings<S> executes(Integer executes) {
builder.executes(executes);
return this;
}
public ServiceSettings<S> register(Boolean register) {
builder.register(register);
return this;
}
public ServiceSettings<S> warmup(Integer warmup) {
builder.warmup(warmup);
return this;
}
public ServiceSettings<S> serialization(String serialization) {
builder.serialization(serialization);
return this;
}
@Deprecated
public ServiceSettings<S> local(String local) {
builder.local(local);
return this;
}
@Deprecated
public ServiceSettings<S> local(Boolean local) {
builder.local(local);
return this;
}
public ServiceSettings<S> stub(String stub) {
builder.stub(stub);
return this;
}
public ServiceSettings<S> stub(Boolean stub) {
builder.stub(stub);
return this;
}
public ServiceSettings<S> monitor(MonitorConfig monitor) {
builder.monitor(monitor);
return this;
}
public ServiceSettings<S> monitor(String monitor) {
builder.monitor(monitor);
return this;
}
public ServiceSettings<S> proxy(String proxy) {
builder.proxy(proxy);
return this;
}
public ServiceSettings<S> cluster(String cluster) {
builder.cluster(cluster);
return this;
}
public ServiceSettings<S> filter(String filter) {
builder.filter(filter);
return this;
}
public ServiceSettings<S> listener(String listener) {
builder.listener(listener);
return this;
}
public ServiceSettings<S> owner(String owner) {
builder.owner(owner);
return this;
}
public ServiceSettings<S> connections(Integer connections) {
builder.connections(connections);
return this;
}
public ServiceSettings<S> layer(String layer) {
builder.layer(layer);
return this;
}
public ServiceSettings<S> application(ApplicationConfig application) {
builder.application(application);
return this;
}
public ServiceSettings<S> module(ModuleConfig module) {
builder.module(module);
return this;
}
public ServiceSettings<S> addRegistries(List<RegistryConfig> registries) {
builder.addRegistries(registries);
return this;
}
public ServiceSettings<S> addRegistry(RegistryConfig registry) {
builder.addRegistry(registry);
return this;
}
public ServiceSettings<S> registryIds(String registryIds) {
builder.registryIds(registryIds);
return this;
}
public ServiceSettings<S> onconnect(String onconnect) {
builder.onconnect(onconnect);
return this;
}
public ServiceSettings<S> ondisconnect(String ondisconnect) {
builder.ondisconnect(ondisconnect);
return this;
}
public ServiceSettings<S> metadataReportConfig(MetadataReportConfig metadataReportConfig) {
builder.metadataReportConfig(metadataReportConfig);
return this;
}
public ServiceSettings<S> configCenter(ConfigCenterConfig configCenter) {
builder.configCenter(configCenter);
return this;
}
public ServiceSettings<S> callbacks(Integer callbacks) {
builder.callbacks(callbacks);
return this;
}
public ServiceSettings<S> scope(String scope) {
builder.scope(scope);
return this;
}
public ServiceSettings<S> tag(String tag) {
builder.tag(tag);
return this;
}
public ServiceSettings<S> timeout(Integer timeout) {
builder.timeout(timeout);
return this;
}
public ServiceSettings<S> retries(Integer retries) {
builder.retries(retries);
return this;
}
public ServiceSettings<S> actives(Integer actives) {
builder.actives(actives);
return this;
}
public ServiceSettings<S> loadbalance(String loadbalance) {
builder.loadbalance(loadbalance);
return this;
}
public ServiceSettings<S> async(Boolean async) {
builder.async(async);
return this;
}
public ServiceSettings<S> sent(Boolean sent) {
builder.sent(sent);
return this;
}
public ServiceSettings<S> merger(String merger) {
builder.merger(merger);
return this;
}
public ServiceSettings<S> cache(String cache) {
builder.cache(cache);
return this;
}
public ServiceSettings<S> validation(String validation) {
builder.validation(validation);
return this;
}
public ServiceSettings<S> appendParameters(Map<String, String> appendParameters) {
builder.appendParameters(appendParameters);
return this;
}
public ServiceSettings<S> appendParameter(String key, String value) {
builder.appendParameter(key, value);
return this;
}
public ServiceSettings<S> forks(Integer forks) {
builder.forks(forks);
return this;
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.bootstrap;
/**
* The Dubbo settings
*
* @since 2.7.3
*/
public interface Settings {
/**
* Go next settings
*
* @return {@link DubboBootstrap}
*/
DubboBootstrap next();
}

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.bootstrap;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.curator.test.TestingServer;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.io.IOException;
/**
* {@link DubboBootstrap} Test
*
* @since 2.7.3
*/
public class DubboBootstrapTest {
private static int zkServerPort = NetUtils.getAvailablePort();
private static TestingServer zkServer;
@BeforeAll
public static void init() throws Exception {
zkServer = new TestingServer(zkServerPort, true);
}
@AfterAll
public static void destroy() throws IOException {
zkServer.stop();
zkServer.close();
}
@Test
public void testProviderInFluentAPI() {
new DubboBootstrap()
.application("dubbo-provider-demo")
.next()
.registry()
.address("zookeeper://127.0.0.1:" + zkServerPort + "?registry-type=service")
.next()
.protocol()
.name("dubbo")
.port(-1)
.next()
.service("test")
.interfaceClass(EchoService.class)
.ref(new EchoServiceImpl())
.group("DEFAULT")
.version("1.0.0")
.next()
.start()
.stop();
}
@Test
public void testProviderInLambda() {
new DubboBootstrap()
.application("dubbo-provider-demo", builder -> {
})
.registry("default", builder ->
builder.address("zookeeper://127.0.0.1:" + zkServerPort + "?registry-type=service")
)
.protocol("defalt", builder ->
builder.name("dubbo")
.port(-1)
)
.service("test", builder ->
builder.interfaceClass(EchoService.class)
.ref(new EchoServiceImpl())
.group("DEFAULT")
.version("1.0.0")
)
.start()
.stop();
}
}

View File

@ -0,0 +1,58 @@
/*
* 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.bootstrap;
import org.apache.dubbo.config.ReferenceConfig;
import static org.apache.dubbo.bootstrap.EchoService.GROUP;
import static org.apache.dubbo.bootstrap.EchoService.VERSION;
/**
* Dubbo Provider Bootstrap
*
* @since 2.7.3
*/
public class DubboServiceConsumerBootstrap {
public static void main(String[] args) throws Exception {
DubboBootstrap bootstrap = new DubboBootstrap()
.application("dubbo-consumer-demo")
.next()
.registry()
.address("nacos://127.0.0.1:8848?registry-type=service&subscribed-services=dubbo-provider-demo")
.next()
.reference("ref")
.interfaceClass(EchoService.class)
.group(GROUP)
.version(VERSION)
.next()
.onlyRegisterProvider(true)
.start()
.await();
ReferenceConfig<EchoService> referenceConfig = bootstrap.referenceConfig("ref");
EchoService echoService = referenceConfig.get();
for (int i = 0; i < 500; i++) {
Thread.sleep(2000L);
System.out.println(echoService.echo("Hello,World"));
}
}
}

View File

@ -0,0 +1,52 @@
/*
* 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.bootstrap;
import java.io.IOException;
import static org.apache.dubbo.bootstrap.EchoService.GROUP;
import static org.apache.dubbo.bootstrap.EchoService.VERSION;
/**
* Dubbo Provider Bootstrap
*
* @since 2.7.3
*/
public class DubboServiceProviderBootstrap {
public static void main(String[] args) throws IOException {
new DubboBootstrap()
.application("dubbo-provider-demo")
.next()
.registry()
.address("nacos://127.0.0.1:8848?registry-type=service")
.next()
.protocol()
.name("dubbo")
.port(-1)
.next()
.service("test")
.interfaceClass(EchoService.class)
.ref(new EchoServiceImpl())
.group(GROUP)
.version(VERSION)
.next()
.start()
.await();
}
}

View File

@ -0,0 +1,31 @@
/*
* 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.bootstrap;
/**
* Echo Service
*
* @since 2.7.3
*/
public interface EchoService {
String GROUP = "DEFAULT";
String VERSION = "1.0.0";
String echo(String message);
}

View File

@ -0,0 +1,36 @@
/*
* 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.bootstrap;
import org.apache.dubbo.rpc.RpcContext;
import static java.lang.String.format;
/**
* The implementation of {@link EchoService}
*
* @see EchoService
* @since 2.7.3
*/
public class EchoServiceImpl implements EchoService {
@Override
public String echo(String message) {
RpcContext rpcContext = RpcContext.getContext();
return format("[%s:%s] ECHO - %s", rpcContext.getLocalHost(), rpcContext.getLocalPort(), message);
}
}

View File

@ -0,0 +1,7 @@
###set log levels###
log4j.rootLogger=info, stdout
###output to the console###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n

View File

@ -38,16 +38,16 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.ADDRESS_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
/**
* ConditionRouter

View File

@ -23,7 +23,6 @@ import org.apache.dubbo.remoting.Constants;
import java.util.HashMap;
import java.util.Map;
import static org.apache.dubbo.rpc.cluster.Constants.TAG_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;
@ -41,6 +40,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.INVOKER_LISTENER_KEY;
import static org.apache.dubbo.rpc.Constants.REFERENCE_FILTER_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.TAG_KEY;
/**
* ClusterUtils

View File

@ -25,6 +25,7 @@ import org.junit.jupiter.api.Test;
import static org.apache.dubbo.common.constants.CommonConstants.ALIVE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CORE_THREADS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;
@ -32,7 +33,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.THREADS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.THREAD_NAME_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
public class ClusterUtilsTest {

View File

@ -40,20 +40,20 @@ import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
/**
* URL - Uniform Resource Locator (Immutable, ThreadSafe)
@ -339,6 +339,30 @@ class URL implements Serializable {
}
}
static String appendDefaultPort(String address, int defaultPort) {
if (address != null && address.length() > 0 && defaultPort > 0) {
int i = address.indexOf(':');
if (i < 0) {
return address + ":" + defaultPort;
} else if (Integer.parseInt(address.substring(i + 1)) == 0) {
return address.substring(0, i + 1) + defaultPort;
}
}
return address;
}
public static String buildKey(String path, String group, String version) {
StringBuilder buf = new StringBuilder();
if (group != null && group.length() > 0) {
buf.append(group).append("/");
}
buf.append(path);
if (version != null && version.length() > 0) {
buf.append(":").append(version);
}
return buf.toString();
}
public String getProtocol() {
return protocol;
}
@ -452,18 +476,6 @@ class URL implements Serializable {
return urls;
}
static String appendDefaultPort(String address, int defaultPort) {
if (address != null && address.length() > 0 && defaultPort > 0) {
int i = address.indexOf(':');
if (i < 0) {
return address + ":" + defaultPort;
} else if (Integer.parseInt(address.substring(i + 1)) == 0) {
return address.substring(0, i + 1) + defaultPort;
}
}
return address;
}
public String getPath() {
return path;
}
@ -1325,6 +1337,7 @@ class URL implements Serializable {
/**
* The format of return value is '{group}/{interfaceName}:{version}'
*
* @return
*/
public String getServiceKey() {
@ -1337,6 +1350,7 @@ class URL implements Serializable {
/**
* The format of return value is '{group}/{path/interfaceName}:{version}'
*
* @return
*/
public String getPathKey() {
@ -1347,18 +1361,6 @@ class URL implements Serializable {
return buildKey(inf, getParameter(GROUP_KEY), getParameter(VERSION_KEY));
}
public static String buildKey(String path, String group, String version) {
StringBuilder buf = new StringBuilder();
if (group != null && group.length() > 0) {
buf.append(group).append("/");
}
buf.append(path);
if (version != null && version.length() > 0) {
buf.append(":").append(version);
}
return buf.toString();
}
public String toServiceStringWithoutResolving() {
return buildString(true, false, false, true);
}

View File

@ -52,4 +52,38 @@ public interface RegistryConstants {
String OVERRIDE_PROTOCOL = "override";
String COMPATIBLE_CONFIG_KEY = "compatible_config";
/**
* The parameter key of Dubbo Registry type
*
* @since 2.7.3
*/
String REGISTRY_TYPE_KEY = "registry-type";
/**
* The parameter value of Service-Oriented Registry type
*
* @since 2.7.3
*/
String SERVICE_REGISTRY_TYPE = "service";
/**
* The parameter key of the subscribed service names for Service-Oriented Registry
*
* @since 2.7.3
*/
String SUBSCRIBED_SERVICE_NAMES_KEY = "subscribed-services";
/**
* The request size of service instances
*
* @since 2.7.3
*/
String INSTANCES_REQUEST_SIZE_KEY = "instances-request-size";
/**
* The default request size of service instances
*/
int DEFAULT_INSTANCES_REQUEST_SIZE = 100;
}

View File

@ -0,0 +1,66 @@
/*
* 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.function;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* {@link Consumer} with {@link Throwable}
*
* @param <T> the source type
* @see Function
* @see Throwable
* @since 2.7.3
*/
@FunctionalInterface
public interface ThrowableConsumer<T> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @throws Throwable if met with any error
*/
void accept(T t) throws Throwable;
/**
* Executes {@link ThrowableConsumer}
*
* @param t the function argument
* @throws RuntimeException wrappers {@link Throwable}
*/
default void execute(T t) throws RuntimeException {
try {
accept(t);
} catch (Throwable e) {
throw new RuntimeException(e.getMessage(), e.getCause());
}
}
/**
* Executes {@link ThrowableConsumer}
*
* @param t the function argument
* @param consumer {@link ThrowableConsumer}
* @param <T> the source type
* @return the result after execution
*/
static <T> void execute(T t, ThrowableConsumer<T> consumer) {
consumer.execute(t);
}
}

View File

@ -0,0 +1,71 @@
/*
* 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.function;
import java.util.function.Function;
/**
* {@link Function} with {@link Throwable}
*
* @param <T> the source type
* @param <R> the return type
* @see Function
* @see Throwable
* @since 2.7.3
*/
@FunctionalInterface
public interface ThrowableFunction<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
* @throws Throwable if met with any error
*/
R apply(T t) throws Throwable;
/**
* Executes {@link ThrowableFunction}
*
* @param t the function argument
* @return the function result
* @throws RuntimeException wrappers {@link Throwable}
*/
default R execute(T t) throws RuntimeException {
R result = null;
try {
result = apply(t);
} catch (Throwable e) {
throw new RuntimeException(e.getCause());
}
return result;
}
/**
* Executes {@link ThrowableFunction}
*
* @param t the function argument
* @param function {@link ThrowableFunction}
* @param <T> the source type
* @param <R> the return type
* @return the result after execution
*/
static <T, R> R execute(T t, ThrowableFunction<T, R> function) {
return function.execute(t);
}
}

View File

@ -0,0 +1,82 @@
/*
* 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.utils;
import java.io.Serializable;
import java.util.List;
/**
* The default implementation of {@link Page}
*
* @since 2.7.3
*/
public class DefaultPage<T> implements Page<T>, Serializable {
private static final long serialVersionUID = 1099331838954070419L;
private final int requestOffset;
private final int pageSize;
private final int totalSize;
private final List<T> data;
private final int totalPages;
private final boolean hasNext;
public DefaultPage(int requestOffset, int pageSize, List<T> data, int totalSize) {
this.requestOffset = requestOffset;
this.pageSize = pageSize;
this.data = data;
this.totalSize = totalSize;
int remain = totalSize % pageSize;
this.totalPages = remain > 0 ? (totalSize / pageSize) + 1 : totalSize / pageSize;
this.hasNext = totalSize - requestOffset - pageSize > 0;
}
@Override
public int getOffset() {
return requestOffset;
}
@Override
public int getPageSize() {
return pageSize;
}
@Override
public int getTotalSize() {
return totalSize;
}
@Override
public int getTotalPages() {
return totalPages;
}
@Override
public List<T> getData() {
return data;
}
@Override
public boolean hasNext() {
return hasNext;
}
}

View File

@ -37,9 +37,9 @@ import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Pattern;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;
import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.LOCALHOST_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_IP_TO_BIND;
/**
* IP and Port Helper for RPC

View File

@ -0,0 +1,87 @@
/*
* 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.utils;
import java.util.List;
/**
* The model class of pagination
*
* @since 2.7.3
*/
public interface Page<T> {
/**
* Gets the offset of request
*
* @return positive integer
*/
int getOffset();
/**
* Gets the size of request for pagination query
*
* @return positive integer
*/
int getPageSize();
/**
* Gets the total amount of elements.
*
* @return the total amount of elements
*/
int getTotalSize();
/**
* Get the number of total pages.
*
* @return the number of total pages.
*/
int getTotalPages();
/**
* The data of current page
*
* @return non-null {@link List}
*/
List<T> getData();
/**
* The size of {@link #getData() data}
*
* @return positive integer
*/
default int getDataSize() {
return getData().size();
}
/**
* It indicates has next page or not
*
* @return if has , return <code>true</code>, or <code>false</code>
*/
boolean hasNext();
/**
* Returns whether the page has data at all.
*
* @return
*/
default boolean hasData() {
return getDataSize() > 0;
}
}

View File

@ -30,19 +30,19 @@ import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.CLASSIFIER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
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.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_SPLIT_PATTERN;
import static org.apache.dubbo.common.constants.CommonConstants.REMOVE_VALUE_PREFIX;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PORT_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.RegistryConstants.CATEGORY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.CONFIGURATORS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.DEFAULT_CATEGORY;

View File

@ -0,0 +1,37 @@
/*
* 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.utils;
import org.junit.jupiter.api.Test;
import java.util.List;
import static java.util.Arrays.asList;
/**
* {@link DefaultPage}
*
* @since 2.7.3
*/
public class DefaultPageTest {
@Test
public void test() {
List<Integer> data = asList(1, 2, 3, 4, 5);
DefaultPage page = new DefaultPage(0, 1, data.subList(0, 1), data.size());
}
}

View File

@ -23,11 +23,11 @@ import com.alibaba.dubbo.rpc.Invoker;
import java.util.HashMap;
import java.util.Map;
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_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.remoting.Constants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.TOKEN_KEY;
/**

View File

@ -14,7 +14,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.dubbo</groupId>
@ -64,6 +65,13 @@
<artifactId>dubbo-filter-cache</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-metadata</artifactId>
<version>${project.parent.version}</version>
</dependency>
<!-- FIXME, we shouldn't rely on these modules, even in test scope -->
<dependency>
<groupId>org.apache.dubbo</groupId>
@ -71,17 +79,55 @@
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-remoting-netty4</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-dubbo</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-multicast</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<!-- Zookeeper Registry -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<!-- Zookeeper configcenter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-configcenter-zookeeper</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-hessian2</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -53,31 +53,30 @@ import java.util.Map;
import java.util.Set;
import static org.apache.dubbo.common.config.ConfigurationUtils.parseProperties;
import static org.apache.dubbo.rpc.cluster.Constants.TAG_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.RELEASE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.config.Constants.LAYER_KEY;
import static org.apache.dubbo.config.Constants.LISTENER_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
import static org.apache.dubbo.config.Constants.REGISTRIES_SUFFIX;
import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SECONDS_KEY;
import static org.apache.dubbo.monitor.Constants.LOGSTAT_PROTOCOL;
import static org.apache.dubbo.registry.Constants.REGISTER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_PROTOCOL;
import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
import static org.apache.dubbo.config.Constants.DUBBO_IP_TO_REGISTRY;
import static org.apache.dubbo.config.Constants.LAYER_KEY;
import static org.apache.dubbo.config.Constants.LISTENER_KEY;
import static org.apache.dubbo.config.Constants.REGISTRIES_SUFFIX;
import static org.apache.dubbo.monitor.Constants.LOGSTAT_PROTOCOL;
import static org.apache.dubbo.registry.Constants.REGISTER_IP_KEY;
import static org.apache.dubbo.registry.Constants.REGISTER_KEY;
import static org.apache.dubbo.registry.Constants.SUBSCRIBE_KEY;
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.rpc.Constants.INVOKER_LISTENER_KEY;
@ -86,7 +85,8 @@ import static org.apache.dubbo.rpc.Constants.PROXY_KEY;
import static org.apache.dubbo.rpc.Constants.REFERENCE_FILTER_KEY;
import static org.apache.dubbo.rpc.Constants.RETURN_PREFIX;
import static org.apache.dubbo.rpc.Constants.THROW_PREFIX;
import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.TAG_KEY;
/**
* AbstractDefaultConfig

View File

@ -19,6 +19,8 @@ package org.apache.dubbo.config;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.event.DubboServiceDestroyedEvent;
import org.apache.dubbo.event.EventDispatcher;
import org.apache.dubbo.registry.support.AbstractRegistryFactory;
import org.apache.dubbo.rpc.Protocol;
@ -42,7 +44,9 @@ public class DubboShutdownHook extends Thread {
/**
* Has it already been destroyed or not?
*/
private final AtomicBoolean destroyed= new AtomicBoolean(false);
private final AtomicBoolean destroyed = new AtomicBoolean(false);
private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
private DubboShutdownHook(String name) {
super(name);
@ -89,6 +93,8 @@ public class DubboShutdownHook extends Thread {
AbstractRegistryFactory.destroyAll();
// destroy all the protocols
destroyProtocols();
// dispatch the DubboDestroyedEvent @since 2.7.3
eventDispatcher.dispatch(new DubboServiceDestroyedEvent(this));
}
/**

View File

@ -32,12 +32,12 @@ import org.apache.dubbo.rpc.Protocol;
import java.util.Map;
import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.THREADPOOL_KEY;
import static org.apache.dubbo.config.Constants.PROTOCOLS_SUFFIX;
import static org.apache.dubbo.remoting.Constants.TELNET;
import static org.apache.dubbo.remoting.Constants.DUBBO_VERSION_KEY;
import static org.apache.dubbo.remoting.Constants.TELNET;
/**
* ProtocolConfig

View File

@ -23,11 +23,11 @@ import org.apache.dubbo.remoting.Constants;
import java.util.Map;
import static org.apache.dubbo.common.constants.CommonConstants.FILE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PASSWORD_KEY;
import static org.apache.dubbo.config.Constants.REGISTRIES_SUFFIX;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.USERNAME_KEY;
import static org.apache.dubbo.config.Constants.REGISTRIES_SUFFIX;
import static org.apache.dubbo.config.Constants.ZOOKEEPER_PROTOCOL;
import static org.apache.dubbo.registry.Constants.EXTRA_KEYS_KEY;

View File

@ -25,9 +25,11 @@ import java.util.Map;
/**
* AbstractBuilder
*
* @param <C> The type of {@link AbstractConfig Config}
* @param <B> The type of {@link AbstractBuilder Builder}
* @since 2.7
*/
public abstract class AbstractBuilder<T extends AbstractConfig, B extends AbstractBuilder> {
public abstract class AbstractBuilder<C extends AbstractConfig, B extends AbstractBuilder> {
/**
* The config id
*/
@ -62,7 +64,7 @@ public abstract class AbstractBuilder<T extends AbstractConfig, B extends Abstra
return parameters;
}
protected void build(T instance) {
protected void build(C instance) {
if (!StringUtils.isEmpty(id)) {
instance.setId(id);
}
@ -70,4 +72,11 @@ public abstract class AbstractBuilder<T extends AbstractConfig, B extends Abstra
instance.setPrefix(prefix);
}
}
/**
* Build an instance of {@link AbstractConfig config}
*
* @return an instance of {@link AbstractConfig config}
*/
public abstract C build();
}

View File

@ -185,6 +185,10 @@ public class ProtocolBuilder extends AbstractBuilder<ProtocolConfig, ProtocolBui
*/
private Boolean isDefault;
public ProtocolBuilder id(String id) {
return super.id(id);
}
public ProtocolBuilder name(String name) {
this.name = name;
return getThis();
@ -206,9 +210,9 @@ public class ProtocolBuilder extends AbstractBuilder<ProtocolConfig, ProtocolBui
}
/**
* @see org.apache.dubbo.config.builders.ProtocolBuilder#contextpath(String)
* @param path
* @return ProtocolBuilder
* @see org.apache.dubbo.config.builders.ProtocolBuilder#contextpath(String)
*/
@Deprecated
public ProtocolBuilder path(String path) {
@ -297,9 +301,9 @@ public class ProtocolBuilder extends AbstractBuilder<ProtocolConfig, ProtocolBui
}
/**
* @see org.apache.dubbo.config.builders.ProtocolBuilder#dispatcher(String)
* @param dispather
* @return ProtocolBuilder
* @see org.apache.dubbo.config.builders.ProtocolBuilder#dispatcher(String)
*/
@Deprecated
public ProtocolBuilder dispather(String dispather) {

View File

@ -64,6 +64,10 @@ public class ReferenceBuilder<T> extends AbstractReferenceBuilder<ReferenceConfi
*/
private String protocol;
public ReferenceBuilder<T> id(String id) {
return super.id(id);
}
public ReferenceBuilder<T> interfaceName(String interfaceName) {
this.interfaceName = interfaceName;
return getThis();

View File

@ -16,10 +16,10 @@
*/
package org.apache.dubbo.config.builders;
import java.util.Map;
import org.apache.dubbo.config.RegistryConfig;
import java.util.Map;
/**
* This is a builder for build {@link RegistryConfig}.
*
@ -134,6 +134,10 @@ public class RegistryBuilder extends AbstractBuilder<RegistryConfig, RegistryBui
*/
private String extraKeys;
public RegistryBuilder id(String id) {
return super.id(id);
}
public RegistryBuilder address(String address) {
this.address = address;
return getThis();

View File

@ -16,13 +16,13 @@
*/
package org.apache.dubbo.config.builders;
import java.util.ArrayList;
import java.util.List;
import org.apache.dubbo.config.MethodConfig;
import org.apache.dubbo.config.ProviderConfig;
import org.apache.dubbo.config.ServiceConfig;
import java.util.ArrayList;
import java.util.List;
/**
* This is a builder for build {@link ServiceConfig}.
*
@ -68,6 +68,10 @@ public class ServiceBuilder<U> extends AbstractServiceBuilder<ServiceConfig, Ser
*/
private String generic;
public ServiceBuilder id(String id) {
return super.id(id);
}
public ServiceBuilder<U> interfaceName(String interfaceName) {
this.interfaceName = interfaceName;
return getThis();

View File

@ -0,0 +1,32 @@
/*
* 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.event;
import org.apache.dubbo.event.Event;
/**
* An {@link Event Dubbo event} when the Dubbo service is about to be destroyed.
*
* @see Event
* @since 2.7.3
*/
public class DubboServiceDestroyedEvent extends Event {
public DubboServiceDestroyedEvent(Object source) {
super(source);
}
}

View File

@ -0,0 +1,41 @@
/*
* 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.event;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.event.Event;
/**
* The {@link ReferenceConfig Dubbo service ReferenceConfig} destroyed {@link Event event}
*
* @see Reference
* @see ReferenceConfig#destroy()
* @see Event
* @since 2.7.3
*/
public class ReferenceConfigDestroyedEvent extends Event {
public ReferenceConfigDestroyedEvent(ReferenceConfig referenceConfig) {
super(referenceConfig);
}
public ReferenceConfig getReferenceConfig() {
return (ReferenceConfig) getSource();
}
}

View File

@ -0,0 +1,48 @@
/*
* 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.event;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.event.Event;
import org.apache.dubbo.rpc.Invoker;
/**
* The {@link ReferenceConfig Dubbo service ReferenceConfig} initialized {@link Event event}
*
* @see Reference
* @see ReferenceConfig#get()
* @see Event
* @since 2.7.3
*/
public class ReferenceConfigInitializedEvent extends Event {
private final Invoker<?> invoker;
public ReferenceConfigInitializedEvent(ReferenceConfig referenceConfig, Invoker<?> invoker) {
super(referenceConfig);
this.invoker = invoker;
}
public ReferenceConfig getReferenceConfig() {
return (ReferenceConfig) getSource();
}
public Invoker<?> getInvoker() {
return invoker;
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.event;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.event.Event;
/**
* {@link ServiceConfig} event post-{@link ServiceConfig#export() export}
*
* @since 2.7.3
*/
public class ServiceConfigExportedEvent extends Event {
public ServiceConfigExportedEvent(ServiceConfig source) {
super(source);
}
public ServiceConfig getServiceConfig() {
return (ServiceConfig) getSource();
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.event;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.event.Event;
/**
* {@link ServiceConfig} event post-{@link ServiceConfig#unexport() unexport}
*
* @since 2.7.3
*/
public class ServiceConfigUnexportedEvent extends Event {
public ServiceConfigUnexportedEvent(ServiceConfig source) {
super(source);
}
public ServiceConfig getServiceConfig() {
return (ServiceConfig) getSource();
}
}

View File

@ -0,0 +1,51 @@
/*
* 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.event.listener;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.event.DubboServiceDestroyedEvent;
import org.apache.dubbo.config.event.ServiceConfigExportedEvent;
import org.apache.dubbo.event.Event;
import org.apache.dubbo.event.GenericEventListener;
import static java.lang.String.format;
/**
* A listener for logging the {@link Event Dubbo event}
*
* @see ServiceConfigExportedEvent
* @since 2.7.3
*/
public class LoggingEventListener extends GenericEventListener {
private static final String NAME = "Dubbo Service";
private final Logger logger = LoggerFactory.getLogger(getClass());
public void onEvent(DubboServiceDestroyedEvent event) {
if (logger.isInfoEnabled()) {
logger.info(NAME + " has been destroyed.");
}
}
private void debug(String pattern, Object... args) {
if (logger.isDebugEnabled()) {
logger.debug(format(pattern, args));
}
}
}

View File

@ -0,0 +1,55 @@
/*
* 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.event.listener;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.config.event.ServiceConfigExportedEvent;
import org.apache.dubbo.event.EventListener;
import org.apache.dubbo.metadata.ServiceNameMapping;
import java.util.List;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.metadata.ServiceNameMapping.getDefaultExtension;
/**
* An {@link EventListener event listener} for mapping {@link ServiceConfig#getExportedUrls() the exported Dubbo
* service inerface} to its service name
*
* @see ServiceNameMapping
* @see ServiceConfig#getExportedUrls()
* @since 2.7.3
*/
public class ServiceNameMappingListener implements EventListener<ServiceConfigExportedEvent> {
private final ServiceNameMapping serviceNameMapping = getDefaultExtension();
@Override
public void onEvent(ServiceConfigExportedEvent event) {
ServiceConfig serviceConfig = event.getServiceConfig();
List<URL> exportedURLs = serviceConfig.getExportedUrls();
exportedURLs.forEach(url -> {
String serviceInterface = url.getServiceInterface();
String group = url.getParameter(GROUP_KEY);
String version = url.getParameter(VERSION_KEY);
String protocol = url.getProtocol();
serviceNameMapping.map(serviceInterface, group, version, protocol);
});
}
}

View File

@ -0,0 +1,131 @@
/*
* 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.metadata;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.AbstractConfig;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.metadata.LocalMetadataService;
import org.apache.dubbo.metadata.MetadataService;
import org.apache.dubbo.metadata.MetadataServiceExporter;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import static java.util.Collections.unmodifiableList;
/**
* {@link MetadataServiceExporter} implementation based on {@link AbstractConfig Dubbo configurations}, the clients
* should make sure the {@link ApplicationConfig}, {@link RegistryConfig} and {@link ProtocolConfig} are ready before
* {@link #export()}.
* <p>
* Typically, do not worry about their ready status, because they are initialized before
* any {@link ServiceConfig} exports, or The Dubbo export will be failed.
*
* @see MetadataServiceExporter
* @see ServiceConfig
* @see ConfigManager
* @since 2.7.3
*/
public class ConfigurableMetadataServiceExporter implements MetadataServiceExporter {
private final Logger logger = LoggerFactory.getLogger(getClass());
private volatile ServiceConfig<MetadataService> serviceConfig;
private ApplicationConfig applicationConfig;
private List<RegistryConfig> registries = new LinkedList<>();
private List<ProtocolConfig> protocols = new LinkedList<>();
public void setApplicationConfig(ApplicationConfig applicationConfig) {
this.applicationConfig = applicationConfig;
}
public void setRegistries(Collection<RegistryConfig> registries) {
this.registries.clear();
this.registries.addAll(registries);
}
public void setProtocols(Collection<ProtocolConfig> protocols) {
this.protocols.clear();
this.protocols.addAll(protocols);
}
@Override
public List<URL> export() {
if (!isExported()) {
LocalMetadataService metadataService = LocalMetadataService.getDefaultExtension();
ServiceConfig<MetadataService> serviceConfig = new ServiceConfig<>();
serviceConfig.setApplication(applicationConfig);
serviceConfig.setRegistries(registries);
serviceConfig.setProtocols(protocols);
serviceConfig.setInterface(MetadataService.class);
serviceConfig.setRef(metadataService);
serviceConfig.setGroup(getApplicationConfig().getName());
serviceConfig.setVersion(metadataService.version());
// export
serviceConfig.export();
if (logger.isInfoEnabled()) {
logger.info("The MetadataService exports urls : " + serviceConfig.getExportedUrls());
}
this.serviceConfig = serviceConfig;
} else {
if (logger.isWarnEnabled()) {
logger.warn("The MetadataService has been exported : " + serviceConfig.getExportedUrls());
}
}
return serviceConfig.getExportedUrls();
}
@Override
public void unexport() {
if (isExported()) {
serviceConfig.unexport();
}
}
private List<ProtocolConfig> getProtocols() {
return unmodifiableList(protocols);
}
private List<RegistryConfig> getRegistries() {
return unmodifiableList(registries);
}
private ApplicationConfig getApplicationConfig() {
return applicationConfig;
}
private boolean isExported() {
return serviceConfig != null && serviceConfig.isExported();
}
}

View File

@ -0,0 +1,53 @@
/*
* 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.metadata;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.registry.client.DefaultServiceInstance;
import org.apache.dubbo.registry.client.ServiceInstance;
import org.apache.dubbo.registry.client.ServiceInstanceCustomizer;
/**
* The {@link ServiceInstanceCustomizer} to customize the {@link ServiceInstance#getPort() port} of service instance.
*
* @since 2.7.3
*/
public class ServiceInstancePortCustomizer implements ServiceInstanceCustomizer {
@Override
public void customize(ServiceInstance serviceInstance) {
if (serviceInstance.getPort() != null
|| serviceInstance.getPort().intValue() < 1) {
return;
}
ConfigManager.getInstance()
.getProtocols()
.values()
.stream()
.findFirst()
.ifPresent(protocolConfig -> {
if (serviceInstance instanceof DefaultServiceInstance) {
DefaultServiceInstance instance = (DefaultServiceInstance) serviceInstance;
if (protocolConfig.getPort() != null) {
instance.setPort(protocolConfig.getPort());
}
}
});
}
}

View File

@ -0,0 +1,2 @@
org.apache.dubbo.config.event.listener.ServiceNameMappingListener
org.apache.dubbo.config.event.listener.LoggingEventListener

View File

@ -0,0 +1 @@
org.apache.dubbo.config.metadata.ServiceInstancePortCustomizer

View File

@ -0,0 +1,63 @@
/*
* 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.api.DemoService;
import java.io.IOException;
/**
* Dubbo Consumer Bootstrap
*
* @since 2.7.3
*/
public class DubboConsumerBootstrap {
public static void main(String[] args) throws IOException, InterruptedException {
ApplicationConfig application = new ApplicationConfig();
application.setName("dubbo-consumer-demo");
// 连接注册中心配置
RegistryConfig registry = new RegistryConfig();
registry.setAddress("zookeeper://127.0.0.1:2181?registry-type=service");
// 服务提供者协议配置
ProtocolConfig protocol = new ProtocolConfig();
protocol.setName("dubbo");
protocol.setPort(12345);
ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>(); // 此实例很重封装了与注册中心的连接以及与提供者的连接请自行缓存否则可能造成内存和连接泄漏
reference.setApplication(application);
reference.setRegistry(registry); // 多个注册中心可以用setRegistries()
reference.setInterface(DemoService.class);
reference.setVersion("1.0.0");
reference.setProtocol("dubbo");
reference.setCheck(false);
// 和本地bean一样使用xxxService
DemoService demoService1 = reference.get();
for (int i = 0; i < 1000; i++) {
System.out.println(demoService1.sayName("Hello,World"));
Thread.sleep(1000);
}
System.in.read();
}
}

View File

@ -0,0 +1,84 @@
/*
* 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.common.URL;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.config.api.DemoService;
import org.apache.dubbo.config.metadata.ConfigurableMetadataServiceExporter;
import org.apache.dubbo.config.provider.impl.DemoServiceImpl;
import org.apache.dubbo.metadata.MetadataServiceExporter;
import org.apache.dubbo.registry.client.DefaultServiceInstance;
import org.apache.dubbo.registry.client.ServiceDiscovery;
import org.apache.dubbo.registry.client.ServiceDiscoveryFactory;
import java.io.IOException;
/**
* Dubbo Provider Bootstrap
*/
public class DubboProviderBootstrap {
public static void main(String[] args) throws IOException {
ApplicationConfig application = new ApplicationConfig();
application.setName("dubbo-provider-demo");
URL connectionURL = URL.valueOf("zookeeper://127.0.0.1:2181?registry-type=service");
// 连接注册中心配置
RegistryConfig registry = new RegistryConfig();
registry.setAddress(connectionURL.toString());
// 服务提供者协议配置
ProtocolConfig protocol = new ProtocolConfig();
protocol.setName("dubbo");
protocol.setPort(NetUtils.getAvailablePort());
DemoService demoService = new DemoServiceImpl();
ServiceConfig<DemoService> service = new ServiceConfig<>();
service.setApplication(application);
service.setRegistry(registry); // 多个注册中心可以用setRegistries()
service.setProtocol(protocol); // 多个协议可以用setProtocols()
service.setInterface(DemoService.class);
service.setRef(demoService);
service.setVersion("1.0.0");
// 暴露及注册服务
service.export();
MetadataServiceExporter exporter = new ConfigurableMetadataServiceExporter();
// 暴露 MetadataService 服务
exporter.export();
ServiceDiscoveryFactory factory = ServiceDiscoveryFactory.getDefaultExtension();
ServiceDiscovery serviceDiscovery = factory.create(connectionURL);
serviceDiscovery.start();
DefaultServiceInstance serviceInstance = new DefaultServiceInstance(application.getName(), "127.0.0.1", protocol.getPort());
serviceDiscovery.register(serviceInstance);
System.in.read();
serviceDiscovery.stop();
}
}

View File

@ -21,20 +21,30 @@ import org.apache.dubbo.config.annotation.Method;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.api.DemoService;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.config.event.ReferenceConfigDestroyedEvent;
import org.apache.dubbo.config.event.ReferenceConfigInitializedEvent;
import org.apache.dubbo.config.provider.impl.DemoServiceImpl;
import org.apache.dubbo.event.EventDispatcher;
import org.apache.dubbo.event.EventListener;
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.concurrent.atomic.AtomicReference;
import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ReferenceConfigTest {
private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
@BeforeEach
public void setUp() {
ConfigManager.getInstance().clear();
eventDispatcher.removeAllEventListeners();
}
@AfterEach
@ -67,12 +77,38 @@ public class ReferenceConfigTest {
rc.setInterface(DemoService.class.getName());
rc.setInjvm(false);
AtomicReference<ReferenceConfig> reference = new AtomicReference<>();
eventDispatcher.addEventListener(new EventListener<ReferenceConfigInitializedEvent>() {
@Override
public void onEvent(ReferenceConfigInitializedEvent event) {
reference.set(event.getReferenceConfig());
}
});
try {
System.setProperty("java.net.preferIPv4Stack", "true");
demoService.export();
rc.get();
assertEquals(rc, reference.get());
reference.compareAndSet(rc, null);
Assertions.assertTrue(!LOCAL_PROTOCOL.equalsIgnoreCase(
rc.getInvoker().getUrl().getProtocol()));
eventDispatcher.addEventListener(new EventListener<ReferenceConfigDestroyedEvent>() {
@Override
public void onEvent(ReferenceConfigDestroyedEvent event) {
reference.set(event.getReferenceConfig());
}
});
rc.destroy();
assertEquals(rc, reference.get());
} finally {
System.clearProperty("java.net.preferIPv4Stack");
demoService.unexport();
@ -134,17 +170,17 @@ public class ReferenceConfigTest {
Reference reference = getClass().getDeclaredField("innerTest").getAnnotation(Reference.class);
ReferenceConfig referenceConfig = new ReferenceConfig(reference);
Assertions.assertTrue(referenceConfig.getMethods().size() == 1);
Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getName(), "sayHello");
assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getName(), "sayHello");
Assertions.assertTrue(((MethodConfig) referenceConfig.getMethods().get(0)).getTimeout() == 1300);
Assertions.assertTrue(((MethodConfig) referenceConfig.getMethods().get(0)).getRetries() == 4);
Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getLoadbalance(), "random");
assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getLoadbalance(), "random");
Assertions.assertTrue(((MethodConfig) referenceConfig.getMethods().get(0)).getActives() == 3);
Assertions.assertTrue(((MethodConfig) referenceConfig.getMethods().get(0)).getExecutes() == 5);
Assertions.assertTrue(((MethodConfig) referenceConfig.getMethods().get(0)).isAsync());
Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOninvoke(), "i");
Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOnreturn(), "r");
Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOnthrow(), "t");
Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getCache(), "c");
assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOninvoke(), "i");
assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOnreturn(), "r");
assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOnthrow(), "t");
assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getCache(), "c");
}

View File

@ -23,8 +23,8 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.apache.dubbo.config.Constants.SHUTDOWN_TIMEOUT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
import static org.apache.dubbo.config.Constants.SHUTDOWN_TIMEOUT_KEY;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;

View File

@ -21,10 +21,14 @@ import org.apache.dubbo.common.URL;
import org.apache.dubbo.config.api.DemoService;
import org.apache.dubbo.config.api.Greeting;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.config.event.ServiceConfigExportedEvent;
import org.apache.dubbo.config.event.ServiceConfigUnexportedEvent;
import org.apache.dubbo.config.mock.MockProtocol2;
import org.apache.dubbo.config.mock.MockRegistryFactory2;
import org.apache.dubbo.config.mock.TestProxyFactory;
import org.apache.dubbo.config.provider.impl.DemoServiceImpl;
import org.apache.dubbo.event.EventDispatcher;
import org.apache.dubbo.event.EventListener;
import org.apache.dubbo.registry.Registry;
import org.apache.dubbo.rpc.Exporter;
import org.apache.dubbo.rpc.Invoker;
@ -40,22 +44,23 @@ import org.mockito.Mockito;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;
import static org.apache.dubbo.config.Constants.SHUTDOWN_TIMEOUT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.config.Constants.SHUTDOWN_TIMEOUT_KEY;
import static org.apache.dubbo.remoting.Constants.BIND_IP_KEY;
import static org.apache.dubbo.remoting.Constants.BIND_PORT_KEY;
import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
import static org.apache.dubbo.rpc.Constants.GENERIC_SERIALIZATION_BEAN;
import static org.apache.dubbo.rpc.Constants.GENERIC_SERIALIZATION_DEFAULT;
import static org.apache.dubbo.rpc.Constants.GENERIC_SERIALIZATION_NATIVE_JAVA;
import static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
@ -75,6 +80,8 @@ public class ServiceConfigTest {
private ServiceConfig<DemoServiceImpl> service2 = new ServiceConfig<DemoServiceImpl>();
private ServiceConfig<DemoServiceImpl> delayService = new ServiceConfig<DemoServiceImpl>();
private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
@BeforeEach
public void setUp() throws Exception {
MockProtocol2.delegate = protocolDelegate;
@ -135,8 +142,20 @@ public class ServiceConfigTest {
@Test
public void testExport() throws Exception {
AtomicReference reference = new AtomicReference();
eventDispatcher.addEventListener(new EventListener<ServiceConfigExportedEvent>() {
@Override
public void onEvent(ServiceConfigExportedEvent event) {
reference.set(event.getServiceConfig());
}
});
service.export();
assertEquals(service, reference.get());
assertThat(service.getExportedUrls(), hasSize(1));
URL url = service.toUrl();
assertThat(url.getProtocol(), equalTo("mockprotocol2"));
@ -178,8 +197,32 @@ public class ServiceConfigTest {
public void testUnexport() throws Exception {
System.setProperty(SHUTDOWN_WAIT_KEY, "0");
try {
AtomicReference reference = new AtomicReference();
eventDispatcher.addEventListener(new EventListener<ServiceConfigExportedEvent>() {
@Override
public void onEvent(ServiceConfigExportedEvent event) {
reference.set(event.getServiceConfig());
}
});
service.export();
assertEquals(service, reference.get());
assertTrue(reference.compareAndSet(service, null));
eventDispatcher.addEventListener(new EventListener<ServiceConfigUnexportedEvent>() {
@Override
public void onEvent(ServiceConfigUnexportedEvent event) {
reference.set(event.getServiceConfig());
}
});
service.unexport();
assertEquals(service, reference.get());
Thread.sleep(1000);
Mockito.verify(exporter, Mockito.atLeastOnce()).unexport();
} finally {

View File

@ -34,4 +34,7 @@ public interface DemoService {
int echo(int i);
// default String name() {
// return getClass().getSimpleName();
// }
}

View File

@ -0,0 +1,63 @@
/*
* 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.event.listener;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.config.api.DemoService;
import org.apache.dubbo.config.provider.impl.DemoServiceImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
* {@link ServiceNameMappingListener} Test
*
* @since 2.7.3
*/
public class ServiceNameMappingListenerTest {
private ServiceConfig<DemoServiceImpl> service = new ServiceConfig<DemoServiceImpl>();
@BeforeEach
public void init() {
ApplicationConfig applicationConfig = new ApplicationConfig("app");
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setName("mockprotocol");
RegistryConfig registry = new RegistryConfig();
registry.setProtocol("mockprotocol");
registry.setAddress("N/A");
service.setInterface(DemoService.class);
service.setRef(new DemoServiceImpl());
service.setApplication(applicationConfig);
service.setProtocol(protocolConfig);
service.setRegistry(registry);
}
@Test
public void testOnEvent() {
service.export();
}
}

View File

@ -0,0 +1,88 @@
/*
* 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.metadata;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ProtocolConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.metadata.MetadataService;
import org.apache.dubbo.metadata.MetadataServiceExporter;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* {@link ConfigurableMetadataServiceExporter} Test
*
* @since 2.7.3
*/
public class ConfigurableMetadataServiceExporterTest {
@BeforeAll
public static void init() {
ConfigManager configManager = ConfigManager.getInstance();
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("test");
configManager.setApplication(applicationConfig);
// Add ProtocolConfig
configManager.addProtocol(protocolConfig());
// Add RegistryConfig
configManager.addRegistry(registryConfig());
}
private static ProtocolConfig protocolConfig() {
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setName("mockprotocol");
protocolConfig.setPort(20880);
return protocolConfig;
}
private static RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("mockregistry://127.0.0.1");
return registryConfig;
}
@Test
public void testExportAndUnexport() {
MetadataServiceExporter exporter = new ConfigurableMetadataServiceExporter();
List<URL> urls = exporter.export();
assertEquals(1, urls.size());
URL url = urls.get(0);
assertEquals("test", url.getParameter(APPLICATION_KEY));
assertEquals(MetadataService.class.getName(), url.getServiceInterface());
assertEquals("test", url.getParameter(GROUP_KEY));
assertEquals(MetadataService.VERSION, url.getParameter(VERSION_KEY));
assertEquals("mockprotocol", url.getProtocol());
exporter.unexport();
}
}

View File

@ -16,20 +16,27 @@
*/
package org.apache.dubbo.config.provider.impl;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.api.Box;
import org.apache.dubbo.config.api.DemoException;
import org.apache.dubbo.config.api.DemoService;
import org.apache.dubbo.config.api.User;
import org.apache.dubbo.rpc.RpcContext;
import java.util.List;
import static java.lang.String.format;
/**
* DemoServiceImpl
*/
public class DemoServiceImpl implements DemoService {
private final Logger logger = LoggerFactory.getLogger(getClass());
public String sayName(String name) {
return "say:" + name;
return log("say:" + name);
}
public Box getBox() {
@ -48,4 +55,12 @@ public class DemoServiceImpl implements DemoService {
return i;
}
private <T> T log(T object) {
RpcContext rpcContext = RpcContext.getContext();
logger.info(format("RPC Invocation [ client - %s:%s , provider - %s:%s] : %s",
rpcContext.getRemoteHost(), rpcContext.getRemotePort(),
rpcContext.getLocalHost(), rpcContext.getLocalPort(),
object));
return object;
}
}

View File

@ -27,10 +27,10 @@ import org.apache.dubbo.rpc.ProxyFactory;
import java.io.IOException;
import java.net.ServerSocket;
import static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_STICKY_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DUBBO_PROTOCOL;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
import static org.apache.dubbo.rpc.Constants.CALLBACK_INSTANCES_LIMIT_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_STICKY_KEY;
/**
* SimpleRegistryExporter

View File

@ -19,7 +19,12 @@ package org.apache.dubbo.configcenter;
import org.apache.dubbo.common.config.Configuration;
import org.apache.dubbo.common.config.Environment;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
@ -28,12 +33,13 @@ import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoad
* <br/>
* From the use scenario internally in framework, there're mainly three kinds of methods:
* <ul>
* <li>1. getConfig, get governance rules or single config item from Config Center.</li>
* <li>2. getConfigFile, get configuration file from Config Center at start up.</li>
* <li>3. addListener/removeListener, add or remove listeners for governance rules or config items that need to watch.</li>
* <li>1. getConfig, get governance rules or single config item from Config Center.</li>
* <li>2. getConfigFile, get configuration file from Config Center at start up.</li>
* <li>3. addListener/removeListener, add or remove listeners for governance rules or config items that need to watch.</li>
* </ul>
*/
public interface DynamicConfiguration extends Configuration {
String DEFAULT_GROUP = "dubbo";
/**
@ -113,7 +119,7 @@ public interface DynamicConfiguration extends Configuration {
/**
* {@see #getConfig(String, String, long)}
*
* <p>
* This method are mostly used to get a compound config file, such as a complete dubbo.properties file.
*/
default String getConfigs(String key, String group) throws IllegalStateException {
@ -122,11 +128,67 @@ public interface DynamicConfiguration extends Configuration {
/**
* {@see #getConfig(String, String, long)}
*
* <p>
* This method are mostly used to get a compound config file, such as a complete dubbo.properties file.
*/
String getConfigs(String key, String group, long timeout) throws IllegalStateException;
/**
* Publish Config mapped to the given key and the given group.
*
* @param key the key to represent a configuration
* @param group the group where the key belongs to
* @param content the content of configuration
* @return <code>true</code> if success, or <code>false</code>
* @throws UnsupportedOperationException If the under layer does not support
* @since 2.7.3
*/
default boolean publishConfig(String key, String group, String content) throws UnsupportedOperationException {
throw new UnsupportedOperationException("No support");
}
/**
* Get the config keys by the specified group
*
* @param group the specified group
* @return the read-only non-null sorted {@link Set set} of config keys
* @throws UnsupportedOperationException If the under layer does not support
* @since 2.7.3
*/
default SortedSet<String> getConfigKeys(String group) throws UnsupportedOperationException {
throw new UnsupportedOperationException("No support");
}
/**
* Get the {@link SortedMap} with with config keys and contents value by the specified group
*
* @param group the specified group
* @return the read-only non-null sorted {@link SortedMap map}
* @throws UnsupportedOperationException If the under layer does not support
* @since 2.7.3
*/
default SortedMap<String, String> getConfigs(String group) throws UnsupportedOperationException {
return getConfigs(group, -1);
}
/**
* Get the {@link SortedMap} with with config keys and content value by the specified group
*
* @param group the specified group
* @param timeout the millisecond for timeout
* @return the read-only non-null sorted {@link SortedMap map}
* @throws UnsupportedOperationException If the under layer does not support
* @throws IllegalStateException If timeout exceeds
* @since 2.7.3
*/
default SortedMap<String, String> getConfigs(String group, long timeout) throws UnsupportedOperationException,
IllegalStateException {
SortedMap<String, String> configs = new TreeMap<>();
SortedSet<String> configKeys = getConfigKeys(group);
configKeys.forEach(key -> configs.put(key, getConfig(key, group, timeout)));
return Collections.unmodifiableSortedMap(configs);
}
/**
* Find DynamicConfiguration instance
*

View File

@ -20,6 +20,10 @@ import org.apache.dubbo.common.URL;
import org.apache.dubbo.configcenter.ConfigurationListener;
import org.apache.dubbo.configcenter.DynamicConfiguration;
import java.util.SortedSet;
import static java.util.Collections.emptySortedSet;
/**
* The default extension of {@link DynamicConfiguration}. If user does not specify a config centre, or specifies one
* that is not a valid extension, it will default to this one.
@ -30,7 +34,6 @@ public class NopDynamicConfiguration implements DynamicConfiguration {
// no-op
}
@Override
public Object getInternalProperty(String key) {
return null;
@ -55,4 +58,20 @@ public class NopDynamicConfiguration implements DynamicConfiguration {
public String getConfigs(String key, String group, long timeout) throws IllegalStateException {
return null;
}
/**
* @since 2.7.3
*/
@Override
public boolean publishConfig(String key, String group, String content) {
return true;
}
/**
* @since 2.7.3
*/
@Override
public SortedSet<String> getConfigKeys(String group) {
return emptySortedSet();
}
}

View File

@ -0,0 +1,70 @@
/*
* 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.configcenter.support.nop;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* {@link NopDynamicConfiguration} Test
*
* @since 2.7.3
*/
public class NopDynamicConfigurationTest {
private NopDynamicConfiguration configuration = new NopDynamicConfiguration(null);
@Test
public void testGetInternalProperty() {
assertNull(configuration.getInternalProperty(null));
}
@Test
public void testGetConfig() {
assertNull(configuration.getConfig(null, null, -1));
}
@Test
public void testGetConfigs() {
assertNull(configuration.getConfigs(null, null, -1));
}
@Test
public void testAddListener() {
configuration.addListener(null, null, null);
}
@Test
public void testRemoveListener() {
configuration.removeListener(null, null, null);
}
@Test
public void testPublishConfig() {
assertTrue(configuration.publishConfig(null, null, null));
}
@Test
public void testGetConfigKeys() {
assertTrue(configuration.getConfigKeys(null).isEmpty());
}
}

View File

@ -27,16 +27,25 @@ import org.apache.dubbo.remoting.zookeeper.ZookeeperTransporter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import static java.util.Collections.emptySortedSet;
import static java.util.Collections.unmodifiableSortedSet;
import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;
import static org.apache.dubbo.configcenter.Constants.CONFIG_NAMESPACE_KEY;
/**
*
*/
public class ZookeeperDynamicConfiguration implements DynamicConfiguration {
private static final String EMPTY_STRING = "";
private static final Logger logger = LoggerFactory.getLogger(ZookeeperDynamicConfiguration.class);
private Executor executor;
@ -91,24 +100,8 @@ public class ZookeeperDynamicConfiguration implements DynamicConfiguration {
@Override
public String getConfig(String key, String group, long timeout) throws IllegalStateException {
/**
* when group is not null, we are getting startup configs from Config Center, for example:
* group=dubbo, key=dubbo.properties
*/
if (StringUtils.isNotEmpty(group)) {
key = group + "/" + key;
}
/**
* when group is null, we are fetching governance rules, for example:
* 1. key=org.apache.dubbo.DemoService.configurators
* 2. key = org.apache.dubbo.DemoService.condition-router
*/
else {
int i = key.lastIndexOf(".");
key = key.substring(0, i) + "/" + key.substring(i + 1);
}
return (String) getInternalProperty(rootPath + "/" + key);
String path = buildPath(key, group);
return (String) getInternalProperty(path);
}
/**
@ -122,6 +115,54 @@ public class ZookeeperDynamicConfiguration implements DynamicConfiguration {
*/
@Override
public String getConfigs(String key, String group, long timeout) throws IllegalStateException {
return (String) getConfig(key, group, timeout);
return getConfig(key, group, timeout);
}
@Override
public boolean publishConfig(String key, String group, String content) {
String path = buildPath(key, group);
zkClient.create(path, content, true);
return true;
}
@Override
public SortedSet<String> getConfigKeys(String group) {
String path = buildPath(group);
List<String> nodes = zkClient.getChildren(path);
return isEmpty(nodes) ? emptySortedSet() : unmodifiableSortedSet(new TreeSet<>(nodes));
}
/**
* Build the config node path by the specified <code>key</code> and <code>group</code>
*
* @param key the key to represent a configuration
* @param group the group where the key belongs to
* @return
*/
protected String buildPath(String key, String group) {
String path = null;
/**
* when group is not null, we are getting startup configs from Config Center, for example:
* group=dubbo, key=dubbo.properties
*/
if (StringUtils.isNotEmpty(group)) {
path = group + "/" + key;
}
/**
* when group is null, we are fetching governance rules, for example:
* 1. key=org.apache.dubbo.DemoService.configurators
* 2. key = org.apache.dubbo.DemoService.condition-router
*/
else {
int i = key.lastIndexOf(".");
path = key.substring(0, i) + "/" + key.substring(i + 1);
}
return buildPath(path);
}
protected String buildPath(String relativePath) {
String path = rootPath + "/" + relativePath;
return path;
}
}

View File

@ -35,8 +35,14 @@ import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* TODO refactor using mockito
*/
@ -122,6 +128,39 @@ public class ZookeeperDynamicConfigurationTest {
Assertions.assertEquals("new value2", listener4.getValue());
}
@Test
public void testPublishConfig() {
String key = "user-service";
String group = "org.apache.dubbo.service.UserService";
String content = "test";
assertTrue(configuration.publishConfig(key, group, content));
assertEquals("test", configuration.getConfigs(key, group));
}
@Test
public void testGetConfigKeysAndContents() {
String key = "user-service";
String group = "org.apache.dubbo.service.UserService";
String content = "test";
String key2 = "user-service-1";
assertTrue(configuration.publishConfig(key, group, content));
assertTrue(configuration.publishConfig(key2, group, content));
Set<String> configKeys = configuration.getConfigKeys(group);
assertEquals(new TreeSet(asList(key, key2)), configKeys);
Map<String, String> configs = configuration.getConfigs(group);
assertEquals(configs.keySet(), configKeys);
configs.forEach((k, value) -> assertEquals(content, value));
}
private class TestListener implements ConfigurationListener {
private CountDownLatch latch;
private String value;

View File

@ -153,7 +153,7 @@
<mortbay_jetty_version>6.1.26</mortbay_jetty_version>
<portlet_version>2.0</portlet_version>
<maven_flatten_version>1.1.0</maven_flatten_version>
<revision>2.7.2-SNAPSHOT</revision>
<revision>2.7.3-SNAPSHOT</revision>
</properties>
<dependencyManagement>
@ -228,6 +228,17 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-x-discovery</artifactId>
<version>${curator_version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>

View File

@ -32,7 +32,7 @@
<packaging>pom</packaging>
<properties>
<revision>2.7.2-SNAPSHOT</revision>
<revision>2.7.3-SNAPSHOT</revision>
<maven_flatten_version>1.1.0</maven_flatten_version>
</properties>

45
dubbo-event/pom.xml Normal file
View File

@ -0,0 +1,45 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-parent</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-event</artifactId>
<packaging>jar</packaging>
<name>dubbo-event</name>
<description>The event module of Dubbo project</description>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-common</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,155 @@
/*
* 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.event;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import static java.util.Collections.sort;
import static java.util.Collections.unmodifiableList;
import static java.util.ServiceLoader.load;
import static org.apache.dubbo.event.EventListener.findEventType;
/**
* The abstract {@link EventDispatcher} providers the common implementation.
*
* @see EventDispatcher
* @see Listenable
* @see ServiceLoader
* @see EventListener
* @see Event
* @since 2.7.3
*/
public abstract class AbstractEventDispatcher implements EventDispatcher {
private final Object mutex = new Object();
private final ConcurrentMap<Class<? extends Event>, List<EventListener>> listenersCache = new ConcurrentHashMap<>();
private final Executor executor;
/**
* Constructor with an instance of {@link Executor}
*
* @param executor {@link Executor}
* @throws NullPointerException <code>executor</code> is <code>null</code>
*/
protected AbstractEventDispatcher(Executor executor) {
if (executor == null) {
throw new NullPointerException("executor must not be null");
}
this.executor = executor;
this.loadEventListenerInstances();
}
@Override
public void addEventListener(EventListener<?> listener) throws NullPointerException, IllegalArgumentException {
Listenable.assertListener(listener);
doInListener(listener, listeners -> {
addIfAbsent(listeners, listener);
});
}
@Override
public void removeEventListener(EventListener<?> listener) throws NullPointerException, IllegalArgumentException {
Listenable.assertListener(listener);
doInListener(listener, listeners -> listeners.remove(listener));
}
@Override
public List<EventListener<?>> getAllEventListeners() {
List<EventListener<?>> listeners = new LinkedList<>();
listenersCache
.entrySet()
.stream()
.map(Map.Entry::getValue)
.flatMap(Collection::stream)
.forEach(listener -> {
addIfAbsent(listeners, listener);
});
sort((List) listeners);
return unmodifiableList(listeners);
}
private <E> void addIfAbsent(Collection<E> collection, E element) {
if (!collection.contains(element)) {
collection.add(element);
}
}
@Override
public void dispatch(Event event) {
Executor executor = getExecutor();
// execute in sequential or parallel execution model
executor.execute(() -> {
listenersCache.entrySet()
.stream()
.filter(entry -> entry.getKey().isAssignableFrom(event.getClass()))
.map(Map.Entry::getValue)
.flatMap(Collection::stream)
.forEach(listener -> {
listener.onEvent(event);
});
});
}
/**
* @return the non-null {@link Executor}
*/
@Override
public final Executor getExecutor() {
return executor;
}
protected void doInListener(EventListener<?> listener, Consumer<Collection<EventListener>> consumer) {
Class<? extends Event> eventType = findEventType(listener);
if (eventType != null) {
synchronized (mutex) {
List<EventListener> listeners = listenersCache.computeIfAbsent(eventType, e -> new LinkedList<>());
// consume
consumer.accept(listeners);
// sort
sort(listeners);
}
}
}
/**
* Default, load the instances of {@link EventListener event listeners} by {@link ServiceLoader}
* <p>
* It could be override by the sub-class
*
* @see EventListener
* @see ServiceLoader#load(Class)
*/
protected void loadEventListenerInstances() {
ServiceLoader<EventListener> serviceLoader = load(EventListener.class, getClass().getClassLoader());
serviceLoader.forEach(this::addEventListener);
}
}

View File

@ -0,0 +1,30 @@
/*
* 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.event;
/**
* Direct {@link EventDispatcher} implementation uses current thread execution model
*
* @see EventDispatcher
* @since 2.7.3
*/
public final class DirectEventDispatcher extends AbstractEventDispatcher {
public DirectEventDispatcher() {
super(DIRECT_EXECUTOR);
}
}

View File

@ -0,0 +1,49 @@
/*
* 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.event;
import java.util.EventObject;
/**
* An event object of Dubbo is based on the Java standard {@link EventObject event}
*
* @since 2.7.3
*/
public abstract class Event extends EventObject {
private static final long serialVersionUID = -1704315605423947137L;
/**
* The timestamp of event occurs
*/
private final long timestamp;
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
public Event(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
public long getTimestamp() {
return timestamp;
}
}

View File

@ -0,0 +1,66 @@
/*
* 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.event;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.extension.SPI;
import java.util.concurrent.Executor;
/**
* {@link Event Dubbo Event} Dispatcher
*
* @see Event
* @see EventListener
* @see DirectEventDispatcher
* @since 2.7.3
*/
@SPI("direct")
public interface EventDispatcher extends Listenable<EventListener<?>> {
/**
* Direct {@link Executor} uses sequential execution model
*/
Executor DIRECT_EXECUTOR = Runnable::run;
/**
* Dispatch a Dubbo event to the registered {@link EventListener Dubbo event listeners}
*
* @param event a {@link Event Dubbo event}
*/
void dispatch(Event event);
/**
* The {@link Executor} to dispatch a {@link Event Dubbo event}
*
* @return default implementation directly invoke {@link Runnable#run()} method, rather than multiple-threaded
* {@link Executor}. If the return value is <code>null</code>, the behavior is same as default.
* @see #DIRECT_EXECUTOR
*/
default Executor getExecutor() {
return DIRECT_EXECUTOR;
}
/**
* The default extension of {@link EventDispatcher} is loaded by {@link ExtensionLoader}
*
* @return the default extension of {@link EventDispatcher}
*/
static EventDispatcher getDefaultExtension() {
return ExtensionLoader.getExtensionLoader(EventDispatcher.class).getDefaultExtension();
}
}

View File

@ -0,0 +1,124 @@
/*
* 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.event;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Objects;
import static java.lang.Integer.compare;
import static org.apache.dubbo.common.utils.ReflectUtils.findParameterizedTypes;
/**
* The {@link Event Dubbo Event} Listener that is based on Java standard {@link java.util.EventListener} interface supports
* the generic {@link Event}.
* <p>
* The {@link #onEvent(Event) handle method} will be notified when the matched-type {@link Event Dubbo Event} is
* published, whose priority could be changed by {@link #getPriority()} method.
*
* @param <E> the concrete class of {@link Event Dubbo Event}
* @see Event
* @see java.util.EventListener
* @since 2.7.3
*/
@FunctionalInterface
public interface EventListener<E extends Event> extends java.util.EventListener, Comparable<EventListener<E>> {
/**
* Handle a {@link Event Dubbo Event} when it's be published
*
* @param event a {@link Event Dubbo Event}
*/
void onEvent(E event);
/**
* The priority of {@link EventListener current listener}.
*
* @return the value is more greater, the priority is more lower.
* {@link Integer#MIN_VALUE} indicates the highest priority. The default value is {@link Integer#MAX_VALUE}.
* The comparison rule , refer to {@link #compareTo(EventListener)}.
* @see #compareTo(EventListener)
* @see Integer#MAX_VALUE
* @see Integer#MIN_VALUE
*/
default int getPriority() {
return Integer.MAX_VALUE;
}
@Override
default int compareTo(EventListener<E> another) {
return compare(this.getPriority(), another.getPriority());
}
/**
* Find the {@link Class type} {@link Event Dubbo event} from the specified {@link EventListener Dubbo event listener}
*
* @param listener the {@link Class class} of {@link EventListener Dubbo event listener}
* @return <code>null</code> if not found
*/
static Class<? extends Event> findEventType(EventListener<?> listener) {
return findEventType(listener.getClass());
}
/**
* Find the {@link Class type} {@link Event Dubbo event} from the specified {@link EventListener Dubbo event listener}
*
* @param listenerClass the {@link Class class} of {@link EventListener Dubbo event listener}
* @return <code>null</code> if not found
*/
static Class<? extends Event> findEventType(Class<?> listenerClass) {
Class<? extends Event> eventType = null;
if (listenerClass != null && EventListener.class.isAssignableFrom(listenerClass)) {
eventType = findParameterizedTypes(listenerClass)
.stream()
.map(EventListener::findEventType)
.filter(Objects::nonNull)
.findAny()
.orElse((Class) findEventType(listenerClass.getSuperclass()));
}
return eventType;
}
/**
* Find the type {@link Event Dubbo event} from the specified {@link ParameterizedType} presents
* a class of {@link EventListener Dubbo event listener}
*
* @param parameterizedType the {@link ParameterizedType} presents a class of {@link EventListener Dubbo event listener}
* @return <code>null</code> if not found
*/
static Class<? extends Event> findEventType(ParameterizedType parameterizedType) {
Class<? extends Event> eventType = null;
Type rawType = parameterizedType.getRawType();
if ((rawType instanceof Class) && EventListener.class.isAssignableFrom((Class) rawType)) {
Type[] typeArguments = parameterizedType.getActualTypeArguments();
for (Type typeArgument : typeArguments) {
if (typeArgument instanceof Class) {
Class argumentClass = (Class) typeArgument;
if (Event.class.isAssignableFrom(argumentClass)) {
eventType = argumentClass;
break;
}
}
}
}
return eventType;
}
}

View File

@ -0,0 +1,34 @@
/*
* 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.event;
/**
* Generic {@link Event Dubbo event}
*
* @param <S> the type of event source
* @since 2.7.3
*/
public class GenericEvent<S> extends Event {
public GenericEvent(S source) {
super(source);
}
public S getSource() {
return (S) super.getSource();
}
}

View File

@ -0,0 +1,130 @@
/*
* 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.event;
import org.apache.dubbo.common.function.ThrowableConsumer;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import static java.util.Collections.emptySet;
import static java.util.stream.Stream.of;
import static org.apache.dubbo.common.function.ThrowableFunction.execute;
/**
* An abstract class of {@link EventListener} for Generic events, the sub class could add more {@link Event event}
* handle methods, rather than only binds the {@link EventListener#onEvent(Event)} method that is declared to be
* <code>final</code> the implementation can't override. It's notable that all {@link Event event} handle methods must
* meet following conditions:
* <ul>
* <li>not {@link #onEvent(Event)} method</li>
* <li><code>public</code> accessibility</li>
* <li><code>void</code> return type</li>
* <li>no {@link Exception exception} declaration</li>
* <li>only one {@link Event} type argument</li>
* </ul>
*
* @see Event
* @see EventListener
* @since 2.7.3
*/
public abstract class GenericEventListener implements EventListener<Event> {
private final Method onEventMethod;
private final Map<Class<?>, Set<Method>> handleEventMethods;
protected GenericEventListener() {
this.onEventMethod = findOnEventMethod();
this.handleEventMethods = findHandleEventMethods();
}
private Method findOnEventMethod() {
return execute(getClass(), listenerClass -> listenerClass.getMethod("onEvent", Event.class));
}
private Map<Class<?>, Set<Method>> findHandleEventMethods() {
// Event class for key, the eventMethods' Set as value
Map<Class<?>, Set<Method>> eventMethods = new HashMap<>();
of(getClass().getMethods())
.filter(this::isHandleEventMethod)
.forEach(method -> {
Class<?> paramType = method.getParameterTypes()[0];
Set<Method> methods = eventMethods.computeIfAbsent(paramType, key -> new LinkedHashSet<>());
methods.add(method);
});
return eventMethods;
}
public final void onEvent(Event event) {
Class<?> eventClass = event.getClass();
handleEventMethods.getOrDefault(eventClass, emptySet()).forEach(method -> {
ThrowableConsumer.execute(method, m -> {
m.invoke(this, event);
});
});
}
/**
* The {@link Event event} handle methods must meet following conditions:
* <ul>
* <li>not {@link #onEvent(Event)} method</li>
* <li><code>public</code> accessibility</li>
* <li><code>void</code> return type</li>
* <li>no {@link Exception exception} declaration</li>
* <li>only one {@link Event} type argument</li>
* </ul>
*
* @param method
* @return
*/
private boolean isHandleEventMethod(Method method) {
if (onEventMethod.equals(method)) { // not {@link #onEvent(Event)} method
return false;
}
if (!Modifier.isPublic(method.getModifiers())) { // not public
return false;
}
if (!void.class.equals(method.getReturnType())) { // void return type
return false;
}
Class[] exceptionTypes = method.getExceptionTypes();
if (exceptionTypes.length > 0) { // no exception declaration
return false;
}
Class[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) { // not only one argument
return false;
}
if (!Event.class.isAssignableFrom(paramTypes[0])) { // not Event type argument
return false;
}
return true;
}
}

View File

@ -0,0 +1,131 @@
/*
* 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.event;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static java.util.stream.StreamSupport.stream;
/**
* Dubbo Event Listenable
*
* @see EventDispatcher
* @since 2.7.3
*/
public interface Listenable<E extends EventListener<?>> {
/**
* Add a {@link EventListener Dubbo event listener}
*
* @param listener a {@link EventListener Dubbo event listener}
* If current {@link EventListener} is existed, return <code>false</code>
* @throws NullPointerException if <code>listener</code> argument is <code>null</code>
* @throws IllegalArgumentException if <code>listener</code> argument is not concrete instance
*/
void addEventListener(E listener) throws NullPointerException, IllegalArgumentException;
/**
* Add one or more {@link EventListener Dubbo event listeners}
*
* @param listener a {@link EventListener Dubbo event listener}
* @param others an optional {@link EventListener Dubbo event listeners}
* @throws NullPointerException if one of arguments is <code>null</code>
* @throws IllegalArgumentException if one of arguments argument is not concrete instance
*/
default void addEventListeners(E listener, E... others) throws NullPointerException,
IllegalArgumentException {
List<E> listeners = new ArrayList<>(1 + others.length);
listeners.add(listener);
listeners.addAll(Arrays.asList(others));
addEventListeners(listeners);
}
/**
* Add multiple {@link EventListener Dubbo event listeners}
*
* @param listeners the {@link EventListener Dubbo event listeners}
* @throws NullPointerException if <code>listeners</code> argument is <code>null</code>
* @throws IllegalArgumentException if any element of <code>listeners</code> is not concrete instance
*/
default void addEventListeners(Iterable<E> listeners) throws NullPointerException, IllegalArgumentException {
stream(listeners.spliterator(), false).forEach(this::addEventListener);
}
/**
* Remove a {@link EventListener Dubbo event listener}
*
* @param listener a {@link EventListener Dubbo event listener}
* @return If remove successfully, return <code>true</code>.
* If current {@link EventListener} is existed, return <code>false</code>
* @throws NullPointerException if <code>listener</code> argument is <code>null</code>
*/
void removeEventListener(E listener) throws NullPointerException, IllegalArgumentException;
/**
* Remove a {@link EventListener Dubbo event listener}
*
* @param listeners the {@link EventListener Dubbo event listeners}
* @return If remove successfully, return <code>true</code>.
* If current {@link EventListener} is existed, return <code>false</code>
* @throws NullPointerException if <code>listener</code> argument is <code>null</code>
* @throws IllegalArgumentException if any element of <code>listeners</code> is not concrete instance
*/
default void removeEventListeners(Iterable<E> listeners) throws NullPointerException, IllegalArgumentException {
stream(listeners.spliterator(), false).forEach(this::removeEventListener);
}
/**
* Remove all {@link EventListener Dubbo event listeners}
*
* @return a amount of removed listeners
*/
default void removeAllEventListeners() {
removeEventListeners(getAllEventListeners());
}
/**
* Get all registered {@link EventListener Dubbo event listeners}
*
* @return non-null read-only ordered {@link EventListener Dubbo event listeners}
* @see EventListener#getPriority()
*/
List<E> getAllEventListeners();
/**
* Assets the listener is valid or not
*
* @param listener the instance of {@link EventListener}
* @throws NullPointerException
*/
static void assertListener(EventListener<?> listener) throws NullPointerException {
if (listener == null) {
throw new NullPointerException("The listener must not be null.");
}
Class<?> listenerClass = listener.getClass();
int modifiers = listenerClass.getModifiers();
if (Modifier.isAbstract(modifiers) || Modifier.isInterface(modifiers)) {
throw new IllegalArgumentException("The listener must be concrete class");
}
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.event;
import java.util.concurrent.ForkJoinPool;
/**
* Parallel {@link EventDispatcher} implementation uses {@link ForkJoinPool#commonPool() JDK common thread pool}
*
* @see ForkJoinPool#commonPool()
* @since 2.7.3
*/
public class ParallelEventDispatcher extends AbstractEventDispatcher {
public ParallelEventDispatcher() {
super(ForkJoinPool.commonPool());
}
}

View File

@ -0,0 +1,2 @@
direct=org.apache.dubbo.event.DirectEventDispatcher
parallel=org.apache.dubbo.event.ParallelEventDispatcher

View File

@ -0,0 +1,40 @@
/*
* 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.event;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class AbstractEventListener<E extends Event> implements EventListener<E> {
private final AtomicInteger eventOccurs = new AtomicInteger(0);
@Override
public final void onEvent(E event) {
eventOccurs.getAndIncrement();
handleEvent(event);
}
protected abstract void handleEvent(E event);
public int getEventOccurs() {
return eventOccurs.get();
}
protected void println(String message) {
System.out.printf("[%s] %s\n", Thread.currentThread().getName(), message);
}
}

View File

@ -0,0 +1,153 @@
/*
* 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.event;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* {@link DirectEventDispatcher} Test
*
* @since 2.7.3
*/
public class DirectEventDispatcherTest {
private DirectEventDispatcher dispatcher;
private EchoEventListener echoEventListener;
private EchoEventListener2 echoEventListener2;
@BeforeEach
public void init() {
dispatcher = new DirectEventDispatcher();
echoEventListener = new EchoEventListener();
echoEventListener2 = new EchoEventListener2();
}
@AfterEach
public void destroy() {
dispatcher.removeAllEventListeners();
}
@Test
public void testGetExecutor() {
assertNotNull(dispatcher.getExecutor());
}
@Test
public void testGetAllListeners() {
assertTrue(dispatcher.getAllEventListeners().isEmpty());
}
@Test
public void testSingleListener() {
// add two listeners
dispatcher.addEventListener(echoEventListener);
dispatcher.addEventListener(echoEventListener2);
assertEquals(asList(echoEventListener2, echoEventListener), dispatcher.getAllEventListeners());
// add a duplicated listener
dispatcher.addEventListener(echoEventListener);
assertEquals(asList(echoEventListener2, echoEventListener), dispatcher.getAllEventListeners());
// remove
dispatcher.removeEventListener(echoEventListener);
assertEquals(asList(echoEventListener2), dispatcher.getAllEventListeners());
dispatcher.removeEventListener(echoEventListener2);
assertEquals(emptyList(), dispatcher.getAllEventListeners());
}
@Test
public void testMultipleListeners() {
// add two listeners
dispatcher.addEventListeners(echoEventListener, echoEventListener2);
assertEquals(asList(echoEventListener2, echoEventListener), dispatcher.getAllEventListeners());
// remove all listeners
dispatcher.removeAllEventListeners();
assertEquals(emptyList(), dispatcher.getAllEventListeners());
// add the duplicated listeners
dispatcher.addEventListeners(echoEventListener, echoEventListener, echoEventListener2);
assertEquals(asList(echoEventListener2, echoEventListener), dispatcher.getAllEventListeners());
// remove all listeners
dispatcher.removeAllEventListeners();
assertEquals(emptyList(), dispatcher.getAllEventListeners());
dispatcher.addEventListeners(asList(echoEventListener, echoEventListener, echoEventListener2));
assertEquals(asList(echoEventListener2, echoEventListener), dispatcher.getAllEventListeners());
dispatcher.removeEventListeners(asList(echoEventListener, echoEventListener, echoEventListener2));
assertEquals(emptyList(), dispatcher.getAllEventListeners());
}
@Test
public void testDispatchEvent() {
dispatcher.addEventListener(echoEventListener);
// dispatch a Event
dispatcher.dispatch(new Event("Test") {
});
// no-op occurs
assertEquals(0, echoEventListener.getEventOccurs());
// dispatch a EchoEvent
dispatcher.dispatch(new EchoEvent("Hello,World"));
// event has been handled
assertEquals(1, echoEventListener.getEventOccurs());
dispatcher.addEventListener(echoEventListener2);
// reset the listeners
init();
dispatcher.addEventListeners(echoEventListener, echoEventListener2);
// dispatch a Event
dispatcher.dispatch(new Event("Test") {
});
// echoEventListener will be not triggered + 0
// echoEventListener2 will be triggered + 1
assertEquals(0, echoEventListener.getEventOccurs());
assertEquals(1, echoEventListener2.getEventOccurs());
// dispatch a EchoEvent
// echoEventListener and echoEventListener2 are triggered both (+1)
dispatcher.dispatch(new EchoEvent("Hello,World"));
assertEquals(1, echoEventListener.getEventOccurs());
assertEquals(2, echoEventListener2.getEventOccurs());
// both +1
dispatcher.dispatch(new EchoEvent("2019"));
assertEquals(2, echoEventListener.getEventOccurs());
assertEquals(3, echoEventListener2.getEventOccurs());
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.event;
/**
* Echo {@link Event}
*
* @since 2.7.3
*/
class EchoEvent extends Event {
public EchoEvent(Object source) {
super(source);
}
}

View File

@ -0,0 +1,32 @@
/*
* 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.event;
import java.io.Serializable;
/**
* {@link EchoEvent} {@link EventListener}
*
* @since 2.7.3
*/
public class EchoEventListener extends AbstractEventListener<EchoEvent> implements Serializable {
@Override
public void handleEvent(EchoEvent event) {
println("EchoEventListener : " + event);
}
}

View File

@ -0,0 +1,61 @@
/*
* 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.event;
import java.io.Serializable;
import java.util.Objects;
import java.util.Vector;
/**
* {@link EchoEvent} {@link EventListener} 2
*
* @since 2.7.3
*/
public class EchoEventListener2 extends Vector<EventListener<Event>> implements Serializable, Comparable<EventListener<Event>>,
EventListener<Event> {
private AbstractEventListener<Event> delegate = new AbstractEventListener<Event>() {
@Override
protected void handleEvent(Event event) {
println("EchoEventListener2 : " + event);
}
};
@Override
public void onEvent(Event event) {
delegate.onEvent(event);
}
@Override
public int getPriority() {
return 0;
}
public int getEventOccurs() {
return delegate.getEventOccurs();
}
@Override
public boolean equals(Object o) {
return this.getClass().equals(o.getClass());
}
@Override
public int hashCode() {
return Objects.hash(this.getClass());
}
}

View File

@ -0,0 +1,45 @@
/*
* 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.event;
import org.junit.jupiter.api.Test;
import static org.apache.dubbo.event.EventDispatcher.DIRECT_EXECUTOR;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* {@link EventDispatcher} Test
*
* @see DirectEventDispatcher
* @since 2.7.3
*/
public class EventDispatcherTest {
private EventDispatcher defaultInstance = EventDispatcher.getDefaultExtension();
@Test
public void testDefaultInstance() {
assertEquals(DirectEventDispatcher.class, defaultInstance.getClass());
}
@Test
public void testDefaultMethods() {
assertEquals(DIRECT_EXECUTOR, defaultInstance.getExecutor());
assertTrue(defaultInstance.getAllEventListeners().isEmpty());
}
}

View File

@ -0,0 +1,44 @@
/*
* 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.event;
import org.junit.jupiter.api.Test;
import static org.apache.dubbo.event.EventListener.findEventType;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* {@link EventListener} Test
*
* @since 2.7.3
*/
public class EventListenerTest {
@Test
public void testFindEventHierarchicalTypes() {
assertEquals(EchoEvent.class, findEventType(new EchoEventListener()));
assertEquals(Event.class, findEventType(new EchoEventListener2()));
assertEquals(EchoEvent.class, findEventType(EchoEventListener.class));
assertEquals(Event.class, findEventType(EchoEventListener2.class));
}
@Test
public void testOnEvent() {
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.event;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* {@link GenericEventListener} Test
*
* @since 2.7.3
*/
public class GenericEventListenerTest {
private EventDispatcher eventDispatcher;
private MyGenericEventListener listener;
@BeforeEach
public void init() {
this.listener = new MyGenericEventListener();
this.eventDispatcher = EventDispatcher.getDefaultExtension();
this.eventDispatcher.addEventListener(listener);
}
@AfterEach
public void destroy() {
this.eventDispatcher.removeAllEventListeners();
}
@Test
public void testOnEvent() {
String value = "Hello,World";
EchoEvent echoEvent = new EchoEvent(value);
eventDispatcher.dispatch(echoEvent);
assertEquals(echoEvent, listener.getEchoEvent());
assertEquals(value, listener.getEchoEvent().getSource());
}
class MyGenericEventListener extends GenericEventListener {
private EchoEvent echoEvent;
public void onEvent(EchoEvent echoEvent) {
this.echoEvent = echoEvent;
}
public void event(EchoEvent echoEvent) {
assertEquals("Hello,World", echoEvent.getSource());
}
public void event(EchoEvent echoEvent, Object arg) {
this.echoEvent = echoEvent;
}
public EchoEvent getEchoEvent() {
return echoEvent;
}
}
}

View File

@ -0,0 +1,41 @@
/*
* 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.event;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* {@link GenericEvent} Test
*
* @since 2.7.3
*/
public class GenericEventTest {
@Test
public void test() {
long timestamp = System.currentTimeMillis();
GenericEvent<String> event = new GenericEvent("Hello,World");
assertEquals("Hello,World", event.getSource());
assertTrue(event.getTimestamp() >= timestamp);
}
}

View File

@ -0,0 +1,59 @@
/*
* 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.event;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* {@link ParallelEventDispatcher} Test
*
* @since 2.7.3
*/
public class ParallelEventDispatcherTest {
private EventDispatcher eventDispatcher;
private AbstractEventListener listener;
@BeforeEach
public void init() {
eventDispatcher = new ParallelEventDispatcher();
listener = new EchoEventListener();
eventDispatcher.addEventListener(listener);
}
@Test
public void testDispatchEvent() throws InterruptedException {
eventDispatcher.dispatch(new EchoEvent("Hello,World"));
ForkJoinPool.commonPool().awaitTermination(1, TimeUnit.SECONDS);
// event has been handled
assertEquals(1, listener.getEventOccurs());
}
@AfterAll
public static void destroy() {
ForkJoinPool.commonPool().shutdown();
}
}

View File

@ -0,0 +1 @@
#org.apache.dubbo.event.EchoEventListener2

View File

@ -21,7 +21,6 @@ import org.junit.jupiter.api.Test;
import static org.apache.dubbo.common.constants.CommonConstants.PATH_SEPARATOR;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER_SIDE;
import static org.apache.dubbo.metadata.identifier.MetadataIdentifier.META_DATA_STORE_TAG;
/**
* 2019/1/7

View File

@ -34,9 +34,9 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;
import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
import static org.apache.dubbo.metadata.identifier.MetadataIdentifier.META_DATA_STORE_TAG;
/**

66
dubbo-metadata/pom.xml Normal file
View File

@ -0,0 +1,66 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-parent</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dubbo-metadata</artifactId>
<packaging>jar</packaging>
<name>dubbo-metadata</name>
<description>The metadata module of Dubbo project</description>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-config-api</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-api</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-configcenter-zookeeper</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,103 @@
/*
* 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.metadata;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.configcenter.DynamicConfiguration;
import org.apache.dubbo.rpc.model.ApplicationModel;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import static java.util.Arrays.asList;
import static org.apache.dubbo.common.utils.StringUtils.isBlank;
/**
* The {@link ServiceNameMapping} implementation based on {@link DynamicConfiguration}
*/
public class DynamicConfigurationServiceNameMapping implements ServiceNameMapping {
private static final List<String> IGNORED_SERVICE_INTERFACES = asList(MetadataService.class.getName());
private static final String SEPARATOR = ":";
private static final String EMPTY = "";
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void map(String serviceInterface, String group, String version, String protocol) {
if (IGNORED_SERVICE_INTERFACES.contains(serviceInterface)) {
return;
}
DynamicConfiguration dynamicConfiguration = DynamicConfiguration.getDynamicConfiguration();
// the Dubbo Service Key as group
// the service(application) name as key
// It does matter whatever the content is, we just need a record
String key = ApplicationModel.getApplication();
String content = String.valueOf(System.currentTimeMillis());
execute(() -> {
dynamicConfiguration.publishConfig(key, buildGroup(serviceInterface, group, version, protocol), content);
if (logger.isInfoEnabled()) {
logger.info(String.format("The Dubbo service key[%s] mapped to service name[%s] with content : %s",
key, group, content));
}
});
}
@Override
public Set<String> get(String serviceInterface, String group, String version, String protocol) {
DynamicConfiguration dynamicConfiguration = DynamicConfiguration.getDynamicConfiguration();
String key = ApplicationModel.getApplication();
Set<String> serviceNames = new LinkedHashSet<>();
execute(() -> {
Set<String> keys = dynamicConfiguration.getConfigKeys(buildGroup(serviceInterface, group, version, protocol));
serviceNames.addAll(keys);
});
return Collections.unmodifiableSet(serviceNames);
}
protected static String buildGroup(String serviceInterface, String group, String version, String protocol) {
StringBuilder groupBuilder = new StringBuilder(serviceInterface)
.append(SEPARATOR).append(defaultString(group))
.append(SEPARATOR).append(defaultString(version))
.append(SEPARATOR).append(defaultString(protocol));
return groupBuilder.toString();
}
private static String defaultString(String value) {
return isBlank(value) ? EMPTY : value;
}
private void execute(Runnable runnable) {
try {
runnable.run();
} catch (Throwable e) {
if (logger.isWarnEnabled()) {
logger.warn(e.getMessage(), e);
}
}
}
}

View File

@ -0,0 +1,192 @@
/*
* 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.metadata;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import static java.util.Collections.emptyList;
import static java.util.Collections.unmodifiableList;
import static org.apache.dubbo.common.URL.buildKey;
import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.utils.CollectionUtils.isEmpty;
/**
* The {@link LocalMetadataService} implementation stores the metadata of Dubbo services in memory locally when they
* exported.
*
* @see MetadataService
* @see LocalMetadataService
* @since 2.7.3
*/
public class InMemoryLocalMetadataService implements LocalMetadataService {
/**
* The class name of {@link MetadataService}
*/
static final String METADATA_SERVICE_CLASS_NAME = MetadataService.class.getName();
private final Logger logger = LoggerFactory.getLogger(getClass());
private final Lock lock = new ReentrantLock();
// =================================== Registration =================================== //
/**
* All exported {@link URL urls} {@link Map} whose key is the return value of {@link URL#getServiceKey()} method
* and value is the {@link List} of the {@link URL URLs}
*/
private ConcurrentMap<String, List<URL>> exportedServiceURLs = new ConcurrentHashMap<>();
// ==================================================================================== //
// =================================== Subscription =================================== //
/**
* The subscribed {@link URL urls} {@link Map} of {@link MetadataService},
* whose key is the return value of {@link URL#getServiceKey()} method and value is the {@link List} of
* the {@link URL URLs}
*/
private final ConcurrentMap<String, List<URL>> subscribedServiceURLs = new ConcurrentHashMap<>();
// ==================================================================================== //
@Override
public List<String> getSubscribedURLs() {
return getAllUnmodifiableServiceURLs(subscribedServiceURLs);
}
@Override
public List<String> getExportedURLs(String serviceInterface, String group, String version, String protocol) {
if (ALL_SERVICE_INTERFACES.equals(serviceInterface)) {
return getAllUnmodifiableServiceURLs(exportedServiceURLs);
}
String serviceKey = buildKey(serviceInterface, group, version);
return unmodifiableList(getServiceURLs(exportedServiceURLs, serviceKey, protocol));
}
@Override
public boolean exportURL(URL url) {
// if (isMetadataServiceURL(url)) { // ignore MetadataService in the export phase
// return true;
// }
return addURL(exportedServiceURLs, url);
}
@Override
public boolean unexportURL(URL url) {
// if (isMetadataServiceURL(url)) { // ignore MetadataService in the export phase
// return true;
// }
return removeURL(exportedServiceURLs, url);
}
@Override
public boolean subscribeURL(URL url) {
return addURL(subscribedServiceURLs, url);
}
@Override
public boolean unsubscribeURL(URL url) {
return removeURL(subscribedServiceURLs, url);
}
private boolean addURL(Map<String, List<URL>> serviceURLs, URL url) {
return executeMutually(() -> {
List<URL> urls = serviceURLs.computeIfAbsent(url.getServiceKey(), s -> new LinkedList());
if (!urls.contains(url)) {
return urls.add(url);
}
return false;
});
}
private boolean removeURL(Map<String, List<URL>> serviceURLs, URL url) {
return executeMutually(() -> {
List<URL> urls = serviceURLs.get(url.getServiceKey());
if (isEmpty(urls)) {
return false;
}
return urls.remove(url);
});
}
private boolean executeMutually(Callable<Boolean> callable) {
boolean success = false;
try {
lock.lock();
try {
success = callable.call();
} catch (Exception e) {
if (logger.isErrorEnabled()) {
logger.error(e);
}
}
} finally {
lock.unlock();
}
return success;
}
private static List<String> getServiceURLs(Map<String, List<URL>> exportedServiceURLs, String serviceKey,
String protocol) {
List<URL> serviceURLs = exportedServiceURLs.get(serviceKey);
if (isEmpty(serviceURLs)) {
return emptyList();
}
return serviceURLs
.stream()
.filter(url -> isAcceptableProtocol(protocol, url))
.map(URL::toFullString)
.collect(Collectors.toList());
}
private static boolean isAcceptableProtocol(String protocol, URL url) {
return protocol == null
|| protocol.equals(url.getParameter(PROTOCOL_KEY))
|| protocol.equals(url.getProtocol());
}
// private static boolean isMetadataServiceURL(URL url) {
// String serviceInterface = url.getServiceInterface();
// return METADATA_SERVICE_CLASS_NAME.equals(serviceInterface);
// }
private static List<String> getAllUnmodifiableServiceURLs(Map<String, List<URL>> serviceURLs) {
return unmodifiableList(
serviceURLs
.values()
.stream()
.flatMap(Collection::stream)
.map(URL::toFullString)
.collect(Collectors.toList()));
}
}

View File

@ -0,0 +1,88 @@
/*
* 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.metadata;
import org.apache.dubbo.common.URL;
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.extension.ExtensionLoader.getExtensionLoader;
/**
* Local {@link MetadataService} that extends {@link MetadataService} and provides the modification, which is used for
* Dubbo's consumers and providers.
*
* @since 2.7.3
*/
@SPI("default")
public interface LocalMetadataService extends MetadataService {
/**
* Gets the current Dubbo Service name
*
* @return non-null
*/
@Override
default String serviceName() {
return ApplicationModel.getApplication();
}
/**
* Exports a {@link URL}
*
* @param url a {@link URL}
* @return If success , return <code>true</code>
*/
boolean exportURL(URL url);
/**
* Unexports a {@link URL}
*
* @param url a {@link URL}
* @return If success , return <code>true</code>
*/
boolean unexportURL(URL url);
/**
* Subscribes a {@link URL}
*
* @param url a {@link URL}
* @return If success , return <code>true</code>
*/
boolean subscribeURL(URL url);
/**
* Unsubscribes a {@link URL}
*
* @param url a {@link URL}
* @return If success , return <code>true</code>
*/
boolean unsubscribeURL(URL url);
/**
* Get {@link ExtensionLoader#getDefaultExtension() the defautl extension} of {@link LocalMetadataService}
*
* @return non-null
* @see InMemoryLocalMetadataService
*/
public static LocalMetadataService getDefaultExtension() {
return getExtensionLoader(LocalMetadataService.class).getDefaultExtension();
}
}

View File

@ -0,0 +1,151 @@
/*
* 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.metadata;
import org.apache.dubbo.common.URL;
import java.util.List;
import java.util.stream.Collectors;
import static java.util.stream.StreamSupport.stream;
/**
* A framework interface of Dubbo Metadata Service defines the contract of Dubbo Services registartion and subscription
* between Dubbo service providers and its consumers. The implementationwill be exported as a normal Dubbo service that
* the clients would subscribe, whose version comes from the {@link #version()} method and group gets from
* {@link #serviceName()}, that means, The different Dubbo service(application) will export the different
* {@link MetadataService} that persists all the exported and subscribed metadata, they are present by
* {@link #getExportedURLs()} and {@link #getSubscribedURLs()} respectively. What's more, {@link MetadataService}
* also providers the fine-grain methods for the precise queries.
*
* @see LocalMetadataService
* @since 2.7.3
*/
public interface MetadataService {
/**
* The value of all service names
*/
String ALL_SERVICE_NAMES = "*";
/**
* The value of All service instances
*/
String ALL_SERVICE_INTERFACES = "*";
/**
* The contract version of {@link MetadataService}, the future update must make sure compatible.
*/
String VERSION = "1.0.0";
/**
* Gets the current Dubbo Service name
*
* @return non-null
*/
String serviceName();
/**
* Gets the version of {@link MetadataService} that always equals {@link #VERSION}
*
* @return non-null
* @see #VERSION
*/
default String version() {
return VERSION;
}
/**
* the list of String that presents all Dubbo subscribed {@link URL urls}
*
* @return non-null read-only {@link List}
*/
List<String> getSubscribedURLs();
/**
* Get the list of String that presents all Dubbo exported {@link URL urls}
*
* @return non-null read-only {@link List}
*/
default List<String> getExportedURLs() {
return getExportedURLs(ALL_SERVICE_INTERFACES);
}
/**
* Get the list of String that presents the specified Dubbo exported {@link URL urls} by the <code>serviceInterface</code>
*
* @param serviceInterface The class name of Dubbo service interface
* @return non-null read-only {@link List}
* @see URL
*/
default List<String> getExportedURLs(String serviceInterface) {
return getExportedURLs(serviceInterface, null);
}
/**
* Get the list of String that presents the specified Dubbo exported {@link URL urls} by the
* <code>serviceInterface</code> and <code>group</code>
*
* @param serviceInterface The class name of Dubbo service interface
* @param group the Dubbo Service Group (optional)
* @return non-null read-only {@link List}
* @see URL
*/
default List<String> getExportedURLs(String serviceInterface, String group) {
return getExportedURLs(serviceInterface, group, null);
}
/**
* Get the list of String that presents the specified Dubbo exported {@link URL urls} by the
* <code>serviceInterface</code>, <code>group</code> and <code>version</code>
*
* @param serviceInterface The class name of Dubbo service interface
* @param group the Dubbo Service Group (optional)
* @param version the Dubbo Service Version (optional)
* @return non-null read-only {@link List}
* @see URL
*/
default List<String> getExportedURLs(String serviceInterface, String group, String version) {
return getExportedURLs(serviceInterface, group, version, null);
}
/**
* Get the list of String that presents the specified Dubbo exported {@link URL urls} by the
* <code>serviceInterface</code>, <code>group</code>, <code>version</code> and <code>protocol</code>
*
* @param serviceInterface The class name of Dubbo service interface
* @param group the Dubbo Service Group (optional)
* @param version the Dubbo Service Version (optional)
* @param protocol the Dubbo Service Protocol (optional)
* @return non-null read-only {@link List}
* @see URL
*/
List<String> getExportedURLs(String serviceInterface, String group, String version, String protocol);
/**
* Convert the multiple {@link URL urls} to a {@link List list} of {@link URL urls}
*
* @param urls the strings presents the {@link URL Dubbo URLs}
* @return non-null
*/
static List<URL> toURLs(Iterable<String> urls) {
return stream(urls.spliterator(), false)
.map(URL::valueOf)
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,44 @@
/*
* 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.metadata;
import org.apache.dubbo.common.URL;
import java.util.List;
/**
* The exporter of {@link MetadataService}
*
* @see MetadataService
* @see #export()
* @see #unexport()
* @since 2.7.3
*/
public interface MetadataServiceExporter {
/**
* Exports the {@link MetadataService} as a Dubbo service
*
* @return the exported {@link URL URLs}
*/
List<URL> export();
/**
* Unexports the {@link MetadataService}
*/
void unexport();
}

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