SpEL在動態執行業務中的應用

前言

相信做java后端的coder都對SpEL有所了解。

本篇blog不是詳細介紹SpEL的定義、功能和詳細的使用方法的文章,是想和大家分享一下實際業務中遇到的問題和最終使用SpEL做為解決方案的思考過程。

在筆者所處的物聯網行業中平臺端需要對設備端上報的數據進行監控和告警。告警規則需要支持后臺配置,可動態配置告警指標和告警閾值以及告警短信和郵件的消息模板

這個業務需要中需要動態配置3個數據

  • 告警指標
  • 告警閾值
  • 告警消息模板

1. 告警指標

告警指標由業務決定了其所在領域內的關注點,程序需要能夠根據配置取得對應的值

2. 告警閾值

告警閾值決定了告警的觸發條件類似于規則引擎中規則命中和工作流引擎中的網關。

會遇到簡單的關系運算如 temperature > 40(溫度大于40°C觸發告警),多條件關系運算 temperature > 25 & humidity > 30 (溫度大于25°C并且濕度大于30%觸發告警)等業務需求。

3. 告警消息模板

產生了相應的告警事件后需要將告警信息通過短信或者郵件發送出去,根據市場需求平臺需要支持客戶可以按照自己的行業特性自行定義告警的內容。

基于SpEL強大的運行時執行,解決監控告警需求

解決動態獲取告警指標值

SpEL 支持訪問屬性,數組,集合,可以根據一個特定的對象實例求其內部的屬性值

比如需要獲取設備上報的電流值

DeviceStatusDTO deviceStatusDto = DeviceStatusDTO.builder()
                .ueSn("P004000000")
                .productCode("6")
                .storeId(20140L)
                .ueType(4)
                .voltage(30.0)
                .electricity(10.0)
                .temperature(40.0)
                .lastReportTime(new Date())
                .build();
                
ExpressionParser parser = new SpelExpressionParser();
Expression expTargetValue = parser.parseExpression("electricity");
// targetValue 即為deviceStatusDto對象中的electricity屬性值
Object targetValue = expTargetValue.getValue(deviceStatusDto);

解決告警閾值即告警規則的命中問題

SpEL 支持關系運算

DeviceStatusDTO deviceStatusDto = DeviceStatusDTO.builder()
                .ueSn("P004000000")
                .productCode("6")
                .storeId(20140L)
                .ueType(4)
                .voltage(30.0)
                .electricity(10.0)
                .temperature(40.0)
                .lastReportTime(new Date())
                .build();
                
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("temperature > 55");
boolean fire = exp.getValue(deviceStatusDto, Boolean.class);
if(fire) {
    // 觸發告警邏輯
    ...
}

告警消息模板

SpEL 支持對象調用等對象操作

DeviceStatusDTO deviceStatusDto = DeviceStatusDTO.builder()
                .ueSn("P004000000")
                .productCode("6")
                .storeId(20140L)
                .ueType(4)
                .voltage(30.0)
                .electricity(10.0)
                .temperature(40.0)
                .lastReportTime(new Date())
                .build();
                
// 根據SpringEL告警模板生成告警內容
ExpressionParser parser = new SpelExpressionParser();
Expression expAlarmDesc = parser.parseExpression("'溫度告警SN:' + ueSn + '溫度:' + temperature + '℃'");
String alarmDesc = expAlarmDesc.getValue(deviceStatusDto, String.class);

使用告警配置表存儲SpEL表達式滿足市場可自由配置化需求

CREATE TABLE `e_ue_alarm_config` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
  `version` int(10) NOT NULL COMMENT '版本',
  `create_time` datetime NOT NULL COMMENT '創建時間',
  `modify_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改時間',
  `product_code` varchar(32) NOT NULL COMMENT '產品編碼',
  `alarm_target` varchar(255) NOT NULL COMMENT '告警指標(SprEL表達式)',
  `alarm_condition` varchar(255) NOT NULL COMMENT '告警條件(SprEL表達式)',
  `alarm_channel` varchar(255) NOT NULL COMMENT '告警通道 郵件:E_MAIL、App推送: PUSH、短信: SMS ,多個使用,號分割',
  `alarm_receiver` varchar(255) NOT NULL COMMENT '告警接收人',
  `alarm_template` varchar(500) NOT NULL COMMENT '告警內容模板(SprEL表達式',
  `alarm_frequency` int(10) NOT NULL COMMENT '告警頻率(告警間隔時間 單位:分鐘)',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4;
告警規則配置示例
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容