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转型, 要转型的话, 直接依赖你对应的字段就好
         */
    }
 }
View Code

如果是集成了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,此参数一般不需要写)
View Code

1 修改switch的值

http://127.0.0.1:8719/switch.set?name=开关或者动态配置项名&value=转为String类型后的JSON字符串

必须参数:

   name:  开关或者动态配置项名

   value: 值字符串
可选参数:

   namespace: 指定namespace, 不填则默认调用注册方法时注册的类名, 只有一个常量类无需填写。

   appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
View Code

2 向Collection类型switch添加新的元素:

http://127.0.0.1:8719/switch.add?name=Collection类型开关或者动态配置项名&value=新元素值

必须参数:

   name:  Collection类型开关或者动态配置项名

   value: 新元素值
可选参数:

   namespace: 指定namespace, 不填则默认调用注册方法时注册的类名, 只有一个常量类无需填写。

   appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
View Code

3 向Collection类型switch删除指定元素:

http://127.0.0.1:8719/switch.remove?name=Collection类型开关或者动态配置项名&value=新元素值

必须参数:

   name:  Collection类型开关或者动态配置项名

   value: 指定要删除的元素值
可选参数:

   namespace: 指定namespace, 不填则默认调用注册方法时注册的类名, 只有一个常量类无需填写。

   appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
View Code

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: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
View Code

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: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
View Code

6 获取应用所有switch值实时状态的MD5值:

http://127.0.0.1:8719/switch.monitor

可选参数:

   appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
View Code

7 获取指定switch信息:

http://127.0.0.1:8719/switch.get?name=开关名或者动态配置项名

必须参数:

   name:  开关或者动态配置项名
可选参数:

   namespace: 指定namespace, 不填则默认调用注册方法时注册的类名, 只有一个常量类无需填写。

   appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
View Code

8 获取应用的所有switch信息列表:

http://127.0.0.1:8719/switch.list

可选参数:

   appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
View Code

9 获取应用switch的简单 键<-->值信息:

http://127.0.0.1:8719/switch.view

可选参数:

   appName: 指定应用, 默认是宿主应用的应用名(两方包应用才有这名词,其它应用可忽略)。
View Code

五 控制台使用

较简单,不再赘述

六 Swich 与 Diamond 的区别

与diamond区别?

开关                                                         Switch                                                                     Diamond

推送粒度                           支持单机,也支持集群,还可以自定义推送范围                    只支持单元维度推送

持久化,非持久化接口      支持持久化,也支持非持久化开关                                         只支持持久化

一致性                               弱一致性,但提供一致性校验服务                                         强一致性校验

类型,泛型校验                类型,泛型强校验                                                                   无

权限控制,安全性             统一权限控制                                                                          无

生命周期管理                    从定义到加载、推送、校验等,提供完整生命周期管理         无

 

应用场景规约:

1.涉及系统启动加载、中间件配置等信息优先使用Diamond开关,业务动态性相关配置推荐使用Switch开关;

2.跨多个系统使用的开关优先使用Diamond;

3.需要考虑非持久化场景的开关优先使用Switch;

4.需要类型强校验场景的开关优先使用Switch;

 

 

原文地址:https://www.cnblogs.com/hup666/p/13899788.html