之前大群里有小伙伴在討論用戶IP日志記錄的一些方案,也有小伙伴在做這個(gè)需求,私底下跟我咨詢過,所以在此特地匯總梳理一下。
### 方案1
在登錄業(yè)務(wù)中直接記錄用戶每次登錄的IP日志,如下圖所示:
用戶請求登錄的Controller,原先用戶直接調(diào)用登錄的service,這里假設(shè)用戶登錄校驗(yàn)都沒問題,這個(gè)時(shí)候新增一個(gè)業(yè)務(wù)方法用于保存用戶的ip,這個(gè)ip需要通過Controller的方法獲得請求參數(shù)Request的IP后傳入到Service,如此就可以保存。這里的數(shù)據(jù)庫可以用MySql這樣的關(guān)系型數(shù)據(jù)庫,也可以使用MongoDB,個(gè)人建議后者。
這種方案簡單粗暴,但是有個(gè)缺點(diǎn),就是耦合太高了。對原先的代碼有了侵入性,Controller與Service的方法都需要進(jìn)行修改后方可生效。
### 方案2
為了降低耦合,使用消息隊(duì)列,消息隊(duì)列可以在controller中發(fā)、也可以在service中發(fā),如下圖所示
如果不考慮事務(wù),并且不修改service的情況下,可以直接在controller中發(fā)消息即可。消費(fèi)監(jiān)聽到消息后,調(diào)用service的保存ip方法即可。
使用消息隊(duì)列方案也有一個(gè)很大的缺點(diǎn),那就是太重了,很多公司一開始可能并沒有消息隊(duì)列,額外增加MQ也會提高運(yùn)維的復(fù)雜度。所以這個(gè)方案看情況而定,沒有必要為了一個(gè)非主線任務(wù)而增加中間件。
### 方案3
同樣是解耦,由于MQ太重,所以可以采用Spring的異步任務(wù)來做。如下圖所示:
此處也不考慮事務(wù),因?yàn)闆]必要,直接在Controller中調(diào)用異步任務(wù)就可以。通過在異步任務(wù)中進(jìn)行IP保存。
這么做其實(shí)沒啥問題,但是有的公司的技術(shù)Leader或架構(gòu)師不喜歡這種方式,因?yàn)檫@仍然對原有代碼進(jìn)行了破壞,也就是Controller需要修改代碼,也依然會存在一定的耦合度。所以請看方案4。
### 方案4
使用Spring的AOP切面,如下圖所示:
通過AOP,可以直接針對某個(gè)指定的方法進(jìn)行切入,結(jié)合AOP的多種通知機(jī)制來做,如此針對性的方法可以在AOP中實(shí)現(xiàn),只要切到登錄業(yè)務(wù)方法,那么就會進(jìn)入AOP的通知,在通知中調(diào)用IP業(yè)務(wù)進(jìn)記錄保存即可。
使用AOP切面也會存在小缺點(diǎn),從長遠(yuǎn)考慮,Service中的方法小概率被其他業(yè)務(wù)或其他子項(xiàng)目調(diào)用,如此便會生成不必要的日志。短期的話AOP簡單方便可以直接用,也降低代碼的耦合,對原有業(yè)務(wù)代碼零侵入。
### 方案5
使用攔截器(有些框架叫做過濾器),本質(zhì)上這也類似于切面,只不過這是針對請求的入口,在進(jìn)入到controller之前進(jìn)行IP數(shù)據(jù)的獲取與記錄。也許有小伙伴會問,AOP也可以直接切controller呀,直接用AOP也行吧?沒錯(cuò),但是習(xí)慣性不這么做,AOP一般對service的切入較多。相對而言,使用攔截器則更佳。參考如下圖所示:
通過攔截器注冊,指定分配給某個(gè)url的路由(如:/user/login)即可。如此每次請求經(jīng)過該路由,則進(jìn)入攔截器中,通過ip的獲得并且調(diào)用IpService進(jìn)行記錄保存即可。
本方案相對可以實(shí)現(xiàn),并且有的小伙伴也在這么用。所以如果在Java后端代碼中實(shí)現(xiàn)的話,比較推薦方案5。當(dāng)然處理方案5之外,還有一個(gè)比較好的方式,請參看方案6。
### 方案6
網(wǎng)關(guān)記錄用戶登錄的IP日志。方案1~5都需要經(jīng)過java代碼的編寫,并且重新打包發(fā)布版本,而且開發(fā)和運(yùn)維還都需要走流程走工單。那么假設(shè)技術(shù)經(jīng)理提出不從java代碼層面來做的話,這個(gè)時(shí)候其實(shí)也可以。請參看如下圖所示:
OpenResty目前在很多公司都是作為業(yè)務(wù)網(wǎng)關(guān)來使用,而且在高并發(fā)場景中出現(xiàn)的很多,幾乎都在用,比如多級緩存架構(gòu)都需要借助于OpenResty來實(shí)現(xiàn)。在圖中,OpenResty可以作為業(yè)務(wù)網(wǎng)關(guān)來控制請求的走向,請求進(jìn)來如果匹配到登錄url(如:/user/login),則進(jìn)行l(wèi)ua腳本的轉(zhuǎn)發(fā),請求會進(jìn)入到lua腳本中進(jìn)行控制,lua腳本可以獲得用戶的ip以及用戶id,如此就可以直接在lua中進(jìn)行數(shù)據(jù)的存儲,不管是mysql、mongodb或是redis,都可以進(jìn)行存取。此處可以直接結(jié)合mongodb來進(jìn)行日志記錄的保存即可。
可以看到,本方案只需要修改網(wǎng)關(guān)增加lua腳本即可生效,對后端的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)代碼,那么這樣就更方便了,減少溝通成本。文章來源:http://www.zghlxwxcb.cn/news/detail-796505.html
「Java架構(gòu)師2.0」正在籌備中...文章來源地址http://www.zghlxwxcb.cn/news/detail-796505.html
到了這里,關(guān)于用戶登錄后IP記錄日志的六種實(shí)現(xiàn)方案探討的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!