使用Dubbo的SPI扩展机制实现自定义LoadBalance——方法一 修改Dubbo源代码
一. 拉取源码
到dubbo官网 https://github.com/apache/incubator-dubbo/tree/2.5.x 下载源码,解压。
二. 导入idea
选择解压后的源码目录,一路点击next
三. 实现loadbalance接口
在loadbalance包中,创建一个class,并实现loadbalance接口。 如下:创建samesessionidloadbalance类实现loadbalance接口
/**
* 保存sessionid和服务地址的映射关系
* invoker.geturl().getaddress()可以获取到该invoker的服务地址信息
* sessinoid存在,那么就返回sessionid所在的invoker
* sessionid不存在,那么就轮训的找一个invoker返回
*/
public class samesessionidloadbalance implements loadbalance { private final static logger logger = loggerfactory.getlogger(samesessionidloadbalance.class); private map<string,string> sessionidaddress = new concurrenthashmap<string,string>(256); private atomicinteger index = new atomicinteger(0); @override public <t> invoker<t> select(list<invoker<t>> invokers, url url, invocation invocation) throws rpcexception { invoker result = null;
//约定方法的第一个参数就是sessionid string sessionid = (string) invocation.getarguments()[0]; if(!sessionidaddress.containskey(sessionid)){ result = invokers.get(index.getandincrement()%invokers.size()); sessionidaddress.put(sessionid,result.geturl().getaddress()); }else{ string destaddress = sessionidaddress.get(sessionid); for (invoker<t> invoker : invokers) { if(invoker.geturl().getaddress().equals(destaddress)){ result = invoker; } } } logger.info("sesisonid: " + sessionid + " ,method: " + invocation.getmethodname() + " ,select " + result.geturl().getaddress() + " broker"); return result; } }
四. 添加配置信息
添加的samesessionloadbalance就是该负载均衡的名字。
五. 构建安装源码
打开终端控制台执行mvn clean install -dmaven.test.skip
最后会在maven的本地仓库中生成jar包
可以通过360解压缩查看jar包中的class文件,看看我们的代码是否编译进去了。
六. 测试代码
公共接口
public interface demoservice { string saysomething(string msg); }
provider实现该接口
public class demoserviceimpl implements demoservice { public string saysomething(string msg) {
//每次启动 把20880改成相应的端口 方便观察结果。 return "this is 20880 " + msg; } }
provider启动
public class provider { public static void main(string[] args) throws ioexception { classpathxmlapplicationcontext ctx = new classpathxmlapplicationcontext("classpath:provider.xml"); ctx.start(); system.in.read(); } }
provider.xml
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- 提供方应用信息,用于计算依赖关系 --> <dubbo:application name="hello-world-app" /> <!-- 使用zookeeper注册中心暴露服务地址 --> <dubbo:registry address="zookeeper://10.130.41.36:2181"/> <!-- 用dubbo协议在20880端口暴露服务 --> <dubbo:protocol name="dubbo" port="20880" /> <!-- 声明需要暴露的服务接口 --> <!--samesessionloadbalance--> <dubbo:service interface="com.xxx.testdubbo.demoservice" ref="demoservice" loadbalance="samesessionloadbalance"/> <!-- 和本地bean一样实现服务 --> <bean id="demoservice" class="com.xxx.testdubbo.provider.demoserviceimpl" /> </beans>
consumer启动
public class customer { public static void main(string[] args){ classpathxmlapplicationcontext ctx = new classpathxmlapplicationcontext("classpath:customer.xml"); demoservice ds = (demoservice) ctx.getbean("demoservice"); system.out.println(ds.saysomething("001")); } }
customer.xml
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 --> <dubbo:application name="consumer-of-helloworld-app" /> <!-- 使用zookeeper注册中心暴露发现服务地址 --> <dubbo:registry address="zookeeper://10.130.41.36:2181" /> <!-- 生成远程服务代理,可以和本地bean一样使用demoservice --> <dubbo:reference id="demoservice" interface="com.xxx.testdubbo.demoservice" /> </beans>
七.启动实例测试
dubbo使用一些容错机制,里面会有一些判断。如下图所示:
当invoker只有一个那么就直接返回
当invoker有两个那么使用轮序机制
当有三个或三个以上的invoker时,才会触发loadbalance机制。
所以我们要启动三个provider
更改provider.xml中dubbo的监听端口为20880,20881,20882分别启动实例
在demoserviceimpl中,每启动一个provider实例,该方法返回相应的ip+端口号信息。
最后启动customer,观察端口号结果。
八. 调试自定义loadbalance
在项目里面一定引用了dubbo的jar包,找到samesessionidloadbalance文件,下断点,consumer调试运行就可以了。