聊聊HystrixPlugins

本文主要研究下HystrixPlugins

HystrixPlugins

hystrix-core-1.5.12-sources.jar!/com/netflix/hystrix/strategy/HystrixPlugins.java

/**
 * 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 the resolved {@link HystrixDynamicProperties} (usually Archaius, see get methods for property names)
  4. *
  5. plugin registered and retrieved using the JDK {@link ServiceLoader}
  6. *
  7. default implementation
  8. *
* * The exception to the above order is the {@link HystrixDynamicProperties} implementation * which is only loaded through System.properties or the ServiceLoader (see the {@link HystrixPlugins#getDynamicProperties() getter} for more details). *

* See the Hystrix GitHub Wiki for more information: https://github.com/Netflix/Hystrix/wiki/Plugins. */ public class HystrixPlugins { //We should not load unless we are requested to. This avoids accidental initialization. @agentgt //See https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom private static class LazyHolder { private static final HystrixPlugins INSTANCE = HystrixPlugins.create(); } private final ClassLoader classLoader; /* package */ final AtomicReference notifier = new AtomicReference(); /* package */ final AtomicReference concurrencyStrategy = new AtomicReference(); /* package */ final AtomicReference metricsPublisher = new AtomicReference(); /* package */ final AtomicReference propertiesFactory = new AtomicReference(); /* package */ final AtomicReference commandExecutionHook = new AtomicReference(); private final HystrixDynamicProperties dynamicProperties; private HystrixPlugins(ClassLoader classLoader, LoggerSupplier logSupplier) { //This will load Archaius if its in the classpath. this.classLoader = classLoader; //N.B. Do not use a logger before this is loaded as it will most likely load the configuration system. //The configuration system may need to do something prior to loading logging. @agentgt dynamicProperties = resolveDynamicProperties(classLoader, logSupplier); } /** * For unit test purposes. * @ExcludeFromJavadoc */ /* private */ static HystrixPlugins create(ClassLoader classLoader, LoggerSupplier logSupplier) { return new HystrixPlugins(classLoader, logSupplier); } /** * For unit test purposes. * @ExcludeFromJavadoc */ /* private */ static HystrixPlugins create(ClassLoader classLoader) { return new HystrixPlugins(classLoader, new LoggerSupplier() { @Override public Logger getLogger() { return LoggerFactory.getLogger(HystrixPlugins.class); } }); } /** * @ExcludeFromJavadoc */ /* private */ static HystrixPlugins create() { return create(HystrixPlugins.class.getClassLoader()); } public static HystrixPlugins getInstance() { return LazyHolder.INSTANCE; } /** * Reset all of the HystrixPlugins to null. You may invoke this directly, or it also gets invoked via Hystrix.reset() */ public static void reset() { getInstance().notifier.set(null); getInstance().concurrencyStrategy.set(null); getInstance().metricsPublisher.set(null); getInstance().propertiesFactory.set(null); getInstance().commandExecutionHook.set(null); HystrixMetricsPublisherFactory.reset(); } /** * Register a {@link HystrixEventNotifier} implementation as a global override of any injected or default implementations. * * @param impl * {@link HystrixEventNotifier} implementation * @throws IllegalStateException * if called more than once or after the default was initialized (if usage occurs before trying to register) */ public void registerEventNotifier(HystrixEventNotifier impl) { if (!notifier.compareAndSet(null, impl)) { throw new IllegalStateException("Another strategy was already registered."); } } /** * Register a {@link HystrixConcurrencyStrategy} implementation as a global override of any injected or default implementations. * * @param impl * {@link HystrixConcurrencyStrategy} implementation * @throws IllegalStateException * if called more than once or after the default was initialized (if usage occurs before trying to register) */ public void registerConcurrencyStrategy(HystrixConcurrencyStrategy impl) { if (!concurrencyStrategy.compareAndSet(null, impl)) { throw new IllegalStateException("Another strategy was already registered."); } } /** * Register a {@link HystrixMetricsPublisher} implementation as a global override of any injected or default implementations. * * @param impl * {@link HystrixMetricsPublisher} implementation * @throws IllegalStateException * if called more than once or after the default was initialized (if usage occurs before trying to register) */ public void registerMetricsPublisher(HystrixMetricsPublisher impl) { if (!metricsPublisher.compareAndSet(null, impl)) { throw new IllegalStateException("Another strategy was already registered."); } } /** * Register a {@link HystrixPropertiesStrategy} implementation as a global override of any injected or default implementations. * * @param impl * {@link HystrixPropertiesStrategy} implementation * @throws IllegalStateException * if called more than once or after the default was initialized (if usage occurs before trying to register) */ public void registerPropertiesStrategy(HystrixPropertiesStrategy impl) { if (!propertiesFactory.compareAndSet(null, impl)) { throw new IllegalStateException("Another strategy was already registered."); } } /** * Register a {@link HystrixCommandExecutionHook} implementation as a global override of any injected or default implementations. * * @param impl * {@link HystrixCommandExecutionHook} implementation * @throws IllegalStateException * if called more than once or after the default was initialized (if usage occurs before trying to register) * * @since 1.2 */ public void registerCommandExecutionHook(HystrixCommandExecutionHook impl) { if (!commandExecutionHook.compareAndSet(null, impl)) { throw new IllegalStateException("Another strategy was already registered."); } } //...... }

  • hystrix提供了一个plugin机制用于修改hystrix的行为,可以作用到所有的HystrixCommand、HystrixObservableCommand、HystrixCollapser的实现
  • 提供了HystrixEventNotifier、HystrixConcurrencyStrategy、HystrixMetricsPublisher、HystrixPropertiesStrategy、HystrixCommandExecutionHook这几个plugin可以自己去实现
  • 这里采用了static holder的模式来实现HystrixPlugins的单例

getPluginImplementation

    private  T getPluginImplementation(Class pluginClass) {
        T p = getPluginImplementationViaProperties(pluginClass, dynamicProperties);
        if (p != null) return p;        
        return findService(pluginClass, classLoader);
    }
    
    @SuppressWarnings("unchecked")
    private static  T getPluginImplementationViaProperties(Class pluginClass, HystrixDynamicProperties dynamicProperties) {
        String classSimpleName = pluginClass.getSimpleName();
        // Check Archaius for plugin class.
        String propertyName = "hystrix.plugin." + classSimpleName + ".implementation";
        String implementingClass = dynamicProperties.getString(propertyName, null).get();
        if (implementingClass != null) {
            try {
                Class cls = Class.forName(implementingClass);
                // narrow the scope (cast) to the type we're expecting
                cls = cls.asSubclass(pluginClass);
                return (T) cls.newInstance();
            } catch (ClassCastException e) {
                throw new RuntimeException(classSimpleName + " implementation is not an instance of " + classSimpleName + ": " + implementingClass);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(classSimpleName + " implementation class not found: " + implementingClass, e);
            } catch (InstantiationException e) {
                throw new RuntimeException(classSimpleName + " implementation not able to be instantiated: " + implementingClass, e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(classSimpleName + " implementation not able to be accessed: " + implementingClass, e);
            }
        } else {
            return null;
        }
    }

    private static  T findService(
            Class spi, 
            ClassLoader classLoader) throws ServiceConfigurationError {
        
        ServiceLoader sl = ServiceLoader.load(spi,
                classLoader);
        for (T s : sl) {
            if (s != null)
                return s;
        }
        return null;
    }
  • 先从动态配置找实现类,如果找不到则使用ServiceLoader进行加载
  • 配置实现类的格式为:"hystrix.plugin." + classSimpleName + ".implementation",比如
hystrix.plugin.HystrixEventNotifier.implementation=com.example.hystrix.hook.CustomHystrixEventNotifierHook
配置可以放到配置文件hystrix-plugins.properties中
  • 从配置文件找到实现类的,采用的是Class.forName的形式来获取Class,然后使用newInstance来实例化

小结

hystrix内置了一个plugin机制,内置了HystrixEventNotifier、HystrixConcurrencyStrategy、HystrixMetricsPublisher、HystrixPropertiesStrategy、HystrixCommandExecutionHook这几个plugin,提供了默认的实现,并允许开发者在指定配置文件自定义该插件的实现类,通过类寻找及实例化的方式来加载,然后作用在HystrixCommand、HystrixObservableCommand及HystrixCollapser上。

doc

  • Hystrix/wiki/Plugins

你可能感兴趣的:(hystrix)