在前面的文章中,我们已经发现了开关的踪影,例如cluster,motan支持多个cluster,当前的cluster因为开关关闭的情况下,就会使用下一个cluster。

1.开关相关的类和接口主要都在包com.weibo.api.motan.switcher下,类Switcher是具体的开关:

public class Switcher {
private boolean on = true;
private String name; // 开关名 public Switcher(String name, boolean on) {//创建开关
this.name = name;
this.on = on;
} public String getName() {//开关名称
return name;
} /**
* isOn: true,服务可用; isOn: false, 服务不可用
*
* @return
*/
public boolean isOn() {
return on;
} /**
* turn on switcher
*/
public void onSwitcher() {//操作开关为开的状态
this.on = true;
} /**
* turn off switcher
*/
public void offSwitcher() {
this.on = false;
}
}

2.开关的服务接口SwitcherService

public interface SwitcherService {
/**
* 获取接口降级开关
*
* @param name
* @return
*/
Switcher getSwitcher(String name); /**
* 获取所有接口降级开关
*
* @return
*/
List<Switcher> getAllSwitchers(); /**
* 初始化开关。
*
* @param switcherName
* @param initialValue
*/
void initSwitcher(String switcherName, boolean initialValue); /**
* 检查开关是否开启。
*
* @param switcherName
* @return true :设置来开关,并且开关值为true false:未设置开关或开关为false
*/
boolean isOpen(String switcherName); /**
* 检查开关是否开启,如果开关不存在则将开关置默认值,并返回。
*
* @param switcherName
* @param defaultValue
* @return 开关存在时返回开关值,开关不存在时设置开关为默认值,并返回默认值。
*/
boolean isOpen(String switcherName, boolean defaultValue); /**
* 设置开关状态。
*
* @param switcherName
* @param value
*/
void setValue(String switcherName, boolean value); /**
* register a listener for switcher value change, register a listener twice will only fire once
*
* @param switcherName
* @param listener
*/
void registerListener(String switcherName, SwitcherListener listener);

3.监听开关变化的接口SwitcherListener,主要是监听开关值的变化,由相关的监听者自行实现

4.SwitcherService的实现类LocalSwitcherService

public class LocalSwitcherService implements SwitcherService {

    private static ConcurrentMap<String, Switcher> switchers = new ConcurrentHashMap<String, Switcher>();//开关集合map

    private Map<String, List<SwitcherListener>> listenerMap = new ConcurrentHashMap();//监听器map

    @Override
public Switcher getSwitcher(String name) {
return switchers.get(name);
} @Override
public List<Switcher> getAllSwitchers() {
return new ArrayList<Switcher>(switchers.values());//获取当前开关服务下的所有开关
} private void putSwitcher(Switcher switcher) {
if (switcher == null) {
throw new MotanFrameworkException("LocalSwitcherService addSwitcher Error: switcher is null");
} switchers.put(switcher.getName(), switcher);
} @Override
public void initSwitcher(String switcherName, boolean initialValue) {
setValue(switcherName, initialValue);
} @Override
public boolean isOpen(String switcherName) {
Switcher switcher = switchers.get(switcherName);
return switcher != null && switcher.isOn();
} @Override
public boolean isOpen(String switcherName, boolean defaultValue) {
Switcher switcher = switchers.get(switcherName);
if (switcher == null) {
switchers.putIfAbsent(switcherName, new Switcher(switcherName, defaultValue));
switcher = switchers.get(switcherName);
}
return switcher.isOn();
} @Override
public void setValue(String switcherName, boolean value) {
putSwitcher(new Switcher(switcherName, value)); List<SwitcherListener> listeners = listenerMap.get(switcherName);
if(listeners != null) {
for (SwitcherListener listener : listeners) {
listener.onValueChanged(switcherName, value);
}
}
} @Override
public void registerListener(String switcherName, SwitcherListener listener) {//为某个开关添加监听器
synchronized (listenerMap) {
if (listenerMap.get(switcherName) == null) {
List listeners = Collections.synchronizedList(new ArrayList());
listenerMap.put(switcherName, listeners);
listeners.add(listener);
} else {
List listeners = listenerMap.get(switcherName);
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
}
} @Override
public void unRegisterListener(String switcherName, SwitcherListener listener) {//为某个开关移出监听器
synchronized (listenerMap) {
if (listener == null) {
listenerMap.remove(switcherName);
} else {
List<SwitcherListener> listeners = listenerMap.get(switcherName);
listeners.remove(listener);
}
}
} }

motan源码分析九:开关的更多相关文章

  1. motan源码分析六:客户端与服务器的通信层分析

    本章将分析motan的序列化和底层通信相关部分的代码. 1.在上一章中,有一个getrefers的操作,来获取所有服务器的引用,每个服务器的引用都是由DefaultRpcReferer来创建的 pub ...

  2. ABP源码分析九:后台工作任务

    文主要说明ABP中后台工作者模块(BackgroundWorker)的实现方式,和后台工作模块(BackgroundJob).ABP通过BackgroundWorkerManager来管理Backgr ...

  3. Heritrix源码分析(九) Heritrix的二次抓取以及如何让Heritrix抓取你不想抓取的URL

    本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/644396       本博客已迁移到本人独立博客: http://www.yun5u ...

  4. MyBatis框架的使用及源码分析(九) Executor

    从<MyBatis框架的使用及源码分析(八) MapperMethod>文中我们知道执行Mapper的每一个接口方法,最后调用的是MapperMethod.execute方法.而当执行Ma ...

  5. jQuery源码分析(九) 异步队列模块 Deferred 详解

    deferred对象就是jQuery的回调函数解决方案,它解决了如何处理耗时操作的问题,比如一些Ajax操作,动画操作等.(P.s:紧跟上一节:https://www.cnblogs.com/grea ...

  6. Vue.js 源码分析(九) 基础篇 生命周期详解

    先来看看官网的介绍: 主要有八个生命周期,分别是: beforeCreate.created.beforeMount.mounted.beforeupdate.updated   .beforeDes ...

  7. motan源码分析十:流量切换

    motan提供了流量切换的功能,可以实现把一个group的流量切换到另一个group(一个或多个服务都可以).大家可以使用tomcat部署motan的管理工具,并设置几个组,例如可以参考demo代码: ...

  8. motan源码分析十一:部分特性

    本章将描述motan部分的特性并对源码进行分析. 1.requestid的维护,使用了当前时间左移20位,再和一个自增变量组合 public class RequestIdGenerator { ); ...

  9. motan源码分析八:涉及到底层的客户端调用

    之前我们分析了客户端调用服务端的源码,但是没有涉及到通讯层和序列化层,本文将之前讲过的内容做一次串联. 1.上层通过动态代理调用refer的call,每个refer又对应一个nettyclient,下 ...

随机推荐

  1. Jmeter软件测试1--webservice测试

    写在前言 程序猿一枚,原本就是负责安安静静的撸代码,后来公司让兼任下测试的工作,还得照顾下面的几个测试兄弟,无奈本人毫无软件测试理论知识,下面的测试兄弟也是初级水平,又面临公司要求做webservic ...

  2. jstl--c:choose标签

    今天使用c:choose标签,一直报错: 严重: Servlet.service() for servlet CheckIncome threw exceptionorg.apache.jasper. ...

  3. Xcode编译项目出现访问private key提示框

    原因: 在编译时Xcode进行codesign时需要访问"private key"时没有权限,然后让询问是否允许,有三个选项,全部允许.否绝.允许,一次弹出4个(我遇到的) 遇到问 ...

  4. 《gzip命令》-linux命令五分钟系列之七

    本原创文章属于<Linux大棚>博客. 博客地址为http://roclinux.cn. 文章作者为roc 希望您能通过捐款的方式支持Linux大棚博客的运行和发展.请见“关于捐款” == ...

  5. CentOS 忘记root密码,解决方法

    1.开机后,在倒数5秒结束前,按下任意键 2.在显示centos...的那个界面下,按e键(edit) 3.会出现三行的界面,选择中间 kernel...那行,然后按e键 4.在接着出现的那个界面最后 ...

  6. phpcms V9利用num++实现多样形式列表标签调用

    在首页或者频道页调用文章列表的时候,经常会使用到左右对称或者每五行出现一条横线的调用形式. 其实代码很简单,利用num++的循环方式,以及{if}{/if}进行样式判断即可.代码如下: {pc:con ...

  7. js获取当前时间戳与日期比较

    如何用javascript获取当前时间戳: 复制代码 代码示例: 方法1: var timestamp = date.parse(new date()); 结果:1280977330000 方法2: ...

  8. 每个Linux新手都应该记住的10个基本Linux命令

    Linux对我们的生活有着很大的影响.至少,你的安卓手机上面就有Linux内核.然而,头一次入手Linux只会让你觉得不适.因为在Linux上,你通常应该使用终端命令,而不是只要点击启动器图像(就像你 ...

  9. document模板

    http://bce.baidu.com/doc/CDS/GettingStarted.html

  10. 如何在search中动态的显示和隐藏tree中的字段

    在tree定义 invisible 来自context <field name="country_id" invisible="context.get('invis ...