由于项目需求特殊,需要在dubbo中实现一种能指定远程地址的分发机制,刚开始想在直连的配置上解决,后来发现对于已经加载了dubbo xml配置的spring容器中是无法在代码层面进行有效的修改的(因为貌似会重新加载xml文件中原有的配置记录),另一方面,这种做法会产生并发冲突的隐患。后来经同事提醒,使用了dubbo留出来的扩展点的方法实现了这个功能,也就是实现了AbstractLoadBalance接口,并重写了doSelect方法,在doSelect方法实现中,根据调度服务方法传进的参数也就是指定的远程主机的ip地址和端口进行了过滤,最终返回满足该条件的Invoker作为最终的返回值给调用端。
实现过程相对简单,但是网上资料并不多,简单记录下:
1. 首先要继承AbstractLoadBalance并重写select方法,并且注意包要和其他dubbo已经提供的LoadBalance类同一级目录,比如我实现的一个子类:
packagecom.alibaba.dubbo.rpc.cluster.loadbalance;
import java.io.File;
import java.util.List;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
importcom.alibaba.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance;
/**
*
* @author : zhengrf1
* @date 创建时间:2017年11月1日 下午5:07:15
* @version 1.0
* @parameter
* @since
* @return
*/
public class AppointLoadBalance extendsAbstractLoadBalance {
/*@author : zhengrf1
* @date 创建时间:2017年11月1日 下午5:07:16
* @seecom.alibaba.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance#doSelect(java.util.List,com.alibaba.dubbo.common.URL, com.alibaba.dubbo.rpc.Invocation)
*/
@Override
protected
//TODO Auto-generated method stub
System.out.println("helloworld"+arg2.getMethodName()+arg2.getArguments().length+arg2.getArguments()[0].toString());
for(Invoker
System.out.println(invoker.getUrl().getAddress()+invoker.getUrl().getHost()+invoker.getUrl().getPort());
if(invoker.getUrl().getHost().equals(arg2.getArguments()[2].toString())){
returninvoker;
}
}
returnnull;
}
}
--在该类逻辑中,取到了调度服务接口的第三个参数也就是指定的ip和端口,并且以此来过滤所有的invoker,返回满足条件的invoker。并且注意包声明:package com.alibaba.dubbo.rpc.cluster.loadbalance;
2.在dubbotisson-2.5.3.2.jar下面的META-INF/dubbo/internal/目录下找到com.alibaba.dubbo.rpc.cluster.LoadBalance文件,并且在该文件最后一行中添加:
Appoint= com.alibaba.dubbo.rpc.cluster.loadbalance.AppointLoadBalance
--我是直接修改了dubbotisson-2.5.3.2.jar下的该文件,并重新加入项目的依赖外包,网上说比较规范的做法是自己创建一个jar包,并且在同样的目录层次下创建同名的文件,并把这行配置内容写进去。这样,dubbo启动时会自动扫描所有com.alibaba.dubbo.rpc.cluster.LoadBalance文件进行合并,另外也可以同时把自己实现的AbstractLoadBalance子类加入jar包,当然这种做法我没真正实践过。
3.在xml配置中,配置service层:
--默认的loadbalance是RandomLoadBalance,所以要显式修改成自己的。
---到此为止,对于dubbo的均衡策略就完成了。但是只截取这一层看起来有点糊涂,所以最好明白整个dubbo的路由均衡机制。
--简单来说,就是Cluster的子类通过自己持有的FailoverClusterInvoker,首先调用Directory的子类的list方法 获取所有符合条件的Invoker,并放置在List容器中,然后调用Router的子类调用route方法过滤掉不满足路由条件的Invoker,然后调用LoadBalance的子类的Select方法,选中最后需要调用的Invoker,最后调用该Invoker的Invoke方法实现远程调用。
可以通过下面的异常报错流程看出一二:
Exception in thread "main"java.lang.NullPointerException
atcom.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.doselect(AbstractClusterInvoker.java:135)
atcom.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.select(AbstractClusterInvoker.java:115)
atcom.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:73)
atcom.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:227)
atcom.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:72)
atcom.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52)
atcom.alibaba.dubbo.common.bytecode.proxy0.dispatch(proxy0.java)
atoperatingPlatform.DispatchClient.main(DispatchClient.java:31)