mirror of
https://github.com/lightbend/config.git
synced 2025-03-26 12:06:02 +08:00
Add ConfigFactory.invalidateCaches() to support reloading system props
This lets people change system props in unit tests for example. Issue #43 on github.
This commit is contained in:
parent
b739f4be6e
commit
5f486f65ac
config/src
main/java/com/typesafe/config
test/scala/com/typesafe/config/impl
@ -227,7 +227,9 @@ public final class ConfigFactory {
|
||||
* load("application")} in most cases. This configuration should be used by
|
||||
* libraries and frameworks unless an application provides a different one.
|
||||
* <p>
|
||||
* This method may return a cached singleton.
|
||||
* This method may return a cached singleton so will not see changes to
|
||||
* system properties or config files. (Use {@link #invalidateCaches()} to
|
||||
* force it to reload.)
|
||||
* <p>
|
||||
* If the system properties <code>config.resource</code>,
|
||||
* <code>config.file</code>, or <code>config.url</code> are set, then the
|
||||
@ -399,6 +401,31 @@ public final class ConfigFactory {
|
||||
return systemProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads any cached configs, picking up changes to system properties for
|
||||
* example. Because a {@link Config} is immutable, anyone with a reference
|
||||
* to the old configs will still have the same outdated objects. However,
|
||||
* new calls to {@link #load()} or {@link #defaultOverrides()} or
|
||||
* {@link #defaultReference} may return a new object.
|
||||
* <p>
|
||||
* This method is primarily intended for use in unit tests, for example,
|
||||
* that may want to update a system property then confirm that it's used
|
||||
* correctly. In many cases, use of this method may indicate there's a
|
||||
* better way to set up your code.
|
||||
* <p>
|
||||
* Caches may be reloaded immediately or lazily; once you call this method,
|
||||
* the reload can occur at any time, even during the invalidation process.
|
||||
* So FIRST make the changes you'd like the caches to notice, then SECOND
|
||||
* call this method to invalidate caches. Don't expect that invalidating,
|
||||
* making changes, then calling {@link #load()}, will work. Make changes
|
||||
* before you invalidate.
|
||||
*/
|
||||
public static void invalidateCaches() {
|
||||
// We rely on this having the side effect that it drops
|
||||
// all caches
|
||||
ConfigImpl.reloadSystemPropertiesConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an empty configuration. See also {@link #empty(String)} to create an
|
||||
* empty configuration with a description, which may improve user-visible
|
||||
@ -429,16 +456,19 @@ public final class ConfigFactory {
|
||||
/**
|
||||
* Gets a <code>Config</code> containing the system properties from
|
||||
* {@link java.lang.System#getProperties()}, parsed and converted as with
|
||||
* {@link #parseProperties}. This method can return a global immutable
|
||||
* singleton, so it's preferred over parsing system properties yourself.
|
||||
*
|
||||
* {@link #parseProperties}.
|
||||
* <p>
|
||||
* This method can return a global immutable singleton, so it's preferred
|
||||
* over parsing system properties yourself.
|
||||
* <p>
|
||||
* {@link #load} will include the system properties as overrides already, as
|
||||
* will {@link #defaultReference} and {@link #defaultOverrides}.
|
||||
*
|
||||
* <p>
|
||||
* Because this returns a singleton, it will not notice changes to system
|
||||
* properties made after the first time this method is called.
|
||||
* properties made after the first time this method is called. Use
|
||||
* {@link #invalidateCaches()} to force the singleton to reload if you
|
||||
* modify system properties.
|
||||
*
|
||||
* @return system properties parsed into a <code>Config</code>
|
||||
*/
|
||||
|
@ -26,21 +26,29 @@ import com.typesafe.config.impl.SimpleIncluder.NameSource;
|
||||
public class ConfigImpl {
|
||||
|
||||
private static class LoaderCache {
|
||||
private ClassLoader current;
|
||||
private Config currentSystemProperties;
|
||||
private ClassLoader currentLoader;
|
||||
private Map<String, Config> cache;
|
||||
|
||||
LoaderCache() {
|
||||
this.current = null;
|
||||
this.currentSystemProperties = null;
|
||||
this.currentLoader = null;
|
||||
this.cache = new HashMap<String, Config>();
|
||||
}
|
||||
|
||||
// for now, caching as long as the loader remains the same,
|
||||
// drop entire cache if it changes.
|
||||
synchronized Config getOrElseUpdate(ClassLoader loader, String key, Callable<Config> updater) {
|
||||
if (loader != current) {
|
||||
if (loader != currentLoader) {
|
||||
// reset the cache if we start using a different loader
|
||||
cache.clear();
|
||||
current = loader;
|
||||
currentLoader = loader;
|
||||
}
|
||||
|
||||
Config systemProperties = systemPropertiesAsConfig();
|
||||
if (systemProperties != currentSystemProperties) {
|
||||
cache.clear();
|
||||
currentSystemProperties = systemProperties;
|
||||
}
|
||||
|
||||
Config config = cache.get(key);
|
||||
@ -288,7 +296,7 @@ public class ConfigImpl {
|
||||
|
||||
private static class SystemPropertiesHolder {
|
||||
// this isn't final due to the reloadSystemPropertiesConfig() hack below
|
||||
static AbstractConfigObject systemProperties = loadSystemProperties();
|
||||
static volatile AbstractConfigObject systemProperties = loadSystemProperties();
|
||||
}
|
||||
|
||||
static AbstractConfigObject systemPropertiesAsConfigObject() {
|
||||
@ -304,9 +312,10 @@ public class ConfigImpl {
|
||||
return systemPropertiesAsConfigObject().toConfig();
|
||||
}
|
||||
|
||||
// this is a hack to let us set system props in the test suite.
|
||||
// obviously not thread-safe.
|
||||
static void reloadSystemPropertiesConfig() {
|
||||
/** For use ONLY by library internals, DO NOT TOUCH not guaranteed ABI */
|
||||
public static void reloadSystemPropertiesConfig() {
|
||||
// ConfigFactory.invalidateCaches() relies on this having the side
|
||||
// effect that it drops all caches
|
||||
SystemPropertiesHolder.systemProperties = loadSystemProperties();
|
||||
}
|
||||
|
||||
|
@ -856,4 +856,46 @@ class PublicApiTest extends TestUtils {
|
||||
assertTrue("cause messages equal after deserialize", e.getCause().getMessage.equals(eCopy.getCause().getMessage))
|
||||
assertTrue("origins equal after deserialize", e.origin().equals(eCopy.origin()))
|
||||
}
|
||||
|
||||
@Test
|
||||
def invalidateCaches() {
|
||||
val conf0 = ConfigFactory.load()
|
||||
val sys0 = ConfigFactory.systemProperties()
|
||||
val conf1 = ConfigFactory.load()
|
||||
val sys1 = ConfigFactory.systemProperties()
|
||||
ConfigFactory.invalidateCaches()
|
||||
val conf2 = ConfigFactory.load()
|
||||
val sys2 = ConfigFactory.systemProperties()
|
||||
System.setProperty("invalidateCachesTest", "Hello!")
|
||||
ConfigFactory.invalidateCaches()
|
||||
val conf3 = ConfigFactory.load()
|
||||
val sys3 = ConfigFactory.systemProperties()
|
||||
val conf4 = ConfigFactory.load()
|
||||
val sys4 = ConfigFactory.systemProperties()
|
||||
System.clearProperty("invalidateCachesTest")
|
||||
|
||||
assertTrue("stuff gets cached sys", sys0 eq sys1)
|
||||
assertTrue("stuff gets cached conf", conf0 eq conf1)
|
||||
|
||||
assertTrue("test system property is not set sys", !sys0.hasPath("invalidateCachesTest"))
|
||||
assertTrue("test system property is not set conf", !conf0.hasPath("invalidateCachesTest"))
|
||||
|
||||
assertTrue("invalidate caches works on unchanged system props sys", sys1 ne sys2)
|
||||
assertTrue("invalidate caches works on unchanged system props conf", conf1 ne conf2)
|
||||
|
||||
assertTrue("invalidate caches works on changed system props sys", sys2 ne sys3)
|
||||
assertTrue("invalidate caches works on changed system props conf", conf2 ne conf3)
|
||||
|
||||
assertTrue("invalidate caches doesn't change value if no system prop changes sys", sys1 == sys2)
|
||||
assertTrue("invalidate caches doesn't change value if no system prop changes conf", conf1 == conf2)
|
||||
|
||||
assertTrue("test system property is set sys", sys3.hasPath("invalidateCachesTest"))
|
||||
assertTrue("test system property is set conf", conf3.hasPath("invalidateCachesTest"))
|
||||
|
||||
assertTrue("invalidate caches DOES change value if system props changed sys", sys2 != sys3)
|
||||
assertTrue("invalidate caches DOES change value if system props changed conf", conf2 != conf3)
|
||||
|
||||
assertTrue("stuff gets cached repeatedly sys", sys3 eq sys4)
|
||||
assertTrue("stuff gets cached repeatedly conf", conf3 eq conf4)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user