Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

增加EnvironmentPostProcessor处理,将Apollo配置加载提到初始化日志系统之前 #1614

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -37,9 +40,23 @@
* # will inject 'application' and 'FX.apollo' namespaces in bootstrap phase
* apollo.bootstrap.namespaces = application,FX.apollo
* </pre>
*
*
* If you want to load Apollo configurations even before Logging System Initialization Phase,
* add
* <pre class="code">
* # set apollo.bootstrap.eagerLoad.enabled
* apollo.bootstrap.eagerLoad.enabled = true
* </pre>
*
* 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<ConfigurableApplicationContext> {
ApplicationContextInitializer<ConfigurableApplicationContext> , 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,
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
2 changes: 2 additions & 0 deletions apollo-client/src/main/resources/META-INF/spring.factories
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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([email protected])
*/
Expand Down Expand Up @@ -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<EnvironmentPostProcessor> processorList = SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class, getClass().getClassLoader());

Boolean containsApollo = !Collections2.filter(processorList, new Predicate<EnvironmentPostProcessor>() {
@Override
public boolean apply(EnvironmentPostProcessor input) {
return input instanceof ApolloApplicationContextInitializer;
}
}).isEmpty();
Assert.assertTrue(containsApollo);
}
}


@EnableAutoConfiguration
@Configuration
static class ConfigurationWithoutConditionalOnProperty {
Expand Down