一、前言
switcher位于motan-core包下,实现业务的开关标识逻辑。
二、类介绍
2. 1 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.2 SwitcherService接口
改接口定义开关的操作逻辑
@Spi(scope = Scope.SINGLETON) // SPI标识,可扩展
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);
/**
* unregister a listener
* 取消开关监听器,null取消所有监听器
* @param switcherName
* @param listener the listener to be unregistered, null for all listeners for this switcherName
*/
void unRegisterListener(String switcherName, SwitcherListener listener);
}
2.3 SwitcherListener接口
创建监听器的接口
public interface SwitcherListener {
void onValueChanged(String key,Boolean value);// key=开关名字,value=开关状态
}
2.4 LocalSwitcherService类
SwitcherService接口提供的实现类
@SpiMeta(name = "localSwitcherService") // 支持ExtensionLoader
public class LocalSwitcherService implements SwitcherService {
// 全局开关名和开关映射关系
private static ConcurrentMap<String, Switcher> switchers = new ConcurrentHashMap<String, Switcher>();
// 开关名对应的监听器列表映射关系
private ConcurrentHashMap<String, List<SwitcherListener>> listenerMap = new ConcurrentHashMap<>();
public static Switcher getSwitcherStatic(String name) {
return switchers.get(name);
}
@Override
public Switcher getSwitcher(String name) {
return switchers.get(name);
}
@Override
public List<Switcher> getAllSwitchers() {
return new ArrayList<Switcher>(switchers.values());
}
public static 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) {
List listeners = Collections.synchronizedList(new ArrayList());
List preListeners= listenerMap.putIfAbsent(switcherName, listeners);
if (preListeners == null) {
listeners.add(listener);
} else {
preListeners.add(listener);
}
}
@Override
public void unRegisterListener(String switcherName, SwitcherListener listener) {
List<SwitcherListener> listeners = listenerMap.get(switcherName);
if (listener == null) {
// keep empty listeners
listeners.clear();
} else {
listeners.remove(listener);
}
}
}
2.5 MotanSwitcherUtil类
静态开关工具类。一般全局开关使用此类。 使用LocalSwitcherService类的实例对象。
public class MotanSwitcherUtil {
private static SwitcherService switcherService = new LocalSwitcherService();
public static void initSwitcher(String switcherName, boolean initialValue) {
switcherService.initSwitcher(switcherName, initialValue);
}
/**
* 检查开关是否开启。
*
* @param switcherName
* @return true :设置了开关,并且开关值为true false:未设置开关或开关为false
*/
public static boolean isOpen(String switcherName) {
return switcherService.isOpen(switcherName);
}
/**
* 检查开关是否开启,如果开关不存在则将开关置默认值,并返回。
*
* @param switcherName
* @param defaultValue
* @return 开关存在时返回开关值,开关不存在时设置开关为默认值,并返回默认值。
*/
public static boolean switcherIsOpenWithDefault(String switcherName, boolean defaultValue) {
return switcherService.isOpen(switcherName, defaultValue);
}
/**
* 设置开关状态。
*
* @param switcherName
* @param value
* @return
*/
public static void setSwitcherValue(String switcherName, boolean value) {
switcherService.setValue(switcherName, value);
}
public static SwitcherService getSwitcherService() {
return switcherService;
}
public static void setSwitcherService(SwitcherService switcherService) {
MotanSwitcherUtil.switcherService = switcherService;
}
public static void registerSwitcherListener(String switcherName, SwitcherListener listener) {
switcherService.registerListener(switcherName, listener);
}
}
三、示例
示例代码
String protocolSwitcher = MotanConstants.PROTOCOL_SWITCHER_PREFIX + "motan";
LocalSwitcherService localSwitcherService = new LocalSwitcherService();// 创建开关操作类
localSwitcherService.setValue(protocolSwitcher, false);// 开关设置关闭
Switcher switcher = localSwitcherService.getSwitcher(protocolSwitcher);
Assert.assertNotNull(switcher);
Assert.assertFalse(switcher.isOn());// 开关关闭
localSwitcherService.setValue(protocolSwitcher, true); // 设置开关开启
switcher = localSwitcherService.getSwitcher(protocolSwitcher);