Skip to content

Commit

Permalink
Reduce bootstrap time in the situation with large properties (apolloc…
Browse files Browse the repository at this point in the history
  • Loading branch information
Shawyeok committed Jul 15, 2021
1 parent 72a0498 commit b37687c
Show file tree
Hide file tree
Showing 10 changed files with 292 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Apollo 1.9.0
* [set default session store-type](https://github.com/ctripcorp/apollo/pull/3812)
* [speed up the stale issue mark and close phase](https://github.com/ctripcorp/apollo/pull/3808)
* [feature: add the delegating password encoder for apollo-portal simple auth](https://github.com/ctripcorp/apollo/pull/3804)
* [Reduce bootstrap time in the situation with large properties](https://github.com/ctripcorp/apollo/pull/3816)
------------------
All issues and pull requests are [here](https://github.com/ctripcorp/apollo/milestone/6?closed=1)

Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@
*/
package com.ctrip.framework.apollo.spring.boot;

import static com.ctrip.framework.apollo.spring.config.PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.build.ApolloInjector;
import com.ctrip.framework.apollo.core.ApolloClientSystemConsts;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.core.utils.DeferredLogger;
import com.ctrip.framework.apollo.spring.config.CompositeConfigPropertySource;
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.ctrip.framework.apollo.util.ConfigUtil;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import java.util.List;
Expand Down Expand Up @@ -85,11 +90,14 @@ public class ApolloApplicationContextInitializer implements
ApolloClientSystemConsts.APOLLO_ACCESS_KEY_SECRET,
ApolloClientSystemConsts.APOLLO_META,
ApolloClientSystemConsts.APOLLO_CONFIG_SERVICE,
ApolloClientSystemConsts.APOLLO_PROPERTY_ORDER_ENABLE};
ApolloClientSystemConsts.APOLLO_PROPERTY_ORDER_ENABLE,
ApolloClientSystemConsts.APOLLO_PROPERTY_NAMES_CACHE_ENABLE};

private final ConfigPropertySourceFactory configPropertySourceFactory = SpringInjector
.getInstance(ConfigPropertySourceFactory.class);

private final ConfigUtil configUtil = ApolloInjector.getInstance(ConfigUtil.class);

private int order = DEFAULT_ORDER;

@Override
Expand All @@ -113,21 +121,29 @@ public void initialize(ConfigurableApplicationContext context) {
*/
protected void initialize(ConfigurableEnvironment environment) {

if (environment.getPropertySources().contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
if (environment.getPropertySources().contains(APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
//already initialized, replay the logs that were printed before the logging system was initialized
DeferredLogger.replayTo();
return;
}

String namespaces = environment.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES, ConfigConsts.NAMESPACE_APPLICATION);
String namespaces = environment
.getProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_NAMESPACES,
ConfigConsts.NAMESPACE_APPLICATION);
logger.debug("Apollo bootstrap namespaces: {}", namespaces);
List<String> namespaceList = NAMESPACE_SPLITTER.splitToList(namespaces);

CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);
CompositePropertySource composite;
if (configUtil.isPropertyNamesCacheEnabled()) {
composite = new CompositeConfigPropertySource(APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);
} else {
composite = new CompositePropertySource(APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME);
}
for (String namespace : namespaceList) {
Config config = ConfigService.getConfig(namespace);

composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config));
composite.addPropertySource(
configPropertySourceFactory.getConfigPropertySource(namespace, config));
}

environment.getPropertySources().addFirst(composite);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2021 Apollo Authors
*
* Licensed 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.
*
*/
package com.ctrip.framework.apollo.spring.config;

import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.PropertySource;

/**
* @author Shawyeok (shawyeok@outlook.com)
*/
public class CompositeConfigPropertySource extends CompositePropertySource implements
ConfigChangeListener {

private String[] names;

public CompositeConfigPropertySource(String name) {
super(name);
}

@Override
public String[] getPropertyNames() {
String[] propertyNames = this.names;
if (propertyNames == null) {
this.names = propertyNames = super.getPropertyNames();
}
return propertyNames;
}

@Override
public void addPropertySource(PropertySource<?> propertySource) {
super.addPropertySource(propertySource);
if (propertySource instanceof ConfigPropertySource) {
((ConfigPropertySource) propertySource).addChangeListener(this);
}
}

@Override
public void addFirstPropertySource(PropertySource<?> propertySource) {
super.addFirstPropertySource(propertySource);
if (propertySource instanceof ConfigPropertySource) {
((ConfigPropertySource) propertySource).addChangeListener(this);
}
}

@Override
public void onChange(ConfigChangeEvent changeEvent) {
// clear property names cache if any sources has changed
this.names = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public class ConfigPropertySource extends EnumerablePropertySource<Config> {
super(name, source);
}

@Override
public boolean containsProperty(String name) {
return this.source.getProperty(name, null) != null;
}

@Override
public String[] getPropertyNames() {
Set<String> propertyNames = this.source.getPropertyNames();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@
*/
package com.ctrip.framework.apollo.spring.config;

import static com.ctrip.framework.apollo.spring.config.PropertySourcesConstants.APOLLO_PROPERTY_SOURCE_NAME;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.build.ApolloInjector;
import com.ctrip.framework.apollo.spring.property.AutoUpdateConfigChangeListener;
import com.ctrip.framework.apollo.spring.util.SpringInjector;
import com.ctrip.framework.apollo.util.ConfigUtil;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;

import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.springframework.beans.BeansException;
Expand All @@ -40,9 +42,6 @@
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;

import java.util.Collection;
import java.util.Iterator;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;

Expand Down Expand Up @@ -76,11 +75,16 @@ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
}

private void initializePropertySources() {
if (environment.getPropertySources().contains(PropertySourcesConstants.APOLLO_PROPERTY_SOURCE_NAME)) {
if (environment.getPropertySources().contains(APOLLO_PROPERTY_SOURCE_NAME)) {
//already initialized
return;
}
CompositePropertySource composite = new CompositePropertySource(PropertySourcesConstants.APOLLO_PROPERTY_SOURCE_NAME);
CompositePropertySource composite;
if (configUtil.isPropertyNamesCacheEnabled()) {
composite = new CompositeConfigPropertySource(APOLLO_PROPERTY_SOURCE_NAME);
} else {
composite = new CompositePropertySource(APOLLO_PROPERTY_SOURCE_NAME);
}

//sort by order asc
ImmutableSortedSet<Integer> orders = ImmutableSortedSet.copyOf(NAMESPACE_NAMES.keySet());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public class ConfigUtil {
private boolean autoUpdateInjectedSpringProperties = true;
private final RateLimiter warnLogRateLimiter;
private boolean propertiesOrdered = false;
private boolean propertyNamesCacheEnabled = false;

public ConfigUtil() {
warnLogRateLimiter = RateLimiter.create(0.017); // 1 warning log output per minute
Expand All @@ -68,6 +69,7 @@ public ConfigUtil() {
initLongPollingInitialDelayInMills();
initAutoUpdateInjectedSpringProperties();
initPropertiesOrdered();
initPropertyNamesCacheEnabled();
}

/**
Expand Down Expand Up @@ -394,4 +396,28 @@ private void initPropertiesOrdered() {
public boolean isPropertiesOrderEnabled() {
return propertiesOrdered;
}

public boolean isPropertyNamesCacheEnabled() {
return propertyNamesCacheEnabled;
}

private void initPropertyNamesCacheEnabled() {
String propertyName = ApolloClientSystemConsts.APOLLO_PROPERTY_NAMES_CACHE_ENABLE;
String propertyEnvName = ApolloClientSystemConsts.APOLLO_PROPERTY_NAMES_CACHE_ENABLE_ENVIRONMENT_VARIABLES;
String enablePropertyNamesCache = System.getProperty(propertyName);
if (Strings.isNullOrEmpty(enablePropertyNamesCache)) {
enablePropertyNamesCache = System.getenv(propertyEnvName);
}
if (Strings.isNullOrEmpty(enablePropertyNamesCache)) {
enablePropertyNamesCache = Foundation.app().getProperty(propertyName, "false");
}
if (!Strings.isNullOrEmpty(enablePropertyNamesCache)) {
try {
propertyNamesCacheEnabled = Boolean.parseBoolean(enablePropertyNamesCache);
} catch (Throwable ex) {
logger.warn("Config for {} is invalid: {}, set default value: false",
propertyName, enablePropertyNamesCache);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigFileChangeListener;
import com.ctrip.framework.apollo.core.ApolloClientSystemConsts;
import com.ctrip.framework.apollo.core.ConfigConsts;
import com.ctrip.framework.apollo.internals.SimpleConfig;
import com.ctrip.framework.apollo.internals.YamlConfigFile;
Expand Down Expand Up @@ -93,6 +94,7 @@ public void tearDown() throws Exception {
System.clearProperty(SystemPropertyKeyConstants.FROM_SYSTEM_YAML_NAMESPACE);
System.clearProperty(SystemPropertyKeyConstants.FROM_NAMESPACE_APPLICATION_KEY);
System.clearProperty(SystemPropertyKeyConstants.FROM_NAMESPACE_APPLICATION_KEY_YAML);
System.clearProperty(ApolloClientSystemConsts.APOLLO_PROPERTY_NAMES_CACHE_ENABLE);
super.tearDown();
}

Expand Down Expand Up @@ -456,13 +458,17 @@ public void testApolloConfigChangeListenerResolveExpressionSimple() {
Config applicationConfig = mock(Config.class);
mockConfig(ConfigConsts.NAMESPACE_APPLICATION, applicationConfig);

System.setProperty(ApolloClientSystemConsts.APOLLO_PROPERTY_NAMES_CACHE_ENABLE, "true");

getSimpleBean(TestApolloConfigChangeListenerResolveExpressionSimpleConfiguration.class);

// no using
verify(ignoreConfig, never()).addChangeListener(any(ConfigChangeListener.class));

// one invocation for spring value auto update and another for the @ApolloConfigChangeListener annotation
verify(applicationConfig, times(2)).addChangeListener(any(ConfigChangeListener.class));
// one invocation for spring value auto update
// one invocation for the @ApolloConfigChangeListener annotation
// one invocation for CompositeConfigPropertySource clear cache listener
verify(applicationConfig, times(3)).addChangeListener(any(ConfigChangeListener.class));
}

/**
Expand Down
Loading

0 comments on commit b37687c

Please sign in to comment.