This is an automated email from the ASF dual-hosted git repository.

albumenj pushed a commit to branch 3.2
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.2 by this push:
     new 3b7934f512 Fix registry repeat export same service (#12578)
3b7934f512 is described below

commit 3b7934f5122833685acc6cd9bcff208f92ee9a6b
Author: Albumen Kevin <[email protected]>
AuthorDate: Wed Jun 21 11:29:54 2023 +0800

    Fix registry repeat export same service (#12578)
    
    * Fix registry repeat export same service
    
    * fix uts
    
    * Fix export
    
    * Fix export
---
 ...egistryCenterExportProviderIntegrationTest.java |  2 +-
 ...egistryCenterExportProviderIntegrationTest.java |  2 +-
 .../registry/RegistryScopeModelInitializer.java    |  4 +-
 .../registry/integration/ExporterFactory.java      | 42 +++++++++++++++
 .../integration/ReferenceCountExporter.java        | 62 ++++++++++++++++++++++
 .../registry/integration/RegistryProtocol.java     | 13 +++--
 6 files changed, 118 insertions(+), 7 deletions(-)

diff --git 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderIntegrationTest.java
 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderIntegrationTest.java
index 445ddb6dfc..d2f9b7ee2d 100644
--- 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderIntegrationTest.java
+++ 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/multiple/exportprovider/MultipleRegistryCenterExportProviderIntegrationTest.java
@@ -188,7 +188,7 @@ class MultipleRegistryCenterExportProviderIntegrationTest 
implements Integration
         // 1. InjvmExporter
         // 2. DubboExporter with service-discovery-registry protocol
         // 3. DubboExporter with registry protocol
-        
Assertions.assertEquals(exporterListener.getExportedExporters().size(), 7);
+        
Assertions.assertEquals(exporterListener.getExportedExporters().size(), 4);
         // The exported exporter contains 
MultipleRegistryCenterExportProviderFilter
         Assertions.assertTrue(exporterListener.getFilters().contains(filter));
 
diff --git 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportprovider/SingleRegistryCenterExportProviderIntegrationTest.java
 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportprovider/SingleRegistryCenterExportProviderIntegrationTest.java
index 3ab4bf7b53..41de19efcb 100644
--- 
a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportprovider/SingleRegistryCenterExportProviderIntegrationTest.java
+++ 
b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/integration/single/exportprovider/SingleRegistryCenterExportProviderIntegrationTest.java
@@ -195,7 +195,7 @@ class SingleRegistryCenterExportProviderIntegrationTest 
implements IntegrationTe
         // 1. InjvmExporter
         // 2. DubboExporter with service-discovery-registry protocol
         // 3. DubboExporter with registry protocol
-        
Assertions.assertEquals(exporterListener.getExportedExporters().size(), 5);
+        
Assertions.assertEquals(exporterListener.getExportedExporters().size(), 4);
         // The exported exporter contains 
SingleRegistryCenterExportProviderFilter
         Assertions.assertTrue(exporterListener.getFilters().contains(filter));
         // The consumer can be notified and get provider's metadata through 
metadata mapping info.
diff --git 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryScopeModelInitializer.java
 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryScopeModelInitializer.java
index 6be4e29947..40c788985c 100644
--- 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryScopeModelInitializer.java
+++ 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryScopeModelInitializer.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.registry;
 
 import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
+import org.apache.dubbo.registry.integration.ExporterFactory;
 import org.apache.dubbo.registry.support.RegistryManager;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
@@ -26,7 +27,8 @@ import org.apache.dubbo.rpc.model.ScopeModelInitializer;
 public class RegistryScopeModelInitializer implements ScopeModelInitializer {
     @Override
     public void initializeFrameworkModel(FrameworkModel frameworkModel) {
-
+        ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();
+        beanFactory.registerBean(ExporterFactory.class);
     }
 
     @Override
diff --git 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/ExporterFactory.java
 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/ExporterFactory.java
new file mode 100644
index 0000000000..5eebc1bcaa
--- /dev/null
+++ 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/ExporterFactory.java
@@ -0,0 +1,42 @@
+/*
+ * 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.registry.integration;
+
+import org.apache.dubbo.rpc.Exporter;
+
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class ExporterFactory {
+    private final Map<String, ReferenceCountExporter<?>> exporters = new 
ConcurrentHashMap<>();
+
+    protected ReferenceCountExporter<?> createExporter(String providerKey, 
Callable<Exporter<?>> exporterProducer) {
+        return exporters.computeIfAbsent(providerKey,
+            key -> {
+                try {
+                    return new 
ReferenceCountExporter<>(exporterProducer.call(), key, this);
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            });
+    }
+
+    protected void remove(String key, ReferenceCountExporter<?> exporter) {
+        exporters.remove(key, exporter);
+    }
+}
diff --git 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/ReferenceCountExporter.java
 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/ReferenceCountExporter.java
new file mode 100644
index 0000000000..bcdce7172f
--- /dev/null
+++ 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/ReferenceCountExporter.java
@@ -0,0 +1,62 @@
+/*
+ * 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.registry.integration;
+
+import org.apache.dubbo.rpc.Exporter;
+import org.apache.dubbo.rpc.Invoker;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ReferenceCountExporter<T> implements Exporter<T> {
+    private final Exporter<T> exporter;
+    private final String providerKey;
+    private final ExporterFactory exporterFactory;
+    private final AtomicInteger count = new AtomicInteger(0);
+
+    public ReferenceCountExporter(Exporter<T> exporter, String providerKey, 
ExporterFactory exporterFactory) {
+        this.exporter = exporter;
+        this.providerKey = providerKey;
+        this.exporterFactory = exporterFactory;
+    }
+
+    @Override
+    public Invoker<T> getInvoker() {
+        return exporter.getInvoker();
+    }
+
+    public void increaseCount() {
+        count.incrementAndGet();
+    }
+
+    @Override
+    public void unexport() {
+        if (count.decrementAndGet() == 0) {
+            exporter.unexport();
+        }
+        exporterFactory.remove(providerKey, this);
+    }
+
+    @Override
+    public void register() {
+
+    }
+
+    @Override
+    public void unregister() {
+
+    }
+}
diff --git 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
index a9e3b908c7..b69376e784 100644
--- 
a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
+++ 
b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/integration/RegistryProtocol.java
@@ -171,6 +171,7 @@ public class RegistryProtocol implements Protocol, 
ScopeModelAware {
     private ConcurrentMap<URL, ReExportTask> reExportFailedTasks = new 
ConcurrentHashMap<>();
     private HashedWheelTimer retryTimer = new HashedWheelTimer(new 
NamedThreadFactory("DubboReexportTimer", true), DEFAULT_REGISTRY_RETRY_PERIOD, 
TimeUnit.MILLISECONDS, 128);
     private FrameworkModel frameworkModel;
+    private ExporterFactory exporterFactory;
 
     //Filter the parameters that do not need to be output in url(Starting with 
.)
     private static String[] getFilteredKeys(URL url) {
@@ -190,6 +191,7 @@ public class RegistryProtocol implements Protocol, 
ScopeModelAware {
     @Override
     public void setFrameworkModel(FrameworkModel frameworkModel) {
         this.frameworkModel = frameworkModel;
+        this.exporterFactory = 
frameworkModel.getBeanFactory().getBean(ExporterFactory.class);
     }
 
     public void setProtocol(Protocol protocol) {
@@ -312,11 +314,13 @@ public class RegistryProtocol implements Protocol, 
ScopeModelAware {
     private <T> ExporterChangeableWrapper<T> doLocalExport(final Invoker<T> 
originInvoker, URL providerUrl) {
         String providerUrlKey = getProviderUrlKey(originInvoker);
         String registryUrlKey = getRegistryUrlKey(originInvoker);
+        Invoker<?> invokerDelegate = new InvokerDelegate<>(originInvoker, 
providerUrl);
 
+        ReferenceCountExporter<?> exporter = 
exporterFactory.createExporter(providerUrlKey, () -> 
protocol.export(invokerDelegate));
         return (ExporterChangeableWrapper<T>) 
bounds.computeIfAbsent(providerUrlKey, _k -> new ConcurrentHashMap<>())
-            .computeIfAbsent(registryUrlKey, s ->{
-                Invoker<?> invokerDelegate = new 
InvokerDelegate<>(originInvoker, providerUrl);
-                return new ExporterChangeableWrapper<>((Exporter<T>) 
protocol.export(invokerDelegate), originInvoker);
+            .computeIfAbsent(registryUrlKey, s -> {
+                return new ExporterChangeableWrapper<>(
+                    (ReferenceCountExporter<T>) exporter, originInvoker);
             });
     }
 
@@ -953,8 +957,9 @@ public class RegistryProtocol implements Protocol, 
ScopeModelAware {
         private NotifyListener notifyListener;
         private final AtomicBoolean registered = new AtomicBoolean(false);
 
-        public ExporterChangeableWrapper(Exporter<T> exporter, Invoker<T> 
originInvoker) {
+        public ExporterChangeableWrapper(ReferenceCountExporter<T> exporter, 
Invoker<T> originInvoker) {
             this.exporter = exporter;
+            exporter.increaseCount();
             this.originInvoker = originInvoker;
             FrameworkExecutorRepository frameworkExecutorRepository = 
originInvoker.getUrl().getOrDefaultFrameworkModel().getBeanFactory()
                 .getBean(FrameworkExecutorRepository.class);

Reply via email to