package com.ssy.www.aspect;
import com.ssy.www.anno.ReLoad;
import com.ssy.www.entity.User;
import com.ssy.www.service.OtherService;
import com.ssy.www.service.impl.OtherServiceImpl;
import com.ssy.www.util.R;
import io.swagger.annotations.ApiModel;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
* @author ssy
* @className AopAspect
* @description AopAspect
* @date 2023-12-13 15:23:52
*/
@Component
@Aspect//这个类就是切面类
public class AopAspect {
/**
* execution(* com.ssy.www.controller.UserController.before(..))这个就类似于切点
* 这个表达式代表所有权限下的com.ssy.www.controller.UserController.before方法
* ..表示参数可有可无
* <p/>
* 前置通知
*/
@Before(value = "execution(* com.ssy.www.controller.UserController.before(..))")
public void before(JoinPoint jp){//这个方法就是通知
System.out.println("前置通知开始了······");
Signature signature = jp.getSignature();
String name = signature.getName();
System.out.println(name);
}
/**
* 最终通知
*/
@After(value = "execution(* com.ssy.www.controller.UserController.after(..))")
public void after(JoinPoint jp){
System.out.println("最终通知开始了······");
Signature signature = jp.getSignature();
String name = signature.getName();
System.out.println(name);
}
/**
* 环绕通知
*/
@Around(value = "execution(* com.ssy.www.controller.UserController.around(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知开始了······");
Signature signature = pjp.getSignature();
String name = signature.getName();
System.out.println(name);
Object[] args = pjp.getArgs();
User user = null;
if(args[0] instanceof User) {
user = (User) args[0];
user.setName("李浩");
}
Object proceed = pjp.proceed(new Object[]{user == null ? args[0] : user});
if( proceed instanceof R){
R info = (R) proceed;
System.out.println(info);
user.setName("王八蛋");
info.setData(user);
System.out.println("环绕通知结束了······");
return info;
}else {
System.out.println("环绕通知结束了······");
return proceed;
}
}
/**
* 后置通知
*/
@AfterReturning(value = "execution(* com.ssy.www.controller.UserController.afterReturning(..))", returning = "info")
public Object afterReturning(JoinPoint jp, Object info){
System.out.println("后置通知开始了······");
Signature signature = jp.getSignature();
String name = signature.getName();
System.out.println(name);
System.out.println(info);
return info;
}
/**
*异常通知
*/
@AfterThrowing(value = "execution(* com.ssy.www.controller.UserController.afterThrowing(..))", throwing = "e")
public void afterThrowing(JoinPoint jp, Throwable e){
System.out.println("异常通知开始了······");
Signature signature = jp.getSignature();
String name = signature.getName();
System.out.println(name);
System.out.println(e.getMessage());
}
@Pointcut(value = "execution(* com.ssy.www.controller.UserController.execution())")
public void pointcut(){}
/**
* @Before(value = "execution(* com.ssy.www.controller.UserController.execution())")
* 也是和@Before(value = "pointcut()")等价的,
* 如果很多通知都用到同一个表达式,那么每次通知都写一大串会很臃肿,所以通过@Pointcut的形式抽取出来
*/
@Before(value = "pointcut()")
public void log(JoinPoint jp){
Signature signature = jp.getSignature();
System.out.println("方法名为" + signature.getName() + "开始执行了······");
}
/**
* 表示具体的类
* within(com.ssy.www.controller.DemoController)
* 表示这个包下的所有类
* within(com.ssy.www.controller.*)
* 表示这个包以及子包下的所有类
* within(com.ssy.www.controller..*)
*/
@Before(value = "within(com.ssy.www.controller.DemoController)")
public void monitor(JoinPoint jp){
System.out.println("within测试开始执行了······");
}
/**
* this是作用于代理对象,指定Spring采用JDK动态代理时才有区别
* 不指定无论是this(com.ssy.www.service.UserService)
* 还是this(com.ssy.www.service.impl.UserServiceImpl)
* 控制层无论是UserService还是UserServiceImpl注入都是可以执行这个通知的
*/
@Before(value = "this(com.ssy.www.service.UserService)")
public void thisExec(JoinPoint jp){
System.out.println("this测试开始执行了······");
System.out.println("this被代理对象:" + jp.getTarget());
}
/**
* 参数类型匹配:args(String,String,com.ssy.www.entity.User,..)
* 这种匹配方式不能在通知中添加相同类型的参数变量
* 反之
* args(username, password, user,..)可以匹配参数,
* 名字随便起不影响,然而通知的方法参数必须加上具体的类型和指定的args中变量,否则切点无效
* 如:
* public void argsExec(JoinPoint jp, String uasername, String password, User user){
*
* }
* 但是,args需要配套其他的表达式使用,太过于模糊会出问题
*/
@Before(value = "args(String,String,com.ssy.www.entity.User,..) && execution(* com.ssy.www.controller.DemoController.argsOne(..))")
public void argsExec(JoinPoint jp){
System.out.println("args测试开始执行了······");
}
@Before(value = "bean(demoServiceImpl)")
public void beanExec(JoinPoint jp){
System.out.println("bean测试开始执行了······");
}
@Before(value = "@within(reLoad)")
public void annoWithinExec(JoinPoint jp, ReLoad reLoad){
System.out.println("@within测试开始执行了······");
System.out.println("ReLoad注解的属性value的值:" + reLoad.value());
//第二种获取注解的方式
ReLoad annotation = jp.getTarget().getClass().getAnnotation(ReLoad.class);
System.out.println("annotation:" + annotation.value());
}
/**
* 获取方法上注解的方式:获取到的签名就是方法的签名,强制转换为MethodSignature
* 注意是org.aspectj.lang.reflect.MethodSignature这个类
*/
@Before(value = "@annotation(com.ssy.www.anno.ReLoad)")
public void annotationExpression(JoinPoint jp){
System.out.println("@annotation测试开始执行了······");
Signature signature = jp.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
ReLoad annotation = methodSignature.getMethod().getAnnotation(ReLoad.class);
System.out.println("annotation:" + annotation.value());
}
@Before(value = "@args(..,io.swagger.annotations.ApiModel) " +
"&& args(String,String,com.ssy.www.entity.User)" +
"&& @annotation(org.springframework.web.bind.annotation.PostMapping)" +
"&& @annotation(io.swagger.annotations.ApiOperation)")
public void annoArgsExpression(JoinPo