From ac2baee2cde66abb50cbf8695a5d6ea97a3b191a Mon Sep 17 00:00:00 2001 From: Luan Louis Date: Mon, 29 Oct 2018 19:48:05 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=A2=9E=E5=8A=A0EnvironmentPostProcessor?= =?UTF-8?q?=E5=A4=84=E7=90=86=EF=BC=8C=E5=B0=86Apollo=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E6=8F=90=E5=88=B0=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E7=B3=BB=E7=BB=9F=E4=B9=8B=E5=89=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ApolloApplicationContextInitializer.java | 70 ++++++++++++++++++- .../config/PropertySourcesConstants.java | 1 + .../main/resources/META-INF/spring.factories | 2 + .../apollo/spring/BootstrapConfigTest.java | 59 ++++++++++++++-- 4 files changed, 125 insertions(+), 7 deletions(-) diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java index 908792b30d9..e442ccefa2e 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java @@ -8,14 +8,17 @@ import com.ctrip.framework.apollo.spring.util.SpringInjector; import com.google.common.base.Splitter; import com.google.common.base.Strings; -import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.ConfigurableEnvironment; +import java.util.List; + /** * Initialize apollo system properties and inject the Apollo config in Spring Boot bootstrap phase * @@ -37,9 +40,23 @@ * # will inject 'application' and 'FX.apollo' namespaces in bootstrap phase * apollo.bootstrap.namespaces = application,FX.apollo * + * + * + * If you want to load Apollo configurations even before Logging System Initialization Phase, + * add + *
+ *   # set apollo.bootstrap.eagerLoad.enabled
+ *   apollo.bootstrap.eagerLoad.enabled = true
+ * 
+ * + * This would be very helpful when your logging configurations is set by Apollo. + * + * for example, you have defined logback-spring.xml in your project , and you want to inject some attributes into logback-spring.xml. + * + * */ public class ApolloApplicationContextInitializer implements - ApplicationContextInitializer { + ApplicationContextInitializer , EnvironmentPostProcessor { private static final Logger logger = LoggerFactory.getLogger(ApolloApplicationContextInitializer.class); private static final Splitter NAMESPACE_SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults(); private static final String[] APOLLO_SYSTEM_PROPERTIES = {"app.id", ConfigConsts.APOLLO_CLUSTER_KEY, @@ -61,6 +78,20 @@ public void initialize(ConfigurableApplicationContext context) { } logger.debug("Apollo bootstrap config is enabled for context {}", context); + initialize(environment); + } + + + /** + * + * + * Initialize Apollo Configurations Just after environment is ready. + * + * + * @param environment + */ + protected void initialize(ConfigurableEnvironment environment) { + if (environment.getPropertySources().contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) { //already initialized return; @@ -102,4 +133,39 @@ private void fillSystemPropertyFromEnvironment(ConfigurableEnvironment environme System.setProperty(propertyName, propertyValue); } + + /** + * + * In order to load Apollo configurations even as early before Spring loading logging system phase, + * + * This EnvironmentPostProcessor can be called Just After ConfigFileApplicationListener has succeeded. + * + * + * The processing sequence would be like this: + * + * Load Bootstrap properties and application properties -----> load Apollo configuration properties ----> Initialize Logging systems + * + * + * + * @param configurableEnvironment + * @param springApplication + */ + @Override + public void postProcessEnvironment(ConfigurableEnvironment configurableEnvironment, SpringApplication springApplication) { + + Boolean eagerLoadEnabled = configurableEnvironment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED,Boolean.class,false); + + + //EnvironmentPostProcessor should not be triggered if you don't want Apollo Loading before Logging System Initialization + if(!eagerLoadEnabled){ + return; + } + + Boolean bootstrapEnabled = configurableEnvironment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED,Boolean.class,false); + + if(bootstrapEnabled) { + initialize(configurableEnvironment); + } + + } } diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesConstants.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesConstants.java index 37b75d28098..b402e06dfea 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesConstants.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesConstants.java @@ -4,5 +4,6 @@ public interface PropertySourcesConstants { String APOLLO_PROPERTY_SOURCE_NAME = "ApolloPropertySources"; String APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME = "ApolloBootstrapPropertySources"; String APOLLO_BOOTSTRAP_ENABLED = "apollo.bootstrap.enabled"; + String APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED = "apollo.bootstrap.eagerLoad.enabled"; String APOLLO_BOOTSTRAP_NAMESPACES = "apollo.bootstrap.namespaces"; } diff --git a/apollo-client/src/main/resources/META-INF/spring.factories b/apollo-client/src/main/resources/META-INF/spring.factories index a4b7944a8d1..80c3b509bd3 100644 --- a/apollo-client/src/main/resources/META-INF/spring.factories +++ b/apollo-client/src/main/resources/META-INF/spring.factories @@ -2,3 +2,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.ctrip.framework.apollo.spring.boot.ApolloAutoConfiguration org.springframework.context.ApplicationContextInitializer=\ com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer +org.springframework.boot.env.EnvironmentPostProcessor=\ +com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/BootstrapConfigTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/BootstrapConfigTest.java index 13961a1959a..d223c3df229 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/BootstrapConfigTest.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/BootstrapConfigTest.java @@ -1,14 +1,12 @@ package com.ctrip.framework.apollo.spring; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.core.ConfigConsts; import com.ctrip.framework.apollo.spring.annotation.ApolloConfig; +import com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer; import com.ctrip.framework.apollo.spring.config.PropertySourcesConstants; +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; import com.google.common.collect.Sets; import org.junit.AfterClass; import org.junit.Assert; @@ -20,12 +18,21 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import java.util.List; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + /** * @author Jason Song(song_s@ctrip.com) */ @@ -265,6 +272,48 @@ public void test() throws Exception { } } + + @RunWith(SpringJUnit4ClassRunner.class) + @SpringBootTest(classes = ConfigurationWithoutConditionalOnProperty.class) + @DirtiesContext + public static class TestWithBootstrapEnabledAndEagerLoadEnabled extends + AbstractSpringIntegrationTest { + + @BeforeClass + public static void beforeClass() { + doSetUp(); + + System.setProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, "true"); + System.setProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED, "true"); + + Config config = mock(Config.class); + + mockConfig(ConfigConsts.NAMESPACE_APPLICATION, config); + } + + @AfterClass + public static void afterClass() { + System.clearProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED); + System.clearProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED); + + doTearDown(); + } + + @Test + public void test() { + List processorList = SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class, getClass().getClassLoader()); + + Boolean containsApollo = !Collections2.filter(processorList, new Predicate() { + @Override + public boolean apply(EnvironmentPostProcessor input) { + return input instanceof ApolloApplicationContextInitializer; + } + }).isEmpty(); + Assert.assertTrue(containsApollo); + } + } + + @EnableAutoConfiguration @Configuration static class ConfigurationWithoutConditionalOnProperty { From 0cbfff96fe49e97637d97d8882eeeea06156aebf Mon Sep 17 00:00:00 2001 From: nobodyiam Date: Sun, 4 Nov 2018 20:15:27 +0800 Subject: [PATCH 2/2] fix the executing sequence of initializeSystemProperty --- .../ApolloApplicationContextInitializer.java | 39 +++++++------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java index e442ccefa2e..3959b1ef962 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/boot/ApolloApplicationContextInitializer.java @@ -8,6 +8,7 @@ import com.ctrip.framework.apollo.spring.util.SpringInjector; import com.google.common.base.Splitter; import com.google.common.base.Strings; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; @@ -17,8 +18,6 @@ import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.ConfigurableEnvironment; -import java.util.List; - /** * Initialize apollo system properties and inject the Apollo config in Spring Boot bootstrap phase * @@ -49,10 +48,9 @@ * apollo.bootstrap.eagerLoad.enabled = true * * - * This would be very helpful when your logging configurations is set by Apollo. - * - * for example, you have defined logback-spring.xml in your project , and you want to inject some attributes into logback-spring.xml. + * This would be very helpful when your logging configurations is set by Apollo. * + * for example, you have defined logback-spring.xml in your project, and you want to inject some attributes into logback-spring.xml. * */ public class ApolloApplicationContextInitializer implements @@ -69,8 +67,6 @@ public class ApolloApplicationContextInitializer implements public void initialize(ConfigurableApplicationContext context) { ConfigurableEnvironment environment = context.getEnvironment(); - initializeSystemProperty(environment); - String enabled = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, "false"); if (!Boolean.valueOf(enabled)) { logger.debug("Apollo bootstrap config is not enabled for context {}, see property: ${{}}", context, PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED); @@ -83,11 +79,8 @@ public void initialize(ConfigurableApplicationContext context) { /** - * - * * Initialize Apollo Configurations Just after environment is ready. * - * * @param environment */ protected void initialize(ConfigurableEnvironment environment) { @@ -136,16 +129,12 @@ private void fillSystemPropertyFromEnvironment(ConfigurableEnvironment environme /** * - * In order to load Apollo configurations even as early before Spring loading logging system phase, - * - * This EnvironmentPostProcessor can be called Just After ConfigFileApplicationListener has succeeded. - * - * - * The processing sequence would be like this: - * - * Load Bootstrap properties and application properties -----> load Apollo configuration properties ----> Initialize Logging systems - * + * In order to load Apollo configurations as early as even before Spring loading logging system phase, + * this EnvironmentPostProcessor can be called Just After ConfigFileApplicationListener has succeeded. * + *
+ * The processing sequence would be like this:
+ * Load Bootstrap properties and application properties -----> load Apollo configuration properties ----> Initialize Logging systems * * @param configurableEnvironment * @param springApplication @@ -153,18 +142,20 @@ private void fillSystemPropertyFromEnvironment(ConfigurableEnvironment environme @Override public void postProcessEnvironment(ConfigurableEnvironment configurableEnvironment, SpringApplication springApplication) { - Boolean eagerLoadEnabled = configurableEnvironment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED,Boolean.class,false); + // should always initialize system properties like app.id in the first place + initializeSystemProperty(configurableEnvironment); + Boolean eagerLoadEnabled = configurableEnvironment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_EAGER_LOAD_ENABLED, Boolean.class, false); //EnvironmentPostProcessor should not be triggered if you don't want Apollo Loading before Logging System Initialization - if(!eagerLoadEnabled){ + if (!eagerLoadEnabled) { return; } - Boolean bootstrapEnabled = configurableEnvironment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED,Boolean.class,false); + Boolean bootstrapEnabled = configurableEnvironment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, Boolean.class, false); - if(bootstrapEnabled) { - initialize(configurableEnvironment); + if (bootstrapEnabled) { + initialize(configurableEnvironment); } }