[ https://issues.apache.org/jira/browse/SCB-453?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16445189#comment-16445189 ]
ASF GitHub Bot commented on SCB-453: ------------------------------------ liubao68 closed pull request #660: [SCB-453] Read config from application yaml properties URL: https://github.com/apache/incubator-servicecomb-java-chassis/pull/660 This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigUtil.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigUtil.java index 076caaf67..a5ff2e61c 100644 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigUtil.java +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigUtil.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -55,6 +56,16 @@ private static Map<String, Object> localConfig = new HashMap<>(); + /** + * <p>The configurations not read by ServiceComb.</p> + * <p> + * For example, this map can store the configurations read by SpringBoot from application.properties, + * If users write the configurations of ServiceComb into application.yml instead of microservice.yaml, + * this can help {@link ConfigUtil} load config correctly. + * </p> + */ + private static final Map<String, Map<String, Object>> EXTRA_CONFIG_MAP = new LinkedHashMap<>(); + private ConfigUtil() { } @@ -110,8 +121,6 @@ public static ConcurrentCompositeConfiguration createLocalConfig() { return config; } - - public static ConcurrentCompositeConfiguration createLocalConfig(List<ConfigModel> configModelList) { ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration(); @@ -125,6 +134,13 @@ public static ConcurrentCompositeConfiguration createLocalConfig(List<ConfigMode new DynamicConfiguration( new MicroserviceConfigurationSource(configModelList), new NeverStartPollingScheduler()), "configFromYamlFile"); + // If there is extra configurations, add it into config. Extra config has lowest priority. + EXTRA_CONFIG_MAP.entrySet().stream() + .filter(mapEntry -> !mapEntry.getValue().isEmpty()) + .forEachOrdered(configMapEntry -> + duplicateServiceCombConfigToCse(config, + new ConcurrentMapConfiguration(configMapEntry.getValue()), + configMapEntry.getKey())); return config; } @@ -210,6 +226,14 @@ public static void installDynamicConfig() { ConfigurationManager.install(dynamicConfig); } + public static void addExtraConfig(String extraConfigName, Map<String, Object> extraConfig) { + EXTRA_CONFIG_MAP.put(extraConfigName, extraConfig); + } + + public static void clearExtraConfig() { + EXTRA_CONFIG_MAP.clear(); + } + private static class ServiceCombPropertyUpdateListener implements WatchedUpdateListener { private final ConcurrentMapConfiguration injectConfig; diff --git a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigurationSpringInitializer.java b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigurationSpringInitializer.java index 05b85cf87..0288d93e6 100644 --- a/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigurationSpringInitializer.java +++ b/foundations/foundation-config/src/main/java/org/apache/servicecomb/config/ConfigurationSpringInitializer.java @@ -18,23 +18,53 @@ package org.apache.servicecomb.config; import java.io.IOException; +import java.util.HashMap; import java.util.Iterator; +import java.util.Map; import java.util.Properties; import org.apache.commons.configuration.AbstractConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; +import org.springframework.context.EnvironmentAware; import org.springframework.core.Ordered; +import org.springframework.core.env.CompositePropertySource; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertySource; +import org.springframework.util.StringUtils; import com.netflix.config.ConfigurationManager; import com.netflix.config.DynamicPropertyFactory; -public class ConfigurationSpringInitializer extends PropertyPlaceholderConfigurer { +public class ConfigurationSpringInitializer extends PropertyPlaceholderConfigurer implements EnvironmentAware { + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationSpringInitializer.class); + + public static final String EXTRA_CONFIG_SOURCE_PREFIX = "extraConfig-"; + public ConfigurationSpringInitializer() { - ConfigUtil.installDynamicConfig(); setOrder(Ordered.LOWEST_PRECEDENCE / 2); setIgnoreUnresolvablePlaceholders(true); } + /** + * Get configurations from Spring, merge them into the configurations of ServiceComb. + * @param environment From which to get the extra config. + */ + @Override + public void setEnvironment(Environment environment) { + String environmentName = generateNameForEnvironment(environment); + LOGGER.info("Environment received, will get configurations from [{}].", environmentName); + + Map<String, Object> extraConfig = getAllProperties(environment); + + ConfigUtil.addExtraConfig(EXTRA_CONFIG_SOURCE_PREFIX + environmentName, extraConfig); + + ConfigUtil.installDynamicConfig(); + } + @Override protected Properties mergeProperties() throws IOException { Properties properties = super.mergeProperties(); @@ -57,4 +87,62 @@ protected String resolvePlaceholder(String placeholder, Properties props) { } return propertyValue; } + + /** + * Try to get a name for identifying the environment. + * @param environment the target that the name is generated for. + * @return The generated name for the environment. + */ + private String generateNameForEnvironment(Environment environment) { + String environmentName = environment.getProperty("spring.config.name"); + if (!StringUtils.isEmpty(environmentName)) { + return environmentName; + } + + environmentName = environment.getProperty("spring.application.name"); + if (!StringUtils.isEmpty(environmentName)) { + return environmentName; + } + + return environment.getClass().getName() + "@" + environment.hashCode(); + } + + /** + * Traversal all {@link PropertySource} of {@link ConfigurableEnvironment}, and try to get all properties. + */ + private Map<String, Object> getAllProperties(Environment environment) { + Map<String, Object> configFromSpringBoot = new HashMap<>(); + + if (!(environment instanceof ConfigurableEnvironment)) { + return configFromSpringBoot; + } + + ConfigurableEnvironment configurableEnvironment = (ConfigurableEnvironment) environment; + for (PropertySource<?> propertySource : configurableEnvironment.getPropertySources()) { + getProperties(configurableEnvironment, propertySource, configFromSpringBoot); + } + return configFromSpringBoot; + } + + /** + * Get property names from {@link EnumerablePropertySource}, and get property value from {@link ConfigurableEnvironment#getProperty(String)} + */ + private void getProperties(ConfigurableEnvironment environment, PropertySource<?> propertySource, + Map<String, Object> configFromSpringBoot) { + if (propertySource instanceof CompositePropertySource) { + // recursively get EnumerablePropertySource + CompositePropertySource compositePropertySource = (CompositePropertySource) propertySource; + compositePropertySource.getPropertySources().forEach(ps -> getProperties(environment, ps, configFromSpringBoot)); + return; + } + if (propertySource instanceof EnumerablePropertySource) { + EnumerablePropertySource<?> enumerablePropertySource = (EnumerablePropertySource<?>) propertySource; + for (String propertyName : enumerablePropertySource.getPropertyNames()) { + configFromSpringBoot.put(propertyName, environment.getProperty(propertyName)); + } + return; + } + + LOGGER.debug("a none EnumerablePropertySource is ignored, propertySourceName = [{}]", propertySource.getName()); + } } diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigUtil.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigUtil.java index a61555a0e..b10142de7 100644 --- a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigUtil.java +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigUtil.java @@ -25,16 +25,16 @@ import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.HashMap; -import com.netflix.config.*; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.servicecomb.config.archaius.sources.ConfigModel; import org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader; import org.apache.servicecomb.config.spi.ConfigCenterConfigurationSource; +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; import org.junit.AfterClass; @@ -42,6 +42,11 @@ import org.junit.BeforeClass; import org.junit.Test; +import com.netflix.config.ConcurrentCompositeConfiguration; +import com.netflix.config.DynamicConfiguration; +import com.netflix.config.DynamicPropertyFactory; +import com.netflix.config.DynamicWatchedConfiguration; + import mockit.Deencapsulation; import mockit.Expectations; import mockit.Mocked; @@ -73,13 +78,13 @@ public static void beforeTest() { } @AfterClass - public static void tearDown() throws Exception { + public static void tearDown() { ArchaiusUtils.resetConfig(); } @Test public void testAddConfig() { - Map config = new HashMap<String, Object>(); + Map<String, Object> config = new HashMap<>(); config.put("service_description.name", "service_name_test"); ConfigUtil.setConfigs(config); ConfigUtil.addConfig("service_description.version", "1.0.2"); @@ -87,7 +92,7 @@ public void testAddConfig() { ConfigUtil.addConfig("cse.test.num", 10); AbstractConfiguration configuration = ConfigUtil.createDynamicConfig(); Assert.assertEquals(configuration.getString("service_description.name"), "service_name_test"); - Assert.assertEquals(configuration.getBoolean("cse.test.enabled"), true); + Assert.assertTrue(configuration.getBoolean("cse.test.enabled")); Assert.assertEquals(configuration.getInt("cse.test.num"), 10); } @@ -116,8 +121,7 @@ public void testCreateDynamicConfigNoConfigCenterSPI() { } @Test - public void testCreateDynamicConfigHasConfigCenter( - @Mocked ConfigCenterConfigurationSource configCenterConfigurationSource) { + public void testCreateDynamicConfigHasConfigCenter() { AbstractConfiguration dynamicConfig = ConfigUtil.createDynamicConfig(); Assert.assertEquals(DynamicWatchedConfiguration.class, ((ConcurrentCompositeConfiguration) dynamicConfig).getConfiguration(0).getClass()); @@ -130,54 +134,54 @@ public void testGetPropertyInvalidConfig() { } @Test - public void propertiesFromFileIsDuplicatedToCse() throws Exception { + public void propertiesFromFileIsDuplicatedToCse() { String expected = "value"; assertThat(DynamicPropertyFactory - .getInstance() - .getStringProperty("servicecomb.cse.servicecomb.file", null) - .get(), + .getInstance() + .getStringProperty("servicecomb.cse.servicecomb.file", null) + .get(), equalTo(expected)); assertThat(DynamicPropertyFactory - .getInstance() - .getStringProperty("cse.cse.servicecomb.file", null) - .get(), + .getInstance() + .getStringProperty("cse.cse.servicecomb.file", null) + .get(), equalTo(expected)); } @Test - public void propertiesFromSystemIsDuplicatedToCse() throws Exception { + public void propertiesFromSystemIsDuplicatedToCse() { assertThat(DynamicPropertyFactory - .getInstance() - .getStringProperty(systemPropertyName, null) - .get(), + .getInstance() + .getStringProperty(systemPropertyName, null) + .get(), equalTo(systemExpected)); assertThat(DynamicPropertyFactory - .getInstance() - .getStringProperty("servicecomb.cse.servicecomb.system.setting", null) - .get(), + .getInstance() + .getStringProperty("servicecomb.cse.servicecomb.system.setting", null) + .get(), equalTo(systemExpected)); } @Test - public void propertiesFromEnvironmentIsDuplicatedToCse() throws Exception { + public void propertiesFromEnvironmentIsDuplicatedToCse() { assertThat(DynamicPropertyFactory - .getInstance() - .getStringProperty(environmentPropertyName, null) - .get(), + .getInstance() + .getStringProperty(environmentPropertyName, null) + .get(), equalTo(environmentExpected)); assertThat(DynamicPropertyFactory - .getInstance() - .getStringProperty("servicecomb.cse.servicecomb.environment.setting", null) - .get(), + .getInstance() + .getStringProperty("servicecomb.cse.servicecomb.environment.setting", null) + .get(), equalTo(environmentExpected)); } @Test - public void duplicateServiceCombConfigToCseListValue() throws Exception { + public void duplicateServiceCombConfigToCseListValue() { List<String> list = Arrays.asList("a", "b"); AbstractConfiguration config = new DynamicConfiguration(); @@ -190,7 +194,7 @@ public void duplicateServiceCombConfigToCseListValue() throws Exception { } @Test - public void propertiesAddFromDynamicConfigSourceIsDuplicated() throws Exception { + public void propertiesAddFromDynamicConfigSourceIsDuplicated() { String expected = uniquify("ran"); String someProperty = "servicecomb.cse.servicecomb.add"; String injectProperty = "cse.cse.servicecomb.add"; @@ -231,7 +235,7 @@ public void propertiesAddFromDynamicConfigSourceIsDuplicated() throws Exception } @Test - public void propertiesChangeFromDynamicConfigSourceIsDuplicated() throws Exception { + public void propertiesChangeFromDynamicConfigSourceIsDuplicated() { String expected = uniquify("ran"); String someProperty = "servicecomb.cse.servicecomb.change"; String injectProperty = "cse.cse.servicecomb.change"; @@ -269,7 +273,7 @@ public void propertiesChangeFromDynamicConfigSourceIsDuplicated() throws Excepti } @Test - public void propertiesDeleteFromDynamicConfigSourceIsDuplicated() throws Exception { + public void propertiesDeleteFromDynamicConfigSourceIsDuplicated() { String expected = uniquify("ran"); String someProperty = "servicecomb.cse.servicecomb.delete"; String injectProperty = "cse.cse.servicecomb.delete"; @@ -315,6 +319,23 @@ public void testConvertEnvVariable() { assertThat(result.getString("cse_service_registry_address"), equalTo("testing")); } + @Test + public void testCreateLocalConfigWithExtraConfig() { + Map<String, Object> extraConfig = new ConcurrentHashMapEx<>(1); + String extraConfigKey = "extraConfigKey"; + String extraConfigValue = "value"; + String overriddenConfigKey = "servicecomb.cse.servicecomb.file"; + extraConfig.put(extraConfigKey, extraConfigValue); + extraConfig.put(overriddenConfigKey, "should_be_overridden"); + + ConfigUtil.addExtraConfig("testExtraConfig", extraConfig); + + ConcurrentCompositeConfiguration localConfiguration = ConfigUtil.createLocalConfig(); + + Assert.assertEquals(extraConfigValue, localConfiguration.getProperty(extraConfigKey)); + Assert.assertEquals("value", localConfiguration.getString(overriddenConfigKey)); + } + @SuppressWarnings("unchecked") private static void setEnv(String key, String value) throws IllegalAccessException, NoSuchFieldException { Class<?>[] classes = Collections.class.getDeclaredClasses(); diff --git a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigurationSpringInitializer.java b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigurationSpringInitializer.java index b2c5da0d4..3dc9b71ad 100644 --- a/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigurationSpringInitializer.java +++ b/foundations/foundation-config/src/test/java/org/apache/servicecomb/config/TestConfigurationSpringInitializer.java @@ -16,36 +16,54 @@ */ package org.apache.servicecomb.config; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.anyString; + +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import org.apache.commons.configuration.Configuration; import org.apache.servicecomb.config.archaius.sources.MicroserviceConfigLoader; import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; -import org.junit.AfterClass; +import org.junit.After; import org.junit.Assert; -import org.junit.BeforeClass; +import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; +import org.mockito.stubbing.Answer; import org.springframework.core.Ordered; +import org.springframework.core.env.CompositePropertySource; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.jndi.JndiPropertySource; import com.netflix.config.ConfigurationManager; import mockit.Deencapsulation; public class TestConfigurationSpringInitializer { - @BeforeClass - public static void classSetup() { + @Before + public void beforeTest() { + ConfigUtil.clearExtraConfig(); ArchaiusUtils.resetConfig(); } - @AfterClass - public static void classTeardown() { + @After + public void afterTest() { + ConfigUtil.clearExtraConfig(); ArchaiusUtils.resetConfig(); } @Test public void testAll() { ConfigurationSpringInitializer configurationSpringInitializer = new ConfigurationSpringInitializer(); + ConfigUtil.installDynamicConfig(); Assert.assertEquals(Ordered.LOWEST_PRECEDENCE / 2, configurationSpringInitializer.getOrder()); Assert.assertEquals(true, @@ -55,7 +73,7 @@ public void testAll() { @SuppressWarnings("unchecked") List<Map<String, Object>> listO = (List<Map<String, Object>>) o; Assert.assertEquals(3, listO.size()); - Assert.assertEquals(null, ConfigUtil.getProperty("notExist")); + Assert.assertNull(ConfigUtil.getProperty("notExist")); MicroserviceConfigLoader loader = ConfigUtil.getMicroserviceConfigLoader(); Assert.assertNotNull(loader); @@ -65,4 +83,144 @@ public void testAll() { // must not reinstall Assert.assertEquals(instance, ConfigurationManager.getConfigInstance()); } + + @Test + public void testSetEnvironment() { + ConfigurableEnvironment environment = Mockito.mock(ConfigurableEnvironment.class); + MutablePropertySources propertySources = new MutablePropertySources(); + Map<String, String> propertyMap = new HashMap<>(); + final String map0Key0 = "map0-Key0"; + final String map1Key0 = "map1-Key0"; + final String map2Key0 = "map2-Key0"; + final String map3Key0 = "map3-Key0"; + propertyMap.put(map0Key0, "map0-Value0"); + propertyMap.put(map1Key0, "map1-Value0"); + propertyMap.put(map2Key0, "map2-Value0"); + propertyMap.put(map3Key0, "map3-Value0"); + + /* + propertySources + |- compositePropertySource0 + | |- mapPropertySource0 + | | |- map0-Key0 = map0-Value0 + | |- compositePropertySource1 + | |- mapPropertySource1 + | | |- map1-Key0 = map1-Value0 + | |- mapPropertySource2 + | |- map2-Key0 = map2-Value0 + | |- JndiPropertySource(mocked) + |- mapPropertySource3 + |- map3-Key0 = map3-Value0 + */ + CompositePropertySource compositePropertySource0 = new CompositePropertySource("compositePropertySource0"); + propertySources.addFirst(compositePropertySource0); + + HashMap<String, Object> map0 = new HashMap<>(); + map0.put(map0Key0, propertyMap.get(map0Key0)); + MapPropertySource mapPropertySource0 = new MapPropertySource("mapPropertySource0", map0); + compositePropertySource0.addFirstPropertySource(mapPropertySource0); + + CompositePropertySource compositePropertySource1 = new CompositePropertySource("compositePropertySource1"); + compositePropertySource0.addPropertySource(compositePropertySource1); + HashMap<String, Object> map1 = new HashMap<>(); + map1.put(map1Key0, propertyMap.get(map1Key0)); + MapPropertySource mapPropertySource1 = new MapPropertySource("mapPropertySource1", map1); + compositePropertySource1.addPropertySource(mapPropertySource1); + HashMap<String, Object> map2 = new HashMap<>(); + map2.put(map2Key0, propertyMap.get(map2Key0)); + MapPropertySource mapPropertySource2 = new MapPropertySource("mapPropertySource2", map2); + compositePropertySource1.addPropertySource(mapPropertySource2); + compositePropertySource1.addPropertySource(Mockito.mock(JndiPropertySource.class)); + + HashMap<String, Object> map3 = new HashMap<>(); + map3.put(map3Key0, propertyMap.get(map3Key0)); + MapPropertySource mapPropertySource3 = new MapPropertySource("mapPropertySource3", map3); + compositePropertySource0.addPropertySource(mapPropertySource3); + + Mockito.when(environment.getPropertySources()).thenReturn(propertySources); + Mockito.doAnswer((Answer<String>) invocation -> { + Object[] args = invocation.getArguments(); + String propertyName = (String) args[0]; + + if ("spring.config.name".equals(propertyName) || "spring.application.name".equals(propertyName)) { + return null; + } + + String value = propertyMap.get(propertyName); + if (null == value) { + fail("get unexpected property name: " + propertyName); + } + return value; + }).when(environment).getProperty(anyString()); + + new ConfigurationSpringInitializer().setEnvironment(environment); + + Map<String, Map<String, Object>> extraLocalConfig = getExtraConfigMapFromConfigUtil(); + assertFalse(extraLocalConfig.isEmpty()); + Map<String, Object> extraProperties = extraLocalConfig + .get(ConfigurationSpringInitializer.EXTRA_CONFIG_SOURCE_PREFIX + environment.getClass().getName() + "@" + + environment.hashCode()); + assertNotNull(extraLocalConfig); + for (Entry<String, String> entry : propertyMap.entrySet()) { + assertEquals(entry.getValue(), extraProperties.get(entry.getKey())); + } + } + + @Test + public void testSetEnvironmentOnEnvironmentName() { + // get environment name from spring.config.name + ConfigurableEnvironment environment0 = Mockito.mock(ConfigurableEnvironment.class); + MutablePropertySources propertySources0 = new MutablePropertySources(); + Mockito.when(environment0.getPropertySources()).thenReturn(propertySources0); + Map<String, Object> map0 = new HashMap<>(1); + map0.put("spring.config.name", "application"); + propertySources0.addFirst(new MapPropertySource("mapPropertySource0", map0)); + Mockito.when(environment0.getProperty("spring.config.name")).thenReturn("application"); + + // get environment name from spring.application.name + ConfigurableEnvironment environment1 = Mockito.mock(ConfigurableEnvironment.class); + MutablePropertySources propertySources1 = new MutablePropertySources(); + Mockito.when(environment1.getPropertySources()).thenReturn(propertySources1); + Map<String, Object> map1 = new HashMap<>(1); + map1.put("spring.application.name", "bootstrap"); + propertySources1.addFirst(new MapPropertySource("mapPropertySource1", map1)); + Mockito.when(environment1.getProperty("spring.application.name")).thenReturn("bootstrap"); + + // get environment name from className+hashcode + ConfigurableEnvironment environment2 = Mockito.mock(ConfigurableEnvironment.class); + MutablePropertySources propertySources2 = new MutablePropertySources(); + Mockito.when(environment2.getPropertySources()).thenReturn(propertySources2); + Map<String, Object> map2 = new HashMap<>(1); + map2.put("key2", "value2"); + propertySources2.addFirst(new MapPropertySource("mapPropertySource2", map2)); + Mockito.when(environment2.getProperty("key2")).thenReturn("value2"); + + ConfigurationSpringInitializer configurationSpringInitializer = new ConfigurationSpringInitializer(); + configurationSpringInitializer.setEnvironment(environment0); + configurationSpringInitializer.setEnvironment(environment1); + configurationSpringInitializer.setEnvironment(environment2); + + Map<String, Map<String, Object>> extraConfig = getExtraConfigMapFromConfigUtil(); + assertEquals(3, extraConfig.size()); + + Map<String, Object> extraProperties = extraConfig + .get(ConfigurationSpringInitializer.EXTRA_CONFIG_SOURCE_PREFIX + "application"); + assertEquals(1, extraProperties.size()); + assertEquals("application", extraProperties.get("spring.config.name")); + + extraProperties = extraConfig.get(ConfigurationSpringInitializer.EXTRA_CONFIG_SOURCE_PREFIX + "bootstrap"); + assertEquals(1, extraProperties.size()); + assertEquals("bootstrap", extraProperties.get("spring.application.name")); + + extraProperties = extraConfig.get( + ConfigurationSpringInitializer.EXTRA_CONFIG_SOURCE_PREFIX + environment2.getClass().getName() + "@" + + environment2.hashCode()); + assertEquals(1, extraProperties.size()); + assertEquals("value2", extraProperties.get("key2")); + } + + private Map<String, Map<String, Object>> getExtraConfigMapFromConfigUtil() { + return Deencapsulation + .getField(ConfigUtil.class, "EXTRA_CONFIG_MAP"); + } } diff --git a/integration-tests/spring-jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsSpringIntegrationTest.java b/integration-tests/spring-jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsSpringIntegrationTest.java index f38df6c87..8bb37bd86 100644 --- a/integration-tests/spring-jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsSpringIntegrationTest.java +++ b/integration-tests/spring-jaxrs-tests/src/test/java/org/apache/servicecomb/demo/jaxrs/tests/JaxrsSpringIntegrationTest.java @@ -17,12 +17,43 @@ package org.apache.servicecomb.demo.jaxrs.tests; +import static org.junit.Assert.assertEquals; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; +import com.netflix.config.DynamicProperty; + @RunWith(SpringRunner.class) @SpringBootTest(classes = JaxrsSpringMain.class) public class JaxrsSpringIntegrationTest extends JaxrsIntegrationTestBase { + @BeforeClass + public static void setUp() { + System.setProperty("property.test5", "from_system_property"); + } + + @AfterClass + public static void tearDown() { + System.clearProperty("property.test5"); + } + @Test + public void testGetConfigFromSpringBoot() { + DynamicProperty dynamicProperty = DynamicProperty.getInstance("property.test0"); + assertEquals("from_properties", dynamicProperty.getString()); + dynamicProperty = DynamicProperty.getInstance("property.test1"); + assertEquals("from_yml", dynamicProperty.getString()); + dynamicProperty = DynamicProperty.getInstance("property.test2"); + assertEquals("from_yaml_from_yml", dynamicProperty.getString()); + dynamicProperty = DynamicProperty.getInstance("property.test3"); + assertEquals("from_yaml_dev_from_properties", dynamicProperty.getString()); + dynamicProperty = DynamicProperty.getInstance("property.test4"); + assertEquals("from_microservice_yaml", dynamicProperty.getString()); + dynamicProperty = DynamicProperty.getInstance("property.test5"); + assertEquals("from_system_property", dynamicProperty.getString()); + } } diff --git a/integration-tests/spring-jaxrs-tests/src/test/resources/application-dev.yaml b/integration-tests/spring-jaxrs-tests/src/test/resources/application-dev.yaml new file mode 100644 index 000000000..5a6e140e5 --- /dev/null +++ b/integration-tests/spring-jaxrs-tests/src/test/resources/application-dev.yaml @@ -0,0 +1,19 @@ +# --------------------------------------------------------------------------- +# 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. +# --------------------------------------------------------------------------- + +property: + test3: from_yaml_dev_${property.test0} diff --git a/integration-tests/spring-jaxrs-tests/src/test/resources/application-prod.yaml b/integration-tests/spring-jaxrs-tests/src/test/resources/application-prod.yaml new file mode 100644 index 000000000..2fcc1991f --- /dev/null +++ b/integration-tests/spring-jaxrs-tests/src/test/resources/application-prod.yaml @@ -0,0 +1,19 @@ +# --------------------------------------------------------------------------- +# 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. +# --------------------------------------------------------------------------- + +property: + test3: from_yaml_prod_${property.test0} diff --git a/integration-tests/spring-jaxrs-tests/src/test/resources/application.properties b/integration-tests/spring-jaxrs-tests/src/test/resources/application.properties new file mode 100644 index 000000000..39d02011b --- /dev/null +++ b/integration-tests/spring-jaxrs-tests/src/test/resources/application.properties @@ -0,0 +1,20 @@ +# +# 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. +# + +property.test0=from_properties +property.test4=from_properties +property.test5=from_properties diff --git a/integration-tests/spring-jaxrs-tests/src/test/resources/application.yaml b/integration-tests/spring-jaxrs-tests/src/test/resources/application.yaml new file mode 100644 index 000000000..ebe87f61e --- /dev/null +++ b/integration-tests/spring-jaxrs-tests/src/test/resources/application.yaml @@ -0,0 +1,21 @@ +# +# 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. +# + +property: + test0: from_yaml + test1: from_yaml + test2: from_yaml_${property.test1} diff --git a/integration-tests/spring-jaxrs-tests/src/test/resources/application.yml b/integration-tests/spring-jaxrs-tests/src/test/resources/application.yml new file mode 100644 index 000000000..a350c10c9 --- /dev/null +++ b/integration-tests/spring-jaxrs-tests/src/test/resources/application.yml @@ -0,0 +1,24 @@ +# --------------------------------------------------------------------------- +# 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. +# --------------------------------------------------------------------------- + +property: + test0: from_yml + test1: from_yml + +spring: + profiles: + active: dev diff --git a/integration-tests/spring-jaxrs-tests/src/test/resources/microservice.yaml b/integration-tests/spring-jaxrs-tests/src/test/resources/microservice.yaml new file mode 100644 index 000000000..49937a23e --- /dev/null +++ b/integration-tests/spring-jaxrs-tests/src/test/resources/microservice.yaml @@ -0,0 +1,20 @@ +# --------------------------------------------------------------------------- +# 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. +# --------------------------------------------------------------------------- + +property: + test4: from_microservice_yaml + test5: from_microservice_yaml diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/SpringCloudZuulTracingTest.java b/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/SpringCloudZuulTracingTest.java index 3859e1276..06dabf594 100644 --- a/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/SpringCloudZuulTracingTest.java +++ b/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/SpringCloudZuulTracingTest.java @@ -19,6 +19,7 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; @@ -29,6 +30,8 @@ import org.apache.servicecomb.tests.tracing.TracingTestBase; import org.junit.After; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -37,6 +40,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringRunner; +import com.netflix.config.DynamicProperty; + @RunWith(SpringRunner.class) @SpringBootTest(classes = TracedZuulMain.class, webEnvironment = RANDOM_PORT) public class SpringCloudZuulTracingTest extends TracingTestBase { @@ -44,8 +49,18 @@ @Autowired private TestRestTemplate testRestTemplate; + @BeforeClass + public static void beforeClass() { + System.setProperty("property.test5", "from_system_property"); + } + + @AfterClass + public static void afterClass() { + System.clearProperty("property.test5"); + } + @After - public void tearDown() throws Exception { + public void tearDown() { appender.clear(); } @@ -77,4 +92,26 @@ public void tracesFailedCallsReceivedByZuul() throws InterruptedException { assertThatSpansReceivedByZipkin(tracingMessages, "/dummy/rest/oops", "500", "/oops", "590"); } + + @Test + public void testGetConfigFromSpringBoot() { + DynamicProperty dynamicProperty = DynamicProperty.getInstance("property.test0"); + assertEquals("from_properties", dynamicProperty.getString()); + dynamicProperty = DynamicProperty.getInstance("property.test1"); + assertEquals("from_yml", dynamicProperty.getString()); + dynamicProperty = DynamicProperty.getInstance("property.test2"); + assertEquals("from_yaml_from_yml", dynamicProperty.getString()); + dynamicProperty = DynamicProperty.getInstance("property.test3"); + assertEquals("from_yaml_dev_from_properties", dynamicProperty.getString()); + dynamicProperty = DynamicProperty.getInstance("property.test4"); + assertEquals("from_microservice_yaml", dynamicProperty.getString()); + dynamicProperty = DynamicProperty.getInstance("property.test5"); + assertEquals("from_system_property", dynamicProperty.getString()); + + ResponseEntity<String> responseEntity = testRestTemplate.getForEntity("/dummy/rest/testProperty", String.class); + + assertThat(responseEntity.getStatusCode(), is(OK)); + assertThat(responseEntity.getBody(), + is("from_properties-from_yml-from_yaml_from_yml-from_yaml_dev_from_properties-from_microservice_yaml-from_system_property")); + } } diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracedController.java b/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracedController.java index d1c2ed931..046359466 100644 --- a/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracedController.java +++ b/integration-tests/spring-zuul-tracing-tests/src/test/java/org/apache/servicecomb/spring/cloud/zuul/tracing/TracedController.java @@ -25,6 +25,7 @@ import org.apache.servicecomb.provider.rest.common.RestSchema; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; @RestSchema(schemaId = "tracedController") @@ -32,6 +33,24 @@ public class TracedController { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + @Value("${property.test0}") + private String propertyTest0; + + @Value("${property.test1}") + private String propertyTest1; + + @Value("${property.test2}") + private String propertyTest2; + + @Value("${property.test3}") + private String propertyTest3; + + @Value("${property.test4}") + private String propertyTest4; + + @Value("${property.test5}") + private String propertyTest5; + @RequestMapping(value = "/blah", method = GET, produces = TEXT_PLAIN_VALUE) public String blah() { logger.info("in /blah"); @@ -45,4 +64,16 @@ public String oops() { throw new IllegalStateException("oops"); } + + @RequestMapping(value = "/testProperty", method = GET, produces = TEXT_PLAIN_VALUE) + public String testProperty() { + logger.info("in /testProperty"); + + return propertyTest0 + + "-" + propertyTest1 + + "-" + propertyTest2 + + "-" + propertyTest3 + + "-" + propertyTest4 + + "-" + propertyTest5; + } } diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application-dev.yaml b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application-dev.yaml new file mode 100644 index 000000000..5a6e140e5 --- /dev/null +++ b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application-dev.yaml @@ -0,0 +1,19 @@ +# --------------------------------------------------------------------------- +# 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. +# --------------------------------------------------------------------------- + +property: + test3: from_yaml_dev_${property.test0} diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application-prod.yaml b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application-prod.yaml new file mode 100644 index 000000000..2fcc1991f --- /dev/null +++ b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application-prod.yaml @@ -0,0 +1,19 @@ +# --------------------------------------------------------------------------- +# 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. +# --------------------------------------------------------------------------- + +property: + test3: from_yaml_prod_${property.test0} diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.properties b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.properties index 4289b8906..9c2440b2e 100644 --- a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.properties +++ b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.properties @@ -16,3 +16,7 @@ # spring.main.web-environment=true + +property.test0=from_properties +property.test4=from_properties +property.test5=from_properties \ No newline at end of file diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.yaml b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.yaml index 3bd39230f..1d4dc74ab 100644 --- a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.yaml +++ b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.yaml @@ -27,3 +27,8 @@ ribbon: server: port: 0 + +property: + test0: from_yaml + test1: from_yaml + test2: from_yaml_${property.test1} \ No newline at end of file diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.yml b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.yml new file mode 100644 index 000000000..a350c10c9 --- /dev/null +++ b/integration-tests/spring-zuul-tracing-tests/src/test/resources/application.yml @@ -0,0 +1,24 @@ +# --------------------------------------------------------------------------- +# 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. +# --------------------------------------------------------------------------- + +property: + test0: from_yml + test1: from_yml + +spring: + profiles: + active: dev diff --git a/integration-tests/spring-zuul-tracing-tests/src/test/resources/microservice.yaml b/integration-tests/spring-zuul-tracing-tests/src/test/resources/microservice.yaml index 6de98d9e7..ca417ce7b 100644 --- a/integration-tests/spring-zuul-tracing-tests/src/test/resources/microservice.yaml +++ b/integration-tests/spring-zuul-tracing-tests/src/test/resources/microservice.yaml @@ -36,3 +36,7 @@ servicecomb: tracing: collector: address: http://localhost:9411/ + +property: + test4: from_microservice_yaml + test5: from_microservice_yaml ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org > Read configuration from application.yml/application.properties > -------------------------------------------------------------- > > Key: SCB-453 > URL: https://issues.apache.org/jira/browse/SCB-453 > Project: Apache ServiceComb > Issue Type: Task > Components: Java-Chassis > Reporter: YaoHaishi > Assignee: YaoHaishi > Priority: Major > Attachments: Compile_Warning.PNG > > > In ServiceComb project transferred from SpringBoot, reading ServiceComb > configurations from application.yml/application.properties should be > supported so that users can write all of the configurations in one config > file. -- This message was sent by Atlassian JIRA (v7.6.3#76005)