前言

在前一章中,我们设计了强大的注解API。本章将深入探讨配置管理系统的设计,学习如何将注解中的声明式配置转换为运行时可用的配置对象。

配置管理的核心挑战

在我们的框架中,配置来源有三个层级:

在这里插入图片描述

主要挑战:

  • 🔀 优先级处理:如何正确合并不同层级的配置
  • 🎯 类型安全:确保配置值的类型正确性
  • 性能优化:避免重复解析和计算
  • 🛡️ 配置验证:及早发现配置错误

LogConfig - 统一配置模型

LogConfig是框架配置管理的核心,承载着从注解解析出来的所有配置信息:

package com.simpleflow.log.config;import com.simpleflow.log.annotation.LogLevel;/*** 日志配置类 - 统一管理所有日志相关的配置项*/
public class LogConfig {// ========== 基础配置 ==========private LogLevel level;private Boolean logArgs;private Boolean logResult;private Boolean logExecutionTime;private Boolean logException;// ========== 消息模板配置 ==========private String prefix;private String startMessage;private String successMessage;private String errorMessage;// ========== 高级配置 ==========private Boolean enableSpel;private Boolean includeRequestId;private int[] excludeArgs;private String[] sensitiveFields;// ========== 类级专用配置 ==========private String[] includeMethods;private String[] excludeMethods;private Boolean includePrivateMethods;private Boolean includeGetterSetter;/*** 合并配置 - 当前配置的非空值会覆盖other配置的对应值*/public LogConfig merge(LogConfig other) {if (other == null) {return new LogConfig(this);}LogConfig merged = new LogConfig();// 基础配置合并(当前配置优先)merged.level = this.level != null ? this.level : other.level;merged.logArgs = this.logArgs != null ? this.logArgs : other.logArgs;merged.logResult = this.logResult != null ? this.logResult : other.logResult;merged.logExecutionTime = this.logExecutionTime != null ? this.logExecutionTime : other.logExecutionTime;merged.logException = this.logException != null ? this.logException : other.logException;// 字符串配置合并merged.prefix = mergeString(this.prefix, other.prefix);merged.startMessage = mergeString(this.startMessage, other.startMessage);merged.successMessage = mergeString(this.successMessage, other.successMessage);merged.errorMessage = mergeString(this.errorMessage, other.errorMessage);// 高级配置合并merged.enableSpel = this.enableSpel != null ? this.enableSpel : other.enableSpel;merged.includeRequestId = this.includeRequestId != null ? this.includeRequestId : other.includeRequestId;// 数组配置合并merged.excludeArgs = mergeIntArray(this.excludeArgs, other.excludeArgs);merged.sensitiveFields = mergeStringArray(this.sensitiveFields, other.sensitiveFields);return merged;}/*** 创建默认配置*/public static LogConfig createDefault() {LogConfig config = new LogConfig();config.level = LogLevel.INFO;config.logArgs = true;config.logResult = true;config.logExecutionTime = true;config.logException = true;config.prefix = "";config.startMessage = "方法开始执行";config.successMessage = "方法执行成功";config.errorMessage = "方法执行异常";config.enableSpel = true;config.includeRequestId = true;config.excludeArgs = new int[0];config.sensitiveFields = new String[0];config.includeMethods = new String[0];config.excludeMethods = new String[0];config.includePrivateMethods = false;config.includeGetterSetter = false;return config;}// 工具方法private String mergeString(String current, String other) {return !isEmpty(current) ? current : other;}private boolean isEmpty(String str) {return str == null || str.trim().isEmpty();}// 省略getter/setter和其他方法...
}

AnnotationConfigResolver - 配置解析器

配置解析器负责将注解转换为LogConfig对象,并处理配置的合并逻辑:

package com.simpleflow.log.processor;import com.simpleflow.log.annotation.*;
import com.simpleflow.log.config.LogConfig;
import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;/*** 注解配置解析器*/
public class AnnotationConfigResolver {// 配置缓存,提升性能private final ConcurrentHashMap<Method, LogConfig> methodConfigCache = new ConcurrentHashMap<>();private final ConcurrentHashMap<Class<?>, LogConfig> classConfigCache = new ConcurrentHashMap<>();private final LogConfig defaultConfig;public AnnotationConfigResolver() {this.defaultConfig = LogConfig.createDefault();}/*** 解析方法的完整配置* 合并优先级:方法配置 > 类配置 > 默认配置*/public LogConfig resolveMethodConfig(Method method) {if (method == null) {return null;}// 检查缓存LogConfig cached = methodConfigCache.get(method);if (cached != null) {return cached;}try {// 1. 检查是否被忽略if (method.isAnnotationPresent(LogIgnore.class)) {methodConfigCache.put(method, null);return null;}// 2. 解析方法级配置LogConfig methodConfig = resolveMethodAnnotation(method);// 3. 解析类级配置LogConfig classConfig = resolveClassConfig(method.getDeclaringClass());// 4. 检查类级配置是否包含此方法if (classConfig != null && !isMethodIncluded(method, classConfig)) {methodConfigCache.put(method, null);return null;}// 5. 合并配置:方法 > 类 > 默认LogConfig finalConfig = mergeConfigs(methodConfig, classConfig, defaultConfig);// 6. 验证和缓存结果if (finalConfig != null) {finalConfig.validate();}methodConfigCache.put(method, finalConfig);return finalConfig;} catch (Exception e) {return null;}}/*** 解析类级配置*/public LogConfig resolveClassConfig(Class<?> clazz) {if (clazz == null) {return null;}LogConfig cached = classConfigCache.get(clazz);if (cached != null) {return cached;}LogConfig classConfig = null;if (clazz.isAnnotationPresent(LogClass.class)) {LogClass logClass = clazz.getAnnotation(LogClass.class);classConfig = createConfigFromClass(logClass);}classConfigCache.put(clazz, classConfig);return classConfig;}/*** 从@LogMethod注解创建配置*/private LogConfig resolveMethodAnnotation(Method method) {if (!method.isAnnotationPresent(LogMethod.class)) {return null;}LogMethod logMethod = method.getAnnotation(LogMethod.class);LogConfig config = new LogConfig();// 基础配置config.setLevel(logMethod.level());config.setLogArgs(logMethod.logArgs());config.setLogResult(logMethod.logResult());config.setLogExecutionTime(logMethod.logExecutionTime());config.setLogException(logMethod.logException());// 消息模板config.setPrefix(emptyToNull(logMethod.prefix()));config.setStartMessage(emptyToNull(logMethod.startMessage()));config.setSuccessMessage(emptyToNull(logMethod.successMessage()));config.setErrorMessage(emptyToNull(logMethod.errorMessage()));// 高级配置config.setEnableSpel(logMethod.enableSpel());config.setIncludeRequestId(logMethod.includeRequestId());if (logMethod.excludeArgs().length > 0) {config.setExcludeArgs(logMethod.excludeArgs());}if (logMethod.sensitiveFields().length > 0) {config.setSensitiveFields(logMethod.sensitiveFields());}return config;}/*** 合并多个配置*/private LogConfig mergeConfigs(LogConfig methodConfig, LogConfig classConfig, LogConfig defaultConfig) {LogConfig result = defaultConfig.copy();if (classConfig != null) {result = result.merge(classConfig);}if (methodConfig != null) {result = result.merge(methodConfig);}return (methodConfig != null || classConfig != null) ? result : null;}// 其他工具方法...
}

配置优先级实战示例

// 示例:配置的继承和覆盖
@LogClass(level = LogLevel.WARN,           // 类级默认:WARN级别logArgs = true,                  // 类级默认:记录参数logResult = false,               // 类级默认:不记录返回值prefix = "用户服务"               // 类级前缀
)
public class UserService {// 继承类级配置public List<User> findAll() {// 最终配置:level=WARN, logArgs=true, logResult=false, prefix="用户服务"}// 部分覆盖类级配置@LogMethod(logResult = true)     // 只覆盖 logResultpublic User findById(Long id) {// 最终配置:level=WARN, logArgs=true, logResult=true, prefix="用户服务"}// 完全覆盖类级配置@LogMethod(level = LogLevel.DEBUG,logArgs = false,prefix = "查询服务")public User findByUsername(String username) {// 最终配置:level=DEBUG, logArgs=false, logResult=false, prefix="查询服务"}// 忽略日志记录@LogIgnore(reason = "内部工具方法")private String formatUserInfo(User user) {// 不会记录任何日志}
}

测试用例

package com.simpleflow.log.processor;import com.simpleflow.log.annotation.*;
import com.simpleflow.log.config.LogConfig;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
import static org.junit.jupiter.api.Assertions.*;class AnnotationConfigResolverTest {private final AnnotationConfigResolver resolver = new AnnotationConfigResolver();@Testvoid testMethodConfigOverridesClassConfig() throws Exception {Method method = TestService.class.getMethod("findById", Long.class);LogConfig config = resolver.resolveMethodConfig(method);assertNotNull(config);assertEquals(LogLevel.INFO, config.getLevel());  // 方法级覆盖assertTrue(config.getLogResult());               // 方法级覆盖assertEquals("用户服务", config.getPrefix());      // 继承类级}@Testvoid testIgnoredMethod() throws Exception {Method method = TestService.class.getMethod("ignoredMethod");LogConfig config = resolver.resolveMethodConfig(method);assertNull(config);  // 被忽略的方法返回null}@LogClass(level = LogLevel.WARN, prefix = "用户服务", logResult = false)static class TestService {@LogMethod(level = LogLevel.INFO, logResult = true)public User findById(Long id) {return new User();}@LogIgnore(reason = "测试忽略")public void ignoredMethod() {}}static class User {}
}

本章小结

✅ 完成的任务

  1. 设计LogConfig:统一的配置模型,支持合并和验证
  2. 实现解析器:AnnotationConfigResolver负责注解解析
  3. 配置优先级:方法 > 类 > 默认的合并策略
  4. 性能优化:通过缓存提升解析性能
  5. 测试验证:编写测试用例验证功能

🎯 学习要点

  • 配置分层:多层级配置的设计思路
  • 合并策略:如何优雅地处理配置优先级
  • 缓存机制:提升框架性能的重要手段
  • 配置验证:保证配置有效性的机制

💡 思考题

  1. 为什么要设计配置缓存机制?
  2. 如何处理配置的循环依赖问题?
  3. 配置合并还有哪些策略可以考虑?

🚀 下章预告

下一章我们将进入AOP切面编程的世界,学习如何使用Spring AOP实现无侵入式的日志拦截。我们将实现LogMethodAspect和LogClassAspect,掌握切点表达式和环绕通知的使用技巧。


💡 设计原则: 好的配置管理应该是灵活、高效、易于理解的。通过分层设计和缓存优化,我们既保证了功能的完整性,又确保了良好的性能表现。

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

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

相关文章

发版混乱怎么规范

你是否经历过这种场景&#xff1a;临到发版&#xff0c;一堆功能代码挤在一起&#xff0c;测试分不清范围&#xff0c;修复一个Bug可能引发三个新Bug&#xff1f;发布过程像一场豪赌&#xff1f;问题的核心往往在于分支策略和流程的混乱。今天&#xff0c;我们就来建立一套在绝…

【golang长途旅行第30站】channel管道------解决线程竞争的好手

channel 为什么需要channel 使用全局变量加锁同步来解决goroutine的竞争&#xff0c;可以但不完美难以精确控制等待时间​&#xff08;主线程无法准确知道所有 goroutine 何时完成&#xff09;。全局变量容易引发竞态条件​&#xff08;即使加锁&#xff0c;代码复杂度也会增加…

苹果XR芯片介绍

苹果的 XR 芯片技术主要体现在 A 系列、M 系列处理器以及专为空间计算设计的 R1 协处理器中。以下从技术架构、产品迭代和综合对比三个维度展开分析&#xff1a;一、技术架构解析1. A 系列芯片&#xff08;以 A12 Bionic 为例&#xff09;制程工艺&#xff1a;7nm&#xff08;台…

达梦数据库巡检常用SQL(三)

达梦数据库巡检常用SQL(三) 数据库SQL运行检查 数据库SQL运行检查 死锁的事务情况: SELECT TO_CHAR(HAPPEN_TIME,YYYY-MM-DD HH24:MI:SS) HAPPEN_TIME,SQL_TEXT FROM V$DEADLOCK_HISTORY WHERE HAPPEN_TIME >DATEADD(DAY,-30,

基于SpringBoot的校园周边美食探索及分享平台

1. 项目简介 项目名称&#xff1a;校园周边美食探索及分享平台 项目背景&#xff1a;针对校园师生对周边美食信息的需求&#xff0c;构建一个集美食推荐、鉴赏、评论互动及社交功能于一体的平台&#xff0c;帮助用户发现优质美食资源并进行分享交流。 主要目标&#xff1a; 提供…

Go数据结构与算法-常见的排序算法

虽然看过别人写了很多遍&#xff0c;而且自己也写过很多遍&#xff08;指的是笔记&#xff09;&#xff0c;但是还是要写的就是排序算法。毕竟是初学Go语言&#xff0c;虽然之前写过&#xff0c;但是还是打算再写一遍。主要包括插入排序、选择排序、冒泡排序、快速排序、堆排序…

第 6 篇:目标规则与负载均衡 - `DestinationRule` 详解

系列文章:《Istio 服务网格详解》 第 6 篇:目标规则与负载均衡 - DestinationRule 详解 本篇焦点: 深入理解 DestinationRule 的核心作用:定义流量在到达目的地之后的行为。 详细剖析其三大核心功能:服务子集 (Subsets), 流量策略 (Traffic Policy), TLS 设置。 动手实战…

一个简洁的 C++ 日志模块实现

一个简洁的 C 日志模块实现 1. 引言 日志功能在软件开发中扮演着至关重要的角色&#xff0c;它帮助开发者追踪程序执行过程、诊断问题以及监控系统运行状态。本文介绍一个使用 C 实现的轻量级日志模块&#xff0c;该模块支持多日志级别、线程安全&#xff0c;并提供了简洁易用…

C语言---数据类型

文章目录数据类型分类1. 基本类型 (Basic Types)a. 整数类型 (Integer Types)char (字符型)int (整型)short (短整型)long (长整型)long long (C99标准引入)图片汇总b. 浮点类型 (Floating-Point Types)float (单精度浮点型)double (双精度浮点型)long double (长双精度浮点型)…

本搭建乌云漏洞库

1.下载镜像站文件&#xff0c;并拖入虚拟机 2.将bugs.rar解压至网站根目录下 /var/www/html 3.配置bugs/conn.php 4.在bugs下创建upload目录&#xff0c;将10-14、15-a、15-b、16压缩包文件解压到该upload目录 5.把wooyun.rar解压到 /mysql/data/wooyun目录下 6.配置hosts文件后…

Vmware虚拟机 处理器配置选项配置介绍

1. 处理器配置选项好&#x1f44c;&#xff0c;我来帮你逐一解读 VMware 里 虚拟机处理器 这些选项的含义。 你截的图里&#xff0c;主要有三块内容&#xff1a; 处理器数量 每个处理器的内核数量 ©虚拟化引擎1️⃣ 处理器数量 这是分配给虚拟机的 逻辑 CPU 插槽数。一般…

day40-tomcat

1.每日复盘与今日内容1.1复盘keepalived高可用配置抢占式与非抢占式脑裂keepalived处理Nginx挂掉1.2今日内容部署、安装、配置tomcat(systemctl)Tomcat主配置文件部署静态页部署zrlog&#x1f35f;&#x1f35f;&#x1f35f;&#x1f35f;&#x1f35f;接入负载均衡挂载到NFS2…

【RA-Eco-RA4E2-64PIN-V1.0 开发板】步进电机的串口控制

【RA-Eco-RA4E2-64PIN-V1.0 开发板】步进电机的串口控制 本文介绍了 RA-Eco-RA4E2-64PIN-V1.0 开发板通过串口指令实现 28BYJ-48 步进电机旋转角度和速度的精确控制的项目设计。 项目介绍 硬件连接&#xff1a;28BYJ-48 步进电机、ULN2003 驱动板、Jlink 调试器、供电电源等&am…

PiscCode基于 Mediapipe 的人体多模态关键点检测与可视化系统 —— HumanMultiLandmarker 深度解析

一、引言 在计算机视觉领域&#xff0c;人体关键点检测&#xff08;Human Pose Estimation&#xff0c;HPE&#xff09;一直是研究和应用的热点方向之一。随着深度学习与实时图像处理技术的发展&#xff0c;人体姿势估计已经从传统的 2D 检测走向了 3D 空间建模&#xff0c;并…

文献阅读笔记【物理信息机器学习】:Physics-informed machine learning

文献阅读笔记&#xff1a;Physics-informed machine learningSummaryResearch ObjectiveBackground / Problem Statement问题背景研究现状需解决的问题问题出现的原因分析问题解决思路Method(s)问题建模作者解决问题的方法/算法1. 观测偏差&#xff08;Observational Biases&am…

Linux服务环境搭建指南

实验拓扑概述**实验拓扑&#xff1a; APPSRV&#xff1a; 主机名&#xff1a;appsrv.example.com ip地址&#xff1a;192.168.100.10 网关&#xff1a;192.168.100.254 网卡为NAT模式 STORAGESRV&#xff1a; 主机名&#xff1a;storagesrv.example.com ip地址&#xff1a;192.…

[特殊字符] 数据库知识点总结(SQL Server 方向)

一、数据库基础概念数据库&#xff08;Database&#xff09;&#xff1a;存储和管理数据的容器。数据表&#xff08;Table&#xff09;&#xff1a;以行和列形式组织数据。行&#xff08;Row&#xff09;&#xff1a;一条记录。列&#xff08;Column&#xff09;&#xff1a;字…

【PSINS工具箱】MATLAB例程,二维平面上的组合导航,EKF融合速度、位置和IMU数据,4维观测量

文章目录关于工具箱程序简介代码概述核心功能与步骤运行结果MATLAB代码关于工具箱 本文所述的代码需要基于PSINS工具箱&#xff0c;工具箱的讲解&#xff1a; PSINS初学指导&#xff1a;https://blog.csdn.net/callmeup/article/details/137087932 本文为二维平面上的定位&am…

MiMo-VL 技术报告

摘要 我们开源了 MiMo-VL-7B-SFT 和 MiMo-VL-7B-RL 两个强大的视觉语言模型,它们在通用视觉理解和多模态推理方面均展现出最先进的性能。MiMo-VL-7B-RL 在 40 项评估任务中的 35 项上优于 Qwen2.5-VL-7B,并在 OlympiadBench 上获得 59.4 分,超越了参数量高达 780 亿的模型。…

CTFshow Pwn入门 - pwn 19

先看main函数&#xff1a;fclose(_bss_start) fclose(stdout) 关闭了默认fd1的输出&#xff0c;所以system的结果无法直接看到。 思路&#xff1a; 输出重定向。 ls 1>&0 ls >&0 ls >&2 ###三种写法均可将输出重定向到能回显的终端并获得一个新的交互…