项目3:从0开始的RPC框架(扩展版)

一. 全局配置加载

1. 需求分析

通常情况下,在RPC框架运行的会涉及到多种配置信息,比如注册中心的地址、序列化方式、网络服务端接口号等。

在简易版框架中,硬编码了这些配置,也就是都写死了,在真实的应用环境中是不利于维护和后期扩展的。同时RPC框架需要被其它项目引入,作为服务提供者和消费者沟通的桥梁,所以应当允许引入框架的项目通过编写配置文件来自定义配置。一般情况下,服务提供者与消费者需要编写相同的RPC配置。

综上,我们需要一套全局配置加载功能。能够让RPC框架轻松地从配置文件中读取配置,并且维护一个全局配置对象,便于框架快速获取到一致的配置。

2. 设计方案

(1)配置项

从最简单出发,先提供几个基础配置项:

  • name 名称
  • version 版本号
  • serverHost 服务器主机名
  • serverPort 服务器端口号

之后随着框架功能的扩展再不断增加新配置即可,比如注册中心地址、服务接口、序列化方式等。

可参考:Dubbo RPC框架的配置项。包括应用配置、协议配置、注册中心等。

(2)读取配置文件

配置文件的读取,使用Java的Properties类自行编写。通常情况下,读取的配置文件名称为application.properties,还可以通过指定文件名称后缀的方式来区分多环境,比如application-prod.properties表示生产环境,application-test.properties表示测试环境。

3. 具体实现

(1)项目初始化

创建khr-rpc-core模块,扩展版RPC项目都基于此模块进行。直接复制粘贴easy模块包并改名。

引入日志库(ch.qos.logback)和单元测试(junit)依赖,并将consumer和provider模块引入的RPC依赖都替换成khr-rpc-core。

(2)配置加载

创建配置类RpcConfig:

用于保存配置信息。

可以给属性指定一些默认值,

package com.khr.krpc.config;import lombok.Data;/*** RPC框架配置*/
@Data
public class RpcConfig {/*** 名称*/private String name = "k-rpc";/*** 版本号*/private String version = "1.0";/*** 服务器主机名*/private String serverHost = "localhost";/*** 服务器端口号*/private String serverPort = "8080";
}

创建工具类ConfigUtils: 

用于读取配置文件并返回配置对象,可以简化调用。配置类应当尽量通用,不和业务强绑定。

之后调用ConfigUtils的静态方法loadConfig就能读取配置了。

package com.khr.krpc.utils;import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.dialect.Props;/*** 配置工具类*/
public class ConfigUtils {/*** 加载配置对象** @param tClass* @param perfix* @param <T>* @return*/public static <T> T loadConfig(Class<T> tClass,String perfix){return loadConfig(tClass,perfix,"");}/*** 加载配置对象,支持区分环境** @param tClass* @param perfix* @param environment* @param <T>* @return*/public static <T> T loadConfig(Class<T> tClass,String perfix,String environment){StringBuilder configFileBuilder = new StringBuilder("application");if (StrUtil.isNotBlank(environment)){configFileBuilder.append("-").append(environment);}configFileBuilder.append(".properties");Props props = new Props(configFileBuilder.toString());return props.toBean(tClass,perfix);}
}

创建RpcConstant接口:

用于存储RPC框架相关的常量。比如默认配置文件的加载前缀为rpc。

package com.khr.krpc.constant;/*** RPC相关常量*/
public interface RpcConstant {/*** 默认配置文件加载前缀*/String DEFAULT_CONFIG_PREFIX = "rpc";
}

可以读取到类似下面的配置:

rpc.name=krpc
rpc.version=2.0
rpc.serverPort=8081

(3)维护全局配置对象

RPC框架中需要维护一个全局的配置对象。在引入RPC框架后并启动项目时,从配置文件中读取配置并创建对象实例,之后就可以集中地从这个对象中获取配置信息,而不需要每次加载配置时再重新读取并创建对象,减少了性能开销。

使用了设计模式中的单例模式。通常情况下会使用holder来维护全局配置对象实例,在本项目中使用RpcApplication类作为RPC项目的启动入口,并维护项目全局用到的变量。

package com.khr.krpc;import com.khr.krpc.config.RpcConfig;
import com.khr.krpc.constant.RpcConstant;
import com.khr.krpc.utils.ConfigUtils;
import lombok.extern.slf4j.Slf4j;/*** RPC框架应用* 相当于holder,存放了项目全局用到的变量。双检锁单例模式实现。*/
@Slf4j
public class RpcApplication {private static volatile RpcConfig rpcConfig;/*** 框架初始化,支持传入自定义配置** @param newRpcConfig*/public static void init(RpcConfig newRpcConfig){rpcConfig = newRpcConfig;log.info("rpc init, config = {}",newRpcConfig.toString());}/*** 初始化*/public static void init(){RpcConfig newRpcConfig;try {newRpcConfig = ConfigUtils.loadConfig(RpcConfig.class,RpcConstant.DEFAULT_CONFIG_PREFIX);}catch (Exception e){//配置加载失败,使用默认值newRpcConfig =new RpcConfig();}init(newRpcConfig);}/*** 获取配置** @return*/public static RpcConfig getRpcConfig(){if (rpcConfig == null){synchronized (RpcApplication.class){if (rpcConfig == null){init();}}}return rpcConfig;}
}

 双检锁单例模式的经典实现,支持在获取配置时才调用init方法实现懒加载。

为了便于扩展,还支持自己传入配置对象,如果不传入的话,默认调用前面写好的ConfigUtils来加载配置。

之后一行代码即可正确加载配置:

RpcConfig rpc = RpcApplication.getRpcConfig();

4. 测试

(1)测试配置文件读取

在example-consumer模块的resources目录下编写配置文件application.properties,

rpc.name=krpc
rpc.version=2.0
rpc.serverPort=8081

创建ConsumerExample作为扩展版RPC项目的示例消费者类,测试配置文件读取,

package com.khr.example.consumer;import com.khr.example.common.model.User;
import com.khr.example.common.service.UserService;
import com.khr.krpc.config.RpcConfig;
import com.khr.krpc.proxy.ServiceProxyFactory;
import com.khr.krpc.utils.ConfigUtils;/*** 服务消费者示例*/
public class ConsumerExample {public static void main(String[] args){RpcConfig rpc = ConfigUtils.loadConfig(RpcConfig.class,"rpc");System.out.println(rpc);}
}

读取结果为,

已成功读到配置文件中的内容。 

(2)测试全局配置对象加载

在example-provider模块中创建ProviderExample服务提供者示例类,能够根据配置动态地在不同端口启动Web服务

package com.khr.example.provider;import com.khr.example.common.service.UserService;
import com.khr.krpc.RpcApplication;
import com.khr.krpc.registry.LocalRegistry;
import com.khr.krpc.server.HttpServer;
import com.khr.krpc.server.VertxHttpServer;/*** 服务提供者示例*/
public class ProviderExample {public static void main(String[] args){//RPC框架初始化RpcApplication.init();//注册服务LocalRegistry.registry(UserService.class.getName(),UserServiceImpl.class);//启动web服务HttpServer httpServer = new VertxHttpServer();httpServer.doStart(Integer.parseInt(RpcApplication.getRpcConfig().getServerPort()));}
}

启动结果为,

 

已成功在8080端口启动。 

至此,扩展功能,全局配置加载完成,后续可能会根据新增的功能逐步修改全局配置信息。

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

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

相关文章

【启程Golang之旅】让文件操作变得简单

欢迎来到Golang的世界&#xff01;在当今快节奏的软件开发领域&#xff0c;选择一种高效、简洁的编程语言至关重要。而在这方面&#xff0c;Golang&#xff08;又称Go&#xff09;无疑是一个备受瞩目的选择。在本文中&#xff0c;带领您探索Golang的世界&#xff0c;一步步地了…

MySQL 与 PostgreSQL 关键对比二(SQL语法)

目录 1 详细示例 1.1自动增量列 1.2 字符串连接 1.3 JSON 支持 2 总结 MySQL 和 PostgreSQL 是两种流行的开源关系数据库管理系统&#xff08;RDBMS&#xff09;。尽管它们在许多方面相似&#xff0c;但在 SQL 语法和功能上存在一些显著差异。 以下SQL语句的执行如果需要开…

1. lvs负载均衡

lvs负载均衡 一、集群技术概述1、集群技术类型2、负载均衡技术3、高可用技术 二、负载均衡 LVS1、LVS介绍2、负载均衡策略/算法3、LVS设计模式3.1 NAT模式的注意事项3.2 DR 直接路由模式的注意事项 三、LVS nat模式的实现1、确认后端服务器网关正确2、安装ipvsadm软件3、开启路…

[AIGC] SpringBoot的自动配置解析

下面是一篇关于SpringBoot自动配置的文章&#xff0c;里面包含了一个简单的示例来解释自动配置的原理。 SpringBoot的自动配置解析 Spring Boot是Spring的一个子项目&#xff0c;用于快速开发应用程序。它主要是简化新Spring应用的初始建立以及开发过程。其中&#xff0c;自动…

java第二十一课 —— 快捷键,包,访问修饰符

IDEA 快捷键 删除行&#xff1a;Ctrl Y复制行&#xff1a;Ctrl D补全代码&#xff1a;Alt /添加取消注释&#xff1a;Ctrl /导入该行需要的类&#xff1a;Alt Enter快速格式化代码&#xff1a;Ctrl Shift L快速运行程序&#xff1a;Ctrl Shift F10生成构造器&#xf…

直播商城源码-PC+APP+H5+小程序现成源码

随着电商行业的不断演进&#xff0c;直播商城已成为连接消费者和商品的新兴桥梁。直播商城源码提供了一个完整的解决方案&#xff0c;使得企业能够迅速搭建起一个覆盖PC、APP、H5和小程序的全渠道电商平台。本文将探讨直播商城源码的优势、关键功能以及如何选择适合的现成源码。…

如何搭建一个高效的帮助网站?

在当今数字化时代&#xff0c;拥有一个高效的帮助网站对于企业来说至关重要。无论是为了提供产品支持、解答常见问题&#xff0c;还是为了增强用户体验和品牌形象&#xff0c;一个贴心、专业的帮助网站都能为企业赢得更多的用户和客户。那么&#xff0c;如何才能搭建一个高效的…

设置电脑定时关机

1.使用快捷键winR 打开运行界面 2.输入cmd &#xff0c;点击确认&#xff0c;打开命令行窗口&#xff0c;输入 shutdown -s -t 100&#xff0c;回车执行命令&#xff0c;自动关机设置成功 shutdown: 这是主命令&#xff0c;用于执行关闭或重启操作。-s: 这个参数用于指定执行关…

华为端云一体化开发 初始化云db表结构和表数据(实践2.0)(HarmonyOS学习第七课)

实例介绍&#xff1a;黑马鸿蒙刷题学习过程 1. 静态页面准备 借用黑马完成的页面&#xff0c;已经提供给大家一套写好的基本模板&#xff0c;大家直接将这套模板覆盖原有entry/src/main目录就可以 &#x1f4ce;main.ziphttps://www.yuque.com/attachments/yuque/0/2024/zip…

IngsollRang伺服拧紧轴控制器维修故障排查

【IngsollRang控制器故障排查】 在开始维修之前&#xff0c;请确保拧紧机已关闭并断开电源。然后&#xff0c;按照以下步骤进行故障排查&#xff1a; 1. 检查电源连接&#xff1a;确保拧紧机的电源线牢固连接&#xff0c;且电源插座正常工作。 2. 检查保险丝&#xff1a;如果电…

贪心算法-加油站

一、题目描述 二、解题思路 1.运动过程分析 这里需要一个油箱剩余油量的变量resGas&#xff0c;初始化resGas0&#xff1b;还需要一个标记从什么位置当做初始位置的startIdx&#xff0c;初始化startIdx0。 我们从数组下标idx0处开始向后遍历&#xff0c;初始时startIdx0&#…

java的核心机制:JVM

JVM&#xff08;java virtual machine&#xff0c;java虚拟机&#xff09;&#xff1a;是一个虚拟的计算机&#xff0c;是java程序的运行环境。JVM具有指令集并使用不同的存储区域&#xff0c;负责执行指令&#xff0c;管理数据、内存、寄存器。 JVM功能1&#xff1a;实现java程…

Unity DOTS技术(十三) ComponentSystem及JobComponentSystem

文章目录 一.ComponentSystem介绍二.JobComponentSystem 一.ComponentSystem介绍 1.继承ComponentSystem需要实现抽象OnUpdate() 2.与SystemBase不同,ComponentSystem不包含LambdaSingleJobDescription, 3.CompoentSystem的带代码都是在主线程上运行,不支持多线程. 4.并不能在…

网络编程之XDP技术介绍

一、简介 XDP&#xff1a;eXpress Data Path&#xff0c;快速数据面&#xff0c;听名字是不是很高大上。其实它就是一个快速处理Rx数据包的数据面技术。为什么现在对数据处理如此敏感&#xff1f;原因非常简单&#xff0c;随着网络的不断覆盖社会的各个层面&#xff0c;海量的…

JVM学习-详解类加载器(二)

双亲委派机制 双亲委派优势 避免类的重复加载&#xff0c;确保一个类的全局唯一性 Java类随着它的类加载器一起具备了一种带有优先级的层次关系&#xff0c;通过这种层次关系可以避免类的重复加载&#xff0c;当父类已经加载了该类&#xff0c;就没有必要子ClassLoader再加载…

图像编解码器在AI绘画中的革新作用

随着人工智能技术的飞速发展&#xff0c;AI绘画已经从一个简单的概念演变为一个充满创意与可能性的领域。在这场技术与艺术的融合中&#xff0c;图像编解码器扮演着至关重要的角色。它们不仅提升了AI绘画的质量和效率&#xff0c;还拓宽了艺术创造的边界。本篇博客将深入探讨图…

数据结构(树)

数据结构&#xff08;树&#xff09; 度&#xff1a;每一个节点的子节点数量 二叉查找树&#xff1a; 每一个节点上最多有两个子节点&#xff1b; 任意节点左子树上的值都小于当前节点&#xff1b; 任意节点右子树上的值都大于当前节点。 添加节点规则&#xff1a; 小的存左边&…

Postman 连接数据库 利用node+xmysql

1、准备nodejs环境 如果没有安装&#xff0c;在网上找教程&#xff0c;安装好后&#xff0c;在控制台输入命令查看版本&#xff0c;如下就成功了 2、安装xmysql 在控制台输入 npm install -g xmysql 3、连接目标数据库 帮助如下&#xff1a; 示例&#xff1a; 目标数据库…

HTML静态网页成品作业(HTML+CSS)—— 美食湘菜介绍网页(5个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有5个页面。 二、作品演示 三、代…

MASA:匹配一切、分割一切、跟踪一切

摘要 https://matchinganything.github.io/ 在复杂场景中跨视频帧稳健地关联相同对象是许多应用的关键&#xff0c;特别是多目标跟踪&#xff08;MOT&#xff09;。当前方法主要依赖于标注的特定领域视频数据集&#xff0c;这限制了学习到的相似度嵌入的跨域泛化能力。我们提…