private ExchangeServer getServer(URL url) {
    // 指定自己的exchanger
    url = url.addParameterIfAbsent(Constants.EXCHANGER_KEY, HeaderExchanger2.NAME);
    // server type setting
    url = url.addParameterIfAbsent(Constants.SERVER_KEY, NettyTransporter2.NAME);
    // check server type
    String str = url.getParameter(Constants.SERVER_KEY, NettyTransporter2.NAME);
    if (str != null
        && str.length() > 0
        && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
      throw new RpcException("Unsupported server type: " + str + ", url: " + url);
    }

    ExchangeServer server;
    try {
      server = Exchangers.bind(url, requestHandler);
    } catch (RemotingException e) {
      throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
    }
    str = url.getParameter(Constants.CLIENT_KEY);
    if (str != null && str.length() > 0) {
      Set<String> supportedTypes =
          ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
      if (!supportedTypes.contains(str)) {
        throw new RpcException("Unsupported client type: " + str);
      }
    }
    return server;
  }
 public static ThriftRpcProtocol getThriftRpcProtocol() {
   if (INSTANCE == null) {
     ExtensionLoader.getExtensionLoader(Protocol.class)
         .getExtension(ThriftRpcProtocol.NAME); // load
   }
   return INSTANCE;
 }
  public WrappedChannelHandler(ChannelHandler handler, URL url) {
    this.handler = handler;
    this.url = url;
    // 从扩展实现中初始化线程池
    executor =
        (ExecutorService)
            ExtensionLoader.getExtensionLoader(ThreadPool.class)
                .getAdaptiveExtension()
                .getExecutor(url);

    String componentKey = Constants.EXECUTOR_SERVICE_COMPONENT_KEY;
    if (Constants.CONSUMER_SIDE.equalsIgnoreCase(url.getParameter(Constants.SIDE_KEY))) {
      componentKey = Constants.CONSUMER_SIDE;
    }
    DataStore dataStore = ExtensionLoader.getExtensionLoader(DataStore.class).getDefaultExtension();
    dataStore.put(componentKey, Integer.toString(url.getPort()), executor); // 保存起来
  }
  /** 创建新连接. */
  private ExchangeClient initClient(URL url) {
    // 指定自己的exchanger
    url = url.addParameterIfAbsent(Constants.EXCHANGER_KEY, HeaderExchanger2.NAME);
    // client type setting.
    url =
        url.addParameterIfAbsent(
            Constants.CLIENT_KEY, url.getParameter(Constants.SERVER_KEY, NettyTransporter2.NAME));
    // check client type
    String str =
        url.getParameter(
            Constants.CLIENT_KEY, url.getParameter(Constants.SERVER_KEY, NettyTransporter2.NAME));
    // BIO存在严重性能问题,暂时不允许使用
    if (str != null
        && str.length() > 0
        && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
      throw new RpcException(
          "Unsupported client type: "
              + str
              + ","
              + " supported client type is "
              + StringUtils.join(
                  ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(),
                  " "));
    }

    ExchangeClient client;
    try {
      // 设置连接应该是lazy的
      if (url.getParameter(Constants.LAZY_CONNECT_KEY, false)) {
        client = new LazyConnectExchangeClient(url, requestHandler);
      } else {
        client = Exchangers.connect(url, requestHandler);
      }
    } catch (RemotingException e) {
      throw new RpcException(
          "Fail to create remoting client for service(" + url + "): " + e.getMessage(), e);
    }
    return client;
  }
Ejemplo n.º 5
0
 public String telnet(Channel channel, String message) {
   if (message.length() > 0) {
     if (!extensionLoader.hasExtension(message)) {
       return "No such command " + message;
     }
     TelnetHandler handler = extensionLoader.getExtension(message);
     Help help = handler.getClass().getAnnotation(Help.class);
     StringBuilder buf = new StringBuilder();
     buf.append("Command:\r\n    ");
     buf.append(message + " " + help.parameter().replace("\r\n", " ").replace("\n", " "));
     buf.append("\r\nSummary:\r\n    ");
     buf.append(help.summary().replace("\r\n", " ").replace("\n", " "));
     buf.append("\r\nDetail:\r\n    ");
     buf.append(help.detail().replace("\r\n", "    \r\n").replace("\n", "    \n"));
     return buf.toString();
   } else {
     List<List<String>> table = new ArrayList<List<String>>();
     List<TelnetHandler> handlers =
         extensionLoader.getActivateExtension(channel.getUrl(), "telnet");
     if (handlers != null && handlers.size() > 0) {
       for (TelnetHandler handler : handlers) {
         Help help = handler.getClass().getAnnotation(Help.class);
         List<String> row = new ArrayList<String>();
         String parameter =
             " "
                 + extensionLoader.getExtensionName(handler)
                 + " "
                 + (help != null ? help.parameter().replace("\r\n", " ").replace("\n", " ") : "");
         row.add(parameter.length() > 50 ? parameter.substring(0, 50) + "..." : parameter);
         String summary =
             help != null ? help.summary().replace("\r\n", " ").replace("\n", " ") : "";
         row.add(summary.length() > 50 ? summary.substring(0, 50) + "..." : summary);
         table.add(row);
       }
     }
     return "Please input \"help [command]\" show detail.\r\n" + TelnetUtils.toList(table);
   }
 }
 public com.alibaba.dubbo.rpc.Invoker refer(
     java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) {
   if (arg1 == null) throw new IllegalArgumentException("url == null");
   com.alibaba.dubbo.common.URL url = arg1;
   String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
   if (extName == null)
     throw new IllegalStateException(
         "Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url("
             + url.toString()
             + ") use keys([protocol])");
   com.alibaba.dubbo.rpc.Protocol extension =
       (com.alibaba.dubbo.rpc.Protocol)
           ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class)
               .getExtension(extName);
   return extension.refer(arg0, arg1);
 }
 public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) {
   if (arg0 == null)
     throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
   if (arg0.getUrl() == null)
     throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
   com.alibaba.dubbo.common.URL url = arg0.getUrl();
   String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
   if (extName == null)
     throw new IllegalStateException(
         "Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url("
             + url.toString()
             + ") use keys([protocol])");
   com.alibaba.dubbo.rpc.Protocol extension =
       (com.alibaba.dubbo.rpc.Protocol)
           ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class)
               .getExtension(extName);
   return extension.export(arg0);
 }
/**
 * Created by bieber on 2015/4/30. Dubbo服务降级Filter 通过拦截每个方法的请求,并且读取每个方法对服务降级条件的配置 从而自动进行服务降级,以及服务恢复
 */
@Activate(group = {Constants.CONSUMER})
public class RemoteFacadeCircuitBreaker implements Filter {

  private static final Logger logger = LoggerFactory.getLogger("CIRCUITBREAKER");

  private static final InetAddress localHost = Config.getLocalAddress();
  // 用于存储某个方法出现异常的计数器key:interfaceName.methodName,value:对应的异常计数器
  private volatile ConcurrentHashMap<String, BreakCounter> breakCounterMap =
      new ConcurrentHashMap<String, BreakCounter>();
  // 对某个方法异常计数器处理器,用于分析记录的异常到当前实现是否失效了(为了满足在某个时间内出现异常次数),如果失效将从BreakCounter中移除
  private BreakCounterLoop[] breakCounterLoops =
      new BreakCounterLoop[Runtime.getRuntime().availableProcessors()];
  // 获取dubbo的代理工程扩展
  private static final ProxyFactory proxyFactory =
      ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
  // 缓存服务降级代理类的Invoker,避免重复创建
  private static final ConcurrentHashMap<String, Invoker> CIRCUIT_BREAKER_INVOKER_CACHE =
      new ConcurrentHashMap<String, Invoker>();

  private volatile AtomicLong loopCount = new AtomicLong(0);

  public RemoteFacadeCircuitBreaker() {
    String intervalConf =
        ConfigUtils.getProperty("dubbo.reference.check.break.marker.interval", "60000");
    logger.info(
        "[{}] has already been initialized circuit breaker,check break marker interval [{}]",
        localHost,
        intervalConf);
    long interval = Long.parseLong(intervalConf);
    for (int i = 0; i < breakCounterLoops.length; i++) {
      BreakCounterLoop loop = new BreakCounterLoop(interval);
      breakCounterLoops[i] = loop;
    }
  }

  // 获取下一个遍历器
  private BreakCounterLoop nextLoop() {
    return breakCounterLoops[((int) (loopCount.incrementAndGet() % breakCounterLoops.length))];
  }

  public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    if (Config.checkFunctionSwitch(invoker, invocation)) {
      logger.info("[{}] had [{}] breaker", localHost, breakCounterMap.size());
      return wrapBreakerInvoke(invoker, invocation);
    }
    Result result = invoker.invoke(invocation);
    toBeNormal(invoker, invocation);
    return result;
  }

  private Result wrapBreakerInvoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    // 首先检查是否需要进入服务降级流程
    if (checkNeedCircuitBreak(invoker, invocation)) {
      logger.info(
          "[{}] activate the circuit break for url [{}],invoke method [{}]",
          localHost,
          invoker.getUrl(),
          invocation.getMethodName());
      // 进入服务降级
      return doCircuitBreak(invoker, invocation);
    }
    try {
      Result result = invoker.invoke(invocation);
      // 将该服务从服务降级中恢复出来
      toBeNormal(invoker, invocation);
      return result;
    } catch (RpcException e) {
      // 如果是请求超时或者网络异常,进行异常统计
      if (!e.isBiz()) {
        caughtException(invoker, invocation, e);
      }
      throw e;
    }
  }

  /**
   * 将服务恢复正常
   *
   * @param invoker
   * @param invocation
   */
  private void toBeNormal(Invoker<?> invoker, Invocation invocation) {
    String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY);
    String method = invocation.getMethodName();
    StringBuffer methodConfig = new StringBuffer(Config.DUBBO_REFERENCE_PREFIX);
    methodConfig.append(interfaceName).append(".").append(method);
    String methodKey = methodConfig.toString();
    // 从其中删除对应的异常计数器
    BreakCounter counter = breakCounterMap.remove(methodKey);
    if (counter != null) {
      logger.info("[{}] [{}.{}] to be normal", localHost, interfaceName, methodKey);
      // 将这个counter设置为失效
      counter.disable();
    }
  }

  /**
   * 这里会判断当前调用服务的状态,分析判断是否需要进入降级状态 如果服务在指定的时间区间内累积的错误,达到了配置的次数,则进入服务降级
   * 如果满足上面条件,并且满足重试机制,则也不会进入降级流程,而是触发远程服务调用
   *
   * @param invoker
   * @param invocation
   * @return
   */
  private boolean checkNeedCircuitBreak(Invoker<?> invoker, Invocation invocation) {
    String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY);
    String method = invocation.getMethodName();
    String methodKey = Config.getMethodPropertyName(invoker, invocation).toString();
    int limit = Config.getBreakLimit(invoker, invocation);
    BreakCounter breakCounter = breakCounterMap.get(methodKey);
    if (breakCounter != null && breakCounter.isEnable()) {
      long currentExceptionCount = breakCounter.getCurrentExceptionCount();
      long currentBreakCount = breakCounter.getCurrentBreakCount();
      logger.info(
          "[{}] check invoke [{}.{}] circuit break,current exception count [{}]  limit [{}]",
          localHost,
          interfaceName,
          method,
          currentExceptionCount,
          limit);
      if (limit <= currentExceptionCount) {
        if (currentBreakCount > 0 && needRetry(invoker, invocation, currentBreakCount)) {
          logger.info(
              "[{}] retry invoke [{}.{}] current break count [{}]",
              localHost,
              interfaceName,
              method,
              currentBreakCount);
          breakCounter.incrementRetryTimes();
          return false;
        }
        return true;
      }
    }
    return false;
  }

  private boolean needRetry(Invoker<?> invoker, Invocation invocation, long currentBreakCount) {
    String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY);
    String method = invocation.getMethodName();
    int frequency = Config.getRetryFrequency(invoker, invocation);
    logger.info(
        "[{}] check invoke [{}.{}] need retry,current break count [{}],retry frequency [{}]",
        localHost,
        interfaceName,
        method,
        currentBreakCount,
        frequency);
    if (currentBreakCount % frequency == 0) {
      logger.info("[{}] retry invoke [{}.{}]", localHost, interfaceName, method);
      return true;
    }
    return false;
  }

  private <T extends Object> Result doCircuitBreak(Invoker<?> invoker, Invocation invocation)
      throws RpcException {
    String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY);
    String circuitBreaker = interfaceName + "CircuitBreak";
    incrementBreakCount(invoker, invocation);
    try {
      logger.info("[{}] check has class [{}] to handle circuit break", localHost, circuitBreaker);
      Invoker<?> breakerInvoker = null;
      if (CIRCUIT_BREAKER_INVOKER_CACHE.containsKey(circuitBreaker)) {
        breakerInvoker = CIRCUIT_BREAKER_INVOKER_CACHE.get(circuitBreaker);
      } else {
        Class<T> breakerType = (Class<T>) Class.forName(circuitBreaker);
        Class<T> interfaceType = (Class<T>) Class.forName(interfaceName);
        if (interfaceType.isAssignableFrom(breakerType)) {
          logger.info("[{}] handle circuit break by class [{}]", localHost, circuitBreaker);
          T breaker = breakerType.newInstance();
          breakerInvoker = proxyFactory.getInvoker(breaker, interfaceType, invoker.getUrl());
          Invoker<?> oldInvoker =
              CIRCUIT_BREAKER_INVOKER_CACHE.putIfAbsent(circuitBreaker, breakerInvoker);
          if (oldInvoker != null) {
            breakerInvoker = oldInvoker;
          }
        }
      }
      if (breakerInvoker != null) {
        return breakerInvoker.invoke(invocation);
      }
    } catch (Exception e) {
      logger.error("failed to invoke circuit breaker", e);
    }
    logger.info("[{}] handle circuit break by exception", localHost);
    CircuitBreakerException baseBusinessException =
        new CircuitBreakerException(interfaceName, invocation.getMethodName());
    throw baseBusinessException;
  }

  private void incrementBreakCount(Invoker<?> invoker, Invocation invocation) {
    String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY);
    String method = invocation.getMethodName();
    StringBuffer interfaceConfig = new StringBuffer(Config.DUBBO_REFERENCE_PREFIX);
    interfaceConfig.append(interfaceName);
    StringBuffer methodConfig = new StringBuffer(interfaceConfig.toString());
    methodConfig.append(".").append(method);
    String methodKey = methodConfig.toString();
    BreakCounter counter = breakCounterMap.get(methodKey);
    counter.incrementBreakCount();
  }

  private void caughtException(Invoker<?> invoker, Invocation invocation, Exception e) {
    String interfaceName = invoker.getUrl().getParameter(Constants.INTERFACE_KEY);
    String method = invocation.getMethodName();
    StringBuffer interfaceConfig = new StringBuffer(Config.DUBBO_REFERENCE_PREFIX);
    interfaceConfig.append(interfaceName);
    StringBuffer methodConfig = new StringBuffer(interfaceConfig.toString());
    methodConfig.append(".").append(method);
    String methodKey = methodConfig.toString();
    int timeout =
        invoker
            .getUrl()
            .getMethodParameter(
                invocation.getMethodName(), Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
    int limit = Config.getBreakLimit(invoker, invocation);
    // 一个异常的有效期,是通过连续出现异常数量乘以每个调用的超时时间,比如你配置连续出现10次异常之后进行服务降级,并且每次服务调用的超时时间是2000ms的话,同时
    // 每个服务重试次数是为2次,那么就是在(2+1)*2000*10
    ExceptionMarker breakMarker =
        new ExceptionMarker(System.currentTimeMillis(), limit * timeout, e);
    if (!breakCounterMap.containsKey(methodKey)) {
      BreakCounter oldValue = breakCounterMap.putIfAbsent(methodKey, new BreakCounter(methodKey));
      // 返回的oldValue为空,表示之前没有创建了赌赢的异常计数器,则需要对它分配一个loop
      if (oldValue == null) {
        nextLoop().register(breakCounterMap.get(methodKey));
      }
    }
    BreakCounter counter = breakCounterMap.get(methodKey);
    counter.addExceptionMarker(breakMarker);
    logger.info(
        "[{}] caught exception for rpc invoke [{}.{}],current exception count [{}]",
        localHost,
        interfaceName,
        method,
        counter.getCurrentExceptionCount());
  }
}
@SuppressWarnings({"rawtypes", "unchecked"})
public class RegistryDirectoryTest {

  RegistryFactory registryFactory =
      ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
  Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
  String service = DemoService.class.getName();
  RpcInvocation invocation = new RpcInvocation();

  URL noMeaningUrl =
      URL.valueOf("notsupport:/" + service + "?refer=" + URL.encode("interface=" + service));
  URL SERVICEURL = URL.valueOf("dubbo://127.0.0.1:9091/" + service + "?lazy=true");
  URL SERVICEURL2 = URL.valueOf("dubbo://127.0.0.1:9092/" + service + "?lazy=true");
  URL SERVICEURL3 = URL.valueOf("dubbo://127.0.0.1:9093/" + service + "?lazy=true");
  URL SERVICEURL_DUBBO_NOPATH = URL.valueOf("dubbo://127.0.0.1:9092" + "?lazy=true");

  @Before
  public void setUp() {}

  private RegistryDirectory getRegistryDirectory(URL url) {
    RegistryDirectory registryDirectory = new RegistryDirectory(URL.class, url);
    registryDirectory.setProtocol(protocol);
    // asert empty
    List invokers = registryDirectory.list(invocation);
    Assert.assertEquals(0, invokers.size());
    Assert.assertEquals(false, registryDirectory.isAvailable());
    return registryDirectory;
  }

  private RegistryDirectory getRegistryDirectory() {
    return getRegistryDirectory(noMeaningUrl);
  }

  @Test
  public void test_Constructor_WithErrorParam() {
    try {
      new RegistryDirectory(null, null);
      fail();
    } catch (IllegalArgumentException e) {

    }
    try {
      // null url
      new RegistryDirectory(null, noMeaningUrl);
      fail();
    } catch (IllegalArgumentException e) {

    }
    try {
      // no servicekey
      new RegistryDirectory(RegistryDirectoryTest.class, URL.valueOf("dubbo://10.20.30.40:9090"));
      fail();
    } catch (IllegalArgumentException e) {

    }
  }

  @Test
  public void test_Constructor_CheckStatus() throws Exception {
    URL url =
        URL.valueOf("notsupported://10.20.30.40/" + service + "?a=b")
            .addParameterAndEncoded(Constants.REFER_KEY, "foo=bar");
    RegistryDirectory reg = getRegistryDirectory(url);
    Field field = reg.getClass().getDeclaredField("queryMap");
    field.setAccessible(true);
    Map<String, String> queryMap = (Map<String, String>) field.get(reg);
    Assert.assertEquals("bar", queryMap.get("foo"));
    Assert.assertEquals(url.clearParameters().addParameter("foo", "bar"), reg.getUrl());
  }

  @Test
  public void testNotified_Normal() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    test_Notified2invokers(registryDirectory);
    test_Notified1invokers(registryDirectory);
    test_Notified3invokers(registryDirectory);
    testforbid(registryDirectory);
  }

  /** 测试推送只有router的情况 */
  @Test
  public void testNotified_Normal_withRouters() {
    LogUtil.start();
    RegistryDirectory registryDirectory = getRegistryDirectory();
    test_Notified1invokers(registryDirectory);
    test_Notified_only_routers(registryDirectory);
    Assert.assertEquals(true, registryDirectory.isAvailable());
    Assert.assertTrue("notify no invoker urls ,should not error", LogUtil.checkNoError());
    LogUtil.stop();
    test_Notified2invokers(registryDirectory);
  }

  @Test
  public void testNotified_WithError() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    List<URL> serviceUrls = new ArrayList<URL>();
    // ignore error log
    URL badurl = URL.valueOf("notsupported://127.0.0.1/" + service);
    serviceUrls.add(badurl);
    serviceUrls.add(SERVICEURL);

    registryDirectory.notify(serviceUrls);
    Assert.assertEquals(true, registryDirectory.isAvailable());
    List invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());
  }

  @Test
  public void testNotified_WithDuplicateUrls() {
    List<URL> serviceUrls = new ArrayList<URL>();
    // ignore error log
    serviceUrls.add(SERVICEURL);
    serviceUrls.add(SERVICEURL);

    RegistryDirectory registryDirectory = getRegistryDirectory();
    registryDirectory.notify(serviceUrls);
    List invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());
  }

  // forbid
  private void testforbid(RegistryDirectory registryDirectory) {
    invocation = new RpcInvocation();
    List<URL> serviceUrls = new ArrayList<URL>();
    serviceUrls.add(
        new URL(
            Constants.EMPTY_PROTOCOL,
            Constants.ANYHOST_VALUE,
            0,
            service,
            Constants.CATEGORY_KEY,
            Constants.PROVIDERS_CATEGORY));
    registryDirectory.notify(serviceUrls);
    Assert.assertEquals(
        "invokers size=0 ,then the registry directory is not available",
        false,
        registryDirectory.isAvailable());
    try {
      registryDirectory.list(invocation);
      fail("forbid must throw RpcException");
    } catch (RpcException e) {
      Assert.assertEquals(RpcException.FORBIDDEN_EXCEPTION, e.getCode());
    }
  }

  // 测试调用和registry url的path无关
  @Test
  public void test_NotifiedDubbo1() {
    URL errorPathUrl =
        URL.valueOf("notsupport:/" + "xxx" + "?refer=" + URL.encode("interface=" + service));
    RegistryDirectory registryDirectory = getRegistryDirectory(errorPathUrl);
    List<URL> serviceUrls = new ArrayList<URL>();
    URL Dubbo1URL = URL.valueOf("dubbo://127.0.0.1:9098?lazy=true");
    serviceUrls.add(Dubbo1URL.addParameter("methods", "getXXX"));
    registryDirectory.notify(serviceUrls);
    Assert.assertEquals(true, registryDirectory.isAvailable());

    invocation = new RpcInvocation();

    List<Invoker<DemoService>> invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());

    invocation.setMethodName("getXXX");
    invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());
    Assert.assertEquals(DemoService.class.getName(), invokers.get(0).getUrl().getPath());
  }

  // notify one invoker
  private void test_Notified_only_routers(RegistryDirectory registryDirectory) {
    List<URL> serviceUrls = new ArrayList<URL>();
    serviceUrls.add(URL.valueOf("empty://127.0.0.1/?category=routers"));
    registryDirectory.notify(serviceUrls);
  }
  // notify one invoker
  private void test_Notified1invokers(RegistryDirectory registryDirectory) {

    List<URL> serviceUrls = new ArrayList<URL>();
    serviceUrls.add(
        SERVICEURL.addParameter(
            "methods", "getXXX1")); // .addParameter("refer.autodestroy", "true")
    registryDirectory.notify(serviceUrls);
    Assert.assertEquals(true, registryDirectory.isAvailable());

    invocation = new RpcInvocation();

    List invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());

    invocation.setMethodName("getXXX");
    invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());

    invocation.setMethodName("getXXX1");
    invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());

    invocation.setMethodName("getXXX2");
    invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());
  }

  // 两个invoker===================================
  private void test_Notified2invokers(RegistryDirectory registryDirectory) {
    List<URL> serviceUrls = new ArrayList<URL>();
    serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1"));
    serviceUrls.add(SERVICEURL2.addParameter("methods", "getXXX1,getXXX2"));
    serviceUrls.add(SERVICEURL2.addParameter("methods", "getXXX1,getXXX2"));

    registryDirectory.notify(serviceUrls);
    Assert.assertEquals(true, registryDirectory.isAvailable());

    invocation = new RpcInvocation();

    List invokers = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers.size());

    invocation.setMethodName("getXXX");
    invokers = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers.size());

    invocation.setMethodName("getXXX1");
    invokers = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers.size());

    invocation.setMethodName("getXXX2");
    invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());
  }

  // 通知成3个invoker===================================
  private void test_Notified3invokers(RegistryDirectory registryDirectory) {
    List<URL> serviceUrls = new ArrayList<URL>();
    serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1"));
    serviceUrls.add(SERVICEURL2.addParameter("methods", "getXXX1,getXXX2"));
    serviceUrls.add(SERVICEURL3.addParameter("methods", "getXXX1,getXXX2,getXXX3"));

    registryDirectory.notify(serviceUrls);
    Assert.assertEquals(true, registryDirectory.isAvailable());

    invocation = new RpcInvocation();

    List invokers = registryDirectory.list(invocation);
    Assert.assertEquals(3, invokers.size());

    invocation.setMethodName("getXXX");
    invokers = registryDirectory.list(invocation);
    Assert.assertEquals(3, invokers.size());

    invocation.setMethodName("getXXX1");
    invokers = registryDirectory.list(invocation);
    Assert.assertEquals(3, invokers.size());

    invocation.setMethodName("getXXX2");
    invokers = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers.size());

    invocation.setMethodName("getXXX3");
    invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());
  }

  @Test
  public void testParametersMerge() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    URL regurl =
        noMeaningUrl
            .addParameter("test", "reg")
            .addParameterAndEncoded(
                Constants.REFER_KEY,
                "key=query&" + Constants.LOADBALANCE_KEY + "=" + LeastActiveLoadBalance.NAME);
    RegistryDirectory<RegistryDirectoryTest> registryDirectory2 =
        new RegistryDirectory(RegistryDirectoryTest.class, regurl);
    registryDirectory2.setProtocol(protocol);

    List<URL> serviceUrls = new ArrayList<URL>();
    // 检验注册中心的参数需要被清除
    {
      serviceUrls.clear();
      serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1"));
      registryDirectory.notify(serviceUrls);

      invocation = new RpcInvocation();
      List invokers = registryDirectory.list(invocation);

      Invoker invoker = (Invoker) invokers.get(0);
      URL url = invoker.getUrl();
      Assert.assertEquals(null, url.getParameter("key"));
    }
    // 检验服务提供方的参数需要merge
    {
      serviceUrls.clear();
      serviceUrls.add(
          SERVICEURL.addParameter("methods", "getXXX2").addParameter("key", "provider"));

      registryDirectory.notify(serviceUrls);
      invocation = new RpcInvocation();
      List invokers = registryDirectory.list(invocation);

      Invoker invoker = (Invoker) invokers.get(0);
      URL url = invoker.getUrl();
      Assert.assertEquals("provider", url.getParameter("key"));
    }
    // 检验服务query的参数需要与providermerge 。
    {
      serviceUrls.clear();
      serviceUrls.add(
          SERVICEURL.addParameter("methods", "getXXX3").addParameter("key", "provider"));

      registryDirectory2.notify(serviceUrls);
      invocation = new RpcInvocation();
      List invokers = registryDirectory2.list(invocation);

      Invoker invoker = (Invoker) invokers.get(0);
      URL url = invoker.getUrl();
      Assert.assertEquals("query", url.getParameter("key"));
    }

    {
      serviceUrls.clear();
      serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1"));
      registryDirectory.notify(serviceUrls);

      invocation = new RpcInvocation();
      List invokers = registryDirectory.list(invocation);

      Invoker invoker = (Invoker) invokers.get(0);
      URL url = invoker.getUrl();
      Assert.assertEquals(false, url.getParameter(Constants.CHECK_KEY, false));
    }
    {
      serviceUrls.clear();
      serviceUrls.add(
          SERVICEURL.addParameter(Constants.LOADBALANCE_KEY, RoundRobinLoadBalance.NAME));
      registryDirectory2.notify(serviceUrls);

      invocation = new RpcInvocation();
      invocation.setMethodName("get");
      List invokers = registryDirectory2.list(invocation);

      Invoker invoker = (Invoker) invokers.get(0);
      URL url = invoker.getUrl();
      Assert.assertEquals(
          LeastActiveLoadBalance.NAME, url.getMethodParameter("get", Constants.LOADBALANCE_KEY));
    }
    // test geturl
    {
      Assert.assertEquals(null, registryDirectory2.getUrl().getParameter("mock"));
      serviceUrls.clear();
      serviceUrls.add(SERVICEURL.addParameter(Constants.MOCK_KEY, "true"));
      registryDirectory2.notify(serviceUrls);

      Assert.assertEquals("true", registryDirectory2.getUrl().getParameter("mock"));
    }
  }

  /**
   * When destroying, RegistryDirectory should: 1. be disconnected from Registry 2. destroy all
   * invokers
   */
  @Test
  public void testDestroy() {
    RegistryDirectory registryDirectory = getRegistryDirectory();

    List<URL> serviceUrls = new ArrayList<URL>();
    serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1"));
    serviceUrls.add(SERVICEURL2.addParameter("methods", "getXXX1,getXXX2"));
    serviceUrls.add(SERVICEURL3.addParameter("methods", "getXXX1,getXXX2,getXXX3"));

    registryDirectory.notify(serviceUrls);
    List<Invoker> invokers = registryDirectory.list(invocation);
    Assert.assertEquals(true, registryDirectory.isAvailable());
    Assert.assertEquals(true, invokers.get(0).isAvailable());

    registryDirectory.destroy();
    Assert.assertEquals(false, registryDirectory.isAvailable());
    Assert.assertEquals(false, invokers.get(0).isAvailable());
    registryDirectory.destroy();

    Map<String, List<Invoker<RegistryDirectoryTest>>> methodInvokerMap =
        registryDirectory.getMethodInvokerMap();
    Map<String, Invoker<RegistryDirectoryTest>> urlInvokerMap =
        registryDirectory.getUrlInvokerMap();

    Assert.assertTrue(methodInvokerMap == null);
    Assert.assertEquals(0, urlInvokerMap.size());
    // List<U> urls = mockRegistry.getSubscribedUrls();

    RpcInvocation inv = new RpcInvocation();
    try {
      registryDirectory.list(inv);
      fail();
    } catch (RpcException e) {
      Assert.assertTrue(e.getMessage().contains("already destroyed"));
    }
  }

  @Test
  public void testDestroy_WithDestroyRegistry() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    CountDownLatch latch = new CountDownLatch(1);
    registryDirectory.setRegistry(new MockRegistry(latch));
    registryDirectory.subscribe(
        URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/DemoService?category=providers"));
    registryDirectory.destroy();
    Assert.assertEquals(0, latch.getCount());
  }

  @Test
  public void testDestroy_WithDestroyRegistry_WithError() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    registryDirectory.setRegistry(new MockRegistry(true));
    registryDirectory.destroy();
  }

  @Test
  public void testDubbo1UrlWithGenericInvocation() {

    RegistryDirectory registryDirectory = getRegistryDirectory();

    List<URL> serviceUrls = new ArrayList<URL>();
    URL serviceURL = SERVICEURL_DUBBO_NOPATH.addParameter("methods", "getXXX1,getXXX2,getXXX3");
    serviceUrls.add(serviceURL);

    registryDirectory.notify(serviceUrls);

    // Object $invoke(String method, String[] parameterTypes, Object[] args) throws
    // GenericException;
    invocation =
        new RpcInvocation(
            Constants.$INVOKE,
            new Class[] {String.class, String[].class, Object[].class},
            new Object[] {"getXXX1", "", new Object[] {}});

    List<Invoker> invokers = registryDirectory.list(invocation);

    Assert.assertEquals(1, invokers.size());
    Assert.assertEquals(
        serviceURL
            .setPath(service)
            .addParameters("check", "false", "interface", DemoService.class.getName()),
        invokers.get(0).getUrl());
  }

  enum Param {
    MORGAN,
  };

  /**
   * When the first arg of a method is String or Enum, Registry server can do parameter-value-based
   * routing.
   */
  @Test
  public void testParmeterRoute() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    List<URL> serviceUrls = new ArrayList<URL>();
    serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1.napoli"));
    serviceUrls.add(SERVICEURL2.addParameter("methods", "getXXX1.MORGAN,getXXX2"));
    serviceUrls.add(SERVICEURL3.addParameter("methods", "getXXX1.morgan,getXXX2,getXXX3"));

    registryDirectory.notify(serviceUrls);

    invocation =
        new RpcInvocation(
            Constants.$INVOKE,
            new Class[] {String.class, String[].class, Object[].class},
            new Object[] {"getXXX1", new String[] {"Enum"}, new Object[] {Param.MORGAN}});

    List invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());
  }

  /** Empty notify cause forbidden, non-empty notify cancels forbidden state */
  @Test
  public void testEmptyNotifyCauseForbidden() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    List invokers = null;

    List<URL> serviceUrls = new ArrayList<URL>();
    registryDirectory.notify(serviceUrls);

    RpcInvocation inv = new RpcInvocation();
    try {
      invokers = registryDirectory.list(inv);
    } catch (RpcException e) {
      Assert.assertEquals(RpcException.FORBIDDEN_EXCEPTION, e.getCode());
      Assert.assertEquals(false, registryDirectory.isAvailable());
    }

    serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1"));
    serviceUrls.add(SERVICEURL2.addParameter("methods", "getXXX1,getXXX2"));
    serviceUrls.add(SERVICEURL3.addParameter("methods", "getXXX1,getXXX2,getXXX3"));

    registryDirectory.notify(serviceUrls);
    inv.setMethodName("getXXX2");
    invokers = registryDirectory.list(inv);
    Assert.assertEquals(true, registryDirectory.isAvailable());
    Assert.assertEquals(2, invokers.size());
  }

  private static boolean isScriptUnsupported =
      new ScriptEngineManager().getEngineByName("javascript") == null;

  /**
   * 1. notify twice, the second time notified router rules should completely replace the former
   * one. 2. notify with no router url, do nothing to current routers 3. notify with only one router
   * url, with router=clean, clear all current routers
   */
  @Test
  public void testNotifyRouterUrls() {
    if (isScriptUnsupported) return;
    RegistryDirectory registryDirectory = getRegistryDirectory();
    URL routerurl = URL.valueOf(Constants.ROUTE_PROTOCOL + "://127.0.0.1:9096/");
    URL routerurl2 = URL.valueOf(Constants.ROUTE_PROTOCOL + "://127.0.0.1:9097/");

    List<URL> serviceUrls = new ArrayList<URL>();
    // without ROUTER_KEY, the first router should not be created.
    serviceUrls.add(
        routerurl
            .addParameter(Constants.CATEGORY_KEY, Constants.ROUTERS_CATEGORY)
            .addParameter(Constants.TYPE_KEY, "javascript")
            .addParameter(Constants.ROUTER_KEY, "notsupported")
            .addParameter(Constants.RULE_KEY, "function test1(){}"));
    serviceUrls.add(
        routerurl2
            .addParameter(Constants.CATEGORY_KEY, Constants.ROUTERS_CATEGORY)
            .addParameter(Constants.TYPE_KEY, "javascript")
            .addParameter(Constants.ROUTER_KEY, ScriptRouterFactory.NAME)
            .addParameter(Constants.RULE_KEY, "function test1(){}"));

    registryDirectory.notify(serviceUrls);
    List<Router> routers = registryDirectory.getRouters();
    // default invocation selector
    Assert.assertEquals(1 + 1, routers.size());
    Assert.assertTrue(
        ScriptRouter.class == routers.get(1).getClass()
            || ScriptRouter.class == routers.get(0).getClass());

    registryDirectory.notify(new ArrayList<URL>());
    routers = registryDirectory.getRouters();
    Assert.assertEquals(1 + 1, routers.size());
    Assert.assertTrue(
        ScriptRouter.class == routers.get(1).getClass()
            || ScriptRouter.class == routers.get(0).getClass());

    serviceUrls.clear();
    serviceUrls.add(routerurl.addParameter(Constants.ROUTER_KEY, Constants.ROUTER_TYPE_CLEAR));
    registryDirectory.notify(serviceUrls);
    routers = registryDirectory.getRouters();
    Assert.assertEquals(0 + 1, routers.size());
  }

  /** 测试override规则是否优先 场景:先推送override,后推送invoker */
  @Test
  public void testNotifyoverrideUrls_beforeInvoker() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    List<URL> overrideUrls = new ArrayList<URL>();
    overrideUrls.add(URL.valueOf("override://0.0.0.0?timeout=1&connections=5"));
    registryDirectory.notify(overrideUrls);
    // 注册中心初始只推送override,dirctory状态应该是false,因为没有invoker存在。
    Assert.assertEquals(false, registryDirectory.isAvailable());

    // 在推送两个provider,directory状态恢复为true
    List<URL> serviceUrls = new ArrayList<URL>();
    serviceUrls.add(SERVICEURL.addParameter("timeout", "1000"));
    serviceUrls.add(SERVICEURL2.addParameter("timeout", "1000").addParameter("connections", "10"));

    registryDirectory.notify(serviceUrls);
    Assert.assertEquals(true, registryDirectory.isAvailable());

    // 开始验证参数值

    invocation = new RpcInvocation();

    List<Invoker<?>> invokers = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers.size());

    Assert.assertEquals(
        "override rute must be first priority",
        "1",
        invokers.get(0).getUrl().getParameter("timeout"));
    Assert.assertEquals(
        "override rute must be first priority",
        "5",
        invokers.get(0).getUrl().getParameter("connections"));
  }

  /** 测试override规则是否优先 场景:先推送override,后推送invoker */
  @Test
  public void testNotifyoverrideUrls_afterInvoker() {
    RegistryDirectory registryDirectory = getRegistryDirectory();

    // 在推送两个provider,directory状态恢复为true
    List<URL> serviceUrls = new ArrayList<URL>();
    serviceUrls.add(SERVICEURL.addParameter("timeout", "1000"));
    serviceUrls.add(SERVICEURL2.addParameter("timeout", "1000").addParameter("connections", "10"));

    registryDirectory.notify(serviceUrls);
    Assert.assertEquals(true, registryDirectory.isAvailable());

    List<URL> overrideUrls = new ArrayList<URL>();
    overrideUrls.add(URL.valueOf("override://0.0.0.0?timeout=1&connections=5"));
    registryDirectory.notify(overrideUrls);

    // 开始验证参数值

    invocation = new RpcInvocation();

    List<Invoker<?>> invokers = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers.size());

    Assert.assertEquals(
        "override rute must be first priority",
        "1",
        invokers.get(0).getUrl().getParameter("timeout"));
    Assert.assertEquals(
        "override rute must be first priority",
        "5",
        invokers.get(0).getUrl().getParameter("connections"));
  }

  /** 测试override规则是否优先 场景:与invoker 一起推override规则 */
  @Test
  public void testNotifyoverrideUrls_withInvoker() {
    RegistryDirectory registryDirectory = getRegistryDirectory();

    List<URL> durls = new ArrayList<URL>();
    durls.add(SERVICEURL.addParameter("timeout", "1000"));
    durls.add(SERVICEURL2.addParameter("timeout", "1000").addParameter("connections", "10"));
    durls.add(URL.valueOf("override://0.0.0.0?timeout=1&connections=5"));

    registryDirectory.notify(durls);
    Assert.assertEquals(true, registryDirectory.isAvailable());

    // 开始验证参数值

    invocation = new RpcInvocation();

    List<Invoker<?>> invokers = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers.size());

    Assert.assertEquals(
        "override rute must be first priority",
        "1",
        invokers.get(0).getUrl().getParameter("timeout"));
    Assert.assertEquals(
        "override rute must be first priority",
        "5",
        invokers.get(0).getUrl().getParameter("connections"));
  }

  /** 测试override规则是否优先 场景:推送的规则与provider的参数是一样的 期望:不需要重新引用 */
  @Test
  public void testNotifyoverrideUrls_Nouse() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    invocation = new RpcInvocation();

    List<URL> durls = new ArrayList<URL>();
    durls.add(SERVICEURL.addParameter("timeout", "1")); // 一个一样,一个不一样
    durls.add(SERVICEURL2.addParameter("timeout", "1").addParameter("connections", "5"));
    registryDirectory.notify(durls);
    List<Invoker<?>> invokers = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers.size());
    Invoker<?> a1Invoker = invokers.get(0);
    Invoker<?> b1Invoker = invokers.get(1);

    durls = new ArrayList<URL>();
    durls.add(URL.valueOf("override://0.0.0.0?timeout=1&connections=5"));
    registryDirectory.notify(durls);
    Assert.assertEquals(true, registryDirectory.isAvailable());

    invokers = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers.size());

    Invoker<?> a2Invoker = invokers.get(0);
    Invoker<?> b2Invoker = invokers.get(1);
    // 参数不一样,必须重新引用
    Assert.assertFalse("object not same", a1Invoker == a2Invoker);

    // 参数一样,不能重新引用
    Assert.assertTrue("object same", b1Invoker == b2Invoker);
  }

  /** 测试针对某个provider的Override规则 */
  @Test
  public void testNofityOverrideUrls_Provider() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    invocation = new RpcInvocation();

    List<URL> durls = new ArrayList<URL>();
    durls.add(SERVICEURL.setHost("10.20.30.140").addParameter("timeout", "1")); // 一个一样,一个不一样
    durls.add(SERVICEURL2.setHost("10.20.30.141").addParameter("timeout", "2"));
    registryDirectory.notify(durls);

    durls = new ArrayList<URL>();
    durls.add(URL.valueOf("override://0.0.0.0?timeout=3"));
    durls.add(URL.valueOf("override://10.20.30.141:9092?timeout=4"));
    registryDirectory.notify(durls);

    List<Invoker<?>> invokers = registryDirectory.list(invocation);
    Invoker<?> aInvoker = invokers.get(0);
    Invoker<?> bInvoker = invokers.get(1);
    Assert.assertEquals("3", aInvoker.getUrl().getParameter("timeout"));
    Assert.assertEquals("4", bInvoker.getUrl().getParameter("timeout"));
  }

  /** 测试清除override规则,同时下发清除规则和其他override规则 测试是否能够恢复到推送时的providerUrl */
  @Test
  public void testNofityOverrideUrls_Clean1() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    invocation = new RpcInvocation();

    List<URL> durls = new ArrayList<URL>();
    durls.add(SERVICEURL.setHost("10.20.30.140").addParameter("timeout", "1"));
    registryDirectory.notify(durls);

    durls = new ArrayList<URL>();
    durls.add(URL.valueOf("override://0.0.0.0?timeout=1000"));
    registryDirectory.notify(durls);

    durls = new ArrayList<URL>();
    durls.add(URL.valueOf("override://0.0.0.0?timeout=3"));
    durls.add(URL.valueOf("override://0.0.0.0"));
    registryDirectory.notify(durls);

    List<Invoker<?>> invokers = registryDirectory.list(invocation);
    Invoker<?> aInvoker = invokers.get(0);
    // 需要恢复到最初的providerUrl
    Assert.assertEquals("1", aInvoker.getUrl().getParameter("timeout"));
  }

  /** 测试清除override规则,只下发override清除规则 测试是否能够恢复到推送时的providerUrl */
  @Test
  public void testNofityOverrideUrls_CleanOnly() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    invocation = new RpcInvocation();

    List<URL> durls = new ArrayList<URL>();
    durls.add(SERVICEURL.setHost("10.20.30.140").addParameter("timeout", "1"));
    registryDirectory.notify(durls);
    Assert.assertEquals(null, registryDirectory.getUrl().getParameter("mock"));

    // override
    durls = new ArrayList<URL>();
    durls.add(URL.valueOf("override://0.0.0.0?timeout=1000&mock=fail"));
    registryDirectory.notify(durls);
    List<Invoker<?>> invokers = registryDirectory.list(invocation);
    Invoker<?> aInvoker = invokers.get(0);
    Assert.assertEquals("1000", aInvoker.getUrl().getParameter("timeout"));
    Assert.assertEquals("fail", registryDirectory.getUrl().getParameter("mock"));

    // override clean
    durls = new ArrayList<URL>();
    durls.add(URL.valueOf("override://0.0.0.0/dubbo.test.api.HelloService"));
    registryDirectory.notify(durls);
    invokers = registryDirectory.list(invocation);
    aInvoker = invokers.get(0);
    // 需要恢复到最初的providerUrl
    Assert.assertEquals("1", aInvoker.getUrl().getParameter("timeout"));

    Assert.assertEquals(null, registryDirectory.getUrl().getParameter("mock"));
  }

  /** 测试同时推送清除override和针对某个provider的override 看override是否能够生效 */
  @Test
  public void testNofityOverrideUrls_CleanNOverride() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    invocation = new RpcInvocation();

    List<URL> durls = new ArrayList<URL>();
    durls.add(SERVICEURL.setHost("10.20.30.140").addParameter("timeout", "1"));
    registryDirectory.notify(durls);

    durls = new ArrayList<URL>();
    durls.add(URL.valueOf("override://0.0.0.0?timeout=3"));
    durls.add(URL.valueOf("override://0.0.0.0"));
    durls.add(URL.valueOf("override://10.20.30.140:9091?timeout=4"));
    registryDirectory.notify(durls);

    List<Invoker<?>> invokers = registryDirectory.list(invocation);
    Invoker<?> aInvoker = invokers.get(0);
    Assert.assertEquals("4", aInvoker.getUrl().getParameter("timeout"));
  }

  /** 测试override通过enable=false,禁用所有服务提供者 预期:不能通过override禁用所有服务提供者. */
  @Test
  public void testNofityOverrideUrls_disabled_allProvider() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    invocation = new RpcInvocation();

    List<URL> durls = new ArrayList<URL>();
    durls.add(SERVICEURL.setHost("10.20.30.140"));
    durls.add(SERVICEURL.setHost("10.20.30.141"));
    registryDirectory.notify(durls);

    durls = new ArrayList<URL>();
    durls.add(URL.valueOf("override://0.0.0.0?" + Constants.ENABLED_KEY + "=false"));
    registryDirectory.notify(durls);

    List<Invoker<?>> invokers = registryDirectory.list(invocation);
    // 不能通过override禁用所有服务提供者.
    Assert.assertEquals(2, invokers.size());
  }

  /** 测试override通过enable=false,禁用指定服务提供者 预期:可以禁用指定的服务提供者。 */
  @Test
  public void testNofityOverrideUrls_disabled_specifiedProvider() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    invocation = new RpcInvocation();

    List<URL> durls = new ArrayList<URL>();
    durls.add(SERVICEURL.setHost("10.20.30.140"));
    durls.add(SERVICEURL.setHost("10.20.30.141"));
    registryDirectory.notify(durls);

    durls = new ArrayList<URL>();
    durls.add(URL.valueOf("override://10.20.30.140?" + Constants.DISABLED_KEY + "=true"));
    registryDirectory.notify(durls);

    List<Invoker<?>> invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());
    Assert.assertEquals("10.20.30.141", invokers.get(0).getUrl().getHost());

    durls = new ArrayList<URL>();
    durls.add(
        URL.valueOf(
            "empty://0.0.0.0?"
                + Constants.DISABLED_KEY
                + "=true&"
                + Constants.CATEGORY_KEY
                + "="
                + Constants.CONFIGURATORS_CATEGORY));
    registryDirectory.notify(durls);
    List<Invoker<?>> invokers2 = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers2.size());
  }

  /** 测试override通过enable=false,禁用指定服务提供者 预期:可以禁用指定的服务提供者。 */
  @Test
  public void testNofity_To_Decrease_provider() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    invocation = new RpcInvocation();

    List<URL> durls = new ArrayList<URL>();
    durls.add(SERVICEURL.setHost("10.20.30.140"));
    durls.add(SERVICEURL.setHost("10.20.30.141"));
    registryDirectory.notify(durls);

    List<Invoker<?>> invokers = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers.size());

    durls = new ArrayList<URL>();
    durls.add(SERVICEURL.setHost("10.20.30.140"));
    registryDirectory.notify(durls);
    List<Invoker<?>> invokers2 = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers2.size());
    Assert.assertEquals("10.20.30.140", invokers.get(0).getUrl().getHost());

    durls = new ArrayList<URL>();
    durls.add(
        URL.valueOf(
            "empty://0.0.0.0?"
                + Constants.DISABLED_KEY
                + "=true&"
                + Constants.CATEGORY_KEY
                + "="
                + Constants.CONFIGURATORS_CATEGORY));
    registryDirectory.notify(durls);
    List<Invoker<?>> invokers3 = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers3.size());
  }

  /** 测试override通过enable=false,禁用指定服务提供者 预期:可以禁用指定的服务提供者。 */
  @Test
  public void testNofity_disabled_specifiedProvider() {
    RegistryDirectory registryDirectory = getRegistryDirectory();
    invocation = new RpcInvocation();

    // 初始就禁用
    List<URL> durls = new ArrayList<URL>();
    durls.add(SERVICEURL.setHost("10.20.30.140").addParameter(Constants.ENABLED_KEY, "false"));
    durls.add(SERVICEURL.setHost("10.20.30.141"));
    registryDirectory.notify(durls);

    List<Invoker<?>> invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());
    Assert.assertEquals("10.20.30.141", invokers.get(0).getUrl().getHost());

    // 通过覆盖规则启用
    durls = new ArrayList<URL>();
    durls.add(URL.valueOf("override://10.20.30.140?" + Constants.DISABLED_KEY + "=false"));
    registryDirectory.notify(durls);
    List<Invoker<?>> invokers2 = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers2.size());
  }

  @Test
  public void testNotifyRouterUrls_Clean() {
    if (isScriptUnsupported) return;
    RegistryDirectory registryDirectory = getRegistryDirectory();
    URL routerurl =
        URL.valueOf(Constants.ROUTE_PROTOCOL + "://127.0.0.1:9096/")
            .addParameter(Constants.ROUTER_KEY, "javascript")
            .addParameter(Constants.RULE_KEY, "function test1(){}")
            .addParameter(Constants.ROUTER_KEY, "script"); // FIX
    // BAD

    List<URL> serviceUrls = new ArrayList<URL>();
    // without ROUTER_KEY, the first router should not be created.
    serviceUrls.add(routerurl);
    registryDirectory.notify(serviceUrls);
    List routers = registryDirectory.getRouters();
    Assert.assertEquals(1 + 1, routers.size());

    serviceUrls.clear();
    serviceUrls.add(routerurl.addParameter(Constants.ROUTER_KEY, Constants.ROUTER_TYPE_CLEAR));
    registryDirectory.notify(serviceUrls);
    routers = registryDirectory.getRouters();
    Assert.assertEquals(0 + 1, routers.size());
  }

  // mock protocol
  /** 测试mock provider下发 */
  @Test
  public void testNotify_MockProviderOnly() {
    RegistryDirectory registryDirectory = getRegistryDirectory();

    List<URL> serviceUrls = new ArrayList<URL>();
    serviceUrls.add(SERVICEURL.addParameter("methods", "getXXX1"));
    serviceUrls.add(SERVICEURL2.addParameter("methods", "getXXX1,getXXX2"));
    serviceUrls.add(SERVICEURL.setProtocol(Constants.MOCK_PROTOCOL));

    registryDirectory.notify(serviceUrls);
    Assert.assertEquals(true, registryDirectory.isAvailable());
    invocation = new RpcInvocation();

    List invokers = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers.size());

    RpcInvocation mockinvocation = new RpcInvocation();
    mockinvocation.setAttachment(Constants.INVOCATION_NEED_MOCK, "true");
    invokers = registryDirectory.list(mockinvocation);
    Assert.assertEquals(1, invokers.size());
  }

  // 测试protocol匹配,只选择匹配的protocol进行refer
  @Test
  public void test_Notified_acceptProtocol0() {
    URL errorPathUrl = URL.valueOf("notsupport:/xxx?refer=" + URL.encode("interface=" + service));
    RegistryDirectory registryDirectory = getRegistryDirectory(errorPathUrl);
    List<URL> serviceUrls = new ArrayList<URL>();
    URL dubbo1URL = URL.valueOf("dubbo://127.0.0.1:9098?lazy=true&methods=getXXX");
    URL dubbo2URL = URL.valueOf("injvm://127.0.0.1:9099?lazy=true&methods=getXXX");
    serviceUrls.add(dubbo1URL);
    serviceUrls.add(dubbo2URL);
    registryDirectory.notify(serviceUrls);

    invocation = new RpcInvocation();

    List<Invoker<DemoService>> invokers = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers.size());
  }

  // 测试protocol匹配,只选择匹配的protocol进行refer
  @Test
  public void test_Notified_acceptProtocol1() {
    URL errorPathUrl = URL.valueOf("notsupport:/xxx");
    errorPathUrl =
        errorPathUrl.addParameterAndEncoded(
            Constants.REFER_KEY, "interface=" + service + "&protocol=dubbo");
    RegistryDirectory registryDirectory = getRegistryDirectory(errorPathUrl);
    List<URL> serviceUrls = new ArrayList<URL>();
    URL dubbo1URL = URL.valueOf("dubbo://127.0.0.1:9098?lazy=true&methods=getXXX");
    URL dubbo2URL = URL.valueOf("injvm://127.0.0.1:9098?lazy=true&methods=getXXX");
    serviceUrls.add(dubbo1URL);
    serviceUrls.add(dubbo2URL);
    registryDirectory.notify(serviceUrls);

    invocation = new RpcInvocation();

    List<Invoker<DemoService>> invokers = registryDirectory.list(invocation);
    Assert.assertEquals(1, invokers.size());
  }

  // 测试protocol匹配,只选择匹配的protocol进行refer
  @Test
  public void test_Notified_acceptProtocol2() {
    URL errorPathUrl = URL.valueOf("notsupport:/xxx");
    errorPathUrl =
        errorPathUrl.addParameterAndEncoded(
            Constants.REFER_KEY, "interface=" + service + "&protocol=dubbo,injvm");
    RegistryDirectory registryDirectory = getRegistryDirectory(errorPathUrl);
    List<URL> serviceUrls = new ArrayList<URL>();
    URL dubbo1URL = URL.valueOf("dubbo://127.0.0.1:9098?lazy=true&methods=getXXX");
    URL dubbo2URL = URL.valueOf("injvm://127.0.0.1:9099?lazy=true&methods=getXXX");
    serviceUrls.add(dubbo1URL);
    serviceUrls.add(dubbo2URL);
    registryDirectory.notify(serviceUrls);

    invocation = new RpcInvocation();

    List<Invoker<DemoService>> invokers = registryDirectory.list(invocation);
    Assert.assertEquals(2, invokers.size());
  }

  private static interface DemoService {}

  private static class MockRegistry implements Registry {

    CountDownLatch latch;
    boolean destroyWithError;

    public MockRegistry(CountDownLatch latch) {
      this.latch = latch;
    }

    public MockRegistry(boolean destroyWithError) {
      this.destroyWithError = destroyWithError;
    }

    public void register(URL url) {}

    public void unregister(URL url) {}

    public void subscribe(URL url, NotifyListener listener) {}

    public void unsubscribe(URL url, NotifyListener listener) {
      if (latch != null) latch.countDown();
    }

    public List<URL> lookup(URL url) {
      return null;
    }

    public URL getUrl() {
      return null;
    }

    public boolean isAvailable() {
      return true;
    }

    public void destroy() {
      if (destroyWithError) {
        throw new RpcException("test exception ignore.");
      }
    }
  }
}
 /**
  * 用扩展点方法设置当前日志输出提供器 个人感觉此处才有用 但运行时候调用 会有很多额外操作 会更改所有缓存的日志输出器
  *
  * @param loggerAdapter
  */
 public static void setLoggerAdapter(String loggerAdapter) {
   if (loggerAdapter != null && loggerAdapter.length() > 0) {
     setLoggerAdapter(
         ExtensionLoader.getExtensionLoader(LoggerAdapter.class).getExtension(loggerAdapter));
   }
 }
Ejemplo n.º 11
0
 public static Group lookup(URL group) throws RemotingException {
   Networker networker =
       ExtensionLoader.getExtensionLoader(Networker.class).getExtension(group.getProtocol());
   return networker.lookup(group);
 }