**本文正在參加「Java主題月 - Java Debug筆記活動」,詳情查看 活動連接 **web
項目初期,爲了快速迭代上線,不少功能都是項目搭建者從別的地方Copy過去,而後根據項目實際狀況進行相應的修改。spring
後期伴隨着業務的迭代,對於中心化組件的需求也漸漸產生。好比個人老東家,在K8S上差很少部署了200個項目,瓜熟蒂落的誕生了受權組件,日誌組件,註解組件,長鏈接服務等。安全
固然啦,咱們今天的主角是日誌組件。markdown
日誌的格式通常包含幾種類型:入參仍是出參,類,方法,內容,開始時間,描述,仍是耗時。有了固定的格式後,日誌的採集會變得相對容易點。app
若是是對安全有要求的,可能還會帶上加密信息和簽名。post
不能說你用了日誌組件,而後全部的方法中都打印日誌,大大浪費了硬盤空間,暴殄天物。測試
看到這裏確定有人要說了,哪有這麼複雜。但相信我,在金融級別的系統裏就是有這種需求。ui
SpringBoot誕生初期爲何會快速流行,就是源於它配置簡單。 若是一個組件的代碼侵入性很強,用的人就會大打折扣甚至無人問津。this
在老東家搞的Dubbo組件就由於須要在apollo加一行配置,推了很久才被同事漸漸接受。太難了~~加密
這是車轍本身在用的日誌格式
[類型:'入參'] | [類:'TestLogService'] | [方法:'annotest'] | [入參:'[{"yuan":"123456.789"}]'] | [開始時間:'2021-05-13 17:49:46'] | [描述:'測試']。
[類型:'出參'] | [類:'TestLogService'] | [方法:'annotest'] | [出參:'null'] | [結束時間:'2021-05-13 17:49:46'] | [耗時:31] | [描述:'測試']
複製代碼
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import(EnableLogRegister.class)
public @interface EnableApplicationLog {
/**
* 是否開啓controller註解
* @return
*/
boolean enableController() default true;
/**
* 是否開啓service註解
* @return
*/
boolean enableService() default true;
}
複製代碼
ImportBeanDefinitionRegistrar
,將本身須要的類交給Spring管理。這樣就根據EnableApplicationLog
註解上的配置判斷是否讓切面類被Spring管理。所以組件沒有采用SpringBoot Starter的形式,相對靈活。能夠參考Mybatis的MapperScan是怎麼作的。class EnableLogRegister implements ImportBeanDefinitionRegistrar{
boolean enableController = annoAttrs.getBoolean("enableController");
if(enableController){
basePackages.add(BASE_HANDLER_CONTROLLER);
}
boolean enableService = annoAttrs.getBoolean("enableService");
if(enableService){
basePackages.add(BASE_HANDLER_SERVICE);
}
}
複製代碼
@Aspect
@Slf4j
public class EnableLogControllerLogHandler extends BaseLogHandler {
@Pointcut("within(@(org.springframework.stereotype.Controller || org.springframework.web.bind.annotation.RestController) *)")
private void allMethod() {
}
@Around("allMethod()")
public Object doAround(ProceedingJoinPoint call) throws Throwable {
return handle(call);
}
}
// service層面切點與controller一致
複製代碼
// 不須要打印日誌註解
public @interface NoNeedLog {
}
// 須要打印日誌的配置註解
public @interface LogParam {
String desc() default "";
boolean isPrintIn() default true;
boolean isPrintOut() default true;
}
複製代碼
// 判斷是否須要打印日誌
if(!needLog(call)){
Object result = call.proceed();
return result;
}
Boolean isPrintIn = true, isPrintOut = true;
String desc = null;
// 獲取是否須要打印入參和出參
LogParam logParam = this.getLogParam(call);
if(logParam != null){
isPrintIn = logParam.isPrintIn();
isPrintOut = logParam.isPrintOut();
desc = logParam.desc();
}
// 入參參數打印
Long startStamp = System.currentTimeMillis();
if(isPrintIn){
doBeforeParam(call, desc);
}
// invoker調用
Object result = call.proceed();
// 返回參數打印
if(isPrintOut){
doAfterParam(result, startStamp, call, desc);
}
return result;
複製代碼
上面的代碼基本上包含了主要的實現,相信小夥伴們應該對此有了必定的認識,能夠在下方評論中留言喲!
SpringBoot啓動類上添加註解開啓日誌打印
@EnableApplicationLog(enableController = false)
public class TrackAdapterApplication {}
複製代碼
方法不須要日誌
@NoNeedLog
public void annotest(AnnoBean annoBean)
複製代碼
日誌配置不須要入參,添加描述
@LogParam(desc = "測試", isPrintIn = false)
public void annotest(AnnoBean annoBean)
複製代碼
其實日誌組件裏還有很多東西能夠寫,好比說拋出的異常我怎麼處理。捕獲打印異常並繼續拋出仍是直接作處理並返回,亦或是作一個異常處理組件用來記錄並告警。這邊也不能給出一個完美的答案,畢竟適合的纔是最好的。
這是時隔多月的第一篇博文,接下來但願出一些更高質量的文章,我們下期見啦!