myrpc 学习笔记-002 配置加载

项目地址 欢迎访问

https://gitee.com/longlong5/myrpc

笔记总览 myrpc 学习笔记-001 实现简易版 rpc myrpc 学习笔记-002 配置加载 myrpc 学习笔记-003 Mock 服务代理 myrpc 学习笔记-004 序列化实现和 SPI 机制 myrpc 学习笔记-005 注册中心 myrpc 学习笔记-006 自定义协议 myrpc 学习笔记-007 负载均衡 myrpc 学习笔记-008 重试机制 myrpc 学习笔记-009 容错机制 myrpc 学习笔记-0010 启动机制和注解驱动

架构图v2.0.0

  • 增加全局配置
  • 支持 yml yaml properties 三种格式的配置文件
  • 如果没有配置文件则会加载默认配置
  • 支持通过后缀区分环境 (dev/test/prod)

v2.0.0.png

一、核心配置类设计(RpcConfig)

用于定义 RPC 框架的核心配置项,提供默认值,无需配置文件也能正常运行。

1. 配置项说明

字段名类型含义默认值
nameString服务名称my-rpc
versionString服务版本1.0.0
serverHostString服务器主机localhost
serverPortInteger服务器端口8080

2. 代码实现

java
复制代码
import lombok.Data; import java.io.Serializable; /** * RPC 框架配置 */ @Data public class RpcConfig implements Serializable { /** * 框架名称 */ private String name = "my-rpc"; /** * 版本号 */ private String version = "1.0.0"; /** * 服务器主机名 */ private String serverHost = "localhost"; /** * 服务器端口号 */ private Integer serverPort = 8080; }

二、基础配置文件支持(properties)

1. 配置文件格式

默认文件名:application.properties

properties
复制代码
# RPC配置 rpc.name=my-rpc rpc.version=2.0.0 rpc.serverHost=localhost rpc.serverPort=8081

2. 多环境配置

通过文件名区分环境,支持动态加载对应环境配置:

  • 开发环境:application-dev.properties
  • 测试环境:application-test.properties
  • 生产环境:application-prod.properties

三、配置工具类(ConfigUtils)

基于 Hutool 工具类实现,加载配置文件并转换为 Java 配置对象,支持指定前缀、多环境。

核心功能

  1. 拼接配置文件名(支持环境标识)
  2. 加载配置文件
  3. 将配置自动映射为 Java 对象

基础版代码(仅支持 properties)

java
复制代码
package com.longlong.myrpc.utils; import cn.hutool.core.util.StrUtil; import cn.hutool.setting.dialect.Props; import lombok.extern.slf4j.Slf4j; /** * 配置工具类 */ @Slf4j public class ConfigUtils { // 默认配置文件名 private static final String APPLICATION_PROPERTIES = "application"; // 环境分隔符 private static final String ENV_SEPARATOR = "-"; /** * 加载配置对象(无环境) * @param clazz 配置类 * @param prefix 配置前缀 * @return 配置实例 */ public static <T> T loadConfig(Class<T> clazz, String prefix) { return loadConfig(clazz, prefix, null); } /** * 加载配置对象(支持多环境) * @param clazz 配置类 * @param prefix 配置前缀 * @param environment 环境标识(dev/test/prod) * @return 配置实例 */ public static <T> T loadConfig(Class<T> clazz, String prefix, String environment) { // 拼接完整配置文件名 StringBuilder configFile = new StringBuilder(APPLICATION_PROPERTIES); if (StrUtil.isNotBlank(environment)) { configFile.append(ENV_SEPARATOR).append(environment); } configFile.append(".properties"); // 加载并转换为Java对象 Props props = new Props(configFile.toString()); return props.toBean(clazz, prefix); } }

四、全局配置加载器(RpcApplication)

RPC 框架全局配置入口,实现单例、懒加载、自定义配置覆盖、默认配置降级。

核心特性

  1. 双检锁单例:保证全局唯一配置实例
  2. 懒加载:第一次获取配置时才加载
  3. 优先级:自定义配置 > 配置文件 > 默认配置
  4. 容错:配置文件加载失败,使用默认配置

代码实现

java
复制代码
package com.longlong.myrpc; import com.longlong.myrpc.config.RpcConfig; import com.longlong.myrpc.constant.RpcConstant; import com.longlong.myrpc.utils.ConfigUtils; import lombok.extern.slf4j.Slf4j; /** * RPC 框架应用(全局唯一配置入口) */ @Slf4j public class RpcApplication { // volatile 保证多线程可见性 private static volatile RpcConfig rpcConfig; /** * 自定义配置初始化 */ public static void init(RpcConfig rpcconfig) { log.info("RpcApplication 初始化"); rpcConfig = rpcconfig; log.info("RPC配置加载完成:{}", rpcConfig); } /** * 自动加载配置文件初始化 */ public static void init() { RpcConfig config; try { // 加载配置文件 config = ConfigUtils.loadConfig(RpcConfig.class, RpcConstant.DEFAULT_CONFIG_PREFIX); } catch (Exception e) { // 加载失败,使用默认配置 log.info("未找到配置文件,使用默认配置"); config = new RpcConfig(); } init(config); } /** * 获取全局配置(双检锁单例) */ public static RpcConfig getRpcConfig() { if (rpcConfig == null) { synchronized (RpcApplication.class) { if (rpcConfig == null) { init(); } } } return rpcConfig; } // 私有构造,防止实例化 private RpcApplication() {} }

五、扩展:支持 YAML/yml 配置文件

1. 依赖引入

使用snakeyaml解析 YAML 格式配置

xml
复制代码
<!-- YAML解析依赖 --> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>2.0</version> <scope>compile</scope> </dependency>

2. 常量类提取(RpcConstant)

统一管理配置相关常量,便于维护

java
复制代码
package com.longlong.myrpc.constant; /** * RPC 相关常量 */ public class RpcConstant { // 默认配置前缀 public static final String DEFAULT_CONFIG_PREFIX = "rpc"; // 默认服务版本 public static final String DEFAULT_SERVICE_VERSION = "1.0.0"; // 配置文件基础名称 public static final String APPLICATION_PROPERTIES = "application"; // 环境分隔符 public static final String ENV_SEPARATOR = "-"; // 配置文件后缀 public static final String PROP_CONFIG_SUFFIX = ".properties"; public static final String YML_CONFIG_SUFFIX = ".yml"; public static final String YAML_CONFIG_SUFFIX = ".yaml"; }

3. 增强版配置工具类(支持 properties/yml/yaml)

加载优先级

yml > yaml > properties,优先级高的配置文件存在则优先加载

核心增强

  1. 支持 YAML 顶层节点(如rpc:
  2. 配置文件不存在时优雅降级
  3. 异常捕获,保证框架稳定性

完整代码

text
复制代码
package com.longlong.myrpc.utils; import cn.hutool.core.util.StrUtil; import cn.hutool.setting.dialect.Props; import cn.hutool.setting.yaml.YamlUtil; import lombok.extern.slf4j.Slf4j; import java.io.InputStream; import java.net.URL; import java.util.Map; import static com.longlong.myrpc.constant.RpcConstant.*; /** * 增强版配置工具类(支持 properties + yml/yaml) */ @Slf4j public class ConfigUtils { /** * 加载配置(无环境) */ public static <T> T loadConfig(Class<T> clazz, String prefix) { return loadConfig(clazz, prefix, null); } /** * 加载配置(支持多环境 + 多格式) */ public static <T> T loadConfig(Class<T> clazz, String prefix, String environment) { // 拼接基础文件名 StringBuilder baseName = new StringBuilder(APPLICATION_PROPERTIES); if (StrUtil.isNotBlank(environment)) { baseName.append(ENV_SEPARATOR).append(environment); } String baseFileName = baseName.toString(); log.info("尝试加载配置,基础文件名:{}", baseFileName); // 1. 优先加载 YML/YAML 配置 T config = loadYamlConfigWithPrefix(baseFileName, clazz, prefix); if (config != null) { log.info("YAML配置加载成功"); return config; } // 2. 加载 Properties 配置 Props props = loadPropsConfig(baseFileName); if (props != null) { log.info("Properties配置加载成功"); return props.toBean(clazz, prefix); } // 3. 无配置文件,使用默认对象 log.warn("未找到任何配置文件,使用默认配置"); try { return clazz.newInstance(); } catch (Exception e) { throw new RuntimeException("配置加载失败", e); } } /** * 加载YAML配置(支持顶层前缀节点,如 rpc:) */ private static <T> T loadYamlConfigWithPrefix(String baseFileName, Class<T> clazz, String prefix) { // 先尝试 .yml String ymlFile = baseFileName + YML_CONFIG_SUFFIX; InputStream inputStream = ConfigUtils.class.getClassLoader().getResourceAsStream(ymlFile); // 不存在则尝试 .yaml if (inputStream == null) { ymlFile = baseFileName + YAML_CONFIG_SUFFIX; inputStream = ConfigUtils.class.getClassLoader().getResourceAsStream(ymlFile); } if (inputStream == null) { return null; } try { log.info("加载YAML文件:{}", ymlFile); // 转为Map,读取顶层节点 Map<String, Object> yamlMap = YamlUtil.load(inputStream, Map.class); Object configData = yamlMap.get(prefix); if (configData == null) { log.error("YAML中未找到顶层节点:{}", prefix); return null; } // Map转Java对象 return cn.hutool.core.bean.BeanUtil.toBean(configData, clazz); } catch (Exception e) { log.error("YAML配置解析失败", e); return null; } } /** * 加载Properties配置 */ private static Props loadPropsConfig(String baseFileName) { String propFile = baseFileName + PROP_CONFIG_SUFFIX; URL resource = ConfigUtils.class.getClassLoader().getResource(propFile); if (resource == null) { return null; } log.info("加载Properties文件:{}", propFile); return new Props(propFile); } }

六、YAML 配置文件示例

yml
复制代码
# application.yml rpc: name: my-rpc version: 2.0.0 serverHost: localhost serverPort: 8081

七、模块核心总结

  1. 配置模型RpcConfig定义配置项 + 默认值
  2. 配置加载ConfigUtils支持properties/yml/yaml三种格式、多环境、优先级加载
  3. 全局管理RpcApplication单例懒加载,保证配置全局唯一、线程安全
  4. 容错机制:无配置文件 / 加载异常时,自动使用默认配置,保证框架可用性
  5. 扩展性:常量统一管理,新增配置项无需修改核心加载逻辑
0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
longlong
下载 APP