@Override
    public <T> Invoker<T> select(final List<Invoker<T>> invokers, final URL url, final Invocation invocation) throws RpcException {
        String shenyuSelectorId = invocation.getAttachment(Constants.DUBBO_SELECTOR_ID);
        String shenyuRuleId = invocation.getAttachment(Constants.DUBBO_RULE_ID);
        String remoteAddressIp = invocation.getAttachment(Constants.DUBBO_REMOTE_ADDRESS);
        List<DubboUpstream> dubboUpstreams = ApacheDubboPluginDataHandler.SELECTOR_CACHED_HANDLE.get().obtainHandle(shenyuSelectorId);
        DubboRuleHandle dubboRuleHandle = ApacheDubboPluginDataHandler.RULE_CACHED_HANDLE.get().obtainHandle(shenyuRuleId);
        // if gray list is not empty,just use load balance to choose one.
        if (CollectionUtils.isNotEmpty(dubboUpstreams)) {
            Upstream upstream = LoadBalancerFactory.selector(UpstreamCacheManager.getInstance().findUpstreamListBySelectorId(shenyuSelectorId), dubboRuleHandle.getLoadBalance(), remoteAddressIp);
            if (StringUtils.isBlank(upstream.getUrl()) && StringUtils.isBlank(upstream.getGroup()) && StringUtils.isBlank(upstream.getVersion())) {
                return select(invokers, url, invocation, dubboRuleHandle.getLoadBalance());
            }
            // url is the first level, then is group, the version is the lowest.
            final List<Invoker<T>> invokerGrays = invokers.stream().filter(each -> {
                if (StringUtils.isNotBlank(upstream.getUrl())) {
                    URL eachUrl = each.getUrl();
                    return eachUrl.getAddress().equals(upstream.getUrl());
                }
                return true;
            }).filter(each -> {
                if (StringUtils.isNotBlank(upstream.getGroup())) {
                    final URL eachUrl = each.getUrl();
                    return upstream.getGroup().equals(eachUrl.getParameter(Constants.GROUP));
                }
                return true;
            }).filter(each -> {
                if (StringUtils.isNotBlank(upstream.getVersion())) {
                    final URL eachUrl = each.getUrl();
                    return upstream.getVersion().equals(eachUrl.getParameter(Constants.VERSION));
                }
                return true;
            }).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(invokerGrays)) {
                return select(invokers, url, invocation, dubboRuleHandle.getLoadBalance());
            }
            return select(invokerGrays, url, invocation, dubboRuleHandle.getLoadBalance());
        }
        return select(invokers, url, invocation, dubboRuleHandle.getLoadBalance());
    }
@Test
    public void apacheDubboLoadBalanceTest() {
        assertEquals(apacheDubboGrayLoadBalance.select(invokers, url, invocation), mockInvoker);
        when(upstream.getUrl()).thenReturn("localhost");
        assertEquals(apacheDubboGrayLoadBalance.select(invokers, url, invocation), mockInvoker);
        when(upstream.getUrl()).thenReturn(null);
        when(upstream.getGroup()).thenReturn("group");
        assertEquals(apacheDubboGrayLoadBalance.select(invokers, url, invocation), mockInvoker);
        when(upstream.getGroup()).thenReturn(null);
        when(upstream.getVersion()).thenReturn("version");
        assertEquals(apacheDubboGrayLoadBalance.select(invokers, url, invocation), mockInvoker);

        ApacheDubboPluginDataHandler.SELECTOR_CACHED_HANDLE.get()
                .removeHandle(Constants.DUBBO_SELECTOR_ID);
        assertEquals(apacheDubboGrayLoadBalance.select(invokers, url, invocation), mockInvoker);
    }