使用Dubbo的SPI扩展机制实现自定义LoadBalance——方法一 修改Dubbo源代码

一. 拉取源码

到Dubbo官网 https://github.com/apache/incubator-dubbo/tree/2.5.x 下载源码,解压。git

 

二. 导入IDEA

选择解压后的源码目录,一路点击nextgithub

三. 实现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就是该负载均衡的名字。spring

五. 构建安装源码

打开终端控制台执行mvn clean install -Dmaven.test.skipapache

最后会在maven的本地仓库中生成jar包session

能够经过360解压缩查看jar包中的class文件,看看咱们的代码是否编译进去了。架构

六. 测试代码

公共接口并发

public interface DemoService {
    String saySomething(String msg);
}

provider实现该接口app

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调试运行就能够了。

总结

欢迎关注+点击连接加入群聊【架构华山论剑836442475】:https://jq.qq.com/?_wv=1027&k=59k1QB9,进个人私人群讨论技术和学习!

群内有大牛架构师分享经验,Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术,欢迎进群一块儿讨论哦!专用于学习交流技术、分享面试机会,拒绝广告,我也会在群内不按期答题、探讨。

相关文章
相关标签/搜索