# 一、手动实现RPC远程本地调用
## 1.0 版本
#### 1.1 实现思路:
基于netty的网络传输实现远程本地调用,无感知远程调用。
实现过程: ![](./netty/img/WX20220119-152458.png)
当前版本的实现思路:
该版本涉及:
- netty
- JDK动态代理。
- Spring 的扫描原理(@CompanScan,@MapperScan 同理)
- Spring的事件监听与处理,
- 反射,SpringListener 配置,负债均衡随机算法。
- 通过Spring注解形式启用RPC,接口暴露扫描,Rpc接口注解引用。
- 等等
该版本实现到的功能:服务注册、服务发现、服务断开注册中心自动剔除服务、多个提供者可对应一个消费者。
注册中心针对服务提供者的数据保存目前保存到本地文件中。
提供者引入咱们自己写的RPC框架,项目启动,加上 @EnableRpc 启动咱们的RPC框架应用,启动的时候,在上下文初始化的时候提供者向注册中心注册服务。 接着扫描咱们自己的 @RpcService 将其注册到Spring中。在Bean初始化之后将其接口暴露出去。
消费者引入接口,使用@RpcRefence 注解,消费者端不需要实现接口。项目启动也加上@EnableRpc。开始处理@RpcRefence 依赖注入。
消费者端调用的时候,在代理类invoke的方法去注册中心拉取可用服务,使用随机算法获得其中一个服务地址。通过netty连接传输我们的协议对象。
提供服务方收到连接请求的时候,读取协议参数,解析出接口名、参数类型、参数值通过反射执行该对应的方法,获取结果值。将结果再次回传给消费者。
#### 1.2 开发实现
基于SpringBoot进行开发,尽可能实现接近Dubbo
项目结构图:
![](./netty//img/WX20220119-154630.png)
- YJRpc 父项目
- server-consumer-one: 消费者一个
- server-provider-one: 提供者一个
- service-api: 我们的API接口(提供者实现,消费者不需要)
- service-common: 公共模块
- service-frame: RPC核心模块
- service-register-center: 注册中心
- service-frame:
- 注解:
- @EnableYJRpc
```java
/**
* RPC启动注解,加载配置类
* @author 永健
* @since 2022-01-18 14:58
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({YJRpcServiceScanRegistrar.class, RegisterConfig.class, BeanConfig.class})
public @interface EnableYJRpc { }
```
- @RpcReference
```java
/**
* 调用方消费者使用
* @author 永健
* @since 2022-01-18 17:09
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RpcReference {
String name() default "";
}
```
- @RpcService
```java
/**
* 暴露服务
* 将其该注解的类接口发布出去
* @author 永健
* @since 2022-01-18 15:28
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RpcService { }
```
- **服务注册**:在我们的提供者启动的时候,当上下文初始化好了,我们进行事件监听(ApplicationContextInitializedEvent)。在这个时候我们开始注册服务,并且启动netty服务
```java
/**
* 在上下文初始化的时候注册服务
* @author 永健
* @since 2022-01-19 10:23
*/
public class ApplicationStartingListener implements ApplicationListener<ApplicationContextInitializedEvent> {
@Override
public void onApplicationEvent(ApplicationContextInitializedEvent applicationContextInitializedEvent) {
ConfigurableEnvironment env = applicationContextInitializedEvent.getApplicationContext().getEnvironment();
// 配置文件里读取
String host = env.getProperty("spring.rpc.provider.host");
String applicationName = env.getProperty("spring.application.name");
if ("".equals(host) || host == null) {
return;
}
String[] split = host.split(":");
InetSocketAddress inetSocketAddress = new InetSocketAddress(split[0], Integer.parseInt(split[1]));
// 启动netty,提供者服务启动,注册服务
RegisterConfig.register(applicationName, host);
new NettyServer().start(inetSocketAddress);
}
}
```
![](./netty//img/WX20220119-155746.png)
- **接口暴露**:接口暴露在@RpcService的Bean初始化好后,将其暴露出去
```java
/**
* @author 永健
* @since 2022-01-18 16:03
*/
public class RpcAnnotationBean implements BeanPostProcessor {
/**
* bean初始化好后,暴露出去,将其注册到注册中心
*
* @param bean
* @param beanName
*
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
RpcService service = bean.getClass().getAnnotation(RpcService.class);
if (service != null) {
// 暴露接口
RegisterConfig.export(bean, beanName);
}
return bean;
}
}
```
![](./netty//WX20220119-161959.png)
- **接口剔除**: 当我们的提供者服务不可用时,我们将其从注册中心剔除
```java
/**
* 在上下文关闭的时候(服务停止)
*
* @author 永健
* @since 2022-01-19 10:23
*/
public class ApplicationCloseListener implements ApplicationListener<ContextClosedEvent> {
@Override
public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
// 移除注册中心的服务
RegisterConfig.logout();
// 关闭netty
NettyServer.closeServer();
}
}
```
- **远程调用实现(核心部分)**:远程调用的实现:调用方使用的是代理对象(接口),通过invoke方法,在此方法中,去注册中心拉取服务,获得服务地址后,通过netty传输该接口对应的协议参数,提供者拿到协议参数后,通过反射调用该接口的实现方法获得返回结果,将结果又返回给消费者。这就是全部过程,这个对于使用方来说是无感知的,即RPC远程本地调用。
- 消费者使用费例子:
- api接口
![](./netty//img/WX20220119-161018.png)
- 消费者: 没有实现该api接口
![](./netty//img/WX20220119-161108.png)
- 提供者:提供者分别实现api接口
![](./netty//img/WX20220119-161216.png)
![](./netty//img/WX20220119-161226.png)
- **消费者的invoke方法**
```java
/**
* Rpc调用方代理对象
* @author 永健
* @since 2022-01-18 17:11
*/
public class RpcReferenceProxy implements InvocationHandler {
private Class<?> aClass;
private String beanName;
public RpcReferenceProxy(Class<?> aClass, String beanName) {
this.beanName = beanName;
this.aClass = aClass;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ResponseHandler responseHandler = new ResponseHandler();
EventLoopGroup group = new NioEventLoopGroup(1);
Bootstrap bootstrap =
new Bootstrap().group(group).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000).channel(NioSocketChannel.c
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
实现思路: 基于netty的网络传输实现远程本地调用,无感知远程调用。 该版本涉及: netty JDK动态代理。 Spring 的扫描原理(@CompanScan,@MapperScan 同理) Spring的事件监听与处理, 反射,SpringListener 配置,负债均衡随机算法。 通过Spring注解形式启用RPC,接口暴露扫描,Rpc接口注解引用。 等等 该版本实现到的功能:服务注册、服务发现、服务断开注册中心自动剔除服务、多个提供者可对应一个消费者。 注册中心针对服务提供者的数据保存目前保存到本地文件中。
资源推荐
资源详情
资源评论
收起资源包目录
基于netty + SpringBoot仿照dubbo手动实现RPC远程本地无感知调用项目源码 (139个子文件)
RabbitTemplateConfig.class 3KB
OrderQueueConfig.class 2KB
OrderQueueListener.class 2KB
RabbitConfirmCallback.class 2KB
PApp.class 2KB
RabbitReturnCallback.class 1KB
OrderQueueConfig.class 685B
CApp.class 678B
spring.factories 97B
.gitignore 384B
server-consumer-one.iml 10KB
producer.iml 9KB
consumer.iml 9KB
AbstractAqs.java 11KB
AbstractRegisterConfig.java 7KB
NettyServer.java 6KB
NettyClient.java 5KB
NettyServer.java 5KB
ProtocolMessageConvert.java 4KB
RpcReferenceProxy.java 3KB
Header.java 3KB
DispatchHandler.java 2KB
HearBeatHandler.java 2KB
AbstractMessageHandler.java 2KB
NettyServerAutoConfig.java 2KB
RpcReferenceAnnotationBeanPostProcessor.java 2KB
MessageProtocol.java 2KB
MessageHandlerFactory.java 2KB
MqServer.java 2KB
AppTest.java 2KB
MessageEncode.java 2KB
AppSync.java 2KB
Provider.java 2KB
YJRpc.java 2KB
APPLock.java 1KB
DecryptHandler.java 1KB
StrUncodeUtils.java 1KB
HeartBeatMessageHandler.java 1KB
ApplicationStartingListener.java 1KB
AuthenticateHandler.java 1KB
BeanConfig.java 1KB
YJRpcServiceScanRegistrar.java 1KB
RpcProtocol.java 1KB
AbstractNettyServer.java 1KB
TestMessageHandler.java 1KB
RabbitTemplateConfig.java 1KB
TestService.java 1KB
RabbitConfirmCallback.java 1KB
OrderQueueListener.java 1KB
OrderQueueConfig.java 1KB
RpcAnnotationBean.java 1008B
App.java 993B
RabbitReturnCallback.java 967B
YJClassPathScanner.java 949B
AbstractNettyServer.java 949B
AbstractMessageChain.java 947B
BasePacket.java 897B
PApp.java 861B
ApplicationCloseListener.java 849B
App.java 840B
EnableNettyServer.java 775B
SpringBean.java 770B
ApplicationStartFailListener.java 747B
EncryptionUtils.java 719B
SimpleChannelOutboundHandler.java 666B
MessageDispatchListener.java 658B
BeanUtils.java 658B
App.java 606B
HelloService.java 604B
RpcReferenceFactoryBean.java 565B
Const.java 558B
MessageDecode.java 543B
EnableYJRpc.java 532B
CommandCode.java 526B
ResponseHandler.java 526B
MessageType.java 520B
YjRpcService.java 519B
IHeartBeatMonitor.java 498B
MessageHandler.java 457B
OrderQueueConfig.java 405B
RpcReferenceProxyFactory.java 377B
Encrypt.java 369B
NettyMessageListener.java 363B
IProtocolMessageConvert.java 338B
MqApp.java 338B
CApp.java 334B
RpcReference.java 288B
RpcService.java 286B
IMessageChain.java 244B
INettyServer.java 207B
INettyServer.java 206B
BodyType.java 185B
ILock.java 176B
IHelloService.java 174B
IYJRpcService.java 170B
RegisterConfig.java 142B
EnCodeType.java 136B
index.jsp 52B
index.jsp 52B
README.md 12KB
共 139 条
- 1
- 2
资源评论
程序员柳
- 粉丝: 6097
- 资源: 1195
下载权益
C知道特权
VIP文章
课程特权
开通VIP
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功