為了設計一個高效、可靠且可擴展的操作日志模塊,可以結合 ?AOP(面向切面編程)?、異步處理?(多線程或MQ)以及合理的存儲策略,具體方案如下:
?1. 技術選型與架構設計?
??(1) AOP 實現非侵入式日志攔截?
- ?目的?:通過切面自動攔截需要記錄日志的操作,避免業務代碼耦合。
- ?實現方式?:
- 自定義注解(如
@Loggable
),標記需要記錄日志的方法。 - 使用 Spring AOP 或 AspectJ 定義切面,在方法執行前后捕獲操作信息(如方法名、參數、返回值、異常等)。
- 結合 SpEL 表達式動態解析日志內容(例如從參數中提取業務ID)。
- 自定義注解(如
- ?示例注解?:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Loggable {String operation() default "";String detail() default ""; }
??(2) 異步處理:選擇多線程或MQ?
- ?目標?:將日志記錄與業務邏輯解耦,避免同步寫入的性能瓶頸。
- ?方案對比?:
- ?多線程線程池?:
- ?優點?:實現簡單,無外部依賴,適合中小型系統。
- ?缺點?:系統宕機可能導致內存中未處理的日志丟失。
- ?實現?:在切面中將日志對象提交到
ThreadPoolTaskExecutor
。
- ?消息隊列(MQ)??:
- ?優點?:解耦徹底,支持削峰填谷,數據可靠性高(如 Kafka 持久化)。
- ?缺點?:依賴中間件,增加系統復雜度。
- ?實現?:切面中發送日志消息到MQ(如 RabbitMQ/Kafka),消費者服務異步消費并存儲。
- ?多線程線程池?:
??(3) 存儲策略?
- ?數據庫存儲?:
- 結構化存儲,便于查詢和管理(如 MySQL)。
- 需設計合理的日志表(字段:操作類型、操作人、時間、IP、參數、結果狀態等)。
- ?Elasticsearch?:
- 適合海量日志的高效檢索與分析。
- ?混合存儲?:核心操作存數據庫,輔助分析日志存ES。
?2. 核心實現步驟?
??(1) 定義日志實體?
public class OperationLog {private Long id;private String operation; // 操作類型(如 "新增用戶")private String operator; // 操作人(從 SecurityContext 獲取)private String params; // 方法參數(JSON序列化)private String result; // 操作結果(成功/失敗)private String errorMsg; // 異常信息private LocalDateTime createTime;private String ip; // 操作IP
}
??(2) AOP 切面實現?
@Aspect
@Component
public class LogAspect {@Autowiredprivate LogService logService; // 異步日志服務@Around("@annotation(loggable)")public Object logOperation(ProceedingJoinPoint joinPoint, Loggable loggable) throws Throwable {// 1. 構建基礎日志信息OperationLog log = new OperationLog();log.setOperation(loggable.operation());log.setOperator(getCurrentUser());log.setParams(serializeParams(joinPoint.getArgs()));try {Object result = joinPoint.proceed(); // 執行原方法log.setResult("SUCCESS");return result;} catch (Exception e) {log.setResult("FAIL");log.setErrorMsg(e.getMessage());throw e;} finally {// 2. 異步提交日志logService.asyncSave(log); // 通過線程池或MQ發送}}
}
??(3) 異步處理實現?
-
?方案1:線程池異步提交?
@Service public class LogService {@Autowiredprivate LogRepository logRepository;private Executor asyncExecutor = Executors.newFixedThreadPool(4);public void asyncSave(OperationLog log) {asyncExecutor.execute(() -> logRepository.save(log));} }
-
?方案2:MQ異步處理?
// 切面中發送消息到MQ @Autowired private RabbitTemplate rabbitTemplate;public void asyncSave(OperationLog log) {rabbitTemplate.convertAndSend("log.exchange", "log.routing.key", log); }// MQ消費者服務 @RabbitListener(queues = "log.queue") public void handleLogMessage(OperationLog log) {logRepository.save(log); }
?3. 擴展性設計?
- ?動態開關?:通過配置中心(如 Apollo)動態開啟/關閉日志記錄。
- ?日志分表?:按時間分表(如按月)避免單表過大。
- ?敏感信息脫敏?:在切面中對參數進行脫敏處理(如手機號、密碼)。
- ?鏈路追蹤?:集成 TraceID(如 Sleuth)關聯操作日志與請求鏈路。
?4. 技術選型建議?
- ?中小型系統?:AOP + 線程池異步,簡單高效。
- ?分布式/高并發系統?:AOP + MQ(如 Kafka),保證可靠性與擴展性。
- ?日志分析場景?:ES + Logstash + Kibana 實現可視化分析。
?5. 注意事項?
- ?異常處理?:確保異步過程有異常捕獲機制(如 MQ 重試、死信隊列)。
- ?性能監控?:監控日志存儲的耗時和成功率,避免成為系統瓶頸。
- ?用戶上下文?:通過 ThreadLocal 或 SecurityContext 獲取操作人信息。