日志拦截AOP,当执行抛异常时@AfterThrowing执行了没效果

来源:互联网 发布:mac os x 10.12 cdr 编辑:程序博客网 时间:2024/06/05 01:58

使用Spring的AOP进行日志记录,对应的代码为

package cn.tiansu.eway.logAop;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;import javax.inject.Inject;import org.apache.shiro.SecurityUtils;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.Ordered;import org.springframework.stereotype.Component;import cn.tiansu.eway.annotation.SystemLog;import cn.tiansu.eway.entity.LogFormMap;import cn.tiansu.eway.mapper.LogMapper;import cn.tiansu.eway.util.Common;/** * 切点类 * * @author LJN * @since 2015-05-05 Pm 20:35 * @version 1.0 */@Aspect@Componentpublic class LogAopAction <span style="color:#ff0000;">implements Ordered</span>{// 本地异常日志记录对象private static final Logger logger = LoggerFactory.getLogger(LogAopAction.class);@Injectprivate LogMapper logMapper;// Controller层切点@Pointcut("@annotation(cn.tiansu.eway.annotation.SystemLog)")public void controllerAspect() {}/** * 操作异常记录 * * @descript * @param point * @param e * @author LJN * @date 2015年5月5日 * @version 1.0 */@AfterThrowing(pointcut = "controllerAspect()", throwing = "e")public void doAfterThrowing(JoinPoint point, Throwable e) {LogFormMap logForm = new LogFormMap();Map<String, Object> map = null;String user = null;String ip = null;Long start = 0L;Long end = 0L;Long time = 0L;try {ip = SecurityUtils.getSubject().getSession().getHost();} catch (Exception ee) {ip = "无法获取登录用户Ip";}try {map = getControllerMethodDescription(point);// 登录名user = SecurityUtils.getSubject().getPrincipal().toString();if (Common.isEmpty(user)) {user = "无法获取登录用户信息!";}} catch (Exception ee) {user = "无法获取登录用户信息!";}try {start = System.currentTimeMillis();end = System.currentTimeMillis();time = end - start;logForm.put("accountName", user);logForm.put("module", map.get("module"));logForm.put("methods", map.get("methods"));logForm.put("description", "执行失败,原因:" + e);logForm.put("actionTime", time);logForm.put("userIP", ip);logForm.put("type", map.get("type"));logMapper.addEntity(logForm);} catch (Exception e1) {e1.printStackTrace();}}/** * 前置通知 用于拦截Controller层记录用户的操作 * * @param joinPoint *            切点 */@Around("controllerAspect()")public Object doController(ProceedingJoinPoint point) {Object result = null;// 执行方法名String methodName = point.getSignature().getName();String className = point.getTarget().getClass().getSimpleName();LogFormMap logForm = new LogFormMap();Map<String, Object> map = null;String user = null;Long start = 0L;Long end = 0L;Long time = 0L;String ip = null;try {ip = SecurityUtils.getSubject().getSession().getHost();} catch (Exception e) {ip = "无法获取登录用户Ip";}try {// 登录名user = SecurityUtils.getSubject().getPrincipal().toString();if (Common.isEmpty(user)) {user = "无法获取登录用户信息!";}} catch (Exception e) {user = "无法获取登录用户信息!";}// 当前用户try {map = getControllerMethodDescription(point);// 执行方法所消耗的时间start = System.currentTimeMillis();result = point.proceed();end = System.currentTimeMillis();time = end - start;} catch (Throwable e) {throw new RuntimeException(e);}try {logForm.put("accountName", user);logForm.put("module", map.get("module"));logForm.put("methods", map.get("methods"));logForm.put("type", map.get("type"));logForm.put("description", map.get("description"));logForm.put("actionTime", time.toString());logForm.put("userIP", ip);logMapper.addEntity(logForm);// *========控制台输出=========*//System.out.println("=====通知开始=====");System.out.println("请求方法:" + className + "." + methodName + "()");System.out.println("方法描述:" + map);System.out.println("请求IP:" + ip);System.out.println("=====通知结束=====");} catch (Exception e) {// 记录本地异常日志logger.error("====通知异常====");logger.error("异常信息:{}", e.getMessage());}return result;}/** * 获取注解中对方法的描述信息 用于Controller层注解 * * @param joinPoint *            切点 * @return 方法描述 * @throws Exception */@SuppressWarnings("rawtypes")public Map<String, Object> getControllerMethodDescription(JoinPoint joinPoint) throws Exception {Map<String, Object> map = new HashMap<String, Object>();String targetName = joinPoint.getTarget().getClass().getName();String methodName = joinPoint.getSignature().getName();Object[] arguments = joinPoint.getArgs();Class targetClass = Class.forName(targetName);Method[] methods = targetClass.getMethods();for (Method method : methods) {if (method.getName().equals(methodName)) {Class[] clazzs = method.getParameterTypes();if (clazzs.length == arguments.length) {map.put("module", method.getAnnotation(SystemLog.class).module());map.put("methods", method.getAnnotation(SystemLog.class).methods());map.put("type", method.getAnnotation(SystemLog.class).type());String de = method.getAnnotation(SystemLog.class).description();if (Common.isEmpty(de))de = "执行成功!";map.put("description", de);break;}}}return map;}<span style="color:#ff0000;">@Overridepublic int getOrder() {// TODO Auto-generated method stubreturn 1;}</span>}
当执行正常时,走@Around;当执行异常时,走@AfterThrowing。结果发现,执行异常时,@AfterThrowing方法正常执行完毕,但是异常日志并没有插入数据表中,插入日志的代码也没报任何错误,遂百度之(http://my.oschina.net/HuifengWang/blog/304188),发现问题所在:

Spring中的事务是通过aop来实现的,当我们自己写aop拦截的时候,会遇到跟spring的事务aop执行的先后顺序问题,比如说动态切换数据源的问题,如果事务在前,数据源切换在后,会导致数据源切换失效,所以就用到了Order(排序)这个关键字.我们可以通过在@AspectJ的方法中实现org.springframework.core.Ordered 这个接口来定义order的顺序,order 的值越小,说明越先被执行。

当实现Ordered 接口之后,我们自己写的aop在事务介入之前就执行了!



1 0
原创粉丝点击