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
PropertiesConfiguration propertiesConfig = new PropertiesConfiguration("test.properties" ); System.out.println(propertiesConfig.getString("app" )); System.out.println(propertiesConfig.getInt("i" )); System.out.println(propertiesConfig.getList("l" )); XMLConfiguration xmlConfig = new XMLConfiguration("test.xml" ); System.out.println(xmlConfig.getString("meta.default" )); System.out.println(xmlConfig.getProperty("bean.background" )); System.out.println(xmlConfig.getString("bean(0).background" )); CompositeConfiguration comConfig = new CompositeConfiguration(); comConfig.addConfiguration(propertiesConfig); comConfig.addConfiguration(xmlConfig); System.out.println(comConfig.getList("l" )); BeanDeclaration decl = new XMLBeanDeclaration(xmlConfig, "testbean" ); Bean bean = (Bean) BeanHelper.createBean(decl); System.out.println(bean.getName()); propertiesConfig.addConfigurationListener(event -> { System.out.println("name:" + event.getPropertyName() + ", value:" + event.getPropertyValue()); }); 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
name=testconfig version=0.1 app=${name} ${version} 大专栏 Hystrix源码:配置 omment"># 引入其他配置 include = test1.properties l = s1, s2, s3 l = s4
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" ?> <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" )); DynamicStringProperty stringProperty = DynamicPropertyFactory.getInstance().getStringProperty("app" , "" ); System.out.println(stringProperty); ConfigurationManager.getConfigInstance().setProperty("app" , "modify" ); System.out.println(ConfigurationManager.getConfigInstance().getString("app" )); System.out.println(DynamicPropertyFactory.getInstance().getStringProperty("app" , "" ));
使用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; }
顺序为:
System property中找key为hystrix.plugin.HystrixDynamicProperties.implementation的配置
通过spi找HystrixDynamicProperties的实现,即读取META-INF/services/com.netflix.hystrix.strategy.properties.HystrixDynamicProperties文件
创建HystrixDynamicPropertiesArchaius实例,使用archaius作为配置源
创建HystrixDynamicPropertiesSystemProperties实例,从System property中读配置