spring的aop功能可以在盡量減少代碼侵入的情況下對原有的功能進行擴展和監控,用來做日志是最適合不過的了。
開發web服務器時需要記錄用戶的訪問和返回信息的日志,因為需求較晚,原有服務代碼較多,懶得修改,所以就想起了spring框架的aop功能來實現一個監控日志。
服務器使用框架:spring boot+mongodb,使用gradle構建
要使用aop功能,需要添加依賴:
"org.springframework.boot:spring-boot-starter-aop:1.2.5.RELEASE",
服務的所有controller都放在 org.youqu.server.controller 包下 ,創建一個日志類ControllerAopLogger用於記錄日志。
spring相關配置如下:
<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>
此處包括了三個切面。
前兩個是標准流程的切面:
aop:before標志在執行前,獲取輸入信息的切面,此處處理純粹的是為了打印日志便與調試。避免因為報錯忽略了部分輸入日志。
aop:after-returning表示在返回之后,獲取返回信息的切面
切面的描述語句:
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之類的庫進行處理。
