# 《RPC手撸专栏》第4章:实现RPC服务核心注解的扫描与解析

作者:冰河
星球:http://m6z.cn/6aeFbs (opens new window)
博客:https://binghe.gitcode.host (opens new window)
文章汇总:https://binghe.gitcode.host/md/all/all.html (opens new window)

沉淀,成长,突破,帮助他人,成就自我。

大家好,我是冰河~~

在第3章中,我们详细说明了RPC核心注解@RpcService和@RpcReference的设计与实现。

@RpcService注解主要使用的场景是:标注到RPC服务实现类上,如果某个接口的实现类被标注了@RpcService注解,则这个接口与实现类会被发布为RPC服务,对外提供远程服务。使用@RpcService注解标注的服务承担服务提供者的角色。

@RpcReference注解主要使用的场景:标注到类字段上,这个字段的引用就是某个标注了@RpcService注解的实现类对应的接口的实例,如果一个类的某个字段被@RpcReference注解标注,则这个类可以通过@RpcReference注解标注的字段来调用使用@RpcService注解标注的对应的远程服务。使用@RpcReference注解标注的服务承担服务消费者的角色。

# 一、文章总体结构

rpc-2022-08-22-001

# 二、设计思路

在实现的RPC框架中的服务提供者、服务消费者、注册中心和监控中心四个部分中,最为核心的就是服务提供者和服务消费者。服务提供提供者和服务消费者要做到支持远程Java调用、整合Spring的xml配置方式调用、整合Spring注解调用、整合SpringBoot调用等等。并且还需要支持同步调用、异步调用、回调和单向调用。

在设计上,服务提供者将自身对外提供的服务注册到注册中心,服务消费者从注册中心订阅到服务提供者提供的服务后,即使注册中心发生宕机不可用,服务提供者与服务消费者之间也能够正常通信。

既然服务提供者和服务消费者需要支持原生的Java方式调用,那么,就需要自行开发一套扫描@RpcService注解和@RpcReference注解的逻辑,而不是直接依赖Spring的包扫描逻辑。

接下来,还需要在性能与实现两个方面做权衡和取舍。

首先,在服务提供者一侧,当使用Java原生程序启动服务提供者时,通过扫描所有实现类上的@RpcService注解将对应的服务注册到注册中心,这种方式没啥问题。

其次,在服务消费者一侧,当使用Java原生程序启动服务消费者时,通过扫描所有@RpcReference注解的类字段,并创建对应实例的代理对象的方式,比起直接通过服务消费者客户端创建服务引用的代理对象的方式性能上略微低下,所以,在设计使用Java原生程序启动服务消费者时,支持直接通过服务消费者客户端和扫描@RpcReference注解两种方式 创建服务应用的代理对象。

# 三、实现通用扫描器

在设计思路时,已经确定了如果使用Java的原生程序启动服务提供者和服务消费者时,需要自行实现一套包扫描逻辑,而不是直接使用Spring提供的包扫描。

# 3.1 通用扫描器需求

在针对于@RpcService注解和@RpcReference注解开发包扫描逻辑之前,我们可以首先实现一个扫描指定包下的所有类的逻辑,具体的需求点如下。

  • 扫描指定包下的所有类,无论这个类是在当前项目中,还是在引用的Jar文件中,都需要被扫描到。
  • 真正需要扫描的类文件的后缀必须是.class,因为只有.class文件是Java编译出的类文件。
  • 返回指定包下所有类的完整类名称集合。

# 3.2 通用扫描器实现

在bhrpc-learning工程下创建bhrpc-common子工程模块,在建bhrpc-common子工程模块的pom.xml文件中添加如下依赖。

<dependencies>
	<dependency>
		<groupId>io.binghe.rpc</groupId>
		<artifactId>bhrpc-annotation</artifactId>
		<version>${project.version}</version>
	</dependency>
</dependencies>
1
2
3
4
5
6
7

# 查看完整文章

加入冰河技术 (opens new window)知识星球,解锁完整技术文章与完整代码