依赖如下
1
2
3
4
5
6<dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-core</artifactId> <version>1.5.18</version> </dependency>
什么是Hystrix
2018.11发布了最后一个版本,目前处理维护阶段,不再升级版本
-
用途:
-
- 停止级联故障。fallback和优雅的降级,Fail fast和快速恢复
-
- 实时监控和配置实时变更
-
- 资源隔离,部分不可用不会导致整体系统不可用
-
场景:商品列表接口中,需要获取红包、价格、标签等数据。这时候可以给这个一个线程池。
如果线程池打满,也不会影响当前服务的非商品列表接口 -
使用的框架:hystrix主要使用Rxjava,上手可参考:https://www.jianshu.com/p/5e93c9101dc5
Hystrix配置外部化、动态化
Hystrix自己实现了一个配置接口HystrixProperty(没用netfix的通用Config:com.netfix.config.Property)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public interface HystrixProperty<T> { // get获取属性方法 public T get(); /** * 生产property的工厂 * HystrixProperty由Factory直接生产,不需要经过第三方依赖。 * - 其核心子接口为(下面会进行讲解):HystrixDynamicProperty */ public static class Factory { public static <T> HystrixProperty<T> asProperty(final T value) { return new HystrixProperty<T>() { @Override public T get() { return value; } }; } //..... 剩下其他各种获取属性asProperty方法 } }
HystrixDynamicProperty
Hystrix中主要通过HystrixDynamicProperty接口来实现动态化属性。其对应 HystrixDynamicProperties 的两个实现类:
- Hystrix也是通过多种方式管理属性类,其中有一个Util类用来管理各个属性,不过目前只支持:String、Integer、Long、Boolean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public interface HystrixDynamicProperties { public HystrixDynamicProperty<String> getString(String name, String fallback); public HystrixDynamicProperty<Integer> getInteger(String name, Integer fallback); public HystrixDynamicProperty<Long> getLong(String name, Long fallback); public HystrixDynamicProperty<Boolean> getBoolean(String name, Boolean fallback); public static class Util { public static <T> HystrixDynamicProperty<T> getProperty( HystrixDynamicProperties properties, String name, T fallback, Class<T> type) { return (HystrixDynamicProperty<T>) doProperty(properties, name, fallback, type); } private static HystrixDynamicProperty<?> doProperty( HystrixDynamicProperties delegate, String name, Object fallback, Class<?> type) {// 仅支持四种类型:String、Integer、Long、Boolean if(type == String.class) return delegate.getString(name, (String) fallback); else if (type == Integer.class) return delegate.getInteger(name, (Integer) fallback); else if (type == Long.class) return delegate.getLong(name, (Long) fallback); else if (type == Boolean.class) return delegate.getBoolean(name, (Boolean) fallback); throw new IllegalStateException(); } } }
上面HystrixDynamicProperties中delegate.getXxxx()的具体实现为如下两种方式
- HystrixDynamicPropertiesSystemProperties:
通过System.getProperty()获取,天然支持动态性,但不支持callback回调及外部化配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public final class HystrixDynamicPropertiesSystemProperties implements HystrixDynamicProperties { public HystrixDynamicPropertiesSystemProperties() {} private static class LazyHolder { private static final HystrixDynamicPropertiesSystemProperties INSTANCE = new HystrixDynamicPropertiesSystemProperties(); } public static HystrixDynamicProperties getInstance() { return LazyHolder.INSTANCE; } @Override public HystrixDynamicProperty<Integer> getInteger(final String name, final Integer fallback) { return new HystrixDynamicProperty<Integer>() { @Override public String getName() { return name; } @Override public Integer get() {//Integer.getInteger其实最终还是调用了System.getProperty() 了 return Integer.getInteger(name, fallback); } @Override public void addCallback(Runnable callback) {} }; } // .......... 剩余其他String、Long、Boolean类型就不列出来,用法一样 }
- HystrixDynamicPropertiesArchaius(Archaius是Netfix自家配置管理库):
Netfix自家的配置管理库,支持动态化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public class HystrixDynamicPropertiesArchaius implements HystrixDynamicProperties { @Override public HystrixDynamicProperty<String> getString(String name, String fallback) { return new StringDynamicProperty(name, fallback); } @Override public HystrixDynamicProperty<Integer> getInteger(String name, Integer fallback) { return new IntegerDynamicProperty(name, fallback); } // ..... 省略其他类型String、Long、Boolean private abstract static class ArchaiusDynamicProperty<T> extends PropertyWrapper<T> implements HystrixDynamicProperty<T> { protected ArchaiusDynamicProperty(String propName, T defaultValue) { super(propName, defaultValue); } @Override public T get() { return getValue(); } } private static class IntegerDynamicProperty extends ArchaiusDynamicProperty<Integer> { protected IntegerDynamicProperty(String propName, Integer defaultValue) { super(propName, defaultValue); } /** prop.getInteger最终调用的是ConcurrentHashMap,那他是怎么塞进去CHM得?见下面解析 **/ @Override public Integer getValue() { return prop.getInteger(defaultValue); } } // ..... 省略其他类型String、Long、Boolean }
Archaius这种模式不同于System(System.getProperty()),他会从配置文件里面读取数据,起流程如下
- 获取IntegerDynamicProperty,是调用到super()方法
1
2
3
4protected IntegerDynamicProperty(String propName, Integer defaultValue) { super(propName, defaultValue);// 在ArchaiusDynamicProperty类中 }
- 追踪调用到PropertyWrapper类,会进行获取对应单例,并赋予默认值等初始化操作
1
2
3
4
5
6
7
8
9public abstract class PropertyWrapper<V> { protected PropertyWrapper(String propName, V defaultValue) { // !!!重点关注这个,这里才是怎么根据属性名拿到对应属性值的入口 this.prop = DynamicProperty.getInstance(propName); this.defaultValue = defaultValue; //.... 期初初始化操作,省略 } }
- DynamicProperty.getInstance获取实例过程中,可能会更新属性值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public class DynamicProperty { // 根据属性名获取对应的动态化属性实例DynamicProperty public static DynamicProperty getInstance(String propName) { if (dynamicPropertySupportImpl == null) { DynamicPropertyFactory.getInstance(); } // 1 先从缓存中获取属性值 DynamicProperty prop = ALL_PROPS.get(propName); if (prop == null) { // 2 如果找不到,就尝试去更新(new DynamicProperty(propName)里面就有更新操作) prop = new DynamicProperty(propName); // 然后把新的属性值设置进去 DynamicProperty oldProp = ALL_PROPS.putIfAbsent(propName, prop); if (oldProp != null) { prop = oldProp; } } return prop; } }
- 最后来看下是怎么更新拉取一个值,核心在于updateValue()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public class DynamicProperty { private DynamicProperty(String propName) { this.propName = propName; updateValue(); } // !!!!最终可以见到是通过一个dynamicPropertySupportImpl进行获取。那这个怎么拿到了, // !!!!关键在于是怎么绑定的,下面继续讲解怎么绑定 private boolean updateValue() { String newValue; try { if (dynamicPropertySupportImpl != null) { // 调用这个实例方法获取属性值 newValue = dynamicPropertySupportImpl.getString(propName); } else { return false; } } catch (Exception e) { logger.error("Unable to update property: " + propName, e); return false; } return updateValue(newValue); } }
Hystrix如何选择合适的配置类进行加载
这一步会解释上一步的dynamicPropertySupportImpl实例是怎么选择?其实最终是通过DynamicPropertyFactory生产配置对象的时候返回回来,然后赋值给dynamicPropertySupportImpl
下面看一下他这个配置对象是怎么实例化的
- 初始化HystrixPlugins时,会加载解析动态属性
1
2
3
4
5
6
7public class HystrixPlugins { private HystrixPlugins(ClassLoader classLoader, LoggerSupplier logSupplier) { this.classLoader = classLoader; dynamicProperties = resolveDynamicProperties(classLoader, logSupplier); } }
- 先看看有没自定义的,有的话就classForName加载。然后用SPI扫描一下,如果扫描到就用第一个配置类。
再看看HystrixDynamicPropertiesArchaius,如果不存在或加载失败则使用HystrixDynamicPropertiesSystemProperties
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35public class HystrixPlugins { private static HystrixDynamicProperties resolveDynamicProperties(ClassLoader classLoader, LoggerSupplier logSupplier) { // 第一步:先看看有没设置属性:"hystrix.plugin.hystrixDynamicProperties.implementation",如果有就用自定义的属性类 HystrixDynamicProperties hp = getPluginImplementationViaProperties(HystrixDynamicProperties.class, HystrixDynamicPropertiesSystemProperties.getInstance()); if (hp != null) { logSupplier.getLogger().debug( "Created HystrixDynamicProperties instance from System property named " + ""hystrix.plugin.HystrixDynamicProperties.implementation". Using class: {}", hp.getClass().getCanonicalName()); return hp; } // 第二步:用SPI的加载器进行扫描,拿到第一个然后返回 hp = findService(HystrixDynamicProperties.class, classLoader); if (hp != null) { logSupplier.getLogger() .debug("Created HystrixDynamicProperties instance by loading from ServiceLoader. Using class: {}", hp.getClass().getCanonicalName()); return hp; } // 第三步:再看看HystrixDynamicPropertiesArchaius这个解析成功否,成功就用这个属性配置类 hp = HystrixArchaiusHelper.createArchaiusDynamicProperties(); if (hp != null) { logSupplier.getLogger().debug("Created HystrixDynamicProperties. Using class : {}", hp.getClass().getCanonicalName()); return hp; } // 第四步:实在上面都找不到了,直接用兜底的系统属性类,用System.getProperty()获取 hp = HystrixDynamicPropertiesSystemProperties.getInstance(); logSupplier.getLogger().info("Using System Properties for HystrixDynamicProperties! Using class: {}", hp.getClass().getCanonicalName()); return hp; } }
看到这步骤,是不是有一点还比较懵逼的!哦,原来发现我们还没搞清他的配置信息是什么时候加载进来的,配置文件是哪一个。别慌,下面讲
配置信息如何加载进来
Hystrix有一个ConfigurationManager,初始化配置加载的时候会调用(默认会从config.properties加载,如果需要添加配置信息请加到这里来)。核心方法步骤如下:
- 获取系统配置(就是通过System.getProperties()全部加载进来)
- 从配置文件里面进行加载数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29public class ConfigurationManager { //.... 其他逻辑省略 public static AbstractConfiguration getConfigInstance() { if (instance == null && !Boolean.getBoolean(DynamicPropertyFactory.DISABLE_DEFAULT_CONFIG)) { synchronized (ConfigurationManager.class) { if (instance == null) { instance = new ConcurrentCompositeConfiguration(); if (!Boolean.getBoolean(DynamicPropertyFactory.DISABLE_DEFAULT_SYS_CONFIG)) { // 第一步:获取系统配置(就是通过System.getProperties()全部加载进来) SystemConfiguration sysConfig = new SystemConfiguration(); ((ConcurrentCompositeConfiguration) instance).addConfiguration(sysConfig, DynamicPropertyFactory.SYS_CONFIG_NAME); try { // 第二步:从默认的config.properties文件加载数据 // 然后看有没设置archaius.configurationSource.additionalUrls属性,如果有也从这个文件进行加载动态配置 // 最后会开启一个长轮询,默认每隔一分钟去刷新缓存数据 DynamicURLConfiguration defaultURLConfig = new DynamicURLConfiguration(); ((ConcurrentCompositeConfiguration) instance).addConfiguration(defaultURLConfig, DynamicPropertyFactory.URL_CONFIG_NAME); } catch (Throwable e) { logger.warn("Failed to create default dynamic configuration", e); } } registerConfigBean(); } } } return instance; } }
动态配置长轮询刷新大概代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 位置:DynamicURLConfiguration.java public DynamicURLConfiguration() { URLConfigurationSource source = new URLConfigurationSource(); if (source.getConfigUrls() != null && source.getConfigUrls().size() > 0) { startPolling(source, new FixedDelayPollingScheduler()); } } // 位置:DynamicConfiguration.java public void startPolling(PolledConfigurationSource source, AbstractPollingScheduler scheduler) { this.scheduler = scheduler; this.source = source; init(source, scheduler); scheduler.startPolling(source, this); }
最后
以上就是粗犷睫毛最近收集整理的关于Hystrix配置插件化源码解析的全部内容,更多相关Hystrix配置插件化源码解析内容请搜索靠谱客的其他文章。
发表评论 取消回复