class MultiGroupSelector<T> implements Selector<T> {
        private final URL clusterUrl;
        private final String loadBalanceName;
        private List<Referer<T>> referers;
        private String weightString;
        private volatile InnerSelector<T> innerSelector;

        public MultiGroupSelector(URL clusterUrl, List<Referer<T>> referers, String loadBalanceName, String weightString) {
            this.referers = referers;
            this.clusterUrl = clusterUrl;
            this.loadBalanceName = loadBalanceName;
            this.weightString = weightString;
            reBuildInnerSelector();
        }

        @Override
        public Referer<T> select(Request request) {
            if (innerSelector == null) {
                return null;
            }
            return innerSelector.select(request);
        }

        public synchronized void refresh(List<Referer<T>> referers, String weightString) {
            this.referers = referers;
            if (this.weightString.equals(weightString)) {
                // When weightString does not change, refresh each LB in innerSelector.
                Map<String, List<Referer<T>>> groupReferers = getGroupReferers(referers);
                for (String groupName : groupReferers.keySet()) {
                    LoadBalance<T> loadBalance = innerSelector.lbMap.get(groupName);
                    if (loadBalance != null) {
                        loadBalance.onRefresh(groupReferers.get(groupName));
                    } else {
                        LoggerUtil.warn("GroupWeightLoadBalance groupName:{} not exist in innerSelector.lbMap", groupName);
                    }
                }
            } else {
                this.weightString = weightString;
                reBuildInnerSelector();
            }
        }

        // depend on referers and weightString
        private void reBuildInnerSelector() {<FILL_FUNCTION_BODY>}

        private LoadBalance<T> reuseOrCreateLB(String group, List<Referer<T>> groupReferers) {
            LoadBalance<T> loadBalance = null;
            if (innerSelector != null) { // Reuse LB by group name
                loadBalance = innerSelector.lbMap.remove(group);
            }
            if (loadBalance == null) { // create new LB
                loadBalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(loadBalanceName);
                loadBalance.init(clusterUrl);
            }
            loadBalance.onRefresh(groupReferers); // Referers in the same group can refresh first
            return loadBalance;
        }

        private Map<String, List<Referer<T>>> getGroupReferers(List<Referer<T>> referers) {
            Map<String, List<Referer<T>>> result = new HashMap<>();
            for (Referer<T> referer : referers) {
                result.computeIfAbsent(referer.getUrl().getGroup(), k -> new ArrayList<>()).add(referer);
            }
            return result;
        }

        @Override
        public void destroy() {
            referers = null;
            if (innerSelector != null) {
                innerSelector.destroy();
                innerSelector = null;
            }
        }
    }

            Map<String, List<Referer<T>>> groupReferers = getGroupReferers(referers);
            // CommandServiceManager ensures that there will be no duplicate groups in the weightString
            // and no abnormal weight value.
            // If it occurs, just throw an exception
            String[] groupsAndWeights = weightString.split(",");
            if (groupsAndWeights.length > 256) {
                throw new MotanFrameworkException("the group in weightString is greater than 256");
            }
            int[] weightsArr = new int[groupsAndWeights.length];
            LoadBalance<T>[] lbArray = new LoadBalance[groupsAndWeights.length];
            ConcurrentHashMap<String, LoadBalance<T>> lbMap = new ConcurrentHashMap<>();
            int totalWeight = 0;
            for (int i = 0; i < groupsAndWeights.length; i++) {
                String[] gw = groupsAndWeights[i].split(":");
                weightsArr[i] = Integer.parseInt(gw[1]);
                totalWeight += weightsArr[i];
                lbArray[i] = reuseOrCreateLB(gw[0], groupReferers.get(gw[0]));
                lbMap.put(gw[0], lbArray[i]);
            }

            // divide the weight by the gcd of all weights
            int weightGcd = MathUtil.findGCD(weightsArr);
            if (weightGcd > 1) {
                totalWeight = 0;
                for (int i = 0; i < weightsArr.length; i++) {
                    weightsArr[i] = weightsArr[i] / weightGcd;
                    totalWeight += weightsArr[i];
                }
            }

            // build weight ring
            byte[] groupWeightRing = new byte[totalWeight];
            int index = 0;
            for (int i = 0; i < weightsArr.length; i++) {
                for (int j = 0; j < weightsArr[i]; j++) {
                    groupWeightRing[index++] = (byte) i;
                }
            }
            CollectionUtil.shuffleByteArray(groupWeightRing);

            ConcurrentHashMap<String, LoadBalance<T>> remain = innerSelector == null ? null : innerSelector.lbMap;
            innerSelector = new InnerSelector<>(lbMap, groupWeightRing, lbArray);

            // Destroy the remaining LB
            if (remain != null) {
                for (LoadBalance<T> lb : remain.values()) {
                    try {
                        lb.destroy();
                    } catch (Exception e) {
                        LoggerUtil.warn("GroupWeightLoadBalance destroy lb fail. url:" + clusterUrl.toSimpleString() + " error: " + e.getMessage());
                    }
                }
            }
        
<methods>public non-sealed void <init>() ,public void init(com.weibo.api.motan.rpc.URL) ,public void onRefresh(List<Referer<T>>) ,public Referer<T> select(com.weibo.api.motan.rpc.Request) ,public void selectToHolder(com.weibo.api.motan.rpc.Request, List<Referer<T>>) ,public void setWeightString(java.lang.String) <variables>public static final int MAX_REFERER_COUNT,protected com.weibo.api.motan.rpc.URL clusterUrl,private List<Referer<T>> referers