基於spring boot框架進行二次封裝,微型框架編寫思路

目標:減小重複代碼,提升開發效率,項目地址:github.com/neatlife/jf…java

歡迎star,歡迎pr(求star, 求star, 求star)git

可封裝功能列表github

E文 功能 目前做用
controller 控制器父類 簡化控制器裏的常見操做
exception 異常 統一全局業務異常操做
handler 異常攔截 全局異常攔截到日誌裏
http 請求響應實體 統一全局響應實體
hystrix hystrix事件攔截 熔斷時發送報警郵件
jpa jpa非業務重複代碼封裝 自動給deleted_at, updated_at, created_at賦值
json 響應json數據的二次處理 自動格式化金額小數位數
listener spring boot框架事件 在框架啓動時給util注入service實例
logback 自定義logback日誌輸出 將日誌輸出到elk的redis,方便elk統一進行日誌處理
model 基礎jpa實體 包含deleted_at, updated_at, created_at字段的實體
redis 自定義redis序列化和反序列化操做 使用GenericJackson2JsonRedisSerializer序列化redis值,提升可讀性
request 自定請求數據的解析 處理json請求
springfox 自定義springfox文檔解析 ApiClass支持文檔描述引用
util 經常使用工具收集 好比json, http請求等經常使用工具類
validator 請求參數自定義校驗 檢查參數長度
apiversion 支持不一樣的api的版本到不一樣的控制器邏輯 參考 MainController

目前已經實現上面列表中的全部功能並開源redis

一些關鍵的點

json & http客戶端的封裝

json & http客戶端常常使用,自行編寫容易踩坑,因此直接拿dew框架的工具類進行了集成spring

github.com/gudaoxuri/d…docker

須要同時發出多個http請求時可使用parallelStream()技術,可顯著減小請求總時長shell

List<String> paramList = ...
paramList.parallelStream().forEach(param -> {
    http post with param
})
複製代碼

經測試, 26個請求,使用parallelStream將請求總時間從23.803減小到1.731秒json

MapperUtil工具類的封裝

由於java裏對象複製很是頻繁,因此封裝了MapperUtil, 雖然複製對象只需下面兩行代碼api

Class1 class1 = new Class1();
BeanUtils.copyProperties(source, class1);
複製代碼

可是因爲很是頻繁的相似代碼,一個項目項目可能出現上千次這種複製,因此將上面兩行代碼合併成了一行bash

Class1 class1 = MapperUtil.to(source, class1);
複製代碼

核心實現代碼以下:

public static <SOURCE, TARGET> TARGET to(SOURCE source, Class<TARGET> targetClass) {
    TARGET target = BeanUtils.instantiateClass(targetClass);
    BeanUtils.copyProperties(source, target);
    return target;
}
複製代碼

雖然使用了反射技術,但通過測試無性能問題

elk日誌

使用redis進行了日誌中轉,因此logstash須要從redis讀取日誌輸出到elasticsearch

logstash從redis讀取日誌輸出到elasticsearch的配置

input {
    redis {
        data_type => "list"
        key => "logstash"
        host => "127.0.0.1"
        port => 6379
        threads => 5
        codec => "json"
    }
}
filter {

}
output {

    elasticsearch {
        hosts => ["elasticsearch:9200"]
        index => "logstash-%{type}-%{+YYYY.MM.dd}"
        document_type => "%{type}"
        workers => 1
        template_overwrite => true
    }
    stdout{}
}
複製代碼

由於elasticsearch裏日誌會愈來愈大,因此須要定時清理,定時清理elasticsearch數據

參考:www.jianshu.com/p/458421dac…

核心代碼以下

#!/bin/bash
# filename:deleteEsData.sh
# 天天2點定時刪除es中指定日期的數據
# crontab: 0 2 * * * sh /home/scripts/deleteEsData.sh >> /home/scripts/logs/deleteEsData.run.log 2>&1
# 現在天是2017-09-21 50天前是2017.08.02
# createdate: 20190921

today=`date +%Y-%m-%d`;
echo "今天是${today}"
 # 不指定參數時,默認刪除daynum天前以logs-開頭的數據
daynum=51
 # 當參數個數大於1時,提示參數錯誤
if [ $# -gt 1 ] ;then
        echo "要麼不傳參數,要麼只傳1個參數!"
        exit 101;
fi
 # 當參數個數爲1時,獲取指定的參數
if [ $# == 1 ] ;then
        daynum=$1
fi

esday=`date -d '-'"${daynum}"' day' +%Y.%m.%d`;
echo "${daynum}天前是${esday}"

curl -XDELETE http://127.0.0.1:9200/logs-${esday}
echo "${esday} 的log刪除執行完成"
複製代碼

全局業務異常

定義全局業務異常,方便進行全局業務異常的捕獲和統一處理 ControllerExceptionHandler

核心處理邏輯以下:

@ExceptionHandler({BusinessRuntimeException.class})
@ResponseBody
public Response handlerBusinessException(BusinessRuntimeException ex) {
    return new Response<Map>(HttpCode.SUCCESS.toString(), ex.getMessage(), Maps.newHashMap());
}
複製代碼

這樣的好處是方便對錯誤的返回數據進行格式化

利用框架事件,簡化util

RedisUtil工具類須要RedisTemplate操做實例對象,若是在RedisUtil使用Autowired自動注入RedisTemplate,則須要RedisUtil也是Service,這將RedisUtil的調用變得複雜化了(使用前必須先注入RedisUtil以獲取RedisTemplate對象) 利用框架事件,可在框架啓動時,獲取RedisTemplate對象,手動注入RedisUtil裏

核心實現代碼以下:

@Component
public class ApplicationStartedEventListener implements ApplicationListener<ApplicationStartedEvent> {

    private final RedisTemplate redisTemplate;
    private final JFrameworkConfig jFrameworkConfig;

    @Autowired
    public ApplicationStartedEventListener(RedisTemplate redisTemplate, JFrameworkConfig jFrameworkConfig) {
        this.redisTemplate = redisTemplate;
        this.jFrameworkConfig = jFrameworkConfig;
    }

    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        RedisUtil.setRedisTemplate(redisTemplate);
        LockUtil.setRedisTemplate(redisTemplate);
        DingTalkUtil.setDdUrl(jFrameworkConfig.getNotification().getDingTalkUrl());
    }
}
複製代碼

docker 鏡像倉庫選擇

自行搭建鏡像倉庫不如使用免費穩定的來得高效可靠

能夠直接使用了aliyun提供的免費docker鏡像倉庫

自動維護created_at, updated_at, deleted_at字段

採用了jpa的事件機制,在建立,修改,刪除事件發生時自動進行維護

核心代碼以下:

@PrePersist
public void touchCreated(BaseEntity target) {
    target.setCreatedAt(DateUtil.currentSecond());
    target.setUpdatedAt(DateUtil.currentSecond());
}

@PreUpdate
public void touchUpdate(BaseEntity target) {
    target.setUpdatedAt(DateUtil.currentSecond());
}

@PreRemove
public void touchDeleted(BaseEntity target) {
    target.setDeletedAt(DateUtil.currentSecond());
}
複製代碼

ci/cd的選擇

目前ci/cd工具選擇很是多,但在生產裏用得最多的應該是gitlab和jenkins

目前仍然採用jenkins做爲ci/cd工具,gitlab的ci目前我的認爲仍然不夠成熟

代碼質量檢測

能夠直接試用sonarkube的開放服務,無需自行搭建:

sonarcloud.io/dashboard?i…

打包分發

通常框架會做爲項目的基礎依賴,那麼可以很是方便的下載這個框架就很是重要了

目前nexus私服仍然是首選,可使用docker搭建nexus私服:

version: "3"

services:
 nexus:
 image: sonatype/nexus3
 environment:
 - INSTALL4J_ADD_VM_PARAMS=-Xms512m -Xmx768m -XX:MaxDirectMemorySize=1g -Djava.util.prefs.userRoot=/nexus-data/javaprefs
 volumes:
 - ./nexus-data:/nexus-data
 ports:
 - "8081:8081"
複製代碼

微服務

因爲是微服務形式的部署,因此日誌,配置都須要中心化,k8s也是標配

日誌選經典的elk

配置中心選擇apollo

部署平臺能夠選擇k8s,或者k8s上的istio,目前使用k8s

微服務的k8s模版參考 應用: raw.githubusercontent.com/neatlife/jf… 網關: raw.githubusercontent.com/neatlife/jf…

核心區別是kind字段,網關是 DaemonSet 應用是 Deployment

項目參考

完成框架的封裝必然少不了不少參考,即便這是個小框架

如下是參考列表

  1. github.com/kmtong/logb…
  2. github.com/looly/hutoo…
  3. github.com/gudaoxuri/d…
  4. github.com/gudaoxuri/d…
  5. github.com/xdd-organ/x…
  6. github.com/indrabasak/…
  7. github.com/ityouknow/s…
  8. github.com/WellJay/spr…

目前文章還在持續更新中,若是對框架開發感興趣,可加做者微信探討,也可提pr,issue等

suxiaolinKing
相關文章
相關標籤/搜索