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之类的库进行处理。