1.开关代码
public class GraySwitchUtil {
/**
* 初级灰度开关判断,一刀切,不支持白名单、百分比
* @param appKey 灰度lion配置appKey
* @param switchConfigName 灰度lion配置,配置为boolean值
* @param businessType 业务类型,日志、打点用
* @return 灰度结果 true命中灰度/false未命中灰度
*/
public static boolean isSwitchedBasic(final String appKey, final String switchConfigName, String businessType) {
boolean switchResult = false;
try {
// 灰度结果
switchResult = Lion.getBoolean(appKey, switchConfigName, false);
return switchResult;
} catch (Exception e) {
log.error("[isSwitchedBasicException]灰度过程异常,默认降级为不灰度", e);
NonIgnorableErrorMonitorUtil.logEvent("isSwitchedBasicException", "switchConfigName=" + switchConfigName + ",businessType=" + businessType);
switchResult = false;
return switchResult;
} finally {
logGrayEvent(switchConfigName, switchResult, businessType);
}
}
/**
* 高级灰度开关判断,支持黑名单、白名单、百分比
* 首先判断黑名单灰度,如果命中黑名单则返回结果为false,黑名单配置为switchConfigNamePre+".black",类型为List<Long>
* 其次判断白名单灰度,如果命中白名单则返回结果为true,白名单配置为switchConfigNamePre+".white",类型为List<Long>
* 最后判断百分比灰度,如果命中百分比(尾号后两位小于配置的百分比值)则返回结果为true,百分比配置为switchConfigNamePre+".percent",类型为int(0-100之间配置,0表示全部不灰度,100表示全部灰度)
* @param target 灰度目标,通常是门店ID、用户ID等
* @param appKey 灰度lion配置appKey
* @param switchConfigNamePre 灰度lion配置前缀
* @param businessType 业务类型,日志、打点用
* @return 灰度结果 true命中灰度/false未命中灰度
*/
public static boolean isSwitchedAdvanced(final Long target, final String appKey, final String switchConfigNamePre, final String businessType) {
boolean switchResult = false;
try {
// 黑名单
List<Long> blackList = Lion.getList(appKey, switchConfigNamePre + ".black", Long.class, new ArrayList<>());
// 白名单
List<Long> whiteList = Lion.getList(appKey, switchConfigNamePre + ".white", Long.class, new ArrayList<>());
// 百分比
int percent = Lion.getInt(appKey, switchConfigNamePre + ".percent", 0);
if (target == null) {
log.error("[grayTargetIsNull]灰度目标为空,全部不灰度,target={},appKey={},switchConfigNamePre={}", target, appKey, switchConfigNamePre);
NonIgnorableErrorMonitorUtil.logEvent("grayTargetIsNull", "switchConfigNamePre=" + switchConfigNamePre + ",bussinessType=" + businessType);
// 如果已经切到全部灰度,则即使灰度目标为null也仍然认为是命中灰度
switchResult = percent >= 100;
return switchResult;
}
if (CollectionUtils.isNotEmpty(blackList)) {
boolean hitBlack = blackList.contains(target);
if (hitBlack) {
BusinessMonitorUtil.logEvent("grayTargetHitBlack", "switchConfigNamePre=" + switchConfigNamePre + ",businessType=" + businessType);
log.info("[grayTargetHitBlack]命中黑名单不灰度,target={},appKey={},switchConfigNamePre={}", target, appKey, switchConfigNamePre);
switchResult = false;
return switchResult;
}
}
if (CollectionUtils.isNotEmpty(whiteList)) {
boolean hitWhite = whiteList.contains(target);
if (hitWhite) {
log.info("[grayTargetHitWhite]命中白名单灰度,target={},appKey={},switchConfigNamePre={}", target, appKey, switchConfigNamePre);
switchResult = true;
return switchResult;
}
}
long tail = target % 100;
boolean hitPercent = tail < percent;
if (hitPercent) {
log.info("[grayTargetHitPercent]命中百分比灰度,target={},appKey={},switchConfigNamePre={}", target, appKey, switchConfigNamePre);
switchResult = true;
return switchResult;
}
log.info("[grayTargetHitNone]没有命中灰度,target={},appKey={},switchConfigNamePre={}", target, appKey, switchConfigNamePre);
switchResult = false;
return switchResult;
} catch (Exception e) {
log.error("[isSwitchedAdvancedException]灰度过程异常,默认降级为不灰度", e);
NonIgnorableErrorMonitorUtil.logEvent("isSwitchedAdvancedException", "switchConfigNamePre=" + switchConfigNamePre + ",businessType=" + businessType);
switchResult = false;
return switchResult;
} finally {
logGrayEvent(target, switchConfigNamePre, switchResult, businessType);
}
}
/**
* 灰度开关判断,支持黑名单、白名单、百分比
* 开关配置为switchConfigName,类型为JSON
* 示例:{"blackList":[],"whiteList":[],"percent":0}
* 首先判断黑名单灰度,如果命中黑名单则返回结果为false
* 其次判断白名单灰度,如果命中白名单则返回结果为true
* 最后判断百分比灰度,如果命中百分比(尾号后两位小于配置的百分比值)则返回结果为true,(0-100之间配置,0表示全部不灰度,100表示全部灰度)
* @param target 灰度目标,通常是门店ID、用户ID等
* @param appKey 灰度lion配置appKey
* @param switchConfigName 灰度lion配置前缀
* @param businessType 业务类型,日志、打点用
* @return 灰度结果 true命中灰度/false未命中灰度
*/
public static boolean isSwitchedAdvancedByConfig(final Long target, final String appKey, final String switchConfigName, final String businessType) {
boolean switchResult = false;
try {
// 1.获取灰度开关配置
GraySwitchConfig graySwitchConfig = Lion.getBean(appKey, switchConfigName, GraySwitchConfig.class, new GraySwitchConfig());
AssertUtil.notNull(graySwitchConfig, switchConfigName + "灰度开关NULL");
// 2.解析百分比、黑白名单
int percent = Optional.ofNullable(graySwitchConfig.getPercent()).orElse(0);
List<Long> blackList = Optional.ofNullable(graySwitchConfig.getBlackList()).orElse(new ArrayList<>());
List<Long> whiteList = Optional.ofNullable(graySwitchConfig.getWhiteList()).orElse(new ArrayList<>());
// 3.灰度目标为空
if (target == null) {
log.error("[grayTargetIsNull]灰度目标为空,全部不灰度,target={},appKey={},switchConfigName={}", target, appKey, switchConfigName);
NonIgnorableErrorMonitorUtil.logEvent("grayTargetIsNull", "switchConfigName=" + switchConfigName + ",bussinessType=" + businessType);
// 如果已经切到全部灰度,则即使灰度目标为null也仍然认为是命中灰度
switchResult = percent >= 100;
return switchResult;
}
// 4.黑白名单处理
if (CollectionUtils.isNotEmpty(blackList)) {
boolean hitBlack = blackList.contains(target);
if (hitBlack) {
BusinessMonitorUtil.logEvent("grayTargetHitBlack", "switchConfigName=" + switchConfigName + ",businessType=" + businessType);
log.info("[grayTargetHitBlack]命中黑名单不灰度,target={},appKey={},switchConfigName={}", target, appKey, switchConfigName);
switchResult = false;
return switchResult;
}
}
if (CollectionUtils.isNotEmpty(whiteList)) {
boolean hitWhite = whiteList.contains(target);
if (hitWhite) {
log.info("[grayTargetHitWhite]命中白名单灰度,target={},appKey={},switchConfigName={}", target, appKey, switchConfigName);
switchResult = true;
return switchResult;
}
}
// 5.百分比逻辑处理
long tail = target % 100;
boolean hitPercent = tail < percent;
if (hitPercent) {
log.info("[grayTargetHitPercent]命中百分比灰度,target={},appKey={},switchConfigName={}", target, appKey, switchConfigName);
switchResult = true;
return switchResult;
}
log.info("[grayTargetHitNone]没有命中灰度,target={},appKey={},switchConfigName={}", target, appKey, switchConfigName);
switchResult = false;
return switchResult;
} catch (Exception e) {
log.error("[isSwitchedException]灰度过程异常,默认降级为不灰度", e);
NonIgnorableErrorMonitorUtil.logEvent("isSwitchedException", "switchConfigName=" + switchConfigName + ",businessType=" + businessType);
switchResult = false;
return switchResult;
} finally {
logGrayEvent(target, switchConfigName, switchResult, businessType);
}
}
private static void logGrayEvent(String switchConfigName, boolean switched, String businessType) {
String nameValuePairs = "TraceId=" + Tracer.getServerTracer().getTraceId() + "&localIp=" + Tracer.getServerTracer().getLocalIp();
Cat.logEvent(BUSINESS_EVENT_TYPE_GRAY_MONITOR, switchConfigName + "_" + businessType, switched? Event.SUCCESS: "FAIL", nameValuePairs);
}
private static void logGrayEvent(Long target, String switchConfigName, boolean switched, String businessType) {
String nameValuePairs = "target=" + target + "&TraceId=" + Tracer.getServerTracer().getTraceId() + "&localIp=" + Tracer.getServerTracer().getLocalIp();
Cat.logEvent(BUSINESS_EVENT_TYPE_GRAY_MONITOR, switchConfigName + "_" + businessType, switched? Event.SUCCESS: "FAIL", nameValuePairs);
}
@Data
public static class GraySwitchConfig {
private List<Long> blackList = Lists.newArrayList();
private List<Long> whiteList = Lists.newArrayList();
private Integer percent = 0;
}
}
2.Lion是作者工作公司的特有中间件,可以理解为nacos的配置文件专门抽出来做了一个功能,用来获取各种类型的配置文件(可修改为nacos配置文件获取工具类)
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.dianping.lion.client;
import com.dianping.lion.Environment;
import com.dianping.lion.client.fileconfig.FileConfigClient;
import com.dianping.lion.client.fileconfig.FileConfigManagerFactory;
import com.dianping.lion.client.http.PollManager;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import org.springframework.util.Assert;
public class Lion {
private static ConfigManager configManager = ConfigManagerFactory.getConfigManager();
private static ConfigRepositoryManager repositoryManager = ConfigRepositoryManager.getInstance();
public Lion() {
}
/** @deprecated */
@Deprecated
public String getEnv() {
return Environment.getEnv();
}
public String getEnvironment() {
return Environment.getEnvironment();
}
public String getAppName() {
return Environment.getAppName();
}
/** @deprecated */
@Deprecated
public static String get(String key) {
return configManager.get(key);
}
/** @deprecated */
@Deprecated
public static String get(String key, String defaultValue) {
return configManager.get(key, defaultValue);
}
/** @deprecated */
@Deprecated
public static String get(String key, String defaultValue, ConfigContext context) {
return configManager.get(key, defaultValue, context);
}
/** @deprecated */
@Deprecated
public static String getStringValue(String key) {
return configManager.get(key);
}
/** @deprecated */
@Deprecated
public static String getStringValue(String key, String defaultValue) {
return configManager.get(key, defaultValue);
}
private static void assertNotNull(String key, String value) {
if (value == null) {
throw new LionException("config [" + key + "] does not exist");
}
}
/** @deprecated */
@Deprecated
public static byte getByteValue(String key) {
String value = configManager.get(key);
assertNotNull(key, value);
return Byte.parseByte(value);
}
/** @deprecated */
@Deprecated
public static Byte getByte(String key) {
return configManager.getByteValue(key);
}
/** @deprecated */
@Deprecated
public static byte getByteValue(String key, byte defaultValue) {
return configManager.getByteValue(key, defaultValue);
}
/** @deprecated */
@Deprecated
public static short getShortValue(String key) {
String value = configManager.get(key);
assertNotNull(key, value);
return Short.parseShort(value);
}
/** @deprecated */
@Deprecated
public static Short getShort(String key) {
return configManager.getShortValue(key);
}
/** @deprecated */
@Deprecated
public static short getShortValue(String key, short defaultValue) {
return configManager.getShortValue(key, defaultValue);
}
/** @deprecated */
@Deprecated
public static int getIntValue(String key) {
String value = configManager.get(key);
assertNotNull(key, value);
return Integer.parseInt(value);
}
/** @deprecated */
@Deprecated
public static Integer getInt(String key) {
return configManager.getIntValue(key);
}
/** @deprecated */
@Deprecated
public static int getIntValue(String key, int defaultValue) {
return configManager.getIntValue(key, defaultValue);
}
/** @deprecated */
@Deprecated
public static long getLongValue(String key) {
String value = configManager.get(key);
assertNotNull(key, value);
return Long.parseLong(value);
}
/** @deprecated */
@Deprecated
public static Long getLong(String key) {
return configManager.getLongValue(key);
}
/** @deprecated */
@Deprecated
public static long getLongValue(String key, long defaultValue) {
return configManager.getLongValue(key, defaultValue);
}
/** @deprecated */
@Deprecated
public static float getFloatValue(String key) {
String value = configManager.get(key);
assertNotNull(key, value);
return Float.parseFloat(value);
}
/** @deprecated */
@Deprecated
public static Float getFloat(String key) {
return configManager.getFloatValue(key);
}
/** @deprecated */
@Deprecated
public static float getFloatValue(String key, float defaultValue) {
return configManager.getFloatValue(key, defaultValue);
}
/** @deprecated */
@Deprecated
public static double getDoubleValue(String key) {
String value = configManager.get(key);
assertNotNull(key, value);
return Double.parseDouble(value);
}
/** @deprecated */
@Deprecated
public static Double getDouble(String key) {
return configManager.getDoubleValue(key);
}
/** @deprecated */
@Deprecated
public static double getDoubleValue(String key, double defaultValue) {
return configManager.getDoubleValue(key, defaultValue);
}
/** @deprecated */
@Deprecated
public static boolean getBooleanValue(String key) {
String value = configManager.get(key);
assertNotNull(key, value);
return Boolean.parseBoolean(value);
}
/** @deprecated */
@Deprecated
public static Boolean getBoolean(String key) {
return configManager.getBooleanValue(key);
}
/** @deprecated */
@Deprecated
public static boolean getBooleanValue(String key, boolean defaultValue) {
return configManager.getBooleanValue(key, defaultValue);
}
/** @deprecated */
@Deprecated
public static List<String> getList(String key) {
return configManager.getList(key);
}
/** @deprecated */
@Deprecated
public static <T> List<T> getList(String key, Class<T> clazz) {
return configManager.getList(key, clazz);
}
/** @deprecated */
@Deprecated
public static <T> List<T> getList(String key, Class<T> clazz, List<T> defaultValue) {
return configManager.getList(key, clazz, defaultValue);
}
/** @deprecated */
@Deprecated
public static Map<String, String> getMap(String key) {
return configManager.getMap(key);
}
/** @deprecated */
@Deprecated
public static <T> Map<String, T> getMap(String key, Class<T> clazz) {
return configManager.getMap(key, clazz);
}
/** @deprecated */
@Deprecated
public static <T> Map<String, T> getMap(String key, Class<T> clazz, Map<String, T> defaultValue) {
return configManager.getMap(key, clazz, defaultValue);
}
/** @deprecated */
@Deprecated
public static <T> T getBean(String key, Class<T> clazz) {
return configManager.getBean(key, clazz);
}
/** @deprecated */
@Deprecated
public static <T> T getBean(String key, Class<T> clazz, T defaultValue) {
return configManager.getBean(key, clazz, defaultValue);
}
public static String getString(String appkey, String key) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.get(key, (String)null);
}
public static String getString(String appkey, String key, String defaultValue) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.get(key, defaultValue);
}
public static Byte getByte(String appkey, String key) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getByteValue(key, (Byte)null);
}
public static Byte getByte(String appkey, String key, Byte defaultValue) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getByteValue(key, defaultValue);
}
public static Short getShort(String appkey, String key) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getShortValue(key, (Short)null);
}
public static Short getShort(String appkey, String key, Short defaultValue) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getShortValue(key, defaultValue);
}
public static Integer getInt(String appkey, String key) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getIntValue(key, (Integer)null);
}
public static Integer getInt(String appkey, String key, Integer defaultValue) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getIntValue(key, defaultValue);
}
public static Long getLong(String appkey, String key) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getLongValue(key, (Long)null);
}
public static Long getLong(String appkey, String key, Long defaultValue) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getLongValue(key, defaultValue);
}
public static Float getFloat(String appkey, String key) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getFloatValue(key, (Float)null);
}
public static Float getFloat(String appkey, String key, Float defaultValue) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getFloatValue(key, defaultValue);
}
public static Double getDouble(String appkey, String key) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getDoubleValue(key, (Double)null);
}
public static Double getDouble(String appkey, String key, Double defaultValue) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getDoubleValue(key, defaultValue);
}
public static Boolean getBoolean(String appkey, String key) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getBooleanValue(key, (Boolean)null);
}
public static Boolean getBoolean(String appkey, String key, Boolean defaultValue) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getBooleanValue(key, defaultValue);
}
public static <T> List<T> getList(String appkey, String key, Class<T> clazz) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getList(key, clazz);
}
public static <T> List<T> getList(String appkey, String key, Class<T> clazz, List<T> defaultValue) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getList(key, clazz, defaultValue);
}
public static <T> Map<String, T> getMap(String appkey, String key, Class<T> clazz) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getMap(key, clazz);
}
public static <T> Map<String, T> getMap(String appkey, String key, Class<T> clazz, Map<String, T> defaultValue) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getMap(key, clazz, defaultValue);
}
public static <T> T getBean(String appkey, String key, Class<T> clazz) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getBean(key, clazz);
}
public static <T> T getBean(String appkey, String key, Class<T> clazz, T defaultValue) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, "default");
return repository.getBean(key, clazz, defaultValue);
}
public static ConfigRepository getConfigRepository() {
return getConfigRepository(Environment.getAppName(), "default");
}
public static ConfigRepository getConfigRepository(String appkey) {
return getConfigRepository(appkey, "default");
}
public static ConfigRepository getConfigRepository(String appkey, String group) {
return ConfigRepositoryManager.getInstance().getConfigRepository(appkey, group);
}
public static ConfigRepository getConfigRepository(String appkey, String userName, String password) {
return getConfigRepository(appkey, "default", userName, password);
}
public static ConfigRepository getConfigRepository(String appkey, String group, String userName, String password) {
return ConfigRepositoryManager.getInstance().getConfigRepository(appkey, group, userName, password);
}
/** @deprecated */
public static void addConfigChangeListener(ConfigChange configChange) {
configManager.addConfigListener(new ConfigListenerWrapper(configChange));
}
/** @deprecated */
public static void removeConfigChangeListener(ConfigChange configChange) {
configManager.removeConfigListener(new ConfigListenerWrapper(configChange));
}
public static void addConfigListener(ConfigListener configListener) {
configManager.addConfigListener(configListener);
}
public static void addConfigListener(ConfigListener configListener, ExecutorService executor) {
configManager.addConfigListener(configListener, executor);
}
/** @deprecated */
@Deprecated
public static void removeConfigListener(ConfigListener configListener) {
configManager.removeConfigListener(configListener);
}
/** @deprecated */
@Deprecated
public static void addConfigListener(String key, ConfigListener configListener) {
configManager.addConfigListener(key, configListener);
}
/** @deprecated */
@Deprecated
public static void addConfigListener(String key, ConfigListener configListener, ExecutorService executor) {
configManager.addConfigListener(key, configListener, executor);
}
/** @deprecated */
@Deprecated
public static void removeConfigListener(String key, ConfigListener configListener) {
configManager.removeConfigListener(key, configListener);
}
public static void addConfigListener(String appkey, String group, ConfigListener configListener) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, group);
repository.addConfigListener(configListener);
}
public static void addConfigListener(String appkey, String group, ConfigListener configListener, ExecutorService executor) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, group);
repository.addConfigListener(configListener, executor);
}
public static void removeConfigListener(String appkey, String group, ConfigListener configListener) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, group);
repository.removeConfigListener(configListener);
}
public static void addConfigListener(String appkey, String group, String name, ConfigListener configListener) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, group);
repository.addConfigListener(name, configListener);
}
public static void addConfigListener(String appkey, String group, String name, ConfigListener configListener, ExecutorService executor) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, group);
repository.addConfigListener(name, configListener, executor);
}
public static void removeConfigListener(String appkey, String group, String name, ConfigListener configListener) {
ConfigRepository repository = repositoryManager.getConfigRepository(appkey, group);
repository.removeConfigListener(name, configListener);
}
public static void quit() {
PollManager.getInstance().stop();
FileConfigManagerFactory.stop();
}
public static FileConfigClient createFileConfigClient(String appkey) {
return new FileConfigClient(appkey);
}
public static FileConfigClient createFileConfigClient() {
String appkey = Environment.getAppName();
Assert.notNull(appkey, "appkey of FileConfigClient should not be null");
return new FileConfigClient(appkey);
}
}