From ec4ee5c4dae6ff4f159d25af199a7aa343380255 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Mon, 28 Oct 2019 20:38:52 +0800 Subject: [PATCH] fix Applicaiton Model related issues. --- .../dubbo/bootstrap/DubboBootstrap.java | 199 +++++++++++------- .../dubbo/bootstrap/ReferenceConfigCache.java | 14 +- .../dubbo/common/config/Environment.java | 8 +- .../dubbo/config/AbstractInterfaceConfig.java | 23 ++ .../apache/dubbo/rpc/model/ConsumerModel.java | 9 +- .../apache/dubbo/rpc/model/ProviderModel.java | 1 + .../dubbo/rpc/model/ServiceMetadata.java | 7 + 7 files changed, 170 insertions(+), 91 deletions(-) diff --git a/dubbo-bootstrap/dubbo-bootstrap-api/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java b/dubbo-bootstrap/dubbo-bootstrap-api/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java index 401cdcaff8..5700fde7b3 100644 --- a/dubbo-bootstrap/dubbo-bootstrap-api/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java +++ b/dubbo-bootstrap/dubbo-bootstrap-api/src/main/java/org/apache/dubbo/bootstrap/DubboBootstrap.java @@ -208,9 +208,9 @@ public class DubboBootstrap extends GenericEventListener { private ReferenceConfigCache cache; - private volatile boolean initialized = false; + private AtomicBoolean initialized = new AtomicBoolean(false); - private volatile boolean started = false; + private AtomicBoolean started = new AtomicBoolean(false); private volatile ServiceInstance serviceInstance; @@ -525,37 +525,74 @@ public class DubboBootstrap extends GenericEventListener { return cache; } + /** + * export a single ServiceConfig + *

+ * Bootstrap must has been started before calling this method. + */ + public void export(ServiceConfig serviceConfig) { + if (!isStarted()) { + throw new IllegalStateException("Bootstrap hasn't been started yet."); + } + this.service(serviceConfig); + exporter.accept(serviceConfig); + } + + public void unExport(ServiceConfig serviceConfig) { + if (!isStarted()) { + throw new IllegalStateException("Bootstrap hasn't been started yet."); + } + configManager.removeConfig(serviceConfig); + List> scExporters = exporters.get(serviceConfig); + if (CollectionUtils.isNotEmpty(scExporters)) { + scExporters.forEach(Exporter::unexport); + } + } + + /** + * refer a single ReferenceConfig + *

+ * Bootstrap must has been started before calling this method. + */ + public void refer(ReferenceConfig referenceConfig) { + if (!isStarted()) { + throw new IllegalStateException("Bootstrap hasn't been started yet."); + } + this.reference(referenceConfig); + referrer.accept(referenceConfig); + } + + public void unRefer(ReferenceConfig referenceConfig) { + if (!isStarted()) { + throw new IllegalStateException("Bootstrap hasn't been started yet."); + } + configManager.removeConfig(referenceConfig); + cache.destroy(referenceConfig); + } + /** * Initialize */ - public DubboBootstrap initialize() { - if (!isInitialized()) { + private void initialize() { + ApplicationModel.initApplication(); - ApplicationModel.initApplication(); + startConfigCenter(); - startConfigCenter(); + startMetadataReport(); - startMetadataReport(); + loadRemoteConfigs(); - loadRemoteConfigs(); + useRegistryAsConfigCenterIfNecessary(); - useRegistryAsConfigCenterIfNecessary(); + initMetadataService(); - initMetadataService(); + initMetadataServiceExporter(); - initMetadataServiceExporter(); - - initEventListener(); - - initialized = true; - - if (logger.isInfoEnabled()) { - logger.info(NAME + " has been initialized!"); - } + initEventListener(); + if (logger.isInfoEnabled()) { + logger.info(NAME + " has been initialized!"); } - - return this; } private void startConfigCenter() { @@ -696,29 +733,24 @@ public class DubboBootstrap extends GenericEventListener { * Start the bootstrap */ public DubboBootstrap start() { - if (!isInitialized()) { + if (started.compareAndSet(false, true)) { initialize(); - } - if (!isStarted()) { if (logger.isInfoEnabled()) { logger.info(NAME + " is starting..."); } // 1. export Dubbo Services exportServices(); - // 2. export MetadataService - exportMetadataService(); - // Not only provider register if (!isOnlyRegisterProvider() || hasExportedServices()) { + // 2. export MetadataService + exportMetadataService(); //3. Register the local ServiceInstance if required registerServiceInstance(); } referServices(); - started = true; - if (logger.isInfoEnabled()) { logger.info(NAME + " has started."); } @@ -779,11 +811,11 @@ public class DubboBootstrap extends GenericEventListener { } public boolean isInitialized() { - return initialized; + return initialized.get(); } public boolean isStarted() { - return started; + return started.get(); } public DubboBootstrap stop() throws IllegalStateException { @@ -872,29 +904,7 @@ public class DubboBootstrap extends GenericEventListener { } private void exportServices() { - configManager.getServices().forEach(sc -> { - // Make sure services with the same service key can be exported only once. - if (exporters.keySet().stream() - .anyMatch(exportedService -> exportedService.getUniqueServiceName().equals(sc.getUniqueServiceName())) - ) { - logger.warn("Service " + sc.getUniqueServiceName() + "has been exported, it's not allowed to export " + - "a service with the same group/interface:version more than once."); - return; - } - - CompletableFuture>> future = Helper.export(sc); - if (future == null) { - return; - } - future.whenComplete((v, t) -> { - if (t != null) { - throw new RuntimeException(t); - } else { - exporters.put(sc, v); - } - }); - delayedExportingFutures.add(future); - }); + configManager.getServices().forEach(exporter); } private void unexportServices() { @@ -910,21 +920,7 @@ public class DubboBootstrap extends GenericEventListener { cache = ReferenceConfigCache.getCache(); } - configManager.getReferences().forEach((rc) -> { - // Make sure service with the same key only refer once. - if (cache.getReferredReferences().values().stream() - .anyMatch(referredService -> referredService.getUniqueServiceName().equals(rc.getUniqueServiceName())) - ) { - logger.warn("Service " + rc.getUniqueServiceName() + "has been referred, it's not allowed to refer " + - "one service with the same group/interface:version more than once."); - return; - } - - // check eager init or not. - if (rc.shouldInit()) { - cache.get(rc); - } - }); + configManager.getReferences().forEach(referrer); } private void unreferServices() { @@ -996,20 +992,20 @@ public class DubboBootstrap extends GenericEventListener { } public void destroy() { - started = false; + if (started.compareAndSet(true, false)) { + unregisterServiceInstance(); + unexportMetadataService(); + unexportServices(); + unreferServices(); - unregisterServiceInstance(); - unexportMetadataService(); - unexportServices(); - unreferServices(); + destroyRegistries(); + destroyProtocols(); + destroyServiceDiscoveries(); - destroyRegistries(); - destroyProtocols(); - destroyServiceDiscoveries(); - - clear(); - shutdown(); - release(); + clear(); + shutdown(); + release(); + } } private void destroyProtocols() { @@ -1079,6 +1075,46 @@ public class DubboBootstrap extends GenericEventListener { } } + private Consumer exporter = (sc) -> { + // Make sure services with the same service key can be exported only once. + if (exporters.keySet().stream() + .anyMatch(exportedService -> exportedService.getUniqueServiceName().equals(sc.getUniqueServiceName())) + ) { + logger.warn("Service " + sc.getUniqueServiceName() + "has been exported, it's not allowed to export " + + "a service with the same group/interface:version more than once."); + return; + } + + CompletableFuture>> future = Helper.export(sc); + if (future == null) { + return; + } + future.whenComplete((v, t) -> { + if (t != null) { + throw new RuntimeException(t); + } else { + exporters.put(sc, v); + } + }); + delayedExportingFutures.add(future); + }; + + private Consumer referrer = (rc) -> { + // Make sure service with the same key only refer once. + if (cache.getReferredReferences().values().stream() + .anyMatch(referredService -> referredService.getUniqueServiceName().equals(rc.getUniqueServiceName())) + ) { + logger.warn("Service " + rc.getUniqueServiceName() + "has been referred, it's not allowed to refer " + + "one service with the same group/interface:version more than once."); + return; + } + + // check eager init or not. + if (rc.shouldInit()) { + cache.get(rc); + } + }; + public static class Helper { public static final Logger logger = LoggerFactory.getLogger(Helper.class); @@ -1250,6 +1286,7 @@ public class DubboBootstrap extends GenericEventListener { String pathKey = URL.buildKey(sc.getContextPath(protocolConfig) .map(p -> p + "/" + sc.getPath()) .orElse(sc.getPath()), sc.getGroup(), sc.getVersion()); + // TODO, uncomment this line once service key is unified sc.getServiceMetadata().setServiceKey(pathKey); exporters.addAll(doExportUrlsFor1Protocol(sc, protocolConfig, registryURLs)); } diff --git a/dubbo-bootstrap/dubbo-bootstrap-api/src/main/java/org/apache/dubbo/bootstrap/ReferenceConfigCache.java b/dubbo-bootstrap/dubbo-bootstrap-api/src/main/java/org/apache/dubbo/bootstrap/ReferenceConfigCache.java index dfc19f169b..8bbf9326ad 100644 --- a/dubbo-bootstrap/dubbo-bootstrap-api/src/main/java/org/apache/dubbo/bootstrap/ReferenceConfigCache.java +++ b/dubbo-bootstrap/dubbo-bootstrap-api/src/main/java/org/apache/dubbo/bootstrap/ReferenceConfigCache.java @@ -337,6 +337,7 @@ public class ReferenceConfigCache { serviceMetadata.setDefaultGroup(rc.getGroup()); serviceMetadata.setServiceType(rc.getActualInterface()); serviceMetadata.setServiceInterfaceName(interfaceName); + // TODO, uncomment this line once service key is unified serviceMetadata.setServiceKey(URL.buildKey(interfaceName, rc.getGroup(), rc.getVersion())); rc.checkStubAndLocal(interfaceClass); @@ -398,11 +399,6 @@ public class ReferenceConfigCache { serviceMetadata.getAttachments().putAll(map); - T proxy = createProxy(map, rc); - - serviceMetadata.setTarget(proxy); - serviceMetadata.addAttribute(PROXY_CLASS_REF, proxy); - ServiceRepository repository = ApplicationModel.getServiceRepository(); ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass); repository.registerConsumer( @@ -410,9 +406,15 @@ public class ReferenceConfigCache { attributes, serviceDescriptor, rc, - proxy, + null, serviceMetadata); + T proxy = createProxy(map, rc); + + serviceMetadata.setTarget(proxy); + serviceMetadata.addAttribute(PROXY_CLASS_REF, proxy); + repository.lookupReferredService(serviceMetadata.getServiceKey()).setProxyObject(proxy); + // dispatch a ReferenceConfigDestroyedEvent since 2.7.4 dispatch(new ReferenceConfigDestroyedEvent(rc)); return proxy; diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java index 83f383a8fd..58ac7e472a 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java @@ -89,11 +89,15 @@ public class Environment extends LifecycleAdapter implements FrameworkExt { } public void setExternalConfigMap(Map externalConfiguration) { - this.externalConfigurationMap = externalConfiguration; + if (externalConfiguration != null) { + this.externalConfigurationMap = externalConfiguration; + } } public void setAppExternalConfigMap(Map appExternalConfiguration) { - this.appExternalConfigurationMap = appExternalConfiguration; + if (appExternalConfiguration != null) { + this.appExternalConfigurationMap = appExternalConfiguration; + } } public Map getExternalConfigurationMap() { diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java index b60b68b8ce..77262d0308 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractInterfaceConfig.java @@ -29,6 +29,7 @@ import org.apache.dubbo.rpc.model.ApplicationModel; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; @@ -496,8 +497,14 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig { return application; } + @Deprecated public void setApplication(ApplicationConfig application) { this.application = application; + ConfigManager configManager = ApplicationModel.getConfigManager(); + configManager.getApplication().orElseGet(() -> { + configManager.setApplication(application); + return application; + }); } private void createApplicationIfAbsent() { @@ -586,12 +593,20 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig { this.owner = owner; } + @Deprecated public ConfigCenterConfig getConfigCenter() { return configCenter; } + @Deprecated public void setConfigCenter(ConfigCenterConfig configCenter) { this.configCenter = configCenter; + ConfigManager configManager = ApplicationModel.getConfigManager(); + Collection configs = configManager.getConfigCenters(); + if (CollectionUtils.isEmpty(configs) + || configs.stream().noneMatch(existed -> existed.getAddress().equals(configCenter.getAddress()))) { + configManager.addConfigCenter(configCenter); + } } public Integer getCallbacks() { @@ -626,12 +641,20 @@ public abstract class AbstractInterfaceConfig extends AbstractMethodConfig { this.scope = scope; } + @Deprecated public MetadataReportConfig getMetadataReportConfig() { return metadataReportConfig; } + @Deprecated public void setMetadataReportConfig(MetadataReportConfig metadataReportConfig) { this.metadataReportConfig = metadataReportConfig; + ConfigManager configManager = ApplicationModel.getConfigManager(); + Collection configs = configManager.getMetadataConfigs(); + if (CollectionUtils.isEmpty(configs) + || configs.stream().noneMatch(existed -> existed.getAddress().equals(metadataReportConfig.getAddress()))) { + configManager.addMetadataReport(metadataReportConfig); + } } public MetricsConfig getMetrics() { diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ConsumerModel.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ConsumerModel.java index d761a21f09..3d5e222dd6 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ConsumerModel.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ConsumerModel.java @@ -35,10 +35,11 @@ import java.util.Set; */ public class ConsumerModel { private final String serviceKey; - private final Object proxyObject; private final ServiceDescriptor serviceModel; private final ReferenceConfig referenceConfig; + private Object proxyObject; + private final Map methodConfigs = new HashMap<>(); /** @@ -56,7 +57,7 @@ public class ConsumerModel { , Map attributes) { Assert.notEmptyString(serviceKey, "Service name can't be null or blank"); - Assert.notNull(proxyObject, "Proxy object can't be null"); +// Assert.notNull(proxyObject, "Proxy object can't be null"); this.serviceKey = serviceKey; this.proxyObject = proxyObject; @@ -78,6 +79,10 @@ public class ConsumerModel { return proxyObject; } + public void setProxyObject(Object proxyObject) { + this.proxyObject = proxyObject; + } + /** * Return all method models for the current service * diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ProviderModel.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ProviderModel.java index 232d268376..e5420838fe 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ProviderModel.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ProviderModel.java @@ -136,6 +136,7 @@ public class ProviderModel { this(serviceKey, serviceInstance, serviceModel, serviceConfig); this.serviceMetadata = serviceMetadata; + initMethod(serviceModel.getServiceInterfaceClass()); } public String getServiceName() { diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ServiceMetadata.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ServiceMetadata.java index 5a09f45cce..f917ac11bf 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ServiceMetadata.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ServiceMetadata.java @@ -16,10 +16,14 @@ */ package org.apache.dubbo.rpc.model; +import org.apache.dubbo.common.utils.StringUtils; + import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** + * Notice, this class currently has no usage inside Dubbo. + * * data related to service level such as name, version, classloader of business service, * security info, etc. Also with a AttributeMap for extension. */ @@ -53,6 +57,9 @@ public class ServiceMetadata { } public String getServiceKey() { + if (StringUtils.isNotEmpty(serviceKey)) { + return serviceKey; + } return serviceInterfaceName + ":" + version; }