记录,备忘……
使用实例:
package test.aop;
public class Test {
/**
*
* 使用spring的aop切面实现日志记录
* 1 aop开启springboot: spring.aop.auto=true
* 2 日志注解
* 3 切面类
*
* 注解使用实例
*/
@SysLog(operationType = "新增",description = "新增用户")
public void addSomeThing(){
// doSomeThing……
}
}
日志注解:
package test.aop;
import java.lang.annotation.*;
/**
* 系统日志注解
*
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
/**
* 要执行的操作类型比如:add操作
**/
String operationType() default "";
/**
* 要执行的具体操作比如:添加用户
**/
String description() default "";
}
切面类:
package test.aop;
import cn.hutool.extra.servlet.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;
/**
* 日志切点类
* 通知:advice(前置,后置,环绕)
*
*/
@Slf4j
@Aspect
//@Order(value=6) // 多个切面时,使用order注解来进行设置顺序,值越小优先级越高
@Component
public class SysLogAspect {
/**
* 切点:配置切点表达式
* execution(* test.*.*(..))代表test包下所有类的所有方法都会被代理
*/
@Pointcut("@annotation(test.aop.SysLog)")
public void logAspect() {
}
/**
* 返回通知:方法返回时调用
*/
@AfterReturning(value = "logAspect() && @annotation(sysLog)")
public void around(JoinPoint point, SysLog sysLog) {
// request请求对象
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//拦截的类名,如某个serviceImpl
Class clazz = point.getTarget().getClass();
//拦截的方法
Method method = ((MethodSignature) point.getSignature()).getMethod();
// 获取request请求参数
Map<String, String> parameterMap = ServletUtil.getParamMap(request);
// 业务处理:存储日志数据……
}
/**
* 前置通知:目标方法执行前执行
*/
@Before(value="logAspect()")
public void before(JoinPoint joinPoint){
System.out.println("目标方法名为:" + joinPoint.getSignature().getName());
System.out.println("目标方法所属类的简单类名:" + joinPoint.getSignature().getDeclaringType().getSimpleName());
System.out.println("目标方法所属类的类名:" + joinPoint.getSignature().getDeclaringTypeName());
System.out.println("目标方法声明类型:" + Modifier.toString(joinPoint.getSignature().getModifiers()));
//获取传入目标方法的参数
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
System.out.println("第" + (i+1) + "个参数为:" + args[i]);
}
System.out.println("被代理的对象:" + joinPoint.getTarget());
System.out.println("代理对象自己:" + joinPoint.getThis());
/*
执行结果:
目标方法名为:getMethod
目标方法所属类的简单类名:TestController
目标方法所属类的类名:test.aop.ClientController
目标方法声明类型:public
// 此处参数即赋值后的形参
第1个参数为:
第2个参数为:
被代理的对象:test.aop.ClientController@30c3876b
代理对象自己:test.aop.ClientController@30c3876b
*/
}
/**
* 后置通知:目标方法执行后执行
*/
@After(value="logAspect()")
public void after(JoinPoint joinPoint){
}
/**
* 异常通知:目标方法异常时执行
*/
@AfterThrowing(value="logAspect()")
public void exeException(JoinPoint joinPoint){
}
/**
* 环绕通知:自定义方法的执行时机。
*
* ProceedingJoinPoint对象是JoinPoint的子接口,该对象只用在@Around的切面方法中,
* Object proceed() throws Throwable //执行目标方法
* Object proceed(Object[] var1) throws Throwable //传入的新的参数去执行目标方法
*
* 方法返回值必须返回,因为环绕通知相当于代理动作。此时方法返回值即视为目标方法返回值
*/
@Around(value="logAspect()")
public Object aroundMethod(ProceedingJoinPoint joinPoint){
//
System.out.println("方法执行前处理……");
// 执行目标方法
Object result = joinPoint.proeed();
//
System.out.println("方法执行后处理……");
return result;
}
}