SpringBoot結(jié)合Aop記錄請求日志

Aop指面向切面編程双妨,在spring mvc 里已經(jīng)出現(xiàn),springBoot作為體系之一叮阅,也包含AOP刁品。在一個Web應(yīng)用中,我希望記錄所有請求的遠(yuǎn)端地址浩姥,請求客戶端類型挑随,請求URI等記錄,一方面是為了做安全記錄勒叠,同時也可以提供后期考慮數(shù)據(jù)分析的基礎(chǔ)數(shù)據(jù)兜挨,具體可以通過Headers信息獲取。常見的比較重要的頭信息包括 user-agent, accept等眯分,其他如URI拌汇,queryString 等在serveletRequest中得到桑涎。如果單獨考慮每個方法里附加方法棵红,太過笨拙,AOP的特性提供了很好的方案壕探∑可以按照包与倡,類,方法昆稿,注解各個級別作為切點纺座,攔截訪問請求,做附加處理溉潭。當(dāng)然比驻,現(xiàn)實中各種項目也是通過AOP實現(xiàn)類似的功能该溯,包括訪問日志記錄,驗證頭信息别惦,數(shù)據(jù)庫SQL分析統(tǒng)計狈茉,redis請求統(tǒng)計等。


看個圖放松

基本功能已經(jīng)完成掸掸,中間有遇到AOP不生效的情況氯庆,查找相關(guān)資料,有建議添加配置項spring.aop.auto=true , spring.aop.proxy-target-class=true扰付,后者是使用CGLIB代理堤撵,可能有性能下降。其實都不需要這些配置羽莺,默認(rèn)是生效的实昨,后面解釋原因;還有建議添加@EnableProxyTargetClass盐固,原因也類似荒给;以及建議添加@ComponentScan覆蓋AOP目錄。以上可能是在某些情況下的適用方案刁卜。這次遇到的問題其實是切入條件不正確志电,在相關(guān)例子中缺少了public前綴,導(dǎo)致的不生效蛔趴。正確是:@Pointcut("execution (public * com.igoso.me.gallery.controller.*.*(..))")挑辆。
另外有個缺陷是,為查詢記錄孝情,添加了查詢的HTTP請求鱼蝉,本身也會被記錄其中,后續(xù)再考慮在入庫之前進(jìn)行過濾箫荡,目前沒有影響蚀乔。

補充:多個Aop可以使用@Order(n),來控制順序菲茬。

如下是整個Aspect的代碼:

/**
 * created by igoso at 2018/5/26
 **/
@Aspect
@Component
public class HttpLogAspect {
    private static final Logger LOGGER = LoggerFactory.getLogger("HTTP_LOG");

    @Resource
    private HeaderDetailDao headerDetailDao;

    @Pointcut("execution (public * com.igoso.me.gallery.controller.*.*(..))")
    public void log() {

    }

    @Before("log()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (null == attributes) {
            LOGGER.error("get servlet request attributes null");
            return;
        }
        HttpServletRequest request = attributes.getRequest();

        Map<String,String> headers = new HashMap<>();
        String name;
        request.getAttributeNames();
        for (Enumeration e = request.getHeaderNames(); e.hasMoreElements();) {
            name = e.nextElement().toString();
            headers.put(name, request.getHeader(name));
        }

        headers.put("uri", request.getRequestURI());
        headers.put("queryString", request.getQueryString());
        headers.put("remoteAddr", request.getRemoteAddr());
        headers.put("method", request.getMethod());
        headers.put("remoteHost",request.getRemoteHost());
        headers.put("remotePort",String.valueOf(request.getRemotePort()));
        headers.put("protocol",request.getProtocol());

        HeaderDetail headerDetail = new HeaderDetail(headers, JSON.toJSONString(headers));
        LOGGER.debug(JSON.toJSONString(headers,true));

        try {
            headerDetailDao.insert(headerDetail);
        } catch (Exception e) {
            LOGGER.error("insert header detail error:{}",e);
        }

    }

}


/**
 * created by igoso at 2018/5/26
 **/

@Getter
@Setter
@NoArgsConstructor
public class HeaderDetail extends Entity{

    private String acceptLanguage;
    private String method;
    private String remoteHost;
    private String remotePort;
    private String remoteAddr;
    private String queryString;
    private String uri;
    private String accept;
    private String localHost;
    private String acceptEncoding;
    private String userAgent;
    private String protocol;
    private String extensions;//json

    public HeaderDetail(Map<String,String> origin, String extensions) {
        this.acceptLanguage = origin.get(HeaderAttributes.ACCEPT_LANGUAGE);
        this.method = origin.get(HeaderAttributes.METHOD);
        this.remoteAddr = origin.get(HeaderAttributes.REMOTE_ADDR);
        this.remoteHost = origin.get(HeaderAttributes.REMOTE_HOST);
        this.remotePort = origin.get(HeaderAttributes.REMOTE_PORT);
        this.queryString = origin.get(HeaderAttributes.QUERY_STRING);
        this.uri = origin.get(HeaderAttributes.URI);
        this.accept = origin.get(HeaderAttributes.ACCEPT);
        this.localHost = origin.get(HeaderAttributes.LOCAL_HOST);
        this.acceptEncoding = origin.get(HeaderAttributes.ACCEPT_ENCODING);
        this.userAgent = origin.get(HeaderAttributes.USER_AGENT);
        this.protocol = origin.get(HeaderAttributes.PROTOCOL);

        this.extensions = extensions; //other
    }

    private class HeaderAttributes{
        static final String ACCEPT_LANGUAGE = "accept-language";
        static final String METHOD = "method";
        static final String REMOTE_ADDR = "remoteAddr";
        static final String REMOTE_HOST = "remoteHost";
        static final String REMOTE_PORT = "remotePort";
        static final String QUERY_STRING = "queryString";
        static final String URI = "uri";
        static final String ACCEPT = "accept";
        static final String LOCAL_HOST = "host";
        static final String ACCEPT_ENCODING = "accept-encoding";
        static final String USER_AGENT = "user-agent";
        static final String PROTOCOL = "protocol";
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吉挣,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子婉弹,更是在濱河造成了極大的恐慌睬魂,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镀赌,死亡現(xiàn)場離奇詭異氯哮,居然都是意外死亡,警方通過查閱死者的電腦和手機商佛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門喉钢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姆打,“玉大人,你說我怎么就攤上這事肠虽♂O罚” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵税课,是天一觀的道長闲延。 經(jīng)常有香客問我,道長韩玩,這世上最難降的妖魔是什么垒玲? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮找颓,結(jié)果婚禮上合愈,老公的妹妹穿的比我還像新娘。我一直安慰自己击狮,他們只是感情好佛析,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著帘不,像睡著了一般。 火紅的嫁衣襯著肌膚如雪杨箭。 梳的紋絲不亂的頭發(fā)上寞焙,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機與錄音互婿,去河邊找鬼捣郊。 笑死,一個胖子當(dāng)著我的面吹牛慈参,可吹牛的內(nèi)容都是我干的呛牲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼驮配,長吁一口氣:“原來是場噩夢啊……” “哼娘扩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起壮锻,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤琐旁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后猜绣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體灰殴,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年掰邢,在試婚紗的時候發(fā)現(xiàn)自己被綠了牺陶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伟阔。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖掰伸,靈堂內(nèi)的尸體忽然破棺而出皱炉,到底是詐尸還是另有隱情,我是刑警寧澤碱工,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布娃承,位于F島的核電站,受9級特大地震影響怕篷,放射性物質(zhì)發(fā)生泄漏历筝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一廊谓、第九天 我趴在偏房一處隱蔽的房頂上張望梳猪。 院中可真熱鬧,春花似錦蒸痹、人聲如沸春弥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽匿沛。三九已至,卻和暖如春榛鼎,著一層夾襖步出監(jiān)牢的瞬間逃呼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工者娱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留抡笼,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓黄鳍,卻偏偏與公主長得像推姻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子框沟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理藏古,服務(wù)發(fā)現(xiàn),斷路器忍燥,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架校翔,建立于...
    Hsinwong閱讀 22,409評論 1 92
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,822評論 6 342
  • 要加“m”說明是MB,否則就是KB了. -Xms:初始值 -Xmx:最大值 -Xmn:最小值 java -Xms8...
    dadong0505閱讀 4,836評論 0 53
  • 從開始讀書課到現(xiàn)在已經(jīng)進(jìn)行一個月的時間灾前,每天事情超級多防症,看書的進(jìn)度也很慢。看啦《拆掉思維里的墻》還有正在進(jìn)行的《...
    瑩268呂瑞瑩閱讀 222評論 0 0