spring的aop功能能夠在儘可能減小代碼侵入的狀況下對原有的功能進行擴展和監控,用來作日誌是最適合不過的了。web
開發web服務器時須要記錄用戶的訪問和返回信息的日誌,由於需求較晚,原有服務代碼較多,懶得修改,因此就想起了spring框架的aop功能來實現一個監控日誌。spring
服務器使用框架:spring boot+mongodb,使用gradle構建mongodb
要使用aop功能,須要添加依賴:數據庫
"org.springframework.boot:spring-boot-starter-aop:1.2.5.RELEASE",
服務的全部controller都放在 org.youqu.server.controller 包下 ,建立一個日誌類ControllerAopLogger用於記錄日誌。服務器
spring相關配置以下:app
<bean name="aopLogger" class="org.youqu.server.aspect.ControllerAopLogger"/> <aop:config> <aop:aspect ref="aopLogger"> <aop:before method="before" pointcut="execution(* org.youqu.server.controller.*.*.*(..))"/> <aop:after-returning method="after" pointcut="execution(* org.youqu.server.controller.*.*.*(..))" returning="returnValue"/> <aop:after-returning method="error" pointcut="execution(* org.youqu.server.controller.BaseController.exceptionHandler(..))" returning="returnValue"/> </aop:aspect> </aop:config>
此處包括了三個切面。框架
前兩個是標準流程的切面:spring-boot
aop:before標誌在執行前,獲取輸入信息的切面,此到處理純粹的是爲了打印日誌便與調試。避免由於報錯忽略了部分輸入日誌。gradle
aop:after-returning表示在返回以後,獲取返回信息的切面url
切面的描述語句:
execution(* org.youqu.server.controller.*.*.*(..))
第一個*表示返回值,而後就是org.youquer.server.controller包下的全部子包下得全部類的全部有任意個參數的方法。
恩,很拗口。簡單地說:
最後的括號裏面表明參數,(..)表示任意個參數。
倒數第一個*表明方法名稱,倒數第二個星號表明類名稱,而後就全都是包名,一層一層的包名。
而後是第三個切面,由於以前將全部的異常都統一進行了捕獲和處理,因此在此選擇了處理方法的返回參數來記錄報錯的信息
ControllerAopLogger的核心代碼以下:
public void after(JoinPoint point,Object returnValue){ if(!(point.getThis() instanceof BaseController)) return; BaseController bc = (BaseController) point.getThis(); HttpServletRequest httpServletRequest = bc.getRequest(); String url = ""; if(httpServletRequest.getRequestURI()!=null) url = httpServletRequest.getRequestURI().toString(); long requestDate = System.currentTimeMillis(); String clientIp = getIpAddr(httpServletRequest); String requestMethod = httpServletRequest.getMethod(); String charset = httpServletRequest.getCharacterEncoding(); Object[] args = point.getArgs(); String executeMethod = point.getSignature().getName(); String result = returnValue.toString(); float resultLength = ((returnValue.toString().length()+40f)/1024f); if(result.length()>100) log.info("返回參數:"+result.substring(0,100)); else log.info("返回參數:"+result); log.info("返回參數大小:"+resultLength); log.info("--------------------------------"); BasicDBObject logUnit = new BasicDBObject(); logUnit.append("url",url) .append("requestDate", requestDate) .append("clientIp",clientIp) .append("requestMethod",requestMethod) .append("charset",charset) .append("args",args) .append("executeMethod", executeMethod) .append("result",result) .append("resultLength", resultLength) .append("status", 200); mongoDao.create(Attributes.MONGO_COL_LOG, logUnit); }
這個方法幹什麼的參照配置文件。目的在於獲取各類須要記錄的信息,最後保存到mongodb數據庫中。
BaseController是我本身建立的全部controller的父類。包括了獲取HttpServletRequest/Response和捕獲異常的功能。
以上就完成了記錄訪問日誌的功能。須要打印到日誌文件的也可使用各類log4j,logback之類的庫進行處理。