From 47e5fef626e3fe31ab028d35bdfb16f80cafa5a8 Mon Sep 17 00:00:00 2001
From: xjs <1294405880@qq.com>
Date: Thu, 10 Mar 2022 10:36:43 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AD=A6=E4=B9=A0---=E8=87=AA=E5=AE=9A?=
=?UTF-8?q?=E4=B9=89rpc=E6=A1=86=E6=9E=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../custom-rpc/lg-rpc-api/pom.xml | 39 ++++++
.../java/com/lagou/rpc/api/IUserService.java | 17 +++
.../java/com/lagou/rpc/common/RpcRequest.java | 34 +++++
.../com/lagou/rpc/common/RpcResponse.java | 26 ++++
.../main/java/com/lagou/rpc/pojo/User.java | 9 ++
.../custom-rpc/lg-rpc-consumer/pom.xml | 27 ++++
.../lagou/rpc/consumer/ClientBootStrap.java | 23 ++++
.../lagou/rpc/consumer/client/RpcClient.java | 127 ++++++++++++++++++
.../consumer/handler/RpcClientHandler.java | 73 ++++++++++
.../rpc/consumer/proxy/RpcClientProxy.java | 68 ++++++++++
.../custom-rpc/lg-rpc-provider/pom.xml | 35 +++++
.../provider/ServerBootstrapApplication.java | 32 +++++
.../rpc/provider/annotation/RpcService.java | 18 +++
.../provider/handler/RpcServerHandler.java | 120 +++++++++++++++++
.../lagou/rpc/provider/server/RpcServer.java | 89 ++++++++++++
.../rpc/provider/service/UserServiceImpl.java | 30 +++++
xjs-study/netty-project/custom-rpc/pom.xml | 30 +++++
.../netty-project/netty-springboot/pom.xml | 11 +-
xjs-study/netty-project/pom.xml | 5 +-
xjs-study/pom.xml | 2 +
xjs-study/xjs-study-base/pom.xml | 5 +-
21 files changed, 806 insertions(+), 14 deletions(-)
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-api/pom.xml
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/api/IUserService.java
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/common/RpcRequest.java
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/common/RpcResponse.java
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/pojo/User.java
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-consumer/pom.xml
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/ClientBootStrap.java
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/client/RpcClient.java
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/handler/RpcClientHandler.java
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/proxy/RpcClientProxy.java
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-provider/pom.xml
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/ServerBootstrapApplication.java
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/annotation/RpcService.java
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/handler/RpcServerHandler.java
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/server/RpcServer.java
create mode 100644 xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/service/UserServiceImpl.java
create mode 100644 xjs-study/netty-project/custom-rpc/pom.xml
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-api/pom.xml b/xjs-study/netty-project/custom-rpc/lg-rpc-api/pom.xml
new file mode 100644
index 00000000..bf65b966
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-api/pom.xml
@@ -0,0 +1,39 @@
+
+
+
+ custom-rpc
+ com.xjs
+ 1.0
+
+ 4.0.0
+ 自定义RPC框架-API
+
+ lg-rpc-api
+
+
+
+ UTF-8
+
+
+
+
+
+ io.netty
+ netty-all
+
+
+
+ com.alibaba
+ fastjson
+ 1.2.73
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.16
+
+
+
\ No newline at end of file
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/api/IUserService.java b/xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/api/IUserService.java
new file mode 100644
index 00000000..9dd56f72
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/api/IUserService.java
@@ -0,0 +1,17 @@
+package com.lagou.rpc.api;
+
+import com.lagou.rpc.pojo.User;
+
+/**
+ * 用户服务
+ */
+public interface IUserService {
+
+ /**
+ * 根据ID查询用户
+ *
+ * @param id
+ * @return
+ */
+ User getById(int id);
+}
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/common/RpcRequest.java b/xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/common/RpcRequest.java
new file mode 100644
index 00000000..c2728f2d
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/common/RpcRequest.java
@@ -0,0 +1,34 @@
+package com.lagou.rpc.common;
+
+import lombok.Data;
+
+import java.util.Arrays;
+
+/**
+ * 封装的请求对象
+ */
+@Data
+public class RpcRequest {
+
+ /**
+ * 请求对象的ID
+ */
+ private String requestId;
+ /**
+ * 类名
+ */
+ private String className;
+ /**
+ * 方法名
+ */
+ private String methodName;
+ /**
+ * 参数类型
+ */
+ private Class>[] parameterTypes;
+ /**
+ * 入参
+ */
+ private Object[] parameters;
+
+}
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/common/RpcResponse.java b/xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/common/RpcResponse.java
new file mode 100644
index 00000000..0bec5f02
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/common/RpcResponse.java
@@ -0,0 +1,26 @@
+package com.lagou.rpc.common;
+
+import lombok.Data;
+
+/**
+ * 封装的响应对象
+ */
+@Data
+public class RpcResponse {
+
+ /**
+ * 响应ID
+ */
+ private String requestId;
+
+ /**
+ * 错误信息
+ */
+ private String error;
+
+ /**
+ * 返回的结果
+ */
+ private Object result;
+
+}
\ No newline at end of file
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/pojo/User.java b/xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/pojo/User.java
new file mode 100644
index 00000000..a2b1480e
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-api/src/main/java/com/lagou/rpc/pojo/User.java
@@ -0,0 +1,9 @@
+package com.lagou.rpc.pojo;
+
+import lombok.Data;
+
+@Data
+public class User {
+ private int id;
+ private String name;
+}
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/pom.xml b/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/pom.xml
new file mode 100644
index 00000000..bfa27a1d
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/pom.xml
@@ -0,0 +1,27 @@
+
+
+
+ custom-rpc
+ com.xjs
+ 1.0
+
+ 4.0.0
+ 自定义RPC框架-消费者
+
+ lg-rpc-consumer
+
+
+ UTF-8
+
+
+
+
+ com.xjs
+ lg-rpc-api
+ 1.0
+
+
+
+
\ No newline at end of file
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/ClientBootStrap.java b/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/ClientBootStrap.java
new file mode 100644
index 00000000..8aabcf8b
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/ClientBootStrap.java
@@ -0,0 +1,23 @@
+package com.lagou.rpc.consumer;
+
+import com.lagou.rpc.api.IUserService;
+import com.lagou.rpc.consumer.proxy.RpcClientProxy;
+import com.lagou.rpc.pojo.User;
+
+/**
+ * 测试类
+ * @author xiejs
+ * @since 2022-03-10
+ */
+public class ClientBootStrap {
+
+ public static void main(String[] args) {
+ IUserService userService = (IUserService) RpcClientProxy.createProxy(IUserService.class);
+
+ User user = userService.getById(1);
+
+ System.out.println(user);
+
+ }
+
+}
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/client/RpcClient.java b/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/client/RpcClient.java
new file mode 100644
index 00000000..56fbd04c
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/client/RpcClient.java
@@ -0,0 +1,127 @@
+package com.lagou.rpc.consumer.client;
+
+import com.lagou.rpc.consumer.handler.RpcClientHandler;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.Channel;
+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.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+/**
+ * 客户端
+ *
+ * - 连接Netty服务端
+ * - 提供个调用者主动关闭资源的方法
+ * - 提供消息发送的方法
+ *
+ *
+ * @author xiejs
+ * @since 2022-03-10
+ */
+@Data
+@NoArgsConstructor
+public class RpcClient {
+
+ private String ip;
+
+ private Integer port;
+
+ private NioEventLoopGroup group;
+
+ private Channel channel;
+
+ private RpcClientHandler clientHandler = new RpcClientHandler();
+
+ private ExecutorService executor = Executors.newCachedThreadPool();
+
+
+ public RpcClient(String ip, Integer port) {
+ this.ip = ip;
+ this.port = port;
+ this.initClient();
+ }
+
+ /**
+ * 初始化方法-连接Netty服务端
+ */
+ public void initClient() {
+
+
+ try {
+ //1、创建线程组
+ group = new NioEventLoopGroup();
+
+ //2、创建启动助手
+ Bootstrap bootstrap = new Bootstrap();
+
+ //3、设置参数
+ bootstrap.group(group)
+ .channel(NioSocketChannel.class)
+ .option(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)
+ .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)
+ .handler(new ChannelInitializer() {
+ @Override
+ protected void initChannel(SocketChannel ch) throws Exception {
+ ChannelPipeline pipeline = ch.pipeline();
+
+ //String类型编解码器
+ pipeline.addLast(new StringEncoder());
+ pipeline.addLast(new StringDecoder());
+
+ //添加客户端处理类
+ pipeline.addLast(clientHandler);
+ }
+ });
+
+ //连接netty服务端
+ channel = bootstrap.connect(ip, port).sync().channel();
+ } catch (Exception e) {
+ e.printStackTrace();
+ if (channel != null) {
+ channel.close();
+ }
+ if (group != null) {
+ group.shutdownGracefully();
+ }
+ }
+ }
+
+
+ /**
+ * 提供资源关闭的方法
+ */
+ public void close() {
+ if (channel != null) {
+ channel.close();
+ }
+ if (group != null) {
+ group.shutdownGracefully();
+ }
+ }
+
+ /**
+ * 提供消息发送的方法
+ *
+ * @return
+ */
+ public Object send(String msg) throws ExecutionException, InterruptedException {
+ clientHandler.setRequestMsg(msg);
+
+ Future future = executor.submit(clientHandler);
+ return future.get();
+
+ }
+
+}
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/handler/RpcClientHandler.java b/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/handler/RpcClientHandler.java
new file mode 100644
index 00000000..2eaa829e
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/handler/RpcClientHandler.java
@@ -0,0 +1,73 @@
+package com.lagou.rpc.consumer.handler;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import lombok.Data;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.Callable;
+
+/**
+ * 客户端处理类
+ *
+ * - 发送消息
+ * - 接收消息
+ *
+ * @author xiejs
+ * @since 2022-03-10
+ */
+@Data
+@Component
+public class RpcClientHandler extends SimpleChannelInboundHandler implements Callable {
+
+ private ChannelHandlerContext ctx;
+
+ /**
+ * 发送的消息
+ */
+ String requestMsg;
+
+
+ String responseMsg;
+
+
+
+
+
+ /**
+ * 通道连接就绪事件
+ * @param ctx
+ * @throws Exception
+ */
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) throws Exception {
+ this.ctx = ctx;
+ }
+
+ /**
+ * 通道读取就绪事件
+ * @param ctx
+ * @param msg
+ * @throws Exception
+ */
+ @Override
+ protected synchronized void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
+ responseMsg = msg;
+
+ //唤醒等待的线程
+ notify();
+
+ }
+
+ @Override
+ public synchronized Object call() throws Exception {
+ //消息发送
+ ctx.writeAndFlush(requestMsg);
+
+ //线程等待
+ wait();
+
+
+ return responseMsg;
+ }
+}
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/proxy/RpcClientProxy.java b/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/proxy/RpcClientProxy.java
new file mode 100644
index 00000000..3a154e41
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-consumer/src/main/java/com/lagou/rpc/consumer/proxy/RpcClientProxy.java
@@ -0,0 +1,68 @@
+package com.lagou.rpc.consumer.proxy;
+
+import com.alibaba.fastjson.JSON;
+import com.lagou.rpc.common.RpcRequest;
+import com.lagou.rpc.common.RpcResponse;
+import com.lagou.rpc.consumer.client.RpcClient;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.UUID;
+
+/**
+ * 客户端代理类-创建代理对象
+ *
+ * - 封装request请求对象
+ * - 创建RpcClient对象
+ * - 发送消息
+ * - 返回结果
+ *
+ *
+ * @author xiejs
+ * @since 2022-03-10
+ */
+public class RpcClientProxy {
+
+ public static Object createProxy(Class serviceClass) {
+ return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
+ new Class[]{serviceClass},
+ new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ //1、封装request对象
+ RpcRequest rpcRequest = new RpcRequest();
+ rpcRequest.setRequestId(UUID.randomUUID().toString());
+ rpcRequest.setClassName(method.getDeclaringClass().getName());
+ rpcRequest.setParameterTypes(method.getParameterTypes());
+ rpcRequest.setMethodName(method.getName());
+ rpcRequest.setParameters(args);
+
+ //2、封装RpcClient对象
+ RpcClient rpcClient = new RpcClient("127.0.0.1", 8887);
+
+ try {
+ //3、发送消息
+ Object responseMsg = rpcClient.send(JSON.toJSONString(rpcRequest));
+
+ RpcResponse rpcResponse = JSON.parseObject(responseMsg.toString(), RpcResponse.class);
+ if (rpcResponse.getError() != null) {
+ throw new RuntimeException(rpcResponse.getError());
+ }
+
+ //4、返回结构
+ Object result = rpcResponse.getResult();
+
+ return JSON.parseObject(result.toString(), method.getReturnType());
+ } catch (Exception e) {
+ throw e;
+ } finally {
+ rpcClient.close();
+ }
+ }
+ }
+ );
+ }
+
+
+}
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-provider/pom.xml b/xjs-study/netty-project/custom-rpc/lg-rpc-provider/pom.xml
new file mode 100644
index 00000000..0dcdd143
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-provider/pom.xml
@@ -0,0 +1,35 @@
+
+
+
+ custom-rpc
+ com.xjs
+ 1.0
+
+ 4.0.0
+ 自定义RPC框架-生产者
+
+ lg-rpc-provider
+
+
+ UTF-8
+
+
+
+
+ com.xjs
+ lg-rpc-api
+ 1.0
+
+
+
+ org.springframework
+ spring-context
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+
+
+
\ No newline at end of file
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/ServerBootstrapApplication.java b/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/ServerBootstrapApplication.java
new file mode 100644
index 00000000..f8f8ae9f
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/ServerBootstrapApplication.java
@@ -0,0 +1,32 @@
+package com.lagou.rpc.provider;
+
+import com.lagou.rpc.provider.server.RpcServer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author xiejs
+ * @since 2022-03-09
+ */
+@SpringBootApplication
+public class ServerBootstrapApplication implements CommandLineRunner {
+
+ @Autowired
+ private RpcServer rpcServer;
+
+ public static void main(String[] args) {
+ SpringApplication.run(ServerBootstrapApplication.class, args);
+ }
+
+ @Override
+ public void run(String... args) throws Exception {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ rpcServer.startServer("127.0.0.1",8887);
+ }
+ }).start();
+ }
+}
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/annotation/RpcService.java b/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/annotation/RpcService.java
new file mode 100644
index 00000000..ac64608b
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/annotation/RpcService.java
@@ -0,0 +1,18 @@
+package com.lagou.rpc.provider.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 对外暴露服务接口
+ * @author xiejs
+ * @since 2022-03-09
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RpcService {
+
+
+}
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/handler/RpcServerHandler.java b/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/handler/RpcServerHandler.java
new file mode 100644
index 00000000..58203dc3
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/handler/RpcServerHandler.java
@@ -0,0 +1,120 @@
+package com.lagou.rpc.provider.handler;
+
+import com.alibaba.fastjson.JSON;
+import com.lagou.rpc.common.RpcRequest;
+import com.lagou.rpc.common.RpcResponse;
+import com.lagou.rpc.provider.annotation.RpcService;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import org.springframework.beans.BeansException;
+import org.springframework.cglib.reflect.FastClass;
+import org.springframework.cglib.reflect.FastMethod;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ *
+ * 服务端业务处理类
+ *
+ *
+ *
+ * - 将标有@RpcService注解的bean缓存
+ * - 接收客户端请求
+ * - 根据传递过来的beanName从缓存中查找到对应的bean
+ * - 解析请求中的方法名称,参数类型 参数信息
+ * - 反射调用bean的方法
+ * - 给客户端进行响应
+ *
+ *
+ * @author xiejs
+ * @since 2022-03-09
+ */
+@Component
+@ChannelHandler.Sharable
+public class RpcServerHandler extends SimpleChannelInboundHandler implements ApplicationContextAware {
+
+ private static final Map SERVICE_INSTANCE_MAP = new ConcurrentHashMap();
+
+
+ /**
+ * 通道读取就绪事件
+ *
+ * @param ctx
+ * @param msg
+ * @throws Exception
+ */
+ @Override
+ protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
+ //1、接收客户端请求--将msg转化RpcRequest对象
+ RpcRequest request = JSON.parseObject(msg, RpcRequest.class);
+
+ RpcResponse response = new RpcResponse();
+ response.setRequestId(request.getRequestId());
+
+ try {
+ response.setResult(handler(request));
+ } catch (Exception e) {
+ response.setError(e.getMessage());
+ e.printStackTrace();
+ }
+
+ //给客户端进行响应
+ ctx.writeAndFlush(JSON.toJSONString(response));
+ }
+
+
+ /**
+ * 业务处理逻辑
+ *
+ * @return obj
+ */
+ private Object handler(RpcRequest request) throws InvocationTargetException {
+ //根据传递过来的beanName从缓存中查找到对应的bean
+ Object serviceBean = SERVICE_INSTANCE_MAP.get(request.getClassName());
+
+ if (serviceBean == null) {
+ throw new RuntimeException("根据beanName找不到服务,beanName:" + request.getClassName());
+ }
+
+ //解析请求中的方法名称,参数类型 参数信息
+ Class> serviceBeanClass = serviceBean.getClass();
+ String methodName = request.getMethodName();
+ Class>[] parameterTypes = request.getParameterTypes();
+ Object[] parameters = request.getParameters();
+
+ //反射调用bean的方法
+ FastClass fastClass = FastClass.create(serviceBeanClass);
+ FastMethod method = fastClass.getMethod(methodName, parameterTypes);
+
+ return method.invoke(serviceBean, parameters);
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+
+ Map serviceMap = applicationContext.getBeansWithAnnotation(RpcService.class);
+ if (serviceMap != null && serviceMap.size() > 0) {
+ Set> entries = serviceMap.entrySet();
+ for (Map.Entry item : entries) {
+ Object serviceBean = item.getValue();
+
+ if (serviceBean.getClass().getInterfaces().length == 0) {
+ throw new RuntimeException("服务必须实现接口");
+ }
+
+ //默认取第一个接口作为缓存bean的名称
+ String name = serviceBean.getClass().getInterfaces()[0].getName();
+ SERVICE_INSTANCE_MAP.put(name, serviceBean);
+ }
+ }
+
+
+ }
+}
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/server/RpcServer.java b/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/server/RpcServer.java
new file mode 100644
index 00000000..57768c49
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/server/RpcServer.java
@@ -0,0 +1,89 @@
+package com.lagou.rpc.provider.server;
+
+import com.lagou.rpc.provider.handler.RpcServerHandler;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.codec.string.StringEncoder;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * netty启动类
+ *
+ * @author xiejs
+ * @since 2022-03-09
+ */
+@Component
+public class RpcServer implements DisposableBean {
+
+ @Autowired
+ private RpcServerHandler serverHandler;
+
+ private NioEventLoopGroup bossGroup;
+
+ private NioEventLoopGroup workerGroup;
+
+
+ public void startServer(String ip, Integer port) {
+
+ try {
+ //1、创建线程组
+ bossGroup = new NioEventLoopGroup(1);
+ workerGroup = new NioEventLoopGroup();
+
+ //2、创建服务端启动助手
+ ServerBootstrap bootstrap = new ServerBootstrap();
+
+ //3、设置参数
+ bootstrap.group(bossGroup, workerGroup)
+ .channel(NioServerSocketChannel.class)
+ .childHandler(new ChannelInitializer() {
+ @Override
+ protected void initChannel(SocketChannel ch) throws Exception {
+ ChannelPipeline pipeline = ch.pipeline();
+
+ //添加String的编解码器
+ pipeline.addLast(new StringDecoder());
+ pipeline.addLast(new StringEncoder());
+
+ //添加业务处理类
+ pipeline.addLast(serverHandler);
+
+ }
+ });
+
+ //4、绑定端口
+ ChannelFuture future = bootstrap.bind(ip, port).sync();
+
+ System.out.println("--------服务端启动成功----------");
+
+ future.channel().closeFuture().sync();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 在容器销毁执行
+ *
+ * @throws Exception
+ */
+ @Override
+ public void destroy() throws Exception {
+ if (bossGroup != null) {
+ bossGroup.shutdownGracefully();
+ }
+
+ if (workerGroup != null) {
+ workerGroup.shutdownGracefully();
+ }
+ }
+
+}
diff --git a/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/service/UserServiceImpl.java b/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/service/UserServiceImpl.java
new file mode 100644
index 00000000..52959422
--- /dev/null
+++ b/xjs-study/netty-project/custom-rpc/lg-rpc-provider/src/main/java/com/lagou/rpc/provider/service/UserServiceImpl.java
@@ -0,0 +1,30 @@
+package com.lagou.rpc.provider.service;
+
+import com.lagou.rpc.api.IUserService;
+import com.lagou.rpc.pojo.User;
+import com.lagou.rpc.provider.annotation.RpcService;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Service
+@RpcService
+public class UserServiceImpl implements IUserService {
+ Map