You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2020/12/17 02:42:16 UTC

[servicecomb-java-chassis] branch master updated: [SCB-2165] allow @ConditionalOnProperty work with configuration from microservice.yaml (#2141)

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

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git


The following commit(s) were added to refs/heads/master by this push:
     new 323d5b7  [SCB-2165] allow @ConditionalOnProperty work with configuration from microservice.yaml (#2141)
323d5b7 is described below

commit 323d5b7c406583867eacaa758b28e0fdcfcbe2c6
Author: wujimin <wu...@huawei.com>
AuthorDate: Thu Dec 17 10:39:44 2020 +0800

    [SCB-2165] allow @ConditionalOnProperty work with configuration from microservice.yaml (#2141)
---
 .../core/ConfigurationSpringInitializer.java       | 132 +++++++++++++--------
 ...andaloneApplication.java => ConditionBean.java} |  20 ++--
 .../it/SpringBoot2StandaloneApplication.java       |  10 ++
 .../src/main/resources/microservice.yaml           |   2 +
 .../ConfigurationSpringBootInitializer.java        |  24 ++--
 .../src/main/resources/META-INF/spring.factories   |  17 +++
 6 files changed, 132 insertions(+), 73 deletions(-)

diff --git a/core/src/main/java/org/apache/servicecomb/core/ConfigurationSpringInitializer.java b/core/src/main/java/org/apache/servicecomb/core/ConfigurationSpringInitializer.java
index dfe9413..afb8417 100644
--- a/core/src/main/java/org/apache/servicecomb/core/ConfigurationSpringInitializer.java
+++ b/core/src/main/java/org/apache/servicecomb/core/ConfigurationSpringInitializer.java
@@ -36,6 +36,7 @@ import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.context.EnvironmentAware;
+import org.springframework.context.annotation.Conditional;
 import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
 import org.springframework.core.Ordered;
 import org.springframework.core.env.CompositePropertySource;
@@ -43,6 +44,7 @@ import org.springframework.core.env.ConfigurableEnvironment;
 import org.springframework.core.env.EnumerablePropertySource;
 import org.springframework.core.env.Environment;
 import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.MutablePropertySources;
 import org.springframework.core.env.PropertySource;
 import org.springframework.util.StringUtils;
 
@@ -68,6 +70,10 @@ public class ConfigurationSpringInitializer extends PropertySourcesPlaceholderCo
 
   public static final String EXTRA_CONFIG_SOURCE_PREFIX = "extraConfig-";
 
+  public static final String MICROSERVICE_PROPERTY_SOURCE_NAME = "microservice.yaml";
+
+  public static final String MAPPING_PROPERTY_SOURCE_NAME = "mapping.yaml";
+
   private final List<BootStrapService> bootStrapServices =
       SPIServiceUtils.getSortedService(BootStrapService.class);
 
@@ -82,77 +88,95 @@ public class ConfigurationSpringInitializer extends PropertySourcesPlaceholderCo
    */
   @Override
   public void setEnvironment(Environment environment) {
+    syncFromSpring(environment);
+    syncToSpring(environment);
+
+    startupBootStrapService(environment);
+    ConfigCenterConfigurationSource configCenterConfigurationSource = ConfigUtil.installDynamicConfig();
+    addDynamicConfigurationToSpring(environment, configCenterConfigurationSource);
+  }
+
+  private void syncFromSpring(Environment environment) {
     String environmentName = generateNameForEnvironment(environment);
     LOGGER.info("Environment received, will get configurations from [{}].", environmentName);
 
     Map<String, Object> extraConfig = getAllProperties(environment);
-
-    addMicroserviceYAMLToSpring(environment);
-
-    addMappingToString(environment);
-
-    startupBootStrapService(environment);
-
     ConfigUtil.addExtraConfig(EXTRA_CONFIG_SOURCE_PREFIX + environmentName, extraConfig);
+  }
 
-    ConfigCenterConfigurationSource configCenterConfigurationSource = ConfigUtil.installDynamicConfig();
-
-    addDynamicConfigurationToSpring(environment, configCenterConfigurationSource);
+  public static void syncToSpring(Environment environment) {
+    addMicroserviceYAMLToSpring(environment);
+    addMappingToSpring(environment);
   }
 
   private void startupBootStrapService(Environment environment) {
     bootStrapServices.forEach(bootStrapService -> bootStrapService.startup(environment));
   }
 
-  private void addMicroserviceYAMLToSpring(Environment environment) {
+  /**
+   * make springboot have a change to add microservice.yaml source earlier<br>
+   * to affect {@link Conditional}
+   * @param environment environment
+   */
+  private static void addMicroserviceYAMLToSpring(Environment environment) {
     if (!(environment instanceof ConfigurableEnvironment)) {
       return;
     }
 
-    ((ConfigurableEnvironment) environment).getPropertySources()
-        .addLast(new EnumerablePropertySource<MicroserviceConfigLoader>("microservice.yaml") {
-          private final Map<String, Object> values = new HashMap<>();
-
-          private final String[] propertyNames;
-
-          {
-            MicroserviceConfigLoader loader = new MicroserviceConfigLoader();
-            loader.loadAndSort();
-
-            loader.getConfigModels()
-                .forEach(configModel -> values.putAll(YAMLUtil.retrieveItems("", configModel.getConfig())));
-
-            propertyNames = values.keySet().toArray(new String[values.size()]);
-          }
-
-          @Override
-          public String[] getPropertyNames() {
-            return propertyNames;
-          }
-
-          @SuppressWarnings("unchecked")
-          @Override
-          public Object getProperty(String name) {
-            Object value = this.values.get(name);
-
-            // spring will not resolve nested placeholder of list, so try to fix the problem
-            if (value instanceof List) {
-              value = ((List<Object>) value).stream()
-                  .filter(item -> item instanceof String)
-                  .map(item -> environment.resolvePlaceholders((String) item))
-                  .collect(Collectors.toList());
-            }
-            return value;
-          }
-        });
+    MutablePropertySources propertySources = ((ConfigurableEnvironment) environment).getPropertySources();
+    if (propertySources.contains(MICROSERVICE_PROPERTY_SOURCE_NAME)) {
+      return;
+    }
+
+    propertySources.addLast(new EnumerablePropertySource<MicroserviceConfigLoader>(MICROSERVICE_PROPERTY_SOURCE_NAME) {
+      private final Map<String, Object> values = new HashMap<>();
+
+      private final String[] propertyNames;
+
+      {
+        MicroserviceConfigLoader loader = new MicroserviceConfigLoader();
+        loader.loadAndSort();
+
+        loader.getConfigModels()
+            .forEach(configModel -> values.putAll(YAMLUtil.retrieveItems("", configModel.getConfig())));
+
+        propertyNames = values.keySet().toArray(new String[values.size()]);
+      }
+
+      @Override
+      public String[] getPropertyNames() {
+        return propertyNames;
+      }
+
+      @SuppressWarnings("unchecked")
+      @Override
+      public Object getProperty(String name) {
+        Object value = this.values.get(name);
+
+        // spring will not resolve nested placeholder of list, so try to fix the problem
+        if (value instanceof List) {
+          value = ((List<Object>) value).stream()
+              .filter(item -> item instanceof String)
+              .map(item -> environment.resolvePlaceholders((String) item))
+              .collect(Collectors.toList());
+        }
+        return value;
+      }
+    });
   }
 
-  private void addMappingToString(Environment environment) {
-    if (environment instanceof ConfigurableEnvironment) {
-      ConfigurableEnvironment ce = (ConfigurableEnvironment) environment;
-      Map<String, Object> mappings = ConfigMapping.getConvertedMap(environment);
-      ce.getPropertySources().addFirst(new MapPropertySource("mapping.yaml", mappings));
+  private static void addMappingToSpring(Environment environment) {
+    if (!(environment instanceof ConfigurableEnvironment)) {
+      return;
     }
+
+    MutablePropertySources propertySources = ((ConfigurableEnvironment) environment).getPropertySources();
+    if (propertySources.contains(MAPPING_PROPERTY_SOURCE_NAME)) {
+      return;
+    }
+
+    Map<String, Object> mappings = ConfigMapping.getConvertedMap(environment);
+    propertySources.addFirst(new MapPropertySource(MAPPING_PROPERTY_SOURCE_NAME, mappings));
   }
 
   private void addDynamicConfigurationToSpring(Environment environment,
@@ -220,6 +244,10 @@ public class ConfigurationSpringInitializer extends PropertySourcesPlaceholderCo
     }
 
     for (PropertySource<?> propertySource : configurableEnvironment.getPropertySources()) {
+      if (MICROSERVICE_PROPERTY_SOURCE_NAME.equals(propertySource.getName())
+          || MAPPING_PROPERTY_SOURCE_NAME.equals(propertySource.getName())) {
+        continue;
+      }
       getProperties(configurableEnvironment, propertySource, configFromSpringBoot);
     }
     return configFromSpringBoot;
diff --git a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/SpringBoot2StandaloneApplication.java b/integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/ConditionBean.java
similarity index 63%
copy from integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/SpringBoot2StandaloneApplication.java
copy to integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/ConditionBean.java
index 75ce296..1920d86 100644
--- a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/SpringBoot2StandaloneApplication.java
+++ b/integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/ConditionBean.java
@@ -14,19 +14,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.servicecomb.it;
 
-import org.apache.servicecomb.springboot2.starter.EnableServiceComb;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Component;
 
-@SpringBootApplication
-@EnableServiceComb
-public class SpringBoot2StandaloneApplication {
-  public static void main(String[] args) {
-    new CommandReceiver();
+@ConditionalOnProperty(value = "condition-bean-flag-from-microservice-yaml", havingValue = "true")
+@Component
+public class ConditionBean {
+  private static final Logger LOGGER = LoggerFactory.getLogger(ConditionBean.class);
 
-    SpringApplication.run(SpringBoot2StandaloneApplication.class, args);
+  public ConditionBean() {
+    LOGGER.warn("ConditionBean created.");
   }
 }
diff --git a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/SpringBoot2StandaloneApplication.java b/integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/SpringBoot2StandaloneApplication.java
index 75ce296..ba02599 100644
--- a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/SpringBoot2StandaloneApplication.java
+++ b/integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/SpringBoot2StandaloneApplication.java
@@ -18,12 +18,22 @@
 package org.apache.servicecomb.it;
 
 import org.apache.servicecomb.springboot2.starter.EnableServiceComb;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 
 @SpringBootApplication
 @EnableServiceComb
 public class SpringBoot2StandaloneApplication {
+  // inject this bean to ensure @ConditionalOnProperty can work with configuration from microservice.yaml
+  private ConditionBean conditionBean;
+
+  @Autowired
+  public SpringBoot2StandaloneApplication setDynamicBean(ConditionBean conditionBean) {
+    this.conditionBean = conditionBean;
+    return this;
+  }
+
   public static void main(String[] args) {
     new CommandReceiver();
 
diff --git a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/resources/microservice.yaml b/integration-tests/it-producer-deploy-springboot2-standalone/src/main/resources/microservice.yaml
index f773dd9..49b0bdd 100644
--- a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/resources/microservice.yaml
+++ b/integration-tests/it-producer-deploy-springboot2-standalone/src/main/resources/microservice.yaml
@@ -23,3 +23,5 @@ servicecomb:
   rest:
     server:
       maxInitialLineLength: 5000
+
+condition-bean-flag-from-microservice-yaml: true
\ No newline at end of file
diff --git a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/SpringBoot2StandaloneApplication.java b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter/src/main/java/org/apache/servicecomb/springboot2/starter/ConfigurationSpringBootInitializer.java
similarity index 55%
copy from integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/SpringBoot2StandaloneApplication.java
copy to spring-boot/spring-boot-starters/java-chassis-spring-boot-starter/src/main/java/org/apache/servicecomb/springboot2/starter/ConfigurationSpringBootInitializer.java
index 75ce296..d86d7ea 100644
--- a/integration-tests/it-producer-deploy-springboot2-standalone/src/main/java/org/apache/servicecomb/it/SpringBoot2StandaloneApplication.java
+++ b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter/src/main/java/org/apache/servicecomb/springboot2/starter/ConfigurationSpringBootInitializer.java
@@ -14,19 +14,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package org.apache.servicecomb.springboot2.starter;
 
-package org.apache.servicecomb.it;
-
-import org.apache.servicecomb.springboot2.starter.EnableServiceComb;
+import org.apache.servicecomb.core.ConfigurationSpringInitializer;
 import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-@EnableServiceComb
-public class SpringBoot2StandaloneApplication {
-  public static void main(String[] args) {
-    new CommandReceiver();
+import org.springframework.boot.env.EnvironmentPostProcessor;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.core.env.ConfigurableEnvironment;
 
-    SpringApplication.run(SpringBoot2StandaloneApplication.class, args);
+/**
+ * when run with springboot, add microservice.yaml to Environment earlier<br>
+ * to affect {@link Conditional}<br>
+ */
+public class ConfigurationSpringBootInitializer implements EnvironmentPostProcessor {
+  @Override
+  public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
+    ConfigurationSpringInitializer.syncToSpring(environment);
   }
 }
diff --git a/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter/src/main/resources/META-INF/spring.factories b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000..8874ae7
--- /dev/null
+++ b/spring-boot/spring-boot-starters/java-chassis-spring-boot-starter/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+org.springframework.boot.env.EnvironmentPostProcessor=org.apache.servicecomb.springboot2.starter.ConfigurationSpringBootInitializer
\ No newline at end of file