16.路由如何实现

com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory.list(Invocation) 中织入了路由的逻辑;

使用路由的test case

package com.code260.ss.dubbo.demov.client.routeruler;

import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.extension.ExtensionLoader;
import com.alibaba.dubbo.registry.Registry;
import com.alibaba.dubbo.registry.RegistryFactory;
import com.code260.ss.dubbo.demov.facade.service.HelloService;

/**
 * <一句话功能简述> <功能详细描述>
 * 
 * @author Chenxiaguang
 * @version [版本号, 2015-8-12]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/com/code260/ss/dubbo/demov/client/conf/routerruler/applicationContext.xml")
public class HelloClientTest
{
    
    @Autowired
    private HelloService helloService;
    
    @BeforeClass
    public static void setup() {
    	RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();

    	// 获取注册中心,这里使用zk
    	Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://127.0.0.1:2182"));

    	// 注册中心上配置规则         
    	URL condition = URL.valueOf("condition://0.0.0.0/com.code260.ss.dubbo.demov.facade.service.HelloService?category=routers&dynamic=false&rule=" 
    	    	+ URL.encode("host = 192.168.2.3 => port = 20880"));
    	System.out.println(condition.toString());
    	registry.register(condition);
    }
    
    @Test
    public void testSayHello()
    {
    	this.helloService.sayHello("Simon1");
    	this.helloService.sayHello("Simon2");
    	this.helloService.sayHello("Simon3");
    	this.helloService.sayHello("Simon4");
    }
}

这是client侧的case,provider继续沿用多个provider的case,此时我们配置了路由规则,让192.168.2.3这台机器发出的调用都路由到端口是20880的服务节点上。

路由实现与服务发现衔接处

dubbo实现路由的地方是在com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory.list(Invocation)。

贴下相应调用栈和关键代码,调用栈如下:

RegistryDirectory<T>(AbstractDirectory<T>).list(Invocation) line: 81	
FailoverClusterInvoker<T>(AbstractClusterInvoker<T>).list(Invocation) line: 260	
FailoverClusterInvoker<T>(AbstractClusterInvoker<T>).invoke(Invocation) line: 219	
MockClusterInvoker<T>.invoke(Invocation) line: 72	
InvokerInvocationHandler.invoke(Object, Method, Object[]) line: 52	
proxy0.sayHello(String) line: not available	
HelloClientTest.testSayHello() line: 56

代码如下:

com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory.list(Invocation)

69    public List<Invoker<T>> list(Invocation invocation) throws RpcException {
70        if (destroyed){
71            throw new RpcException("Directory already destroyed .url: "+ getUrl());
        }
        List<Invoker<T>> invokers = doList(invocation);
74        List<Router> localRouters = this.routers; // local reference
        if (localRouters != null && localRouters.size() > 0) {
76            for (Router router: localRouters){
                try {
                    if (router.getUrl() == null || router.getUrl().getParameter(Constants.RUNTIME_KEY, true)) {
79                        invokers = router.route(invokers, getConsumerUrl(), invocation);
                    }
                } catch (Throwable t) {
                    logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
                }
            }
        }
        return invokers;
    }

79行会根据我们配置的路由规则,过滤出符合路由条件的invoker列表。

此处路由我们使用的是条件路由,具体实现比较简单,阅读com.alibaba.dubbo.rpc.cluster.router.condition.ConditionRouter.route(List<Invoker>, URL, Invocation)代码即可。