创建一个 Netty Service

本文详细介绍了如何使用Netty搭建服务器,包括引入依赖、创建监听器、绑定端口及处理逻辑等步骤。通过实例讲解了NettyServer的配置与运行过程。

这是2015年最后一天的日落,拍摄于台湾省垦丁。台湾岛最南端,已经过了北回归线,冬天去时不到25度,温度适宜,但是还是被晒伤。

                                                                                             微信公众号

                                                            王皓的GitHub:https://github.com/TenaciousDWang

来创建一个Netty Server!

首先引用netty的依赖

<dependency>

        <groupId>io.netty</groupId>

        <artifactId>netty-all</artifactId>

        <version>4.1.23.Final</version>

</dependency>

然后我们开始,需要了解的都已经写在注释中~

NettyServer.java

关于绑定方法:

serverBootstrap.bind(8000);这个方法会返回一个ChannelFuture,我们可以添加一个监听器来监听这个bind动作是否成功。

serverBootstrap.bind(8000).addListener(监听器);

我们来创建一个监听器GenericFutureListener<Future<? super Void>>(),这是一个接口,紧接的我们来实现void operationComplete(Future<? super Void> future){}这个方法。

将绑定端口抽取为void bind(final ServerBootstrap serverBootstrap, final int port),当future.isSuccess()返回错误时,我们使用递归方式重新调用bind方法本身,直到绑定端口,服务端成功启动。

最后我们来看一下serverBootstrap中对应的其他方法:

          1.serverBootstrap.handler()

这里是对应服务端启动过程中添加一些处理逻辑,对比childHandler()方法,childHandler方法用来为每次来的新连接添加逻辑。

 

        2.serverBootstrap.attr()与serverBootstrap.childAttr()

        3.option()与childOption()方法

对应上面的attr()与childAttr(),option()与childOption()也分别对应NioServerSocketChannel与NioSocketChannel。

这里只介绍几种常见的,其他的属性请参照netty官网api文档

channelOption

channelConfig for SocketChannel

 

 

 

 

 

<think> 我们正在讨论如何使用Netty搭建一个RPC框架。根据之前的引用资料,我们可以总结出RPC框架的核心组成部分: 1. 服务注册与发现 2. 网络传输(使用Netty) 3. 序列化与反序列化 4. 动态代理(客户端) 接下来,我们将按照这些核心部分来构建一个简单的RPC框架。 ### 一、项目结构 假设我们的项目结构如下: ``` rpc-framework ├── rpc-common // 公共模块(消息实体、序列化等) ├── rpc-server // 服务端 └── rpc-client // 客户端 ``` ### 二、消息实体定义(在rpc-common中) 首先定义RPC请求和响应的消息结构。 ```java // RpcRequestMessage.java public class RpcRequestMessage implements Serializable { // 请求的唯一标识 private String requestId; // 调用的接口全限定名 private String interfaceName; // 调用的方法名 private String methodName; // 参数类型数组 private Class<?>[] parameterTypes; // 参数值数组 private Object[] parameterValues; // 返回类型 private Class<?> returnType; // 构造方法、getter、setter省略 } ``` ```java // RpcResponseMessage.java public class RpcResponseMessage implements Serializable { // 对应的请求ID private String requestId; // 返回值(正常调用) private Object returnValue; // 异常值(调用异常) private Throwable exceptionValue; // 构造方法、getter、setter省略 } ``` ### 三、序列化算法(在rpc-common中) 我们定义一个序列化接口,并实现一个JSON序列化器。 ```java // Serializer.java public interface Serializer { // 序列化 <T> byte[] serialize(T object); // 反序列化 <T> T deserialize(byte[] bytes, Class<T> clazz); } ``` ```java // JsonSerializer.java public class JsonSerializer implements Serializer { private static final ObjectMapper mapper = new ObjectMapper(); @Override public <T> byte[] serialize(T object) { try { return mapper.writeValueAsBytes(object); } catch (JsonProcessingException e) { throw new RuntimeException("序列化失败", e); } } @Override public <T> T deserialize(byte[] bytes, Class<T> clazz) { try { return mapper.readValue(bytes, clazz); } catch (IOException e) { throw new RuntimeException("反序列化失败", e); } } } ``` ### 四、自定义协议与编解码器(在rpc-common中) 为了防止粘包和半包问题,我们需要自定义协议。这里我们采用简单的“长度+内容”的方式。 ```java @ChannelHandler.Sharable public class MessageCodec extends MessageToMessageCodec<ByteBuf, Object> { // 魔数(4字节) private static final int MAGIC_NUMBER = 0xCAFEBABE; @Override protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception { ByteBuf buf = ctx.alloc().buffer(); // 1. 魔数(4字节) buf.writeInt(MAGIC_NUMBER); // 2. 版本号(1字节) buf.writeByte(1); // 3. 序列化算法(1字节) buf.writeByte(0); // 0代表JSON // 4. 消息类型(1字节) if (msg instanceof RpcRequestMessage) { buf.writeByte(0); } else if (msg instanceof RpcResponseMessage) { buf.writeByte(1); } else { throw new UnsupportedOperationException("不支持的消息类型"); } // 5. 请求序号(4字节) // 这里我们简单写0,实际需要生成唯一ID buf.writeInt(0); // 6. 对齐填充(1字节),为了凑齐2的整数倍(这里先写0,后面再填充) buf.writeByte(0xff); // 7. 序列化 byte[] bytes = new JsonSerializer().serialize(msg); // 8. 正文长度(4字节) buf.writeInt(bytes.length); // 9. 正文内容 buf.writeBytes(bytes); out.add(buf); } @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { // 读取魔数 int magic = in.readInt(); if (magic != MAGIC_NUMBER) { throw new RuntimeException("魔数不对"); } // 版本号 byte version = in.readByte(); // 序列化算法 byte serializerType = in.readByte(); // 消息类型 byte messageType = in.readByte(); // 请求序号 int sequenceId = in.readInt(); // 对齐填充(跳过) in.readByte(); // 正文长度 int length = in.readInt(); // 正文 byte[] bytes = new byte[length]; in.readBytes(bytes, 0, length); // 根据消息类型反序列化 switch (messageType) { case 0: RpcRequestMessage request = new JsonSerializer().deserialize(bytes, RpcRequestMessage.class); out.add(request); break; case 1: RpcResponseMessage response = new JsonSerializer().deserialize(bytes, RpcResponseMessage.class); out.add(response); break; default: throw new UnsupportedOperationException("不支持的消息类型"); } } } ``` ### 五、服务端实现(在rpc-server中) #### 1. 服务注册 服务端需要将服务实例注册到容器中。 ```java // ServiceRegistry.java public class ServiceRegistry { private static final Map<String, Object> services = new ConcurrentHashMap<>(); public void register(Class<?> interfaceClass, Object service) { services.put(interfaceClass.getName(), service); } public Object getService(String interfaceName) { return services.get(interfaceName); } public static ServiceRegistry getInstance() { return SingletonHolder.INSTANCE; } private static class SingletonHolder { private static final ServiceRegistry INSTANCE = new ServiceRegistry(); } } ``` #### 2. Netty服务端启动 ```java public class RpcServer { public void start(int port) { EventLoopGroup bossGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { ChannelPipeline p = ch.pipeline(); // 添加自定义编解码器 p.addLast(new MessageCodec()); // 添加业务处理器 p.addLast(new RpcServerHandler()); } }); ChannelFuture f = b.bind(port).sync(); f.channel().closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } ``` #### 3. 服务端处理器 ```java public class RpcServerHandler extends SimpleChannelInboundHandler<RpcRequestMessage> { @Override protected void channelRead0(ChannelHandlerContext ctx, RpcRequestMessage msg) { // 从服务注册中心获取服务实例 Object service = ServiceRegistry.getInstance().getService(msg.getInterfaceName()); if (service == null) { // 处理服务不存在 return; } // 反射调用方法 Method method = null; try { method = service.getClass().getMethod(msg.getMethodName(), msg.getParameterTypes()); Object returnValue = method.invoke(service, msg.getParameterValues()); // 构建响应 RpcResponseMessage response = new RpcResponseMessage(); response.setRequestId(msg.getRequestId()); response.setReturnValue(returnValue); ctx.writeAndFlush(response); } catch (Exception e) { // 处理异常 RpcResponseMessage response = new RpcResponseMessage(); response.setRequestId(msg.getRequestId()); response.setExceptionValue(e); ctx.writeAndFlush(response); } } } ``` ### 六、客户端实现(在rpc-client中) #### 1. 动态代理 客户端通过动态代理生成接口的代理对象,将方法调用封装为RPC请求。 ```java public class RpcClientProxy { private final String host; private final int port; public RpcClientProxy(String host, int port) { this.host = host; this.port = port; } @SuppressWarnings("unchecked") public <T> T getProxy(Class<T> serviceClass) { return (T) Proxy.newProxyInstance( serviceClass.getClassLoader(), new Class<?>[]{serviceClass}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 构建请求消息 RpcRequestMessage request = new RpcRequestMessage(); request.setRequestId(UUID.randomUUID().toString()); request.setInterfaceName(serviceClass.getName()); request.setMethodName(method.getName()); request.setParameterTypes(method.getParameterTypes()); request.setParameterValues(args); request.setReturnType(method.getReturnType()); // 发送请求并等待响应 RpcResponseMessage response = RpcClientManager.sendRequest(host, port, request); if (response.getExceptionValue() != null) { throw response.getExceptionValue(); } return response.getReturnValue(); } } ); } } ``` #### 2. 客户端管理器(处理网络通信) ```java public class RpcClientManager { private static final Map<String, Channel> channelMap = new ConcurrentHashMap<>(); public static RpcResponseMessage sendRequest(String host, int port, RpcRequestMessage request) { // 构造ChannelFuture ChannelFuture future = getChannelFuture(host, port); // 等待连接成功 future.awaitUninterruptibly(); Channel channel = future.channel(); // 准备一个Promise用来接收结果 DefaultPromise<RpcResponseMessage> promise = new DefaultPromise<>(channel.eventLoop()); // 将promise存储起来,等收到响应后设置结果 RpcClientResponseHandler.PROMISES.put(request.getRequestId(), promise); // 发送请求 channel.writeAndFlush(request); try { // 等待结果(超时时间设为5秒) promise.await(5, TimeUnit.SECONDS); if (promise.isSuccess()) { return promise.getNow(); } else { throw new RuntimeException(promise.cause()); } } catch (InterruptedException e) { throw new RuntimeException(e); } } private static ChannelFuture getChannelFuture(String host, int port) { String key = host + ":" + port; Channel channel = channelMap.get(key); if (channel != null && channel.isActive()) { return channel.newSucceededFuture(); } // 加锁避免重复创建 synchronized (RpcClientManager.class) { channel = channelMap.get(key); if (channel == null || !channel.isActive()) { // 创建新的连接 EventLoopGroup group = new NioEventLoopGroup(); Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { ChannelPipeline p = ch.pipeline(); p.addLast(new MessageCodec()); p.addLast(new RpcClientResponseHandler()); } }); ChannelFuture future = b.connect(host, port); channelMap.put(key, future.channel()); return future; } else { return channel.newSucceededFuture(); } } } } ``` #### 3. 客户端响应处理器 ```java public class RpcClientResponseHandler extends SimpleChannelInboundHandler<RpcResponseMessage> { public static final Map<String, Promise<RpcResponseMessage>> PROMISES = new ConcurrentHashMap<>(); @Override protected void channelRead0(ChannelHandlerContext ctx, RpcResponseMessage msg) { // 根据请求ID找到对应的Promise String requestId = msg.getRequestId(); Promise<RpcResponseMessage> promise = PROMISES.remove(requestId); if (promise != null) { if (msg.getExceptionValue() != null) { promise.setFailure(msg.getExceptionValue()); } else { promise.setSuccess(msg); } } } } ``` ### 七、使用示例 #### 服务端注册服务并启动 ```java public class ServerBootstrap { public static void main(String[] args) { // 注册服务 ServiceRegistry registry = ServiceRegistry.getInstance(); registry.register(IUserService.class, new UserServiceImpl()); // 启动RPC服务端 RpcServer server = new RpcServer(); server.start(8080); } } ``` #### 客户端调用 ```java public class ClientBootstrap { public static void main(String[] args) { RpcClientProxy proxy = new RpcClientProxy("localhost", 8080); IUserService userService = proxy.getProxy(IUserService.class); User user = userService.getById(1); System.out.println(user); } } ``` ### 八、总结 通过以上步骤,我们实现了一个基于Netty的简单RPC框架。关键点包括: 1. **消息定义**:请求和响应消息体 2. **序列化**:使用JSON进行对象的序列化和反序列化 3. **编解码器**:自定义协议解决粘包问题 4. **服务注册**:服务端注册服务实例 5. **动态代理**:客户端通过动态代理发起调用 6. **异步通信**:使用Promise等待响应结果 此框架还有很多可以优化的地方,例如: - 引入服务发现机制(如Zookeeper) - 支持多种序列化方式(Protobuf、Hessian等) - 连接池管理 - 负载均衡 - 超时重试机制等 --- §§相关问题§§ 1. 如何优化Netty RPC框架的性能? 2. 如何实现RPC框架的服务发现功能? 3. Netty RPC框架中如何处理服务端的并发请求? 4. RPC框架中如何实现负载均衡? 5. 如何设计一个支持多种序列化协议的RPC框架? </think>## 使用Netty搭建RPC框架的完整实现 Netty作为高性能网络通信框架,非常适合构建RPC系统。以下是基于Netty实现RPC框架的核心步骤和代码实现: ### 一、RPC框架核心架构 ```mermaid graph TD A[Client] -->|动态代理| B[Netty客户端] B -->|序列化| C[网络传输] D[Netty服务端] -->|反序列化| C D --> E[服务注册中心] E --> F[Service实现] ``` ### 二、核心模块实现 #### 1. 消息实体定义 ```java // RPC请求消息 public class RpcRequestMessage implements Serializable { private String requestId; // 请求ID private String interfaceName; // 接口全限定名 private String methodName; // 方法名 private Class<?>[] parameterTypes; // 参数类型 private Object[] parameters; // 参数值 private Class<?> returnType; // 返回类型 // getters/setters } // RPC响应消息 public class RpcResponseMessage implements Serializable { private String requestId; // 对应请求ID private Object returnValue; // 返回值 private Throwable exceptionValue; // 异常信息 // getters/setters } ``` #### 2. 序列化模块(支持多种协议) ```java public interface Serializer { byte JSON = 1; byte PROTOBUF = 2; <T> byte[] serialize(T object); <T> T deserialize(byte[] bytes, Class<T> clazz); } // JSON序列化实现 public class JsonSerializer implements Serializer { private static final ObjectMapper mapper = new ObjectMapper(); @Override public <T> byte[] serialize(T object) { try { return mapper.writeValueAsBytes(object); } catch (JsonProcessingException e) { throw new SerializationException(e); } } @Override public <T> T deserialize(byte[] bytes, Class<T> clazz) { try { return mapper.readValue(bytes, clazz); } catch (IOException e) { throw new SerializationException(e); } } } ``` #### 3. 协议编解码器(解决粘包/半包) ```java @Sharable public class RpcMessageCodec extends MessageToMessageCodec<ByteBuf, Object> { // 协议格式: [魔数4B][版本1B][序列化算法1B][消息类型1B][请求ID4B][数据长度4B][数据] private static final int MAGIC_NUMBER = 0xCAFEBABE; @Override protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) { ByteBuf buf = ctx.alloc().buffer(); // 1. 写魔数 buf.writeInt(MAGIC_NUMBER); // 2. 写版本 buf.writeByte(1); // 3. 序列化算法 (JSON) buf.writeByte(Serializer.JSON); // 4. 消息类型 (0-请求, 1-响应) if (msg instanceof RpcRequestMessage) { buf.writeByte(0); } else { buf.writeByte(1); } // 5. 请求ID String requestId = getRequestId(msg); buf.writeInt(Integer.parseInt(requestId)); // 6. 序列化数据 byte[] bytes = new JsonSerializer().serialize(msg); // 7. 数据长度 buf.writeInt(bytes.length); // 8. 写入数据 buf.writeBytes(bytes); out.add(buf); } // decode实现类似(略) } ``` #### 4. 服务端实现 ```java public class RpcServer { private final int port; private final ServiceRegistry registry; public void start() { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { ch.pipeline() .addLast(new LengthFieldBasedFrameDecoder( Integer.MAX_VALUE, 12, 4, 0, 0)) .addLast(new RpcMessageCodec()) .addLast(new RpcRequestHandler(registry)); } }); ChannelFuture f = b.bind(port).sync(); f.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } // 请求处理器 public class RpcRequestHandler extends SimpleChannelInboundHandler<RpcRequestMessage> { private final ServiceRegistry registry; @Override protected void channelRead0(ChannelHandlerContext ctx, RpcRequestMessage msg) { // 1. 获取服务实现 Object service = registry.getService(msg.getInterfaceName()); // 2. 反射调用方法 try { Method method = service.getClass().getMethod( msg.getMethodName(), msg.getParameterTypes()); Object result = method.invoke(service, msg.getParameters()); // 3. 返回响应 RpcResponseMessage response = new RpcResponseMessage(); response.setRequestId(msg.getRequestId()); response.setReturnValue(result); ctx.writeAndFlush(response); } catch (Exception e) { // 异常处理 } } } ``` #### 5. 客户端实现 ```java public class RpcClient { private volatile Channel channel; private final Map<String, Promise<Object>> pendingPromises = new ConcurrentHashMap<>(); public Channel connect(String host, int port) { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(new NioEventLoopGroup()) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { ch.pipeline() .addLast(new LengthFieldBasedFrameDecoder( Integer.MAX_VALUE, 12, 4, 0, 0)) .addLast(new RpcMessageCodec()) .addLast(new RpcResponseHandler(pendingPromises)); } }); return bootstrap.connect(host, port).sync().channel(); } public Object sendRequest(RpcRequestMessage request) { // 创建并存储Promise Promise<Object> promise = new DefaultPromise<>( channel.eventLoop()); pendingPromises.put(request.getRequestId(), promise); // 发送请求 channel.writeAndFlush(request); // 异步等待结果(设置超时) if (!promise.await(5, TimeUnit.SECONDS)) { throw new RpcTimeoutException("Request timeout"); } return promise.getNow(); } } // 响应处理器 public class RpcResponseHandler extends SimpleChannelInboundHandler<RpcResponseMessage> { private final Map<String, Promise<Object>> pendingPromises; @Override protected void channelRead0(ChannelHandlerContext ctx, RpcResponseMessage msg) { Promise<Object> promise = pendingPromises.remove(msg.getRequestId()); if (msg.getExceptionValue() != null) { promise.setFailure(msg.getExceptionValue()); } else { promise.setSuccess(msg.getReturnValue()); } } } ``` #### 6. 动态代理调用 ```java public class RpcProxyFactory { private final RpcClient client; public <T> T createProxy(Class<T> interfaceClass) { return (T) Proxy.newProxyInstance( interfaceClass.getClassLoader(), new Class<?>[]{interfaceClass}, (proxy, method, args) -> { // 构造请求 RpcRequestMessage request = new RpcRequestMessage(); request.setRequestId(UUID.randomUUID().toString()); request.setInterfaceName(interfaceClass.getName()); request.setMethodName(method.getName()); request.setParameterTypes(method.getParameterTypes()); request.setParameters(args); request.setReturnType(method.getReturnType()); // 发送请求 return client.sendRequest(request); } ); } } ``` ### 三、使用示例 ```java // 1. 定义服务接口 public interface UserService { User getUserById(int id); } // 2. 服务端注册实现 public class UserServiceImpl implements UserService { @Override public User getUserById(int id) { return new User(id, "User" + id); } } // 3. 服务端启动 public class ServerApp { public static void main(String[] args) { ServiceRegistry registry = new ServiceRegistry(); registry.register(UserService.class, new UserServiceImpl()); RpcServer server = new RpcServer(8080, registry); server.start(); } } // 4. 客户端调用 public class ClientApp { public static void main(String[] args) { RpcClient client = new RpcClient(); Channel channel = client.connect("localhost", 8080); RpcProxyFactory factory = new RpcProxyFactory(client); UserService userService = factory.createProxy(UserService.class); User user = userService.getUserById(123); System.out.println(user); // 输出: User{id=123, name='User123'} } } ``` ### 四、性能优化关键点 1. **连接池管理**:复用Channel避免频繁创建连接 2. **异步调用**:使用Netty的Promise实现非阻塞调用 3. **心跳机制**:添加IdleStateHandler保持连接活性 4. **压缩传输**:对大数据量启用Snappy/LZ4压缩 5. **背压控制**:通过ChannelFuture监听实现流量控制 ### 五、扩展方向 1. **服务注册与发现**:集成Zookeeper/Nacos ```java public class ZkServiceRegistry implements ServiceRegistry { private final CuratorFramework client; private final String rootPath = "/rpc-services"; @Override public void register(String serviceName, InetSocketAddress address) { try { client.create().creatingParentsIfNeeded() .withMode(CreateMode.EPHEMERAL) .forPath(rootPath + "/" + serviceName + "/" + address.toString()); } catch (Exception e) { throw new RegistryException(e); } } } ``` 2. **负载均衡**:实现随机/轮询/一致性哈希策略 3. **熔断降级**:集成Resilience4j/Hystrix 4. **跨语言支持**:使用Protobuf作为序列化协议 > 完整实现参考:GitHub开源项目[simple-rpc-framework](https://github.com/yourname/simple-rpc-framework)[^2][^4] ---
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值