From 07460fba3d51e5b32c3d512b2cf149976316a2dd Mon Sep 17 00:00:00 2001 From: eirslett Date: Tue, 10 Mar 2015 14:09:22 +0100 Subject: [PATCH 1/2] Use Archaius for Hystrix plugin setup Currently, Hystrix lets you define custom strategies in two ways: 1) with System properties 2) with bootstrapping via HystrixPlugins.getInstance().registerXXX If neither is specified, the default strategy is used. This change replaces hardwired System.getProperty calls with lookup via Archaius. So one can override the plugin strategies used with any configuration provider Archaius is configured with. Most importantly, it has the effect of checking any file called "config.properties" on the classpath as well as using system properties. This lets you configure plugin strategies without having to write Java code for it, or having to run the application with additional system properties. Fixes #92 --- .../hystrix/strategy/HystrixPlugins.java | 65 +++++++++---------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/strategy/HystrixPlugins.java b/hystrix-core/src/main/java/com/netflix/hystrix/strategy/HystrixPlugins.java index 29af60688..8f7cdfaae 100644 --- a/hystrix-core/src/main/java/com/netflix/hystrix/strategy/HystrixPlugins.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/strategy/HystrixPlugins.java @@ -17,6 +17,7 @@ import java.util.concurrent.atomic.AtomicReference; +import com.netflix.config.DynamicPropertyFactory; import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy; import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault; import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier; @@ -33,7 +34,7 @@ * Registry for plugin implementations that allows global override and handles the retrieval of correct implementation based on order of precedence: *
    *
  1. plugin registered globally via register methods in this class
  2. - *
  3. plugin registered and retrieved using {@link java.lang.System#getProperty(String)} (see get methods for property names)
  4. + *
  5. plugin registered and retrieved using Archaius (see get methods for property names)
  6. *
  7. default implementation
  8. *
* See the Hystrix GitHub Wiki for more information: https://github.com/Netflix/Hystrix/wiki/Plugins. @@ -71,21 +72,21 @@ public static void reset() { /** * Retrieve instance of {@link HystrixEventNotifier} to use based on order of precedence as defined in {@link HystrixPlugins} class header. *

- * Override default by using {@link #registerEventNotifier(HystrixEventNotifier)} or setting property: hystrix.plugin.HystrixEventNotifier.implementation with the full classname to + * Override default by using {@link #registerEventNotifier(HystrixEventNotifier)} or setting property (via Archaius): hystrix.plugin.HystrixEventNotifier.implementation with the full classname to * load. * * @return {@link HystrixEventNotifier} implementation to use */ public HystrixEventNotifier getEventNotifier() { if (notifier.get() == null) { - // check for an implementation from System.getProperty first - Object impl = getPluginImplementationViaProperty(HystrixEventNotifier.class); + // check for an implementation from Archaius first + Object impl = getPluginImplementationViaArchaius(HystrixEventNotifier.class); if (impl == null) { - // nothing set via properties so initialize with default + // nothing set via Archaius so initialize with default notifier.compareAndSet(null, HystrixEventNotifierDefault.getInstance()); // we don't return from here but call get() again in case of thread-race so the winner will always get returned } else { - // we received an implementation from the system property so use it + // we received an implementation from Archaius so use it notifier.compareAndSet(null, (HystrixEventNotifier) impl); } } @@ -109,21 +110,21 @@ public void registerEventNotifier(HystrixEventNotifier impl) { /** * Retrieve instance of {@link HystrixConcurrencyStrategy} to use based on order of precedence as defined in {@link HystrixPlugins} class header. *

- * Override default by using {@link #registerConcurrencyStrategy(HystrixConcurrencyStrategy)} or setting property: hystrix.plugin.HystrixConcurrencyStrategy.implementation with the + * Override default by using {@link #registerConcurrencyStrategy(HystrixConcurrencyStrategy)} or setting property (via Archaius): hystrix.plugin.HystrixConcurrencyStrategy.implementation with the * full classname to load. * * @return {@link HystrixConcurrencyStrategy} implementation to use */ public HystrixConcurrencyStrategy getConcurrencyStrategy() { if (concurrencyStrategy.get() == null) { - // check for an implementation from System.getProperty first - Object impl = getPluginImplementationViaProperty(HystrixConcurrencyStrategy.class); + // check for an implementation from Archaius first + Object impl = getPluginImplementationViaArchaius(HystrixConcurrencyStrategy.class); if (impl == null) { - // nothing set via properties so initialize with default + // nothing set via Archaius so initialize with default concurrencyStrategy.compareAndSet(null, HystrixConcurrencyStrategyDefault.getInstance()); // we don't return from here but call get() again in case of thread-race so the winner will always get returned } else { - // we received an implementation from the system property so use it + // we received an implementation from Archaius so use it concurrencyStrategy.compareAndSet(null, (HystrixConcurrencyStrategy) impl); } } @@ -147,21 +148,21 @@ public void registerConcurrencyStrategy(HystrixConcurrencyStrategy impl) { /** * Retrieve instance of {@link HystrixMetricsPublisher} to use based on order of precedence as defined in {@link HystrixPlugins} class header. *

- * Override default by using {@link #registerMetricsPublisher(HystrixMetricsPublisher)} or setting property: hystrix.plugin.HystrixMetricsPublisher.implementation with the full + * Override default by using {@link #registerMetricsPublisher(HystrixMetricsPublisher)} or setting property (via Archaius): hystrix.plugin.HystrixMetricsPublisher.implementation with the full * classname to load. * * @return {@link HystrixMetricsPublisher} implementation to use */ public HystrixMetricsPublisher getMetricsPublisher() { if (metricsPublisher.get() == null) { - // check for an implementation from System.getProperty first - Object impl = getPluginImplementationViaProperty(HystrixMetricsPublisher.class); + // check for an implementation from Archaius first + Object impl = getPluginImplementationViaArchaius(HystrixMetricsPublisher.class); if (impl == null) { - // nothing set via properties so initialize with default + // nothing set via Archaius so initialize with default metricsPublisher.compareAndSet(null, HystrixMetricsPublisherDefault.getInstance()); // we don't return from here but call get() again in case of thread-race so the winner will always get returned } else { - // we received an implementation from the system property so use it + // we received an implementation from Archaius so use it metricsPublisher.compareAndSet(null, (HystrixMetricsPublisher) impl); } } @@ -185,21 +186,21 @@ public void registerMetricsPublisher(HystrixMetricsPublisher impl) { /** * Retrieve instance of {@link HystrixPropertiesStrategy} to use based on order of precedence as defined in {@link HystrixPlugins} class header. *

- * Override default by using {@link #registerPropertiesStrategy(HystrixPropertiesStrategy)} or setting property: hystrix.plugin.HystrixPropertiesStrategy.implementation with the full + * Override default by using {@link #registerPropertiesStrategy(HystrixPropertiesStrategy)} or setting property (via Archaius): hystrix.plugin.HystrixPropertiesStrategy.implementation with the full * classname to load. * * @return {@link HystrixPropertiesStrategy} implementation to use */ public HystrixPropertiesStrategy getPropertiesStrategy() { if (propertiesFactory.get() == null) { - // check for an implementation from System.getProperty first - Object impl = getPluginImplementationViaProperty(HystrixPropertiesStrategy.class); + // check for an implementation from Archaius first + Object impl = getPluginImplementationViaArchaius(HystrixPropertiesStrategy.class); if (impl == null) { - // nothing set via properties so initialize with default + // nothing set via Archaius so initialize with default propertiesFactory.compareAndSet(null, HystrixPropertiesStrategyDefault.getInstance()); // we don't return from here but call get() again in case of thread-race so the winner will always get returned } else { - // we received an implementation from the system property so use it + // we received an implementation from Archaius so use it propertiesFactory.compareAndSet(null, (HystrixPropertiesStrategy) impl); } } @@ -223,7 +224,7 @@ public void registerPropertiesStrategy(HystrixPropertiesStrategy impl) { /** * Retrieve instance of {@link HystrixCommandExecutionHook} to use based on order of precedence as defined in {@link HystrixPlugins} class header. *

- * Override default by using {@link #registerCommandExecutionHook(HystrixCommandExecutionHook)} or setting property: hystrix.plugin.HystrixCommandExecutionHook.implementation with the + * Override default by using {@link #registerCommandExecutionHook(HystrixCommandExecutionHook)} or setting property (via Archaius): hystrix.plugin.HystrixCommandExecutionHook.implementation with the * full classname to * load. * @@ -233,14 +234,14 @@ public void registerPropertiesStrategy(HystrixPropertiesStrategy impl) { */ public HystrixCommandExecutionHook getCommandExecutionHook() { if (commandExecutionHook.get() == null) { - // check for an implementation from System.getProperty first - Object impl = getPluginImplementationViaProperty(HystrixCommandExecutionHook.class); + // check for an implementation from Archaius first + Object impl = getPluginImplementationViaArchaius(HystrixCommandExecutionHook.class); if (impl == null) { - // nothing set via properties so initialize with default + // nothing set via Archaius so initialize with default commandExecutionHook.compareAndSet(null, HystrixCommandExecutionHookDefault.getInstance()); // we don't return from here but call get() again in case of thread-race so the winner will always get returned } else { - // we received an implementation from the system property so use it + // we received an implementation from Archaius so use it commandExecutionHook.compareAndSet(null, (HystrixCommandExecutionHook) impl); } } @@ -263,15 +264,11 @@ public void registerCommandExecutionHook(HystrixCommandExecutionHook impl) { } } - private static Object getPluginImplementationViaProperty(Class pluginClass) { + private static Object getPluginImplementationViaArchaius(Class pluginClass) { String classSimpleName = pluginClass.getSimpleName(); - /* - * Check system properties for plugin class. - *

- * This will only happen during system startup thus it's okay to use the synchronized System.getProperties - * as it will never get called in normal operations. - */ - String implementingClass = System.getProperty("hystrix.plugin." + classSimpleName + ".implementation"); + // Check Archaius for plugin class. + String propertyName = "hystrix.plugin." + classSimpleName + ".implementation"; + String implementingClass = DynamicPropertyFactory.getInstance().getStringProperty(propertyName, null).get(); if (implementingClass != null) { try { Class cls = Class.forName(implementingClass); From 82b8e6cf05618dd3ad5e83212df6a1209ccf7344 Mon Sep 17 00:00:00 2001 From: eirslett Date: Tue, 10 Mar 2015 17:13:50 +0100 Subject: [PATCH 2/2] Load configuration from hystrix-plugins.properties as well If the file hystrix-plugins.properties exists on the class path, its configuration will be used to setup HystrixPlugins. This makes it possible to bundle bootstrap configuration for Hystrix in higher-level libraries without polluting the global namespace with a 'config.properties' file; that name should better be reserved for top-level applications only. --- .../com/netflix/hystrix/strategy/HystrixPlugins.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hystrix-core/src/main/java/com/netflix/hystrix/strategy/HystrixPlugins.java b/hystrix-core/src/main/java/com/netflix/hystrix/strategy/HystrixPlugins.java index 8f7cdfaae..812406642 100644 --- a/hystrix-core/src/main/java/com/netflix/hystrix/strategy/HystrixPlugins.java +++ b/hystrix-core/src/main/java/com/netflix/hystrix/strategy/HystrixPlugins.java @@ -15,8 +15,10 @@ */ package com.netflix.hystrix.strategy; +import java.io.IOException; import java.util.concurrent.atomic.AtomicReference; +import com.netflix.config.ConfigurationManager; import com.netflix.config.DynamicPropertyFactory; import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy; import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategyDefault; @@ -50,7 +52,12 @@ public class HystrixPlugins { /* package */ final AtomicReference commandExecutionHook = new AtomicReference<>(); private HystrixPlugins() { - + try { + // Load configuration from hystrix-plugins.properties, if that file exists + ConfigurationManager.loadCascadedPropertiesFromResources("hystrix-plugins"); + } catch (IOException e) { + // fail silently + } } public static HystrixPlugins getInstance() {