spring中的切面类实践
目标功能:自定义一个在方法执行前后做日志记录的切面方法,需要考虑到方法执行成功与失败的情况,并记录方法名与意义与参数。
自定义的切面类需要配套一个自定义注解执行
import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Documented
public @interface LogRec {String value() default ""; // 接口名称描述
}
切面类的类层面
@Aspect
@Component
public class LogRecordAspect {private static final Logger logger = LoggerFactory.getLogger(LogRecordAspect.class);@Autowiredprivate SystemService systemService;@Pointcut("@annotation(com.example.config.aspect.LogRec)")public void logRecMethods() { }...
}
类里面环绕目标方法的增强方法
/*** 环绕通知并记录日志* @param joinPoint* @param logRec* @return* @throws Throwable*/@Around("logRecMethods() && @annotation(logRec)")public Object logAround(ProceedingJoinPoint joinPoint, LogRec logRec) throws Throwable {long startTime = System.currentTimeMillis();// 获取注解值String methodDesc = logRec.value();Object result = null;Object logRes = null;try {// 获取 requestHttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();// 执行原方法result = joinPoint.proceed();logRes = result;//logRes可以用来做额外处理,保留最终返回的result的完整性,避免误修改//正常日志记录...return result;} catch (Exception e) {//异常日志记录logger.error("接口调用异常:{}", e.getMessage(), e);throw e;} finally {//收尾代码...}}
起初考虑不全时,只想到before和after,这里也记录一下。特别提示:这俩和around不能共存。
@Before("logRecMethods() && @annotation(logRec)")public void logBefore(JoinPoint joinPoint,LogRec logRec){String methodName = joinPoint.getSignature().getName();String methodParams = logRec.value();String interfaceName = joinPoint.getTarget().getClass().getName();logger.info("【"+interfaceName+"】"+methodName+"("+methodParams+")");Object[] args = joinPoint.getArgs();for (Object arg : args){if (arg instanceof HttpServletRequest){HttpServletRequest request = (HttpServletRequest) arg;systemService.writeReqLog(request,methodParams+":开始执行");}}}
@After("logRecMethods() && @annotation(logRec)")public void logAfter(JoinPoint joinPoint,LogRec logRec){String methodName = joinPoint.getSignature().getName();String methodParams = logRec.value();;String interfaceName = joinPoint.getTarget().getClass().getName();logger.info("【"+interfaceName+"】"+methodName+"("+methodParams+")");Object[] args = joinPoint.getArgs();for (Object arg : args){if (arg instanceof HttpServletRequest){HttpServletRequest request = (HttpServletRequest) arg;systemService.writeReqLog(request,methodParams+":结束执行");}}}
除了环绕方法,还有出现异常时的处理方法
/*** 异常通知:记录失败日志*/@AfterThrowing(pointcut = "logRecMethods()", throwing = "ex")public void logAfterThrowing(JoinPoint joinPoint, Throwable ex) {String methodName = joinPoint.getSignature().getName();String methodParams = ex.getMessage();String interfaceName = joinPoint.getTarget().getClass().getName();logger.info("【"+interfaceName+"】"+methodName+"("+methodParams+")");Object[] args = joinPoint.getArgs();for (Object arg : args){if (arg instanceof HttpServletRequest){HttpServletRequest request = (HttpServletRequest) arg;systemService.writeReqLog(request,"发生异常:"+ex.getMessage());}}}