运用环绕通知查看方法执行时间
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Service;
/**
* AOP切面编程
* @author DELL
*/
@Aspect
@Service
@Slf4j
public class SysLogAspect {
@Pointcut("bean(sysUserServiceImpl)")
public void logPointCut(){}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint jp) throws Throwable {
try {
log.info("start:"+System.currentTimeMillis());
Object result = jp.proceed();
log.info("end:"+System.currentTimeMillis());
return result;
} catch (Throwable e) {
log.error(e.getMessage());
throw e;
}
}
}
使用异常通知打印出异常方法 和异常参数
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
/**
* @author DELL
*/
@Component
@Aspect
@Slf4j
public class SysTimeAspect {
@Pointcut("bean(*ServiceImpl)")
public void doTime(){}
@AfterThrowing(value = "doTime()",throwing = "e")
public void doAfterThrowing(JoinPoint jp, Exception e){
String className = jp.getTarget().getClass().getName();
MethodSignature ms = (MethodSignature)jp.getSignature();
log.error("{}exception msg is {}",ms.getName(),e.getMessage());
}
}
使用自定义注解,并且利用aop获取注解上的value
自定义注解
/**
* 作用于运行时
* 作用于方法上
* @author DELL
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiredLog {
String operation() default "";
}
切面类
MethodSignature ms = (MethodSignature) jp.getSignature();
Method targetMethod = targetClass.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
RequiredLog rLog = targetMethod.getAnnotation(RequiredLog.class);
String operation = rLog.operation();
核心代码以上四行
@Pointcut("@annotation(com.cy.pj.common.annotation.RequiredLog)")这样标注切点即可
@Pointcut("@annotation(com.cy.pj.common.annotation.RequiredLog)")
public void logPointCut(){}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint jp) throws Throwable {
long t1 = System.currentTimeMillis();
Object result = jp.proceed();
long t2 = System.currentTimeMillis();
saveLog((t2-t1),jp);
return result;
}
/**
* 将用户行为信息存储到数据库中
*/
private void saveLog(Long time, JoinPoint jp) throws Exception {
//1.获取用户行为日志
//2.1获取目标方法
MethodSignature ms = (MethodSignature) jp.getSignature();
Class<?> targetClass = jp.getTarget().getClass();
Method targetMethod = targetClass.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
RequiredLog rLog = targetMethod.getAnnotation(RequiredLog.class);
String operation = rLog.operation();
String dType = targetClass.getName();
String methodName = targetMethod.getName();
String targetClassMethod = dType+"."+methodName;
//2.2获取方法参数
String params = Arrays.toString(jp.getArgs());
//2.对信息进行封装
SysLog log = new SysLog();
log.setUsername("admin");
log.setOperation(operation);
log.setTime(time);
log.setIp("192.168.56.1");
log.setCreatedTime(new Date());
log.setMethod(targetClassMethod);
log.setParams(params);
//3.将信息写入到数据库
sysLogDao.saveObject(log);
}
最终通知和异常通知不会同时出现,简单比喻—转账中commit就是 @AfterReturning而事务回滚就是异常通知,即不会同时出现
如果按这样的说法@After释法资源,那么是不是会出现在释法资源后commint,其实,commit在@AfterReturning之前完成了,然后再@After
通知执行顺序是
@around–>@before—>TargetMethod(目标方法)—>@around—>@After 之后会出现两种情况
情况一 出现异常执行@AfterThrowing
情况二 正常执行 @AfterReturning
只有环绕通知才有ProceedingJoinPoint
其他通知可以用JoinPoint
有个哥们老说,切面是连接点的集合,那连接点是不是每一个集合中的元素呢,那切点就是连接点的子集喽