com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer Maven / Gradle / Ivy
The newest version!
package com.ctrip.framework.apollo.spring.boot;
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.spring.config.ConfigPropertySourceFactory;
import com.ctrip.framework.apollo.spring.config.PropertySourcesConstants;
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.Ordered;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* Initialize apollo system properties and inject the Apollo config in Spring Boot bootstrap phase
*
* Configuration example:
*
* # set app.id
* app.id = 100004458
* # enable apollo bootstrap config and inject 'application' namespace in bootstrap phase
* apollo.bootstrap.enabled = true
*
*
* or
*
*
* # set app.id
* app.id = 100004458
* # enable apollo bootstrap config
* apollo.bootstrap.enabled = true
* # 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 , EnvironmentPostProcessor, Ordered {
public static final int DEFAULT_ORDER = 0;
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,
"apollo.cacheDir", ConfigConsts.APOLLO_META_KEY};
private final ConfigPropertySourceFactory configPropertySourceFactory = SpringInjector
.getInstance(ConfigPropertySourceFactory.class);
private int order = DEFAULT_ORDER;
@Override
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
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);
return;
}
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;
}
String namespaces = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES, ConfigConsts.NAMESPACE_APPLICATION);
logger.debug("Apollo bootstrap namespaces: {}", namespaces);
List namespaceList = NAMESPACE_SPLITTER.splitToList(namespaces);
CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);
for (String namespace : namespaceList) {
Config config = ConfigService.getConfig(namespace);
composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config));
}
environment.getPropertySources().addFirst(composite);
}
/**
* To fill system properties from environment config
*/
void initializeSystemProperty(ConfigurableEnvironment environment) {
for (String propertyName : APOLLO_SYSTEM_PROPERTIES) {
fillSystemPropertyFromEnvironment(environment, propertyName);
}
}
private void fillSystemPropertyFromEnvironment(ConfigurableEnvironment environment, String propertyName) {
if (System.getProperty(propertyName) != null) {
return;
}
String propertyValue = environment.getProperty(propertyName);
if (Strings.isNullOrEmpty(propertyValue)) {
return;
}
System.setProperty(propertyName, propertyValue);
}
/**
*
* 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
*/
@Override
public void postProcessEnvironment(ConfigurableEnvironment configurableEnvironment, SpringApplication springApplication) {
// 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) {
return;
}
Boolean bootstrapEnabled = configurableEnvironment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED, Boolean.class, false);
if (bootstrapEnabled) {
initialize(configurableEnvironment);
}
}
/**
* @since 1.3.0
*/
@Override
public int getOrder() {
return order;
}
/**
* @since 1.3.0
*/
public void setOrder(int order) {
this.order = order;
}
}