Hystrix源码:配置

1. 配置介绍

Hystrix配置主要是为command设置各个属性的值,在Configuration中可以看到所有的属性。

每个command的属性的名字为由四部分组成:<prefix>.command.<commandKey>.<属性名>

  • prefix,属性前缀,默认hystrix
  • commandKey,command名,默认是当前类名
  • 属性名,就是上面链接中各个属性的名称,写死的

比如commandKey为test的execution.isolation.strategy属性名为hystrix.command.test.execution.isolation.strategy,这个名字一般没有什么用,但是要修改command某个属性值的时候需要知道该名字,后面会讲到。

除了commandKey,还有一个commandGroupKey,并且commandGroupKey是生成command时必填的,commandGroupKey的作用是聚合同一个group下的command数据,用于在dashboard上显示。

commandGroupKey,commandKey都相同的command,共享同一个全局配置,包括统计metric的滑动数组。

2. 两种使用方式对比

使用Hystrix主要有两种方式:加注解,继承HystrixCommand。这两种方式有各自的优缺点,对比如下。

2.1 注解方式

1
2
3
4
5
6
7
8
(groupKey = "test", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "10000")
})
public List<User> (List<String> ids) {
List<User> users = new ArrayList<User>();

return users;
}

优点:对业务系统侵入性较小,只需要加一个注解
缺点:相关参数没法动态修改

2.2 继承方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class CommandHelloWorld extends HystrixCommand<String> {

private final String name;

public CommandHelloWorld(String name) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(name))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(1000)));
this.name = name;
}

@Override
protected String run() {
return "Hello " + name + "!";
}
}

优点:参数可以在构造方法里设置,也就是可以从配置中心中获取,动态设置
缺点:对业务系统侵入性太大,需要继承HystrixCommand

2.3 有没有综合两者优点的方法?

能不能即用注解,又能够动态调整参数?

1
2
3
HystrixCommandProperties properties = new TestPropertiesCommand(TestKey.TEST, new HystrixCommandProperties.Setter(), "unitTestPrefix");
assertEquals(false, properties.circuitBreakerForceClosed().get());
ConfigurationManager.getConfigInstance().setProperty("unitTestPrefix.command.default.circuitBreaker.forceClosed", true);

通过ConfigurationManager可以在运行时调整参数,ConfigurationManager这个类并不是Hystrix自身的,而是 archaius 中的,archaius也是由Netflix开发的,用来实现动态配置的,而archaius又是基于 Apache Commons Configuration ,所以要弄清楚Hystrix的动态配置,需要先了解这两个类库的使用。

3. 动态配置实现

3.1 Apache Commons Configuration

Java中自带的读取配置的类是Properties,但是这个类功能太弱,只能从文件中读,而且配置都是String类型的,Commons Configuration是对Properties的扩展,不仅能从多种数据源(文件,数据库,网络等)中读取配置,还支持配置的类型,而且还可以配置listener来监听配置的修改。

下面的例子用的版本是1.8。

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
// properties配置
PropertiesConfiguration propertiesConfig = new PropertiesConfiguration("test.properties");
System.out.println(propertiesConfig.getString("app")); // testconfig 0.1
System.out.println(propertiesConfig.getInt("i")); // 100
System.out.println(propertiesConfig.getList("l")); // [s1, s2, s3, s4]

// xml配置
XMLConfiguration xmlConfig = new XMLConfiguration("test.xml");
System.out.println(xmlConfig.getString("meta.default")); // 3
System.out.println(xmlConfig.getProperty("bean.background")); // [#000000, #111111, #222222]
System.out.println(xmlConfig.getString("bean(0).background")); // #000000

// 合并多个配置
CompositeConfiguration comConfig = new CompositeConfiguration();
comConfig.addConfiguration(propertiesConfig);
comConfig.addConfiguration(xmlConfig);
System.out.println(comConfig.getList("l")); // [s1, s2, s3, s4]

// 直接将配置映射为bean
BeanDeclaration decl = new XMLBeanDeclaration(xmlConfig, "testbean");
Bean bean = (Bean) BeanHelper.createBean(decl);
System.out.println(bean.getName()); // beanname

// 监听配置修改
propertiesConfig.addConfigurationListener(event -> {
System.out.println("name:" + event.getPropertyName() + ", value:" + event.getPropertyValue()); // name:i, value:100
});
propertiesConfig.setProperty("i", 100);
1
2
3
4
@Data
public class Bean {
String name;
}
1
2
3
4
5
6
7
8
9
10
11
12
# test.properties
# 占位符
name=testconfig
version=0.1
app=${name} ${version}

大专栏  Hystrix源码:配置omment"># 引入其他配置
include = test1.properties

# 数组
l = s1, s2, s3
l = s4
1
2
# test1.properties
i=100
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!--test.xml-->
<colors>
<meta>
<num>3</num>
<default>${meta.num}</default>
</meta>
<bean>
<background>#000000</background>
</bean>
<bean>
<background>#111111</background>
</bean>
<bean>
<background>#222222</background>
</bean>
<testbean config-class="testapacheconfig.Bean" name="beanname">

</testbean>
</colors>

3.2 archaius

Commons Configuration看起来功能足够了,为什么archaius还会出现呢?主要是因为Commons Configuration并不是线程安全的,所有配置从文件读取后放在一个LinkedHashMap中,archaius在其基础上实现了线程安全,并且对配置的类型支持的更好。

1
2
3
4
5
6
7
8
9
10
PropertiesConfiguration propertiesConfiguration = new PropertiesConfiguration("test.properties");
ConfigurationManager.install(propertiesConfiguration);

System.out.println(ConfigurationManager.getConfigInstance().getString("app")); // testconfig 0.1
DynamicStringProperty stringProperty = DynamicPropertyFactory.getInstance().getStringProperty("app", "");
System.out.println(stringProperty); // DynamicProperty: {name=app, current value=testconfig 0.1}

ConfigurationManager.getConfigInstance().setProperty("app", "modify");
System.out.println(ConfigurationManager.getConfigInstance().getString("app")); // modify
System.out.println(DynamicPropertyFactory.getInstance().getStringProperty("app", "")); // DynamicProperty: {name=app, current value=modify}

使用archaius时一般不会直接和Configuration类交互,而是和DynamicXXXProperty交互,DynamicXXXProperty中XXX就是配置的类型,如果要修改配置的话,仍然需要通过Configuration来做。

archaius源码中有几个比较重要的类:ConfigurationBackedDynamicPropertySupportImpl,DynamicProperty,PropertyWrapper。

  • ConfigurationBackedDynamicPropertySupportImpl是沟通common config中Configuration和archaius中的DynamicXXXProperty的桥梁,从DynamicXXXProperty的数据来源于Configuration,并且Configuration中的配置修改了,DynamicXXXProperty对应的值也会修改,就是通过Configuration的listener来实现的。
  • DynamicProperty是archaius实现配置类型的核心,内部的ALL_PROPS放置了所有的DynamicXXXProperty。
  • PropertyWrapper只是包装了一下DynamicProperty,用于通过DynamicProperty实现不同类型的配置。

在翻archaius源码的过程中,感觉它的实现并不好,Configuration中维护了一套配置,DynamicXXXProperty中又维护了一套配置,两个配置是等价的,每次修改Configuration时,需要同时修改DynamicXXXProperty。

3.3 Hystrix的插件式配置

archaius的功能基本上是能够满足Hystrix的,即线程安全,性能也比较好,但是Hystrix并没有直接使用archaius,而是又在archaius的基础上包装了一下,主要原因是Hystrix希望将配置做成插件式的,配置的提供者不限于archaius,可以是任何满足条件的类。

3.3.1 相关接口

其中涉及到的接口主要有:HystrixDynamicProperties,HystrixProperty,HystrixDynamicProperty。

  • HystrixDynamicProperties是Hystrix自身提供的一套配置规范,只要实现这个接口,就可以向Hystrix提供配置,比如如果不想从archaius读配置,可以自己实现一套从zk等其他地方读配置的方式,实现完了后如何将这个实现插入Hystrix会在后面说明。
  • HystrixProperty和HystrixDynamicProperty和archaius的DynamicProperty一样的作用,只是Hystrix没用DynamicXXXProperty这些类,而是自己重新弄了一套,为了将具体配置的实现独立出去。

3.3.2 搜索配置插件过程

在HystrixPlugins初始化时就会搜索配置插件,具体过程在resolveDynamicProperties方法中:

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
private static HystrixDynamicProperties resolveDynamicProperties(ClassLoader classLoader, LoggerSupplier logSupplier) {
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;
}
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;
}
hp = HystrixArchaiusHelper.createArchaiusDynamicProperties();
if (hp != null) {
logSupplier.getLogger().debug("Created HystrixDynamicProperties. Using class : {}",
hp.getClass().getCanonicalName());
return hp;
}
hp = HystrixDynamicPropertiesSystemProperties.getInstance();
logSupplier.getLogger().info("Using System Properties for HystrixDynamicProperties! Using class: {}",
hp.getClass().getCanonicalName());
return hp;
}

顺序为:

  1. System property中找key为hystrix.plugin.HystrixDynamicProperties.implementation的配置
  2. 通过spi找HystrixDynamicProperties的实现,即读取META-INF/services/com.netflix.hystrix.strategy.properties.HystrixDynamicProperties文件
  3. 创建HystrixDynamicPropertiesArchaius实例,使用archaius作为配置源
  4. 创建HystrixDynamicPropertiesSystemProperties实例,从System property中读配置

dynamic-properties.jpg

猜你喜欢

转载自www.cnblogs.com/liuzhongrong/p/12365385.html