switch
一 概念
Switch是一个轻量级的开关和动态配置项管理框架, 在保证低侵入性的同时, 提供统一、安全的接口来修改各应用程序的业务开关或者动态配置项。
什么是开关?
开关就是内存变量,可以是任意类型和任意值,只是它具有业务意义,通过改变开关的值,使程序逻辑进入不同的分支。你可以用它来开启、关闭某个功能,或者用来设置某个业务或性能指标的阈值。
应用场景:
业务开关管理。集团很多业务应用都是由多个系统、多个模块组成, 为了保证某些业务的动态性, 后端程序通常会配置动态开关来控制程序的逻辑。
基础动态配置项管理。无需写死的URL, 接口名, 阈值, 读取文件用的编码等,都可以使用switch来管理。
二 快速接入
2.1 加入依赖包
<dependency> <groupId>com.taobao.csp</groupId> <artifactId>switchcenter</artifactId> <version>2.1.0.2</version> </dependency>
如果是集成了pandora boot提供的switch starter 则使用
<dependency> <groupId>com.alibaba.boot</groupId> <artifactId>pandora-switchcenter-spring-boot-starter</artifactId> </dependency>
2.2 接入流程
在常量类对应的开关或者动态配置项上填写com.taobao.csp.switchcenter.annotation.AppSwitch
注解
public class CommonTypeSwitch { @AppSwitch(des = "String 类型开关", level = Level.p2) public static String stringSwitch = "string"; @AppSwitch(des = "Integer 类型开关", level = Level.p1) public static Integer integerSwitch = 2; @AppSwitch(des = "Boolean 类型开关", level = Level.p4) public static Boolean booleanSwitch = true; @AppSwitch(des = "AtomicInteger 类型开关", level = Level.p1) public static AtomicInteger atomicIntegerSwitch = new AtomicInteger(21); @AppSwitch(des = "AtomicBoolean 类型开关", level = Level.p1) public static AtomicBoolean atomicBooleanSwitch = new AtomicBoolean(true); }
1)常量类要求
- Switch所管理的字段必须是
static
的; - 字段必须是
public
或者是 符合JAVA BEAN 规范的static get/set方法。 - 因为Switch在变量注册为开关时需要支持泛型实际类型的识别,因此你需要在变量申明的地方同时进行初始化(new一个默认值)
2)调用注册方法进行注册
/* 应用调用此方法完成注册, 应用名请保持和Aone一致, 大小写敏感。同时请保证应用在启动的时候, 调用过且只调用过一次此方法, 多次调用会抛出异常。 其中,常量类参数是可变参数, 可注册多个常量类。如常量类未添加 com.taobao.csp.switchcenter.annotation.NameSpace 注解, 默认使用完整类名作为namespace。 */ SwitchManager.init("app2", PrimitiveTypeSwitch.class); /* 两方包应用(自身也是一个jar包提供给应用用)调用此方法完成注册, 应用名请保持和aone一致, 大小写敏感, 可多次调用。 其中,常量类参数是可变参数, 可注册多个常量类。如常量类未添加 com.taobao.csp.switchcenter.annotation.NameSpace 注解, 默认使用完整类名作为namespace。 注意, 2.0.7及以下版本不支持两方包应用, 无此方法。控制台功能还没开发好, 请大家暂时不要调用此注册方法。 */ SwitchManager.register("app2", PrimitiveTypeSwitch.class);
例子:
在Spring管理的bean中调用init方法,确保应用起来就注册 public class SwitchConfigInitBean { private static final String APP_NAME = "switch"; public void init () { try { //SwitchManager.init(APP_NAME, A.class, B.class, ...); SwitchManager.init(APP_NAME, CommonTypeSwitch.class); } catch (SwitchCenterException e) { // TODO Auto-generated catch block } } } 在Spring xml中相关配置 <bean id="switchInitBean" class="com.taobao.csp.switchconsole.config.SwitchConfigInitBean" init-method="init" scope="singleton"> </bean>
如果是集成了pandora boot提供的switch starter
则不用手动注册,加上@SwitchGroup注解即可,自动注册了
@SwitchGroup
public class TestSwitch {
@AppSwitch(des = "AtomicBoolean 类型开关", level = Level.p1)
public static AtomicBoolean atomicBooleanSwitch = new AtomicBoolean(true);
@AppSwitch(des = "String 类型开关", level = Level.p2)
public static String stringSwitch = "string";
}
编写完成后,将应用部署到日常环境中,在web控制台刷新即可看到创建的两个开关
之后如果需要修改开关指,在控制台修改,点击“推送”,设置开关值即可,自此Switch的简单用法就介绍完成了
三 API使用
@AppSwitch
注解名:com.taobao.csp.switchcenter.annotation.AppSwitch 注解项 必填项 des 开关描述 必填 String 型 level 开关级别,为 Switch.Level 的枚举型,共有 p1,p2,p3,p4 四级,从高到低。 选填项 valueDes 开关值的填写说明 String 型 values 开关的值的可选择项,String[]型 一旦配置,则在管理台是使用下拉框来填写。填写时每一项,以 value,display 表示,例 {"1,男","2,女"} 也可以是value,例{"1","2","3"}
Listener API
- Listener回调实现样例
public class TestListener implements com.taobao.csp.switchcenter.core.Listener { @Override public void valueChange(String appName, String nameSpace, String name, String value) { //当Field值变更成功时, 会调此方法。不要依赖value字段转型, 未转义, 可直接依赖对应字段值。 } } //注册listener SwitchManager.addListenner (new TestListener());
在Listener里面使用Spring管理的Bean
public class TestService implements Listener, InitializingBean{ private static final String APP_NAME = "switch"; @Autowired private AppService appService; //使用spring管理的bean @Override public void afterPropertiesSet() throws Exception { /* * 注意下, 当前的这个bean的配置建议配置成singleton, * 否则可能注册多个重复Listener. */ SwitchManager.addListener(this); SwitchManager.init(APP_NAME, PrimitiveTypeSwitch.class); } @Override public void valueChange(String appName, String nameSpace, String name, String value) { /* * 每次开关值变更会调用此方法, 实现你自己的逻辑 * 注意, 不要依赖value转型, 要转型的话, 直接依赖你对应的字段就好 */ } }
如果是集成了pandora boot提供的switch starter则不需要实现监听方法
四 HTTP API
格式说明
修改类操作 持久化接口 : ${domain}/api/v1/persistence/{appName}/{name}.json 非持久化接口 : ${domain}/api/v1/publish/{appName}/{name}.json 非持久化单机接口:${domain}/api/v1/publish/{appName}/{machine}/{name}.json 参数: value 开关值 isExecuteInYaceGroup true 表示只推送压测环境, false 表示所有环境 authAppName 调用api authAppName authKey token 查询类操作 查询开关接口:${domain}/api/v1/{appName}/switches.json 参数: authAppName 调用api authAppName authKey token requestPort(可选) switch服务端口(默认8719,此参数一般不需要写)
1 修改switch的值
http://127.0.0.1:8719/switch.set?name=开关或者动态配置项名&value=转为String类型后的JSON字符串 必须参数: name: 开关或者动态配置项名 value: 值字符串 可选参数: namespace: 指定namespace, 不填则默认调用注册方法时注册的类名, 只有一个常量类无需填写。 appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
2 向Collection类型switch添加新的元素:
http://127.0.0.1:8719/switch.add?name=Collection类型开关或者动态配置项名&value=新元素值 必须参数: name: Collection类型开关或者动态配置项名 value: 新元素值 可选参数: namespace: 指定namespace, 不填则默认调用注册方法时注册的类名, 只有一个常量类无需填写。 appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
3 向Collection类型switch删除指定元素:
http://127.0.0.1:8719/switch.remove?name=Collection类型开关或者动态配置项名&value=新元素值 必须参数: name: Collection类型开关或者动态配置项名 value: 指定要删除的元素值 可选参数: namespace: 指定namespace, 不填则默认调用注册方法时注册的类名, 只有一个常量类无需填写。 appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
4 向Map类型switch添加或更新键值对:
http://127.0.0.1:8719/switch.add?name=Map类型switch名&key=Map key值&value=Map value值 必须参数: name: Map类型switch名 key: Map key值 value: Map value值 可选参数: namespace: 指定namespace, 不填则默认调用注册方法时注册的类名, 只有一个常量类无需填写。 appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
5 向Map类型switch删除键值对:
http://127.0.0.1:8719/switch.remove?name=Map类型switch名&key=Map key值 必须参数: name: Map类型switch名 key: Map key值 可选参数: namespace: 指定namespace, 不填则默认调用注册方法时注册的类名, 只有一个常量类无需填写。 appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
6 获取应用所有switch值实时状态的MD5值:
http://127.0.0.1:8719/switch.monitor 可选参数: appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
7 获取指定switch信息:
http://127.0.0.1:8719/switch.get?name=开关名或者动态配置项名 必须参数: name: 开关或者动态配置项名 可选参数: namespace: 指定namespace, 不填则默认调用注册方法时注册的类名, 只有一个常量类无需填写。 appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
8 获取应用的所有switch信息列表:
http://127.0.0.1:8719/switch.list 可选参数: appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
9 获取应用switch的简单 键<-->值信息:
http://127.0.0.1:8719/switch.view 可选参数: appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
五 控制台使用
较简单,不再赘述
六 Swich 与 Diamond 的区别
与diamond区别?
开关 Switch Diamond
推送粒度 支持单机,也支持集群,还可以自定义推送范围 只支持单元维度推送
持久化,非持久化接口 支持持久化,也支持非持久化开关 只支持持久化
一致性 弱一致性,但提供一致性校验服务 强一致性校验
类型,泛型校验 类型,泛型强校验 无
权限控制,安全性 统一权限控制 无
生命周期管理 从定义到加载、推送、校验等,提供完整生命周期管理 无
应用场景规约:
1.涉及系统启动加载、中间件配置等信息优先使用Diamond开关,业务动态性相关配置推荐使用Switch开关;
2.跨多个系统使用的开关优先使用Diamond;
3.需要考虑非持久化场景的开关优先使用Switch;
4.需要类型强校验场景的开关优先使用Switch;