Dubbo 源码学习系列 优化篇《工厂模式在Dubbo中的应用》

Posted Dream_it_possible!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo 源码学习系列 优化篇《工厂模式在Dubbo中的应用》相关的知识,希望对你有一定的参考价值。

前言

           前四篇实现了基于zookeeper和Netty的远程调用的流程,我们可以继续对代码进行优化,利用简单工厂模式使其支持两种协议,代码会更加简洁、有层次感。可以将共有方法抽离出来成一个接口,我在用Http实现的时候,服务端使用了start(URL url)方法,客户端实现了send(URL url,Invocation invocation)方法,同样使用netty时,用Start()方法启动nettyServer, 用nettyClient去发送Invocation对象。

          Protocol 接口:

package com.example.dubbo.framework;

public interface Protocol {

    void start(URL url);

    Object send(URL url, Invocation invocation);


}

添加DubboProtocol和HttpProtocol实现类, 将之前的client的send()方法和server的start()方法迁移到实现类里。

 DubboProtocol

package com.example.dubbo.protocol.dubbo;

import com.example.dubbo.framework.Invocation;
import com.example.dubbo.framework.URL;
import com.example.dubbo.framework.Protocol;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NiosocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

import java.util.concurrent.*;

public class DubboProtocol implements Protocol {


    public NettyClientHandler client = null;

    private URL url;

    // 使用线程池开启线程
    private static ExecutorService executorService = Executors.newCachedThreadPool();

    @Override
    public void start(URL url) {
        client = new NettyClientHandler();

        final Bootstrap bootstrap = new Bootstrap();

        bootstrap.group(new NioEventLoopGroup())
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        pipeline.addLast("decoder", new ObjectDecoder(ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader())));
                        pipeline.addLast("encoder", new ObjectEncoder());
                        pipeline.addLast("handler", client);
                    }
                });

        // 连接socket
        try {
            bootstrap.connect(url.getHost(), url.getPort()).sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 通过线程来发送信息给Server
    @Override
    public Object send(URL url, Invocation invocation) {
        this.url = url;
        if (client == null) {
            start(url);
        }
        client.setInvocation(invocation);
        try {
            Object obj = null;
            try {
                obj = executorService.submit(client).get(3L, TimeUnit.SECONDS);
            } catch (TimeoutException e) {
                e.printStackTrace();
            }
            return obj;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return null;
    }
}

 HttpProtocol

package com.example.dubbo.protocol.http;

import com.alibaba.fastjson.JSONObject;
import com.example.dubbo.framework.Invocation;
import com.example.dubbo.framework.URL;
import com.example.dubbo.framework.Protocol;
import com.example.dubbo.utils.HttpUtils;

public class HttpProtocol implements Protocol {


    @Override
    public void start(URL url) {
        HttpServer server = new HttpServer();
        server.start(url);
    }

    @Override
    public Object send(URL url, Invocation invocation) {
        try {
            return HttpUtils.doPostData(url.getHost() + ":" + url.getPort(), JSONObject.toJSONString(invocation));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

1.  工厂模式

          用泛型定义简单工厂,此方式适用于对象少,数量不复杂的情况。

package com.example.dubbo.framework;


import com.example.dubbo.protocol.http.HttpProtocol;

import java.lang.reflect.Proxy;

/**
 * 协议工厂
 */
public class ProtocolFactory {


    public static Protocol getProtocol(Class<? extends Protocol> clazz) {
        if (null != clazz) {
            try {
                return clazz.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

}

2.  整合工厂模式

      服务端:

      

      消费端:

      在proxyFactory的getProxy()方法里修改为

     

     重新启动后观察结果,依然可以达到RPC的目的!

  如果要使用dubbo协议,那么用getProtocol(DubboProtocol.class)即可!

3. 总结

        工厂模式的优点:       

    1) 可扩展性强,易于维护,再来一个协议也不怕。

    2)  减少重复代码,通过工厂来统一管理创建实例。

         利用接口将共有的行为给抽象出来,让代码更有层次感! 

 

代码地址:  https://gitee.com/bingbing-123456/dubbo-rpc

以上是关于Dubbo 源码学习系列 优化篇《工厂模式在Dubbo中的应用》的主要内容,如果未能解决你的问题,请参考以下文章

《跟二师兄学Nacos吧》EXT-01篇 看看Nacos是怎么活学活用简单工厂模式的!

《跟二师兄学Nacos吧》EXT-01篇 看看Nacos是怎么活学活用简单工厂模式的!

dubbo 源码 v2.7 分析:核心机制

Dubbo源码,详解dubbo协议数据包及解包过程

设计模式系列,六大设计原则

[设计模式系列] 抽象工厂