第3篇:配置管理的藝術 - 讓框架更靈活

前言

在前一章中,我們設計了強大的注解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 ###三種寫法均可將輸出重定向到能回顯的終端并獲得一個新的交互…