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 注解方式
12345678 | (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 继承方式
123456789101112131415 | 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 有没有综合两者优点的方法?
能不能即用注解,又能够动态调整参数?
123 | 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。
12345678910111213141516171819202122232425262728 | // properties配置PropertiesConfiguration propertiesConfig = new PropertiesConfiguration("test.properties");System.out.println(propertiesConfig.getString("app")); // testconfig 0.1System.out.println(propertiesConfig.getInt("i")); // 100System.out.println(propertiesConfig.getList("l")); // [s1, s2, s3, s4]// xml配置XMLConfiguration xmlConfig = new XMLConfiguration("test.xml");System.out.println(xmlConfig.getString("meta.default")); // 3System.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] // 直接将配置映射为beanBeanDeclaration 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); |
1234 | @Datapublic class Bean { String name;} |
123456789101112 | # test.properties# 占位符name=testconfigversion=0.1app=${name} ${version}大专栏 Hystrix源码:配置omment"># 引入其他配置include = test1.properties# 数组l = s1, s2, s3l = s4 |
12 | # test1.propertiesi=100 |
1234567891011121314151617181920 | <?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在其基础上实现了线程安全,并且对配置的类型支持的更好。
12345678910 | 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方法中:
12345678910111213141516171819202122232425262728 | 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;} |
顺序为:
- System property中找key为hystrix.plugin.HystrixDynamicProperties.implementation的配置
- 通过spi找HystrixDynamicProperties的实现,即读取META-INF/services/com.netflix.hystrix.strategy.properties.HystrixDynamicProperties文件
- 创建HystrixDynamicPropertiesArchaius实例,使用archaius作为配置源
- 创建HystrixDynamicPropertiesSystemProperties实例,从System property中读配置

来源:https://www.cnblogs.com/liuzhongrong/p/12365385.html