diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java index f2aa57ff3e..f6375b0bb8 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java @@ -24,6 +24,8 @@ */ package net.runelite.client.config; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; @@ -34,9 +36,15 @@ import lombok.extern.slf4j.Slf4j; @Slf4j class ConfigInvocationHandler implements InvocationHandler { - private final ConfigManager manager; + // Special object to represent null values in the cache + private static final Object NULL = new Object(); - public ConfigInvocationHandler(ConfigManager manager) + private final ConfigManager manager; + private final Cache cache = CacheBuilder.newBuilder() + .maximumSize(128) + .build(); + + ConfigInvocationHandler(ConfigManager manager) { this.manager = manager; } @@ -44,6 +52,16 @@ class ConfigInvocationHandler implements InvocationHandler @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + // Use cached configuration value if available + if (args == null) + { + Object cachedValue = cache.getIfPresent(method); + if (cachedValue != null) + { + return cachedValue == NULL ? null : cachedValue; + } + } + Class iface = proxy.getClass().getInterfaces()[0]; ConfigGroup group = iface.getAnnotation(ConfigGroup.class); @@ -63,6 +81,8 @@ class ConfigInvocationHandler implements InvocationHandler if (args == null) { + log.trace("cache miss (size: {}, group: {}, key: {})", cache.size(), group.value(), item.keyName()); + // Getting configuration item String value = manager.getConfiguration(group.value(), item.keyName()); @@ -70,9 +90,12 @@ class ConfigInvocationHandler implements InvocationHandler { if (method.isDefault()) { - return callDefaultMethod(proxy, method, null); + Object defaultValue = callDefaultMethod(proxy, method, null); + cache.put(method, defaultValue == null ? NULL : defaultValue); + return defaultValue; } + cache.put(method, NULL); return null; } @@ -81,7 +104,9 @@ class ConfigInvocationHandler implements InvocationHandler try { - return ConfigManager.stringToObject(value, returnType); + Object objectValue = ConfigManager.stringToObject(value, returnType); + cache.put(method, objectValue == null ? NULL : objectValue); + return objectValue; } catch (Exception e) { @@ -150,4 +175,10 @@ class ConfigInvocationHandler implements InvocationHandler .bindTo(proxy) .invokeWithArguments(args); } + + void invalidate() + { + log.trace("cache invalidate"); + cache.invalidateAll(); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java index 8ff9434069..4e6c1e65ae 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java @@ -167,6 +167,7 @@ public class ConfigManager return; } + handler.invalidate(); properties.clear(); for (ConfigEntry entry : configuration.getConfig()) @@ -275,6 +276,7 @@ public class ConfigManager private synchronized void loadFromFile() { + handler.invalidate(); properties.clear(); try (FileInputStream in = new FileInputStream(propertiesFile)) @@ -391,6 +393,7 @@ public class ConfigManager } log.debug("Setting configuration value for {}.{} to {}", groupName, key, value); + handler.invalidate(); synchronized (pendingChanges) { @@ -421,6 +424,7 @@ public class ConfigManager } log.debug("Unsetting configuration value for {}.{}", groupName, key); + handler.invalidate(); synchronized (pendingChanges) {