-
-
Notifications
You must be signed in to change notification settings - Fork 10.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reduce bootstrap time in the situation with large properties (#3800)
- Loading branch information
Showing
18 changed files
with
262 additions
and
213 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,6 @@ | |
|
||
import com.ctrip.framework.apollo.enums.ConfigSourceType; | ||
import com.google.common.base.Function; | ||
|
||
import java.util.Date; | ||
import java.util.Locale; | ||
import java.util.Set; | ||
|
@@ -27,8 +26,12 @@ | |
* @author Jason Song([email protected]) | ||
*/ | ||
public interface Config { | ||
|
||
String[] EMPTY_NAMES = new String[0]; | ||
|
||
/** | ||
* Return the property value with the given key, or {@code defaultValue} if the key doesn't exist. | ||
* Return the property value with the given key, or {@code defaultValue} if the key doesn't | ||
* exist. | ||
* | ||
* @param key the property name | ||
* @param defaultValue the default value when key is not found or any error occurred | ||
|
@@ -224,11 +227,11 @@ void addChangeListener(ConfigChangeListener listener, Set<String> interestedKeys | |
boolean removeChangeListener(ConfigChangeListener listener); | ||
|
||
/** | ||
* Return a set of the property names | ||
* Return the names of all properties | ||
* | ||
* @return the property names | ||
* @return the property names (never null) | ||
*/ | ||
Set<String> getPropertyNames(); | ||
String[] getPropertyNames(); | ||
|
||
/** | ||
* Return the user-defined property value with the given key, or {@code defaultValue} if the key doesn't exist. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,29 +16,25 @@ | |
*/ | ||
package com.ctrip.framework.apollo.internals; | ||
|
||
import com.ctrip.framework.apollo.core.utils.ClassLoaderUtil; | ||
import com.ctrip.framework.apollo.core.utils.DeferredLoggerFactory; | ||
import com.ctrip.framework.apollo.enums.ConfigSourceType; | ||
import com.ctrip.framework.apollo.enums.PropertyChangeType; | ||
import com.ctrip.framework.apollo.model.ConfigChange; | ||
import com.ctrip.framework.apollo.tracer.Tracer; | ||
import com.ctrip.framework.apollo.util.ExceptionUtil; | ||
import com.google.common.collect.ImmutableMap; | ||
import com.google.common.util.concurrent.RateLimiter; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.util.Collections; | ||
import java.util.LinkedHashMap; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.Properties; | ||
import java.util.Set; | ||
import java.util.concurrent.atomic.AtomicReference; | ||
|
||
import org.slf4j.Logger; | ||
|
||
import com.ctrip.framework.apollo.core.utils.ClassLoaderUtil; | ||
import com.ctrip.framework.apollo.enums.PropertyChangeType; | ||
import com.ctrip.framework.apollo.model.ConfigChange; | ||
import com.ctrip.framework.apollo.tracer.Tracer; | ||
import com.ctrip.framework.apollo.util.ExceptionUtil; | ||
import com.google.common.collect.ImmutableMap; | ||
import com.google.common.util.concurrent.RateLimiter; | ||
|
||
|
||
/** | ||
* @author Jason Song([email protected]) | ||
|
@@ -49,6 +45,7 @@ public class DefaultConfig extends AbstractConfig implements RepositoryChangeLis | |
private final String m_namespace; | ||
private final Properties m_resourceProperties; | ||
private final AtomicReference<Properties> m_configProperties; | ||
private String[] m_propertyNames; | ||
private final ConfigRepository m_configRepository; | ||
private final RateLimiter m_warnLogRateLimiter; | ||
|
||
|
@@ -65,6 +62,7 @@ public DefaultConfig(String namespace, ConfigRepository configRepository) { | |
m_resourceProperties = loadFromResource(m_namespace); | ||
m_configRepository = configRepository; | ||
m_configProperties = new AtomicReference<>(); | ||
m_propertyNames = EMPTY_NAMES; | ||
m_warnLogRateLimiter = RateLimiter.create(0.017); // 1 warning log output per minute | ||
initialize(); | ||
} | ||
|
@@ -117,31 +115,26 @@ public String getProperty(String key, String defaultValue) { | |
} | ||
|
||
@Override | ||
public Set<String> getPropertyNames() { | ||
Properties properties = m_configProperties.get(); | ||
if (properties == null) { | ||
return Collections.emptySet(); | ||
} | ||
|
||
return stringPropertyNames(properties); | ||
public String[] getPropertyNames() { | ||
return m_propertyNames; | ||
} | ||
|
||
@Override | ||
public ConfigSourceType getSourceType() { | ||
return m_sourceType; | ||
} | ||
|
||
private Set<String> stringPropertyNames(Properties properties) { | ||
private String[] stringPropertyNames(Properties properties) { | ||
//jdk9以下版本Properties#enumerateStringProperties方法存在性能问题,keys() + get(k) 重复迭代, jdk9之后改为entrySet遍历. | ||
Map<String, String> h = new LinkedHashMap<>(); | ||
List<String> names = new ArrayList<>(properties.size()); | ||
for (Map.Entry<Object, Object> e : properties.entrySet()) { | ||
Object k = e.getKey(); | ||
Object v = e.getValue(); | ||
if (k instanceof String && v instanceof String) { | ||
h.put((String) k, (String) v); | ||
names.add((String) k); | ||
} | ||
} | ||
return h.keySet(); | ||
return names.toArray(EMPTY_NAMES); | ||
} | ||
|
||
@Override | ||
|
@@ -170,6 +163,11 @@ public synchronized void onRepositoryChange(String namespace, Properties newProp | |
private void updateConfig(Properties newConfigProperties, ConfigSourceType sourceType) { | ||
m_configProperties.set(newConfigProperties); | ||
m_sourceType = sourceType; | ||
if (newConfigProperties == null) { | ||
m_propertyNames = EMPTY_NAMES; | ||
} else { | ||
m_propertyNames = stringPropertyNames(newConfigProperties); | ||
} | ||
} | ||
|
||
private Map<String, ConfigChange> updateAndCalcConfigChanges(Properties newConfigProperties, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,20 +17,16 @@ | |
package com.ctrip.framework.apollo.internals; | ||
|
||
import com.ctrip.framework.apollo.enums.ConfigSourceType; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Properties; | ||
import java.util.Set; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import com.ctrip.framework.apollo.model.ConfigChange; | ||
import com.ctrip.framework.apollo.tracer.Tracer; | ||
import com.ctrip.framework.apollo.util.ExceptionUtil; | ||
import com.google.common.base.Function; | ||
import com.google.common.collect.Maps; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Properties; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
/** | ||
* @author Jason Song([email protected]) | ||
|
@@ -40,6 +36,7 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList | |
private final String m_namespace; | ||
private final ConfigRepository m_configRepository; | ||
private volatile Properties m_configProperties; | ||
private String[] m_propertyNames; | ||
private volatile ConfigSourceType m_sourceType = ConfigSourceType.NONE; | ||
|
||
/** | ||
|
@@ -51,6 +48,7 @@ public class SimpleConfig extends AbstractConfig implements RepositoryChangeList | |
public SimpleConfig(String namespace, ConfigRepository configRepository) { | ||
m_namespace = namespace; | ||
m_configRepository = configRepository; | ||
m_propertyNames = EMPTY_NAMES; | ||
this.initialize(); | ||
} | ||
|
||
|
@@ -78,12 +76,8 @@ public String getProperty(String key, String defaultValue) { | |
} | ||
|
||
@Override | ||
public Set<String> getPropertyNames() { | ||
if (m_configProperties == null) { | ||
return Collections.emptySet(); | ||
} | ||
|
||
return m_configProperties.stringPropertyNames(); | ||
public String[] getPropertyNames() { | ||
return m_propertyNames; | ||
} | ||
|
||
@Override | ||
|
@@ -119,5 +113,10 @@ public String apply(ConfigChange input) { | |
private void updateConfig(Properties newConfigProperties, ConfigSourceType sourceType) { | ||
m_configProperties = newConfigProperties; | ||
m_sourceType = sourceType; | ||
if (newConfigProperties == null) { | ||
m_propertyNames = EMPTY_NAMES; | ||
} else { | ||
m_propertyNames = newConfigProperties.stringPropertyNames().toArray(EMPTY_NAMES); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
57 changes: 57 additions & 0 deletions
57
...src/main/java/com/ctrip/framework/apollo/spring/config/CompositeConfigPropertySource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
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 ([email protected]) | ||
*/ | ||
public class CompositeConfigPropertySource extends CompositePropertySource { | ||
|
||
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(new ClearNameCacheListener(this)); | ||
} | ||
} | ||
|
||
@Override | ||
public void addFirstPropertySource(PropertySource<?> propertySource) { | ||
super.addFirstPropertySource(propertySource); | ||
if (propertySource instanceof ConfigPropertySource) { | ||
((ConfigPropertySource) propertySource).addChangeListener(new ClearNameCacheListener(this)); | ||
} | ||
} | ||
|
||
static class ClearNameCacheListener implements ConfigChangeListener { | ||
|
||
private final CompositeConfigPropertySource source; | ||
|
||
public ClearNameCacheListener(CompositeConfigPropertySource source) { | ||
this.source = source; | ||
} | ||
|
||
@Override | ||
public void onChange(ConfigChangeEvent changeEvent) { | ||
source.names = null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,32 +16,29 @@ | |
*/ | ||
package com.ctrip.framework.apollo.spring.config; | ||
|
||
import com.ctrip.framework.apollo.Config; | ||
import com.ctrip.framework.apollo.ConfigChangeListener; | ||
import java.util.Set; | ||
|
||
import org.springframework.core.env.EnumerablePropertySource; | ||
|
||
import com.ctrip.framework.apollo.Config; | ||
|
||
/** | ||
* Property source wrapper for Config | ||
* | ||
* @author Jason Song([email protected]) | ||
*/ | ||
public class ConfigPropertySource extends EnumerablePropertySource<Config> { | ||
private static final String[] EMPTY_ARRAY = new String[0]; | ||
|
||
ConfigPropertySource(String name, Config source) { | ||
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(); | ||
if (propertyNames.isEmpty()) { | ||
return EMPTY_ARRAY; | ||
} | ||
return propertyNames.toArray(new String[propertyNames.size()]); | ||
return this.source.getPropertyNames(); | ||
} | ||
|
||
@Override | ||
|
Oops, something went wrong.