聊一聊計(jì)算機(jī)軟件類項(xiàng)目的敏捷開發(fā) Scrum

之前大群里有小伙伴在討論用戶IP日志記錄的一些方案,也有小伙伴在做這個(gè)需求,私底下跟我咨詢過,所以在此特地匯總梳理一下。

方案1

在登錄業(yè)務(wù)中直接記錄用戶每次登錄的IP日志,如下圖所示:

image.png

用戶請(qǐng)求登錄的Controller,原先用戶直接調(diào)用登錄的service,這里假設(shè)用戶登錄校驗(yàn)都沒問題,這個(gè)時(shí)候新增一個(gè)業(yè)務(wù)方法用于保存用戶的ip,這個(gè)ip需要通過Controller的方法獲得請(qǐng)求參數(shù)Request的IP后傳入到Service,如此就可以保存。這里的數(shù)據(jù)庫可以用MySql這樣的關(guān)系型數(shù)據(jù)庫,也可以使用MongoDB,個(gè)人建議后者。

這種方案簡單粗暴,但是有個(gè)缺點(diǎn),就是耦合太高了。對(duì)原先的代碼有了侵入性,Controller與Service的方法都需要進(jìn)行修改后方可生效。

方案2

為了降低耦合,使用消息隊(duì)列,消息隊(duì)列可以在controller中發(fā)、也可以在service中發(fā),如下圖所示

image.png

如果不考慮事務(wù),并且不修改service的情況下,可以直接在controller中發(fā)消息即可。消費(fèi)監(jiān)聽到消息后,調(diào)用service的保存ip方法即可。

使用消息隊(duì)列方案也有一個(gè)很大的缺點(diǎn),那就是太重了,很多公司一開始可能并沒有消息隊(duì)列,額外增加MQ也會(huì)提高運(yùn)維的復(fù)雜度。所以這個(gè)方案看情況而定,沒有必要為了一個(gè)非主線任務(wù)而增加中間件。

方案3

同樣是解耦,由于MQ太重,所以可以采用Spring的異步任務(wù)來做。如下圖所示:


image.png

此處也不考慮事務(wù),因?yàn)闆]必要,直接在Controller中調(diào)用異步任務(wù)就可以。通過在異步任務(wù)中進(jìn)行IP保存。

這么做其實(shí)沒啥問題,但是有的公司的技術(shù)Leader或架構(gòu)師不喜歡這種方式,因?yàn)檫@仍然對(duì)原有代碼進(jìn)行了破壞,也就是Controller需要修改代碼,也依然會(huì)存在一定的耦合度。所以請(qǐng)看方案4。

方案4

使用Spring的AOP切面,如下圖所示:


image.png

通過AOP,可以直接針對(duì)某個(gè)指定的方法進(jìn)行切入,結(jié)合AOP的多種通知機(jī)制來做,如此針對(duì)性的方法可以在AOP中實(shí)現(xiàn),只要切到登錄業(yè)務(wù)方法,那么就會(huì)進(jìn)入AOP的通知,在通知中調(diào)用IP業(yè)務(wù)進(jìn)記錄保存即可。

使用AOP切面也會(huì)存在小缺點(diǎn),從長遠(yuǎn)考慮,Service中的方法小概率被其他業(yè)務(wù)或其他子項(xiàng)目調(diào)用,如此便會(huì)生成不必要的日志。短期的話AOP簡單方便可以直接用,也降低代碼的耦合,對(duì)原有業(yè)務(wù)代碼零侵入。

方案5

使用攔截器(有些框架叫做過濾器),本質(zhì)上這也類似于切面,只不過這是針對(duì)請(qǐng)求的入口,在進(jìn)入到controller之前進(jìn)行IP數(shù)據(jù)的獲取與記錄。也許有小伙伴會(huì)問,AOP也可以直接切controller呀,直接用AOP也行吧?沒錯(cuò),但是習(xí)慣性不這么做,AOP一般對(duì)service的切入較多。相對(duì)而言,使用攔截器則更佳。參考如下圖所示:

image.png

通過攔截器注冊(cè),指定分配給某個(gè)url的路由(如:/user/login)即可。如此每次請(qǐng)求經(jīng)過該路由,則進(jìn)入攔截器中,通過ip的獲得并且調(diào)用IpService進(jìn)行記錄保存即可。

本方案相對(duì)可以實(shí)現(xiàn),并且有的小伙伴也在這么用。所以如果在Java后端代碼中實(shí)現(xiàn)的話,比較推薦方案5。當(dāng)然處理方案5之外,還有一個(gè)比較好的方式,請(qǐng)參看方案6。

方案6

網(wǎng)關(guān)記錄用戶登錄的IP日志。方案1~5都需要經(jīng)過java代碼的編寫,并且重新打包發(fā)布版本,而且開發(fā)和運(yùn)維還都需要走流程走工單。那么假設(shè)技術(shù)經(jīng)理提出不從java代碼層面來做的話,這個(gè)時(shí)候其實(shí)也可以。請(qǐng)參看如下圖所示:

image.png

OpenResty目前在很多公司都是作為業(yè)務(wù)網(wǎng)關(guān)來使用,而且在高并發(fā)場景中出現(xiàn)的很多,幾乎都在用,比如多級(jí)緩存架構(gòu)都需要借助于OpenResty來實(shí)現(xiàn)。在圖中,OpenResty可以作為業(yè)務(wù)網(wǎng)關(guān)來控制請(qǐng)求的走向,請(qǐng)求進(jìn)來如果匹配到登錄url(如:/user/login),則進(jìn)行l(wèi)ua腳本的轉(zhuǎn)發(fā),請(qǐng)求會(huì)進(jìn)入到lua腳本中進(jìn)行控制,lua腳本可以獲得用戶的ip以及用戶id,如此就可以直接在lua中進(jìn)行數(shù)據(jù)的存儲(chǔ),不管是mysql、mongodb或是redis,都可以進(jìn)行存取。此處可以直接結(jié)合mongodb來進(jìn)行日志記錄的保存即可。

可以看到,本方案只需要修改網(wǎng)關(guān)增加lua腳本即可生效,對(duì)后端的Java代碼是0侵入的,并且也降低業(yè)務(wù)代碼的復(fù)雜度。當(dāng)然缺點(diǎn)也有,那就是需要和運(yùn)維人員協(xié)調(diào),讓運(yùn)維來進(jìn)行網(wǎng)關(guān)的業(yè)務(wù)編寫。當(dāng)然有些公司是由Java開發(fā)來實(shí)現(xiàn)OpenResty的相關(guān)代碼,那么這樣就更方便了,減少溝通成本。

「Java架構(gòu)師2.0」正在籌備中...

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容