手写RPC框架第8版-通过SpringBoot-Starter接入SpringBoot

news2024/11/25 4:31:54

源代码地址:https://github.com/lhj502819/IRpc/tree/v9

系列文章:

  • 注册中心模块实现
  • 路由模块实现
  • 序列化模块实现
  • 过滤器模块实现
  • 自定义SPI机制增加框架的扩展性的设计与实现
  • 基于线程和队列提升框架并发处理能力
  • 框架容错性相关设计
  • 通过SpringBoot-Starter接入SpringBoot

为什么要接入Spring/SpringBoot?

目前Spring和SpringBoot在Java领域应该是主流的开发框架了,国内的小伙伴应该是无人不用,唯一的差异点可能就是有的人还没有使用过SpringBoot,但Spring肯定是事实标准了。

Spring/SpringBoot有啥优点呢?简单来说是它帮我们减少了很多不必要的工作,比如第三方中间件的集成、框架的集成,它都有一套自己的封装,因此目前主流的框架或者中间件都会去适配Spring/SpringBoot,一方面为了自己框架的推广,另一方面也是为了使用Spring/SpringBoot的特性,让框架的使用更加简单便捷。

那是怎么让框架的使用更加简单便捷的呢?首先我们就要先了解我们框架目前使用的困难点,可以看到我们发起一次调用都要写这么复杂的代码。
在这里插入图片描述

那通过集成Spring/SpringBoot能达到什么效果呢?我们先看下接入后的使用流程,如下图,对你没有看错,就是这么简单,相信使用过Dubbo的朋友一定很熟悉,就是借鉴的Dubbo~

在这里插入图片描述

接下来让我们一起看看怎么操作吧!

自定义Spingboot starter

这里我们就不去实现对Spring的集成了,直接上高阶的,因为Spring的比较麻烦哈哈,目前主流的应该也是Springboot了。

如何自定义Springboot starter

我们需要在META-INF中创建自动装配配置文件spring.factories,文件内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.onenine.irpc.framework.springboot.starter.config.IRpcServerAutoConfiguration,\
cn.onenine.irpc.framework.springboot.starter.config.IRpcClientAutoConfiguration

EnableAutoConfiguration为SpringBoot的注解,见名知意就是开启自动配置的意思,其=号后边的就是我们需要装配的类,通过这样的方式,我们将starter项目编译打包之后推送到maven仓库,他人在便可以通过引用我们的starter maven坐标来集成RPC框架,具体的使用方式会在后边进行演示。

Client端自动装配/配置实现

自定义Reference注解

为了我们能一眼就认出哪些属性需要我们进行动态代理(比如DataService dataService),因此我们需要设计一个注解来标识,并且我们还可以把该Service的调用相关参数通过注解进行配置,这样我们在自动装配的时候直接读取注解的元信息再去执行相关的封装操作岂不美哉。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IRpcReference {

    String url() default "";

    String group() default "";

    String serviceToken() default "";

    int timeOut() default 3000;

    int retry() default 1;

    boolean async() default false;
}

可以看到和这里的属性是一一对应的。

自动装配逻辑

接下来该咋办呢?我们都知道在使用Spring的时候都需要去定义Controller/Service/DAO,在里边去注入我们需要的其他Bean,并且我们的Controller/Service/DAO也会作为一个Bean被Spring容器管理起来,那我们就需要想办法在Bean创建完之后,获取到有标记IRpcReference注解属性的Bean,再执行后续的生成代理对象,获取Provider和建立连接的逻辑。
在Spring中为我们提供了一些列的扩展点,其中有一个接口BeanPostProcessor,该接口提供了两个方法,如下:

public interface BeanPostProcessor {
    //Bean实例化之前执行
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
    //Bean实例化之后执行
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

那这里很明显我们就要去实现postProcessAfterInitialization去完成我们的相关逻辑,以下是代码实现,比较简单,就不过多解释了:

public class IRpcClientAutoConfiguration implements BeanPostProcessor, ApplicationListener<ApplicationReadyEvent>, ApplicationContextAware {

    private static final Logger LOGGER = LoggerFactory.getLogger(IRpcClientAutoConfiguration.class);

    private Client client;

    private RpcReference rpcReference;

    /**
     * 是否需要启动NettyClient
     */
    private boolean hasInitClientApplication;

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Field[] fields = bean.getClass().getDeclaredFields();
        for (Field field : fields) {
            try {
                //设置私有变量可访问
                field.setAccessible(true);
                IRpcReference rpcReferenceAnnotation = field.getAnnotation(IRpcReference.class);
                if (rpcReferenceAnnotation == null) {
                    continue;
                }
                if (!hasInitClientApplication){
                    try {
                        client = new Client();
                        rpcReference = client.initClientApplication();
                    } catch (Exception e) {
                        LOGGER.error("init and start netty client error" , e);
                        throw new RuntimeException(e);
                    }
                }
                hasInitClientApplication = true;
                RpcReferenceWrapper rpcReferenceWrapper = new RpcReferenceWrapper();
                rpcReferenceWrapper.setAimClass(field.getType());
                rpcReferenceWrapper.setGroup(rpcReferenceAnnotation.group());
                rpcReferenceWrapper.setTimeOut(rpcReferenceAnnotation.timeOut());
                rpcReferenceWrapper.setToken(rpcReferenceAnnotation.serviceToken());
                rpcReferenceWrapper.setUrl(rpcReferenceAnnotation.url());
                rpcReferenceWrapper.setRetry(rpcReferenceAnnotation.retry());
                rpcReferenceWrapper.setAsync(rpcReferenceAnnotation.async());
                field.set(bean,rpcReference.get(rpcReferenceWrapper));
                //订阅服务,提前获取到所有的service Provider
                client.doSubscribeService(field.getType());
            } catch (Throwable e) {
                throw new RuntimeException("[IRpcClientAutoConfiguration#postProcessAfterInitialization] init rpcReference error", e);
            }
        }
        return bean;
    }

    public void onApplicationEvent(ApplicationReadyEvent event) {
       if (hasInitClientApplication){
           ConnectionHandler.setBootstrap(client.getBootstrap());
           client.doConnectServer();
           client.startClient();
       }
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println(applicationContext);
    }
}

Server端自动装配/配置实现

自定义IRpcService注解

Client端我们整了个注解来解决自动装配需要远程调用的属性字段,那Server端需要做啥呢?首先我们需要考虑的是Server端其实就是将我们的Service注册到注册中心,创建Socket等待连接接入和处理IO请求,对于Socket我们使用Netty框架来完成NIO的操作,而唯一需要简化的便是如何简单的将需要暴露注册的Service更加简单的注册到注册中心,其实最简单的方式还是通过注解去标识,在自动装配逻辑中去获取到标记了这些注解的Class,自动执行后续的注册逻辑。


自定义注解如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface IRpcService {

    int limit() default 0;

    String group() default "";

    String serviceToken() default "";

}

其实和我们的直接使用API还是一一对应的:

在这里插入图片描述

自动装配逻辑

自动装配这里的逻辑还是比较简单,我们也就不过多解释了,上代码:

public class IRpcServerAutoConfiguration implements InitializingBean, ApplicationContextAware {

    private static final Logger LOGGER = LoggerFactory.getLogger(IRpcServerAutoConfiguration.class);

    private ApplicationContext applicationContext;

    public void afterPropertiesSet() throws Exception {
        Server server = null;
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(IRpcService.class);
        if (beansWithAnnotation.isEmpty()) {
            //没有带暴露的服务
            return;
        }

        printBanner();
        long start = System.currentTimeMillis();
        server = new Server();
        server.initServerConfig();
        for (String beanName : beansWithAnnotation.keySet()) {
            Object beanObject = beansWithAnnotation.get(beanName);
            IRpcService iRpcService = beanObject.getClass().getAnnotation(IRpcService.class);
            ServiceWrapper serviceWrapper = new ServiceWrapper(beanObject, iRpcService.group());
            serviceWrapper.setLimit(iRpcService.limit());
            serviceWrapper.setServiceToken(iRpcService.serviceToken());
            server.exportService(serviceWrapper);
            LOGGER.info("service {} export success!", beanName);
        }
        long end = System.currentTimeMillis();
        ApplicationShutdownHook.registryShutdownHook();
        server.startApplication();
        LOGGER.info("{} start success in {} times", server.getConfig(), end - start);
    }

    private void printBanner() {
        System.out.println();
        System.out.println("==============================================");
        System.out.println("|||---------- IRpc Starting Now! ----------|||");
        System.out.println("==============================================");
        System.out.println("源代码地址: https://github.com/lhj502819/IRpc");
        System.out.println("version: 1.9.0");
        System.out.println();
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

待优化项

目前我们只是对Client和Server的目标Service和待暴露Service进行了自动装配,而却少了对相关的配置与SpringBoot集成,本打算去集成一下试试,鉴于时间的原因一直没做,大家可以参照比较流行的框架,如SpringCloudGateway去仿照着实现下,但我们自动装配的方式可能就需要调整下,感兴趣的可以去研究研究,但是目前的实现方式不影响大家理解!

接入一个SpringBoot项目

首先需要引入相关的Maven依赖,irpc-starter和springboot-web为主,其他的大家看项目需要。

<dependency>
    <groupId>cn.onenine</groupId>
    <artifactId>irpc-framework-spring-start</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.7.0</version>
</dependency>

其次我们在配置完相关Client/Server的配置后就可以直接使用了。

Client

在这里插入图片描述

Server

在这里插入图片描述

是不是很简单,就是这么简单,大家自行去看源码即可~

总结

本次我们主要通过自定义的Springboot-starter来完成了我们RPC框架对Springboot的集成,方便了框架的接入和使用成本,大家还有什么需要直接在基础上扩展即可,新年即将来临,别的也不祝福了,就祝大家身体健康吧,目前虽然很难,让我们一起前行,共渡难关!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/154351.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LayoutInflater学习(二)之创建布局View

这篇是在上篇的基础上继续学习LayoutInflater,上篇主要讲了LayoutInflater是怎么解析布局的,但是并没有去仔细地说明LayoutInflater创建View的过程,这篇就补上这部分。 LayoutInflater创建xml布局View是分开创建的: 1. 先创建xml布局最外层的View,也就是布局的根View 2. 递归…

package.json和package-lock.json的区别

前言 今天正在写代码&#xff0c;同学突然问我&#xff0c;package.json和package-lock.json有什么区别&#xff0c;这两个文件有什么用&#xff1f;我愣住了… 模块化开发 经过这么多年的发展&#xff0c;现在的前端开发基本上都是模块化开发了。而node和npm则可以很方便的…

电网调频及一次调频、二次调频

电网调频的基本概念电力系统运行的主要任务之一是对电网频率进行控制—控制电网频率在50Hz附近的一个允许范围内。电网频率偏离额定值50Hz的原因是能源侧&#xff08;水电、火电、核电……&#xff09;的供电功率与负荷侧的用电功率之间的平衡被破坏而引起的。负荷的用电功率是…

Sentinel热点参数限流

何为热点&#xff1f; 何为热点&#xff1f;热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K数据&#xff0c;并对其访问进行限制。比如&#xff1a; 1&#xff09;商品 ID 为参数&#xff0c;统计一段时间内最常购买的商品 ID 并进行限制&am…

正确的清理内存方式,才能让你的空间更加充裕

我们的手机用了一段时间后&#xff0c;有没有感觉卡变了&#xff0c;运行速度也很慢&#xff1f;估计是手机内存不足造成的&#xff0c;今天就来教教大家如何快速清理空间。方法一&#xff1a;清除微信缓存文件 我们每天都用微信。 其实它最占内存&#xff0c;我们还需要定时打…

原子化带来化学反应,视频号万粉创作者增加3倍,点赞10w+的爆款内容增长186%

1月10日&#xff0c;以“在场”为主题的2023微信公开课PRO正式开讲。本年度微信公开课重点从视频号内容生态发展、微信生态内各类产品助力实体转型以及数字生活服务升级三个方面&#xff0c;展示微信生态各产品的新能力、新计划。在2022年的微信公开课Pro上&#xff0c;“视频号…

广告业务系统 之 数据中转站 —— “日志中心-实时服务监控”

文章目录广告业务系统 之 数据中转站 —— “日志中心-实时服务监控”日志中心实时服务监控 —— 前链路日志分析日志收敛手段 —— “手术开口”基于 metrics 的日志分析 —— Prometheus & Graphite监控服务是怎么监控自身 & 比常规服务更坚强高扩展、高性能的架构设…

[L1 - 5分合集]心理阴影面积

L1-060 心理阴影面积 分数 5 作者 陈越 单位 浙江大学 题目&#xff1a; 这是一幅心理阴影面积图。我们都以为自己可以匀速前进&#xff08;图中蓝色直线&#xff09;&#xff0c;而拖延症晚期的我们往往执行的是最后时刻的疯狂赶工&#xff08;图中的红色折线&#xff09;。由…

外贸邮件营销的优势

邮件营销相对于其他营销方式&#xff0c;历史更悠久。邮件营销具有成本低廉、快速、精准的特点。那么邮件营销有哪些优势&#xff0c;才能获得如此的关注。接下来&#xff0c;米贸搜和大家分享一下邮件营销的优势。1.节约成本的考虑:当前&#xff0c;世界经济复苏乏力&#xff…

Kafka消息队列使用及原理

消息队列作用&#xff1a;异步、削峰、解耦 1、kafka简介 ​ Apache Kafka 是一个分布式的流平台&#xff0c;有三个关键的功能&#xff1a; 能够发布&#xff08;写入&#xff09;和订阅&#xff08;读取&#xff09;事件流持续可靠的存储事件流在事件发生时回顾性的处理事件…

IB生物笔记:Structure and function of organelles

国际学校生物老师解读IB生物&#xff0c;感兴趣的同学记得收藏哦~IB生物分为SL(standard level)和HL(higher level)SL有6个topic∶细胞生物&#xff0c;分子生物&#xff0c;遗传学&#xff0c;生态学&#xff0c;物种进化以及多样性和人体生理。HL除了上述6个topic外还要加上∶…

C++模板类

目录 前言 类模板 模板类继承 前言 随着c发展&#xff0c;有一部分代码就会出现这样的情况&#xff1a;实现的内容相同&#xff0c;但是参数不同。模板类就是为解决这类情况来的&#xff0c;是一种泛型编码。即与数据类型无关的通用程序设计技术。 模板类本身不占空间&…

C语言模块化

&#x1f31e;欢迎来到C语言的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f64f;作者水平很有限&#xff0c;如果发现错误&#xff0c;…

MySQL的行锁总结

文章目录前言一、行锁的介绍二、行锁的使用三、使用行锁所带来的问题四、死锁和死锁检测前言 上篇文章已经学习了MySQL的全局锁和表锁&#xff0c;今天这篇文章我们对行锁进行以下学习 一、行锁的介绍 行锁就是针对数据表中行记录的锁&#xff0c;比如事务A更新了一行&#x…

切面AOP

1.2 AOP体系与概念 简单地去理解&#xff0c;其实AOP要做三类事&#xff1a; 在哪里切入&#xff0c;也就是权限校验等非业务操作在哪些业务代码中执行。 在什么时候切入&#xff0c;是业务代码执行前还是执行后。 切入后做什么事&#xff0c;比如做权限校验、日志记录等。 因…

ES索引切分

提示&#xff1a;对于一些日志类的数据&#xff0c;我们常用到es作为存储&#xff0c;数据量过大时&#xff0c;可能会用到索引切分&#xff0c;这里可以参考 ES索引切分前言方案一&#xff1a;ES索引切分验证&#xff08;policy策略&#xff09;配置ilm策略 &#xff08;max_d…

照片如何修复清晰度?这些修复方法值得你收藏

我们都知道以前的拍照技术落后&#xff0c;拍摄出来的照片像素都比较低&#xff0c;从而导致照片有些模糊不清&#xff0c;再加上我们保存不当&#xff0c;很多旧照片都变得模糊破损&#xff0c;因此很多人为了不让这些旧照片消失&#xff0c;都会选择找人来修复这些旧照片&…

爬虫 大规模数据 采集心得和示例

本篇主要介绍网站数据很是大的采集心得数据库1. 什么样的数据才能称为数据量大&#xff1a;编程我以为这个可能会由于每一个人的理解不太同样&#xff0c;给出的定义 也不相同。我认为定义一个采集网站的数据大小&#xff0c;不单单要看这个网站包括的数据量的大小&#xff0c;…

MySQL高级【锁】

1&#xff1a;锁的概述锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资源&#xff08;CPU、 RAM、I/O&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有 效性是所有数据库必…

基于java springmvc+mybatis酒水商城管理系统设计和实现

基于java springmvcmybatis酒水商城管理系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取…