目标功能:自定义一个在方法执行前后做日志记录的切面方法,需要考虑到方法执行成功与失败的情况,并记录方法名与意义与参数。
自定义的切面类需要配套一个自定义注解执行
java
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Documented
public @interface LogRec {
String value() default ""; // 接口名称描述
}
切面类的类层面
java
@Aspect
@Component
public class LogRecordAspect {
private static final Logger logger = LoggerFactory.getLogger(LogRecordAspect.class);
@Autowired
private SystemService systemService;
@Pointcut("@annotation(com.example.config.aspect.LogRec)")
public void logRecMethods() { }
...
}
类里面环绕目标方法的增强方法
java
/**
* 环绕通知并记录日志
* @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 {
// 获取 request
HttpServletRequest 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不能共存。
java
@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+":开始执行");
}
}
}
java
@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+":结束执行");
}
}
}
除了环绕方法,还有出现异常时的处理方法
java
/**
* 异常通知:记录失败日志
*/
@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());
}
}
}