序
本文主要研究下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:
* <ol>
* <li>plugin registered globally via <code>register</code> methods in this class</li>
* <li>plugin registered and retrieved using the resolved {@link HystrixDynamicProperties} (usually Archaius, see get methods for property names)</li>
* <li>plugin registered and retrieved using the JDK {@link ServiceLoader}</li>
* <li>default implementation</li>
* </ol>
*
* The exception to the above order is the {@link HystrixDynamicProperties} implementation
* which is only loaded through <code>System.properties</code> or the ServiceLoader (see the {@link HystrixPlugins#getDynamicProperties() getter} for more details).
* <p>
* See the Hystrix GitHub Wiki for more information: <a href="https://github.com/Netflix/Hystrix/wiki/Plugins">https://github.com/Netflix/Hystrix/wiki/Plugins</a>.
*/
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<HystrixEventNotifier> notifier = new AtomicReference<HystrixEventNotifier>();
/* package */ final AtomicReference<HystrixConcurrencyStrategy> concurrencyStrategy = new AtomicReference<HystrixConcurrencyStrategy>();
/* package */ final AtomicReference<HystrixMetricsPublisher> metricsPublisher = new AtomicReference<HystrixMetricsPublisher>();
/* package */ final AtomicReference<HystrixPropertiesStrategy> propertiesFactory = new AtomicReference<HystrixPropertiesStrategy>();
/* package */ final AtomicReference<HystrixCommandExecutionHook> commandExecutionHook = new AtomicReference<HystrixCommandExecutionHook>();
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 <code>Hystrix.reset()</code>
*/
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> T getPluginImplementation(Class<T> pluginClass) {
T p = getPluginImplementationViaProperties(pluginClass, dynamicProperties);
if (p != null) return p;
return findService(pluginClass, classLoader);
}
@SuppressWarnings("unchecked")
private static <T> T getPluginImplementationViaProperties(Class<T> 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> T findService(
Class<T> spi,
ClassLoader classLoader) throws ServiceConfigurationError {
ServiceLoader<T> 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
来源:oschina
链接:https://my.oschina.net/u/2922256/blog/1837105