Dubbo路由到本地服务的实现

原因: 由于每次开发时都需要开启多个服务,非常占用内存与效率,而我们开发者一般只针对单一模块(服务)进行开发,所以希望能够实现控制dubbo的路由(服务器上的服务与本地服务)

实现逻辑:

   利用dubbo的路由规则扩展,如果请求上下文中存在已经配置的ip,即-Ddubbo.protocol.host,则会优先路由到同ip的服务,即你本地服务,如果没有,则匹配其他非本地服务

步骤:

1. 扩展路由规则

创建GrayscaleRouter类, 重点看route方法

import java.util.ArrayList;
import java.util.List;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.cluster.Router;

/**
 * 同ip访问同一个服务
 * 
 *
 */
public class GrayscaleRouter implements Router, Comparable<Router> {

    private URL url;
    private final int priority;

    public GrayscaleRouter(URL url) {
        this.url = url;
        this.priority = url.getParameter(Constants.PRIORITY_KEY, 0);
    }

    @Override
    public int compareTo(Router o) {
        if (o == null || o.getClass() != GrayscaleRouter.class) {
            return 1;
        }
        GrayscaleRouter c = (GrayscaleRouter)o;
        return this.priority == c.priority ? url.toFullString().compareTo(c.url.toFullString())
            : (this.priority > c.priority ? 1 : -1);
    }

    @Override
    public URL getUrl() {
        return url;
    }

   /**
     * 实现:添加一个路由规则,即本地服务路由到本地,其他服务调用zk上的
     * 		1.在启动本地服务时设置环境变量dubbo.protocol.host(本地ip),然后注册到服务器zk上
     *      2.新路由规则直接获取本地ip配置,然后遍历所有的invoker(服务),检测如果invoker上的ip是本地ip(本代码本地服务ip是10开头的),
     *        将其加入到一个List<Invoker<T>>并返回。
     */
    @Override
    public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL tempUrl, Invocation invocation)
        throws RpcException {
        String ip = RpcContext.getContext().getAttachment("client_ip");
        if (ip == null) {
            ip = System.getProperty("dubbo.protocol.host");
        }

        if (ip == null) {
            return excludeLocalService(invokers);
        } else {
            RpcContext.getContext().setAttachment("client_ip", ip);
        }
        List<Invoker<T>> result = new ArrayList<Invoker<T>>();
        for (Invoker<T> invoker : invokers) {
            if (ip.equals(invoker.getUrl().getIp())) {
                result.add(invoker);
            }
        }
        if (result.isEmpty()) {
            return excludeLocalService(invokers);
        }
        return result;
    }

    /**
     * 排除本地服务
     * 
     * @param invokers
     * @return
     */
    private <T> List<Invoker<T>> excludeLocalService(List<Invoker<T>> invokers) {
        List<Invoker<T>> result = new ArrayList<Invoker<T>>();
        invokers.forEach(invoker -> {
            String serviceIp = invoker.getUrl().getIp();
            if (!serviceIp.startsWith("10.")) {
                result.add(invoker);
            }
        });
        return result;
    }

    @Override
    public boolean equals(Object object) {
        return super.equals(object);
    }
    
    @Override
    public int hashCode(){
        return super.hashCode();
    }

}

创建GrayscaleRouterFactory类

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.cluster.Router;
import com.alibaba.dubbo.rpc.cluster.RouterFactory;

/**
 * 根据ip访问特定接口
 *
 */
public class GrayscaleRouterFactory implements RouterFactory {

    @Override
    public Router getRouter(URL url) {
        return new GrayscaleRouter(url);
    }

}

2. zk上添加路由规则

创建并执行DubboConfig类,给所有服务添加路由规则,需自己指定注册中心,新增一个服务就需要执行一次,会自动给所有服务添加路由规则

import java.util.List;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

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.wu.trade.common.exceptions.CheckException;

/**
 * dubbo的配置,路由规则加载
 * 
 *
 */
@Component
public class DubboConfig {

    static Logger logger = LoggerFactory.getLogger(DubboConfig.class);

    /**
     * 添加路由规则
     * 
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) {
        // 服务器zk地址        
        String zkServerPath = "192.168.16.203:2181";
        List<String> paths = lookup(zkServerPath, "/trade");
        paths.forEach(System.out::println);

        paths.forEach(path -> deleteAll(zkServerPath, String.format("/trade/%s/routers", path)));

        register(paths, zkServerPath);
    }

    /**
     * 删除所有zk节点
     * 
     * @throws Exception
     */
    public static void deleteAll(String zkServerPath, String path) {
        CuratorFramework zkClient =
            CuratorFrameworkFactory.newClient(zkServerPath, new ExponentialBackoffRetry(1000, 3));
        zkClient.start();
        try {
            zkClient.delete().guaranteed().deletingChildrenIfNeeded().forPath(path);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 检索所有服务
     * 
     * @return
     * @throws Exception
     */
    public static List<String> lookup(String zkServerPath, String path) {
        try {
            CuratorFramework zkClient =
                CuratorFrameworkFactory.newClient(zkServerPath, new ExponentialBackoffRetry(1000, 3));
            zkClient.start();
            return zkClient.getChildren().forPath(path);
        } catch (Exception e) {
            throw new CheckException(e);
        }
    }

    /**
     * 注册规则
     * 
     * @param paths
     */
    public static void register(List<String> paths, String zkServerPath) {
        RegistryFactory registryFactory =
            ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
        Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://" + zkServerPath + "?group=trade"));
        paths.forEach(path -> {
            registry.unregister(URL.valueOf("routers://0.0.0.0/" + path + "?name=gray"
                + "&category=routers&router=grayscaleRouter&dynamic=false&version=1.0&runtime=true"));
            registry.register(URL.valueOf("routers://0.0.0.0/" + path + "?name=gray"
                + "&category=routers&router=grayscaleRouter&dynamic=false&version=1.0&runtime=true"));
        });
    }

}

3. 设置系统变量,启动service

-Ddubbo.protocol.host="10.13.130.109"               //设置你本地IP

 

然后就可以实现了

参考资料:

http://dubbo.apache.org/zh-cn/docs/dev/impls/router.html

https://blog.csdn.net/u012345283/article/details/51789196

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值