上文讲解了sping Aop的基础概念与实现逻辑,本文从实践出发介绍sping进行aop配置并实现日志打印过程。
环境介绍:spring4.0 release版本,前端使用spring mvc框架。
1. 定义注解拦截器
/** * 自定义注解 拦截service */ @Component public class LogInterceptor { @Resource private SystemLogService systemLogService; private final Logger logger = LoggerFactory.getLogger(LogInterceptor.class); /** * @Description: 前置通知 * @param @param joinPoint * @return void * @author whp */ public void before(JoinPoint joinPoint) { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder .getRequestAttributes()).getRequest(); HttpSession session = request.getSession(); String methodName = joinPoint.getSignature().getName(); try { logger.info("=====Entering " + methodName + "()====="); logger.info("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")); } catch (Exception e) { // 记录本地异常日志 logger.error("==Entering " + methodName + "()异常=="); logger.error("异常信息:{}", e.getMessage()); } } /** * @Description: 后置通知 * @param @param joinPoint * @return void * @author whp */ public void after(JoinPoint joinPoint) { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder .getRequestAttributes()).getRequest(); HttpSession session = request.getSession(); // 请求的IP String methodName = joinPoint.getSignature().getName(); try { logger.info("=====leaving " + methodName + "()====="); // contentToTxt("=====leaving " + methodName + "()====="); } catch (Exception e) { // 记录本地异常日志 logger.error("==leaving " + methodName + "()异常=="); logger.error("异常信息:{}", e.getMessage()); } } /** * @Description: 通用异常通知 * @param @param joinPoint * @param @param e * @param @throws NoSuchFieldException * @param @throws SecurityException * @return void * @author whp */ public void afterThrowing(JoinPoint joinPoint, Throwable e) throws NoSuchFieldException, SecurityException { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder .getRequestAttributes()).getRequest(); HttpSession session = request.getSession(); // 请求的IP String params = ""; Object[] args = joinPoint.getArgs(); if (args != null && args.length > 0) { for (Object obj : args) { if (null != obj) { Field[] fields = obj.getClass().getDeclaredFields(); if (null != fields && fields.length > 0) { params += obj.getClass().getSimpleName() + "["; for (Field field : fields) { String name = field.getName(); Object value = getFieldValueByName(name, obj); if (null != value && (!"".equals(value))) { params += name + ":" + value + ";"; } } params += "],"; } else { params += obj.getClass().getSimpleName() + ":" + obj.toString() + ";"; } } } } String methodName = joinPoint.getSignature().getName(); try { /* ========控制台输出========= */ logger.info("=====Entering " + methodName + "()异常====="); logger.info("异常代码:" + e.getClass().getName()); logger.info("异常信息:" + e.getMessage()); logger.info("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()")); logger.info("请求参数:" + params); // ==========数据库日志========= logger.info("=====leaving " + methodName + "()异常====="); } catch (Exception ex) { // 记录本地异常日志 logger.error("==" + methodName + "()异常通知异常=="); logger.error("异常信息:{}", ex.getMessage()); logger.error("==" + methodName + "()异常结束=="); } // ==========记录本地异常日志========== logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget() .getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage(), params); } /** * @Description: 根据属性名获取属性值 * @param @param fieldName * @param @param o * @param @return * @return Object * @author whp */ private Object getFieldValueByName(String fieldName, Object o) { try { String firstLetter = fieldName.substring(0, 1).toUpperCase(); String getter = "get" + firstLetter + fieldName.substring(1); if (o.getClass().getName().startsWith("com.cxg")) { Method method = o.getClass().getMethod(getter, new Class[] {}); Object value = method.invoke(o, new Object[] {}); return value; } else { return null; } } catch (Exception e) { logger.error(e.getMessage(), e); return null; } } }
<bean id="logInterceptor" class="com.cxg.interactiveweb.logs.util.LogInterceptor" />
3. 配置aop容器
<aop:config proxy-target-class="true"> <aop:aspect id="logAspect" ref="logInterceptor"> <aop:pointcut expression="execution(* com.cxg.interactiveweb.*.controller..*.*(..))" id="logControllerCut" /> <aop:pointcut expression="execution(* com.cxg.interactiveweb.*.service..*.*(..))" id="logServiceCut" /> <!-- <aop:around method="around" pointcut-ref="logPointCut" /> --> <aop:before method="before" pointcut-ref="logControllerCut" /> <aop:after method="after" pointcut-ref="logControllerCut" /> <aop:after-throwing method="afterThrowing" pointcut-ref="logControllerCut" throwing="e" /> <aop:before method="before" pointcut-ref="logServiceCut" /> <aop:after method="after" pointcut-ref="logServiceCut" /> </aop:aspect> </aop:config>
配置AOP,定义aspect切面,定义pointcut切入点,使用expression将所有的controller和service方法定义切入点,通过before,after,after-throwing定义advice,指定切入方法。