myrpc 学习笔记-002 配置加载
项目地址 欢迎访问
笔记总览 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)

一、核心配置类设计(RpcConfig)
用于定义 RPC 框架的核心配置项,提供默认值,无需配置文件也能正常运行。
1. 配置项说明
| 字段名 | 类型 | 含义 | 默认值 |
|---|---|---|---|
| name | String | 服务名称 | my-rpc |
| version | String | 服务版本 | 1.0.0 |
| serverHost | String | 服务器主机 | localhost |
| serverPort | Integer | 服务器端口 | 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 配置对象,支持指定前缀、多环境。
核心功能
- 拼接配置文件名(支持环境标识)
- 加载配置文件
- 将配置自动映射为 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 框架全局配置入口,实现单例、懒加载、自定义配置覆盖、默认配置降级。
核心特性
- 双检锁单例:保证全局唯一配置实例
- 懒加载:第一次获取配置时才加载
- 优先级:自定义配置 > 配置文件 > 默认配置
- 容错:配置文件加载失败,使用默认配置
代码实现
▼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,优先级高的配置文件存在则优先加载
核心增强
- 支持 YAML 顶层节点(如
rpc:) - 配置文件不存在时优雅降级
- 异常捕获,保证框架稳定性
完整代码
▼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
七、模块核心总结
- 配置模型:
RpcConfig定义配置项 + 默认值 - 配置加载:
ConfigUtils支持properties/yml/yaml三种格式、多环境、优先级加载 - 全局管理:
RpcApplication单例懒加载,保证配置全局唯一、线程安全 - 容错机制:无配置文件 / 加载异常时,自动使用默认配置,保证框架可用性
- 扩展性:常量统一管理,新增配置项无需修改核心加载逻辑
评论
问答助学
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
内容推荐
Day 103✅ 今天做了:复习了多用户通信系统⏰ 明天计划:学习Java反射
0
Day 68时间19:00~ 22:00(3h)✅ 今天做了:Component注解、Mybatis配置、使用⏰ 明天计划:Lombok、Mapper映射、动态SQL📚 今日感悟:自动配置类DataSourceAutoConfiguration ,会读取properties文件,通过注解:@EnableConfigurationProperties(DataSourceProperties.cl
1
Day 19✅ 今天做了:MCP⏰ 明天计划:AI智能体构建📚 今日感悟:今天MCP问题有点多有点杂,明天找时间再捋一下。继续加油
0
Day 25✅ 今天做了:1、扇贝英语单词打卡2、英语听说读写、听力练习3、微信阅读15分钟4、编程导航学习⏰ 明天计划:待定📚 今日感悟:Keep going!
1
Day 104✅ 今天做了:学习了Java反射及快速入门⏰ 明天计划:继续学习Java反射
0
