手把手带你0到1摸透RPC框架轮子项目-day5拦截器层、SPI、容错层、线程池 完结

原视频参考地址:[全网最全的手写RPC教程] 手摸手教你写一个RPC-架构-设计-落地实现_哔哩哔哩_bilibili

项目地址:kkoneone11/kkoneoneRPC-master (github.com)

觉得对你有帮助的帮忙文章给个like和项目给个stars呀!!!

因为我的设计是从顶到底去写代码,因此这一部分的代码量会比往后的多,大家可以分几天去编写

拦截器层

在服务发送前后以及服务接收前后可进行一系列的拦截操作,或者是增强行为等。这是一个拓展机制。

写了ClientAfterFilter、ClientBeforeFilter、ServiceAfterFilter、ServiceBeforeFilter四个拦截器方便SPI的扩展。

FilterChain采用的是责任链的形式,addFilter用来加入过滤链,然后doFilter用来执行

而FilterConfig则是初始化服务提供方和服务调用方的SPI拓展。其中在extensionLoader的loadExtension方法先传入对应过滤器的接口去配置文件中找到对应的配置类,然后再通过get方法进行初始化并加入到addFilter中进行执行对应的过滤器链。

ServiceTokenFilter

首先如果客户端想要设置token的话得先在RpcProperties中客户端Map配置

从filterData拿到客户端的token之后,再到服务提供方拿对应的token然后进行token的检验

RpcInvokerProxy的invoke方法就是在此处开始进行第一次拦截

代码部分

ServiceTokenFilter

typescript 复制代码
package org.kkoneone.rpc.Filter.service;
​
import org.kkoneone.rpc.Filter.FilterData;
import org.kkoneone.rpc.Filter.ServiceBeforeFilter;
import org.kkoneone.rpc.config.RpcProperties;
​
import java.util.Map;
​
/**
 * token拦截器
 * @Author:kkoneone11
 * @name:ServiceTokenFilter
 * @Date:2023/12/11 23:25
 */
public class ServiceTokenFilter implements ServiceBeforeFilter {
    @Override
    public void doFilter(FilterData filterData) {
        final Map<String, Object> attachments = filterData.getClientAttachments();
        final Map<String, Object> serviceAttachments = RpcProperties.getInstance().getServiceAttachments();
        if (!attachments.getOrDefault("token","").equals(serviceAttachments.getOrDefault("token",""))){
            throw new IllegalArgumentException("token不正确");
        }
    }
}
​

SPI

使用SPI后对于整个程序的拓展性有了极大的提升。 概念: 制定好接口规范协议后,其他服务按照你制定好的服务协议。随后使用SPI进行可插拔方式来加载不同的类。 例如:mysql的jdbc驱动,我先制定好一个协议,我不管你是什么sql厂商,你都遵循我的协议来然后并把依赖给我,然后我使用spi机制来进行加载类就行。

其中 load方法是懒加载的形式,

因为ServiceLoader底层实现的是一个懒迭代器的形式

而只有当load被调用的时候,如以下情况,才会被加载

而加载对应的服务就是依靠迭代器中的hasNextService()方法

通过这个来拼接去寻找对应的服务名,通常是在META-INF下会有services,里面放的就是接口名和路径。

当用户或者客户想要实现自己的注册中心或者编码序列化或者拦截器的时候

只需要实现一个ExtensionLoader,里面配置好客户要动态实现的前缀为寻找该动态配置的路径,然后在下面撰写自己的方案即可

而加载方法就是loadExtention()方法,传入接口之后,然后同时去系统SPI和用户SPI中寻找该接口下面的类

前缀和类名拼接起来之后就是对应的路径名,然后根据对应的路径名去读取对应配置的文件然后放到对应的map中,并没有进行初始化

例如:ConsumerPostProcessor中的afterPropertiesSet()方法

其中序列化工厂初始化的时候就是里面实现了init()方法是通过SPI机制的ExtensionLoader的loadExtension方法传入RpcSerialization这个接口去加载,而加载之后不会立刻去初始化。

只有当要调用get方法,传入的是对应的是key,key是前面的这个,=后面的是value

容错层

在服务提供方发生错误时(无法提供服务),此时有可能还会有其他服务能提供,因此还需要尝试找其他服务。而这里采用的是switch的方式去选择对应的容错策略,这样的缺点是没有办法实现拓展性,因此此处也可以通过SPI机制来进行策略的拓展。

如果想改造的可以根据自己的需求去拓展,这里只是先创建了容错策略接口和容错策略工厂。这里的作用和实现SPI的流程是一致的。如果要实现具体的容错策略算法,要先继承接口FaultTolerantStrategy,具体的逻辑写在对应的类中(如FailoverFaultTolerantStrategy),并在META-INF配置写上对应的配置文件。然后把工厂类就get和init方法即可。

线程池

如果服务提供方B和C都挂了,那么请求就都打到A上了,这样也会增大A的压力导致A挂掉,因此加一个线程池还可以进一步减缓压力

相关推荐
Alive~o.07 分钟前
Go语言进阶&依赖管理
开发语言·后端·golang
许苑向上13 分钟前
Dubbo集成SpringBoot实现远程服务调用
spring boot·后端·dubbo
郑祎亦1 小时前
Spring Boot 项目 myblog 整理
spring boot·后端·java-ee·maven·mybatis
本当迷ya1 小时前
💖2025年不会Stream流被同事排挤了┭┮﹏┭┮(强烈建议实操)
后端·程序员
计算机毕设指导62 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
paopaokaka_luck2 小时前
[371]基于springboot的高校实习管理系统
java·spring boot·后端
捂月4 小时前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
瓜牛_gn4 小时前
依赖注入注解
java·后端·spring
Estar.Lee4 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
喜欢猪猪4 小时前
Django:从入门到精通
后端·python·django