You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2021/10/12 07:59:06 UTC

[dubbo] branch 3.0 updated: Support Cache Properties in model field (#9025)

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

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


The following commit(s) were added to refs/heads/3.0 by this push:
     new 8e26729  Support Cache Properties in model field (#9025)
8e26729 is described below

commit 8e267291286c04782c27f7eb50f103a6fcbe26ae
Author: Albumen Kevin <jh...@gmail.com>
AuthorDate: Tue Oct 12 15:58:40 2021 +0800

    Support Cache Properties in model field (#9025)
    
    * Support Cache Properties in model field
    
    * tolerate null
---
 .../dubbo/common/CommonScopeModelInitializer.java  |  5 ++-
 .../dubbo/common/config/ConfigurationCache.java    | 47 ++++++++++++++++++++++
 .../dubbo/common/config/ConfigurationUtils.java    | 10 ++---
 .../common/config/ConfigurationUtilsTest.java      | 41 +++++++++++++++++++
 4 files changed, 97 insertions(+), 6 deletions(-)

diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java b/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java
index 4ac60c6..34d6867 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/CommonScopeModelInitializer.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.common;
 
 import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
+import org.apache.dubbo.common.config.ConfigurationCache;
 import org.apache.dubbo.common.lang.ShutdownHookCallbacks;
 import org.apache.dubbo.common.status.reporter.FrameworkStatusReportService;
 import org.apache.dubbo.rpc.model.ApplicationModel;
@@ -35,10 +36,12 @@ public class CommonScopeModelInitializer implements ScopeModelInitializer {
         ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
         beanFactory.registerBean(ShutdownHookCallbacks.class);
         beanFactory.registerBean(FrameworkStatusReportService.class);
+        beanFactory.registerBean(new ConfigurationCache());
     }
 
     @Override
     public void initializeModuleModel(ModuleModel moduleModel) {
-
+        ScopeBeanFactory beanFactory = moduleModel.getBeanFactory();
+        beanFactory.registerBean(new ConfigurationCache());
     }
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationCache.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationCache.java
new file mode 100644
index 0000000..977cdfb
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationCache.java
@@ -0,0 +1,47 @@
+/*
+ * 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.config;
+
+import org.apache.dubbo.rpc.model.ScopeModel;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+
+/**
+ * Properties Cache of Configuration {@link ConfigurationUtils#getCachedDynamicProperty(ScopeModel, String, String)}
+ */
+public class ConfigurationCache {
+    private final Map<String, String> cache = new ConcurrentHashMap<>();
+
+    /**
+     * Get Cached Value
+     *
+     * @param key key
+     * @param function function to produce value, should not return `null`
+     * @return value
+     */
+    public String computeIfAbsent(String key, Function<String, String> function) {
+        String value = cache.get(key);
+        if (value == null) {
+            // lock free, tolerate repeat apply, will return previous value
+            cache.putIfAbsent(key, function.apply(key));
+            value = cache.get(key);
+        }
+        return value;
+    }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java
index 037593e..7b3576d 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/ConfigurationUtils.java
@@ -38,7 +38,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 
 import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_SERVER_SHUTDOWN_TIMEOUT;
 import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
@@ -49,7 +48,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SE
  */
 public class ConfigurationUtils {
     private static final Logger logger = LoggerFactory.getLogger(ConfigurationUtils.class);
-    private static Map<String, String> CACHED_DYNAMIC_PROPERTIES = new ConcurrentHashMap<>();
     private static final List<String> securityKey;
 
     static {
@@ -94,7 +92,7 @@ public class ConfigurationUtils {
     }
 
     public static Configuration getDynamicGlobalConfiguration(ScopeModel scopeModel) {
-        return ScopeModelUtil.getModuleModel(scopeModel).getModelEnvironment().getDynamicGlobalConfiguration();
+        return scopeModel.getModelEnvironment().getDynamicGlobalConfiguration();
     }
 
     // FIXME
@@ -128,8 +126,10 @@ public class ConfigurationUtils {
         return timeout;
     }
 
-    public static String getCachedDynamicProperty(ScopeModel scopeModel, String key, String defaultValue) {
-        String value = CACHED_DYNAMIC_PROPERTIES.computeIfAbsent(key, _k -> ConfigurationUtils.getDynamicProperty(scopeModel, key, ""));
+    public static String getCachedDynamicProperty(ScopeModel realScopeModel, String key, String defaultValue) {
+        ScopeModel scopeModel = ScopeModelUtil.getOrDefaultApplicationModel(realScopeModel);
+        ConfigurationCache configurationCache = scopeModel.getBeanFactory().getBean(ConfigurationCache.class);
+        String value = configurationCache.computeIfAbsent(key, _k -> ConfigurationUtils.getDynamicProperty(scopeModel, _k, ""));
         return StringUtils.isEmpty(value) ? defaultValue : value;
     }
 
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/config/ConfigurationUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/config/ConfigurationUtilsTest.java
index d10ad6a..e7d58b6 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/config/ConfigurationUtilsTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/config/ConfigurationUtilsTest.java
@@ -17,9 +17,12 @@
 package org.apache.dubbo.common.config;
 
 import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.model.ModuleModel;
 
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
 
 import java.util.Map;
 
@@ -29,6 +32,44 @@ import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KE
  *
  */
 public class ConfigurationUtilsTest {
+    @Test
+    public void testCachedProperties() {
+        FrameworkModel frameworkModel = new FrameworkModel();
+
+        ApplicationModel applicationModel = new ApplicationModel(frameworkModel);
+        Environment originApplicationEnvironment = applicationModel.getModelEnvironment();
+        Environment applicationEnvironment = Mockito.spy(originApplicationEnvironment);
+        applicationModel.setEnvironment(applicationEnvironment);
+
+        Configuration configuration = Mockito.mock(Configuration.class);
+        Mockito.when(applicationEnvironment.getDynamicGlobalConfiguration()).thenReturn(configuration);
+        Mockito.when(configuration.getString("TestKey", "")).thenReturn("a");
+
+        Assertions.assertEquals("a", ConfigurationUtils.getCachedDynamicProperty(applicationModel, "TestKey", "xxx"));
+
+        Mockito.when(configuration.getString("TestKey", "")).thenReturn("b");
+        // cached key
+        Assertions.assertEquals("a", ConfigurationUtils.getCachedDynamicProperty(applicationModel, "TestKey", "xxx"));
+
+        ModuleModel moduleModel = new ModuleModel(applicationModel);
+        ModuleEnvironment originModuleEnvironment = moduleModel.getModelEnvironment();
+        ModuleEnvironment moduleEnvironment = Mockito.spy(originModuleEnvironment);
+        moduleModel.setModuleEnvironment(moduleEnvironment);
+
+        Mockito.when(moduleEnvironment.getDynamicGlobalConfiguration()).thenReturn(configuration);
+
+        // ApplicationModel should not affect ModuleModel
+        Assertions.assertEquals("b", ConfigurationUtils.getCachedDynamicProperty(moduleModel, "TestKey", "xxx"));
+
+        Mockito.when(configuration.getString("TestKey", "")).thenReturn("c");
+        // cached key
+        Assertions.assertEquals("b", ConfigurationUtils.getCachedDynamicProperty(moduleModel, "TestKey", "xxx"));
+
+        moduleModel.setModuleEnvironment(originModuleEnvironment);
+        applicationModel.setEnvironment(originApplicationEnvironment);
+
+        frameworkModel.destroy();
+    }
 
     @Test
     public void testGetServerShutdownTimeout () {