使用netty模仿dubbo服务

先上一张图

思路

使用netty 5.* 实现类似dubbo的服务调用

公共类

api

实际开发时 提供者需要实现该包下面所有接口, 而服务调用者则是通过该包内提供的接口调用方法

package apis;

/**
 * Created by xuchonggao on 2017/6/26.
 */
public interface UserService {
    public String findUser(String userName);

    String findUserList(int pageNum, int pageSize);
}

请求POJO

注意: 这个类必须是可序列化的,包括里面的属性

package dub;

import java.io.Serializable;
import java.util.Arrays;

/**
 * 调用请求类
 * Created by xuchonggao on 2017/6/27.
 */
public class DubReq implements Serializable {
    private static final long serialVersionUID = 422805234202183587L;
    private Class interfaceClass;
    private String methonName;
    private Class[] paramTypes;
    private Object[] args;

    public DubReq() {
    }

    public Class getInterfaceClass() {
        return interfaceClass;
    }

    public DubReq setInterfaceClass(Class interfaceClass) {
        this.interfaceClass = interfaceClass;
        return this;
    }

    public String getMethonName() {
        return methonName;
    }

    public DubReq setMethonName(String methonName) {
        this.methonName = methonName;
        return this;
    }

    public Class[] getParamTypes() {
        return paramTypes;
    }

    public DubReq setParamTypes(Class[] paramTypes) {
        this.paramTypes = paramTypes;
        return this;
    }

    public Object[] getArgs() {
        return args;
    }

    public DubReq setArgs(Object[] args) {
        this.args = args;
        return this;
    }

    public DubReq(Class interfaceClass, String methonName, Class[] paramTypes, Object[] args) {

        this.interfaceClass = interfaceClass;
        this.methonName = methonName;
        this.paramTypes = paramTypes;
        this.args = args;
    }

    @Override
    public String toString() {
        return "DubReq{" +
                "interfaceClass=" + interfaceClass +
                ", methonName='" + methonName + '\'' +
                ", paramTypes=" + Arrays.toString(paramTypes) +
                ", args=" + Arrays.toString(args) +
                '}';
    }
}

服务端

package dub.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;

/**
 * Created by xuchonggao on 2017/6/26.
 */
public class DubServer {

    private int port;

    public DubServer(int port) {
        this.port = port;
    }

    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); // (2)
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class) // (3)
                    .childHandler(new ChannelInitializer<SocketChannel>() { // (4)
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new ObjectDecoder(1024*1024, ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader())));
                            ch.pipeline().addLast(new ObjectEncoder());
                            ch.pipeline().addLast(new DuBHandler());
                        }
                    })
                    .option(ChannelOption.SO_BACKLOG, 128)          // (5)
                    .childOption(ChannelOption.SO_KEEPALIVE, true); // (6)

            // Bind and start to accept incoming connections.
            ChannelFuture f = b.bind(port).sync(); // (7)

            // Wait until the dub.server socket is closed.
            // In this example, this does not happen, but you can do that to gracefully
            // shut down your dub.server.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        new DubServer(8080).run();
    }

}

package dub.server;

import apis.UserService;
import dub.DubReq;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import provider.UserServiceImpl;

import java.lang.reflect.Method;

/**
 * Created by xuchonggao on 2017/6/26.
 */
public class DuBHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("服务端收到消息:   " + msg);
        DubReq req = (DubReq) msg;
        // 1. 根据类名返回对象
        Object target = this.getInstenceByInterfaceClass(req.getInterfaceClass());
        // 2. 获取方法名
        String methodName = req.getMethonName();
        // 3. 获取方法参数类型
        // 4. 获取方法
        Method method = target.getClass().getMethod(methodName, req.getParamTypes());
        // 5. 获取参数值
        //调用方法 获取返回值
        Object res = method.invoke(new UserServiceImpl(), req.getArgs());
        // 写回给调用端
        ctx.writeAndFlush(res);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    private Object getInstenceByInterfaceClass(Class clazz) {
        //根据接口返回对应的实例
        if (UserService.class.equals(clazz)) {
            return new UserServiceImpl();
        }
        return null;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
    }
}

调用方

package dub.client;

import apis.UserService;

/**
 * Created by xuchonggao on 2017/6/26.
 */
public class DubClient {
    public static void main(String[] args) throws Exception {
        // 实际上返回的是一个代理类  通过代理类发送网络请求调用服务提供者
        UserService userService  = (UserService) DubServiceProxy.remote(UserService.class);


        System.out.println(userService.findUser("aaa"));
        System.out.println(userService.findUser("0001"));
        System.out.println(userService.findUserList(1,10));
    }
}

package dub.client;

import dub.DubReq;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
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.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 消费者handler
 * Created by xuchonggao on 2017/6/26.
 */
public class DubConsumeHandler implements InvocationHandler {

    private Object res;

    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
        //配置客户端线程组
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            //配置客户端启动辅助类
            Bootstrap b = new Bootstrap();
            b.group(group).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new ObjectDecoder(1024, ClassResolvers.cacheDisabled(this.getClass().getClassLoader())));
                            ch.pipeline().addLast(new ObjectEncoder());
                            ch.pipeline().addLast(new ConsumeHandler(proxy, method, args));

                        }
                    });
            //从注册中心获取ip和端口
            ChannelFuture f = b.connect("127.0.0.1", 8080).sync();
            f.channel().closeFuture().sync();

        } finally {
            group.shutdownGracefully();
        }
        return res;
    }

    private class ConsumeHandler extends ChannelInboundHandlerAdapter {
        private Object proxy;
        private Method method;
        private Object[] args;

        public ConsumeHandler(Object proxy, Method method, Object[] args) {
            this.proxy = proxy;
            this.method = method;
            this.args = args;
        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            // 传输的对象必须实现序列化接口 包括其中的属性
            DubReq req = new DubReq(proxy.getClass().getInterfaces()[0], method.getName(), method.getParameterTypes(), args);
            ctx.write(req);
            ctx.flush();
        }

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            System.out.println("调用成功");
            res = msg;
            ctx.flush();
            //收到响应后断开连接
            ctx.close();
        }

        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            ctx.flush();
        }
    }


}


package dub.client;

import java.lang.reflect.Proxy;

/**
 * 生成接口代理类
 * Created by xuchonggao on 2017/6/26.
 */
public class DubServiceProxy {
    public static Object remote(Class clazz) {
        return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new DubConsumeHandler());
    }
}

结果显示

Connected to the target VM, address: '127.0.0.1:64393', transport: 'socket'
调用成功
userName:aaa
调用成功
userName:0001
调用成功
查询第1页,10条数据
Disconnected from the target VM, address: '127.0.0.1:64393', transport: 'socket'

Process finished with exit code 0

码云地址

点我

转载于:https://my.oschina.net/razox/blog/1036892

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值