Netty手写微服务注册中心

主流的序列化框架
Google 的 Protobuf
Facebook 的 Thrift
Jboos 的 Marshaling

使用编码器和解码器能够让我接收到的数据直接就是一个java对象。 而不需要json

Marshaling编码器

maven依赖
<dependency>
    <groupId>org.jboss.marshalling</groupId>
    <artifactId>jboss-marshalling-serial</artifactId>
    <version>1.4.11.Final</version>
</dependency>

实体类

/**
 * 存放地址信息的实体类视图
 */
public class Address implements Serializable {
    // 生产的连接
    private String address;

    private ChannelHandlerContext ctx;

    //todo 想要实现上下线 可以增加state字段 这里因为时间关系不再拓展

    public Address(String address, ChannelHandlerContext ctx) {
        this.address = address;
        this.ctx = ctx;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public ChannelHandlerContext getCtx() {
        return ctx;
    }

    public void setCtx(ChannelHandlerContext ctx) {
        this.ctx = ctx;
    }

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}

 

package com.shanheyongmu.netty.server.entity;

import java.io.Serializable;



/**
 * 返回给消费者的实体类视图
 * 需要去除敏感信息
 */
public class AddressDto implements Serializable {
    private String address;

    public AddressDto(String address) {
        this.address = address;
    }

    public AddressDto() {

    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "AddressDto{" +
                "address='" + address + '\'' +
                '}';
    }
}
 
package com.shanheyongmu.netty.server.entity;

import java.io.Serializable;

/**
 * 生产者消费者约定实体类
 */
public class Agreement implements Serializable {
    // 0为生产者  1为消费者
    private Integer type;

    // 服务id
    private String serviceId;

    // 服务地址
    private String address;

    public Agreement(Integer type, String serviceId, String address) {
        this.type = type;
        this.serviceId = serviceId;
        this.address = address;
    }

    public Integer getType() {
        return type;
    }

    public String getServiceId() {
        return serviceId;
    }

    public String getAddress() {
        return address;
    }

    public void setType(Integer type) {
        this.type = type;
    }

    public void setServiceId(String serviceId) {
        this.serviceId = serviceId;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
package com.shanheyongmu.netty.server.entity;

import java.io.Serializable;
import java.util.List;

/**
 * 响应
 */
public class RespEntity implements Serializable  {

    private Integer code;
    private String msg;
    private Object data;

    public RespEntity(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public RespEntity(Integer code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    @Override
    public String toString() {
        return "RespEntity{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }
}

 

Marshalling 编解码器工厂
package com.shanheyongmu.netty;

import io.netty.handler.codec.marshalling.*;
import org.jboss.marshalling.MarshallerFactory;
import org.jboss.marshalling.Marshalling;
import org.jboss.marshalling.MarshallingConfiguration;

/**
 *Marshalling 编解码器工厂
 */
public final class MarshallingCodeCFactory
{

    /**
     * 创建Jboss Marshalling解码器MarshallingDecoder
     *
     * @return MarshallingDecoder
     */
    public static MarshallingDecoder buildMarshallingDecoder()
    {
        // 首先通过Marshalling工具类的精通方法获取Marshalling实例对象 参数serial标识创建的是java序列化工厂对象。
        final MarshallerFactory marshallerFactory = Marshalling
                .getProvidedMarshallerFactory("serial");
        // 创建了MarshallingConfiguration对象,配置了版本号为5
        final MarshallingConfiguration configuration = new MarshallingConfiguration();
        configuration.setVersion(5);
        // 根据marshallerFactory和configuration创建provider
        UnmarshallerProvider provider = new DefaultUnmarshallerProvider(
                marshallerFactory , configuration);
        // 构建Netty的MarshallingDecoder对象,俩个参数分别为provider和单个消息序列化后的最大长度
        return new MarshallingDecoder(provider ,
                1024 * 1024 * 1);
    }

    /**
     * 创建Jboss Marshalling编码器MarshallingEncoder
     *
     * @return MarshallingEncoder
     */
    public static MarshallingEncoder buildMarshallingEncoder()
    {
        final MarshallerFactory marshallerFactory = Marshalling
                .getProvidedMarshallerFactory("serial");
        final MarshallingConfiguration configuration = new MarshallingConfiguration();
        configuration.setVersion(5);
        MarshallerProvider provider = new DefaultMarshallerProvider(
                marshallerFactory , configuration);
        // 构建Netty的MarshallingEncoder对象,MarshallingEncoder用于实现序列化接口的POJO对象序列化为二进制数组
        return new MarshallingEncoder(provider);
    }
}

注册中心server

package com.shanheyongmu.netty.server;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springblade.merchant.netty.server.entity.Address;
import org.springblade.merchant.netty.server.entity.AddressDto;
import org.springblade.merchant.netty.MarshallingCodeCFactory;
import org.springblade.merchant.netty.server.entity.Agreement;
import org.springblade.merchant.netty.server.entity.RespEntity;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;


/**
 * 注册中心RegistryServer
 *
 */
public class RegistryServer {

    public void bind(int port) throws InterruptedException {
        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1280)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            // 新增Marshaling编码器
                            ch.pipeline().addLast(
                                    MarshallingCodeCFactory.buildMarshallingDecoder()
                            );
                            ch.pipeline().addLast(
                                    MarshallingCodeCFactory.buildMarshallingEncoder()
                            );
                            ch.pipeline().addLast(
                                    new ServerHandler()
                            );
                        }
                    });

            ChannelFuture f = b.bind(port).sync();

            f.channel().closeFuture().sync();
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        int port = 8006;
        new RegistryServer().bind(port);
    }

    public static final int type_producer = 0;
    public static final int type_consumer = 1;

    // key 服务的名称 value 多个生产者集群地址列表
    private static ConcurrentHashMap<String, List<Address>> keyAddres = new ConcurrentHashMap<>();
    //key 为连接 value 服务名称
    private static ConcurrentHashMap<ChannelHandlerContext, String> ctxs = new ConcurrentHashMap<>();

    @ChannelHandler.Sharable
    public class ServerHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            Agreement agreement = (Agreement) msg;
            // 1.判断通讯协议类型: 生产还是消费者
            switch (agreement.getType()) {
                case type_producer:
                    producer(agreement, ctx);
                    ctxs.put(ctx, agreement.getServiceId());
                    break;
                case type_consumer:
                    consumer(agreement, ctx);
                    // 应该存放消费者连接
                    break;

            }
        }

        /**
         * 生产者
         *
         * @param agreement
         * @param ctx
         */
        private void producer(Agreement agreement, ChannelHandlerContext ctx) {
            String serviceId = agreement.getServiceId();
            // 根据服务名称查找之前是否有缓存地址数据
            List<Address> listAddres = keyAddres.get(serviceId);
            if (listAddres == null) {
                listAddres = new ArrayList<>();
                keyAddres.put(serviceId, listAddres);
            }
            // 注册中心插入服务地址信息
            String address = agreement.getAddress();
            listAddres.add(new Address(address, ctx));
        }

        /**
         * 消费者
         */
        private void consumer(Agreement agreement, ChannelHandlerContext ctx) {
            String serviceId = agreement.getServiceId();
            List<Address> addresEntities = keyAddres.get(serviceId);
            if (addresEntities == null || addresEntities.size() == 0) {
                ctx.writeAndFlush(new RespEntity(500, "未获取接口地址列表"));
                return;
            }
            // 数据格式转换
            ArrayList<AddressDto> addresDtos = new ArrayList<>();
            addresEntities.forEach((t) -> {
                addresDtos.add(new AddressDto(t.getAddress()));
            });
            ctx.writeAndFlush(new RespEntity(200, "接口地址列表", addresDtos));
        }


        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            // 如果客户端主动断开连接的时候 走该方法 那个连接主动断开

            // 服务名称 缓存3个  每个服务名称对应缓存三个集群地址列表
            //  private static ConcurrentHashMap<String, List<AddresEntity>> keyAddres = new ConcurrentHashMap<>();
            // 多个服务名称 对应对个 服务地址集群理列表

            //ChannelHandlerContext ctx==对应地址
            String serviceId = ctxs.get(ctx);
            // 根据服务名称查找缓存地址
            List<Address> addresEntities = keyAddres.get(serviceId);
            // 遍历缓存地址剔除
            addresEntities.forEach((t) -> {
                if (t.getCtx() == ctx) {
                    //剔除
                    addresEntities.remove(t);
                }
            });
            // 注册中心通知消费者删除失效地址
            // 循环遍历所有的消费者连接,通知  服务名称 那个地址 应该从内存删除
            ctx.close();
        }
    }


}

编写生产者客户端

package com.shanheyongmu.netty.client;


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 org.springblade.merchant.netty.MarshallingCodeCFactory;


/**
 * 生产者客户端
 */
public class ProducerClient {
    public void connect(int port, String host) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            // 设置 Marshalling 编码
                            ch.pipeline().addLast(
                                    MarshallingCodeCFactory.buildMarshallingDecoder()
                            );
                            ch.pipeline().addLast(
                                    MarshallingCodeCFactory.buildMarshallingEncoder()
                            );
                            ch.pipeline().addLast(new ClientHandler());
                        }
                    });

            ChannelFuture f = b.connect(host, port).sync();
            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }

    public static final int type_producer = 0;

    public static void main(String[] args) throws InterruptedException {
        int port = 8006;
        String host = "127.0.0.1";
        new ProducerClient().connect(port, host);
    }
    // 客户端Handler

    public class ClientHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            // 发送数据给我们服务器端
            ctx.writeAndFlush(new Agreement(type_producer, "shanhe-member", "192.168.110.111"));
        }

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

消费者客户端

package com.shanheyongmut.netty.client;


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 org.springblade.merchant.netty.MarshallingCodeCFactory;


/**
 * 消费者客户端
 */
public class ConsumerClient {
    public void connect(int port, String host) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            // 设置 Marshalling 编码
                            ch.pipeline().addLast(
                                    MarshallingCodeCFactory.buildMarshallingDecoder()
                            );
                            ch.pipeline().addLast(
                                    MarshallingCodeCFactory.buildMarshallingEncoder()
                            );
                            ch.pipeline().addLast(new ConsumerClientHandler());
                        }
                    });

            ChannelFuture f = b.connect(host, port).sync();
            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }
    public static final int type_consumer= 1;
    public static void main(String[] args) throws InterruptedException {
        int port = 8006;
        String host = "127.0.0.1";
        new ConsumerClient().connect(port, host);
    }

    // 客户端Handler
    public class ConsumerClientHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            //type =1 代表消费者
            Agreement agreementEntity = new Agreement(type_consumer,
                    "shanhe-member", null);
            ctx.writeAndFlush(agreementEntity);
        }

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

        /**
         * 客户端读取到服务器端数据
         *
         * @param ctx
         * @param msg
         * @throws Exception
         */
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            RespEntity respEntity = (RespEntity) msg;
            System.out.println("消费者读取数据:" + respEntity.toString());
        }
    }
}

 

 

 

 

posted @ 2023-02-06 14:30  山河永慕~  阅读(112)  评论(0编辑  收藏  举报