前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

一、灰度枚举 GrayEnum

public interface GrayEnum {


    /**
     * 灰度进度
     */
    @Getter
    @AllArgsConstructor
    enum GraySwitchEnum implements GrayEnum {

        /**
         * GRAY_CLOSE
         */
        GRAY_CLOSE("GrayClose", "灰度关闭"),
        GRAY_PERCENT("Percent", "灰度中"),
        ALL_PERCENT("AllPercent", "全量"),

        ;

        /**
         * code
         */
        private final String code;
        /**
         * desc
         */
        private final String desc;

        /**
         * GraySwitchEnum
         *
         * @param code code
         * @return GraySwitchEnum
         */
        public static GraySwitchEnum toGraySwitchEnum(String code) {
            return Arrays.stream(GraySwitchEnum.values()).filter(item -> item.getCode().equals(code)).findAny().orElse(null);
        }
    }



    /**
     * 灰度业务
     */
    @Getter
    @AllArgsConstructor
    enum GrayBusinessEnum implements GrayEnum {
        /**
         * INSURANCE_6067
         */
        BUSINESS_OOO1("businessDemo", "灰度场景1"),
        ;

        /**
         * insuranceId
         */
        private final String bizType;

        /**
         * desc
         */
        private final String bizDesc;


        /**
         * GrayBusinessEnum
         * @param bizType insuranceId
         * @return GrayBusinessEnum
         */
        public static GrayBusinessEnum toGrayBusinessEnum(String bizType) {
            return Arrays.stream(GrayBusinessEnum.values()).filter(item->item.getBizType().equals(bizType)).findAny().orElse(null);
        }
    }

}

二、灰度配置

依靠配置中心进行配置

@Slf4j
@Data
@Configuration
public class GrayConfiguration {

    /**
     * 灰度对象
     */
    @Value("${gray.business.demo}")
    private GrayBusinessDemoBO grayBusiness;


}

@Data
public class GrayBusinessDemoBO implements Serializable {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 5110796299306482078L;
    /**
     * 灰度开关(GraySwitchEnum)
     */
    private String graySwitchCode;

    /**
     * 灰度比例
     */
    private Integer grayPercent;

    /**
     * 灰度总额
     */
    private Integer grayPercentAmount;

    /**
     * 灰度白名单用户
     */
    private Set<String> whiteUsers;

}

三、灰度工具

@Service
@Slf4j
public class GrayUtil {

    /**
     * grayConfiguration
     */
    @Resource
    private GrayConfiguration grayConfiguration;

    /**
     * 是否命中灰度
     *
     * @param grayBusinessEnum 灰度业务枚举
     * @param grayObject       灰度值
     * @return 灰度开关是否打开
     */
    public <T> boolean hitGray(GrayEnum.GrayBusinessEnum grayBusinessEnum, T grayObject) {
        if (Objects.requireNonNull(grayBusinessEnum) == GrayEnum.GrayBusinessEnum.BUSINESS_OOO1) {
            return grayBusinessDemo((String) grayObject);
        }
        return false;
    }


    /**
     * ducc险种灰度开关 (定制化)
     * 1、如果配置中间配置为空则返回 灰度关闭
     * 2、灰度开关判断
     * 2.1、如果灰度开关状态不存在或者开关关闭,则返回false
     * 2.2、如果灰度开关状态显示全量,则返回true
     * 3、商家白名单判断,如果商家在白名单,则返回true
     * 4、灰度比例判断
     * 4.1、灰度比例不存在,则返回false
     * 4.2、灰度比例计算,命中返回ture,不命中返回false
     *
     * @return 路由切换开关
     */
    private boolean grayBusinessDemo(String userId) {
        GrayBusinessDemoBO grayBusiness = grayConfiguration.getGrayBusiness();
        // 1、如果配置中间配置为空则返回 灰度关闭
        if (Objects.isNull(grayBusiness)) {
            return false;
        }

        // 2、灰度开关判断
        // 2.1、如果灰度开关状态不存在或者开关关闭,则返回false
        String graySwitchCode = grayBusiness.getGraySwitchCode();
        GrayEnum.GraySwitchEnum graySwitchEnum = GrayEnum.GraySwitchEnum.toGraySwitchEnum(graySwitchCode);
        if (Objects.isNull(graySwitchEnum) || GrayEnum.GraySwitchEnum.GRAY_CLOSE == graySwitchEnum) {
            return false;
        }

        // 2.2、如果灰度开关状态显示全量,则返回true
        if (GrayEnum.GraySwitchEnum.ALL_PERCENT == graySwitchEnum) {
            return true;
        }
        if (GrayEnum.GraySwitchEnum.GRAY_PERCENT != graySwitchEnum) {
            return false;
        }

        // 3、商家白名单判断,如果商家在白名单,则返回true
        Set<String> whiteUsers = grayBusiness.getWhiteUsers();
        if (!CollectionUtils.isEmpty(whiteUsers) && whiteUsers.contains(userId)) {
            log.info("[GrayUtil#grayBusinessDemo] 白名单用户命中,userId:{}, whiteUsers:{}:灰度状态:true", userId, whiteUsers);
            return true;
        }

        // 4.1、灰度比例不存在,则返回false
        Integer grayPercent = grayBusiness.getGrayPercent();
        Integer grayPercentAmount = grayBusiness.getGrayPercentAmount();
        if (Objects.isNull(grayPercent) || Objects.isNull(grayPercentAmount)) {
            return false;
        }
        // 4.2、灰度比例计算,命中返回ture,不命中返回false
        int hashCode = userId.hashCode();
        int rate = Math.abs(hashCode) % grayPercentAmount;
        if (rate <= grayPercent) {
            log.info("[GrayUtil#grayBusinessDemo] userId:{},命中灰度:{} grayPercent:{}, grayPercentAmount:{}, 灰度状态:true", userId, rate, grayPercent, grayPercentAmount);
            return true;
        }
        return false;
    }

}

ContactAuthor