主要的maven依赖如下
<!--引入SpringBoot的Web模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入AOP依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
注意:在完成了引入AOP依赖包后,不需要去做其他配置。AOP的默认配置属性中,spring.aop.auto属性默认是开启的,也就是说只要引入了AOP依赖后,默认已经增加了@EnableAspectJAutoProxy,不需要在程序主类中增加@EnableAspectJAutoProxy来启用。
编写自定义注解
import java.lang.annotation.*;
/**
* @author Lxin
* @version 1.0
* @date 2020/5/7 9:23
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
public @interface Logs {
/**
* 操作
*
* @return 操作
*/
Opts opts() default Opts.get;
/**
* 使用者
*
* @return 使用者
*/
String user() default "Lxin";
/**
* 所属机构
*
* @return 所属机构
*/
String company() default "NBA";
}
可有可无的
/**
* @author Lxin
* @version 1.0
* @date 2020/5/7 9:23
*/
public enum Opts {
/**
* 添加
*/
add,
/**
* 修改
*/
update,
/**
* 删除
*/
delete,
/**
* 查询
*/
get;
}
主要的Controller入口
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Lxin
* @version 1.0
* @date 2020/5/7 9:46
*/
@RestController
public class AopLogsController{
@RequestMapping(value = "/Kobe/Forever/{point}")
@Logs
public void Kobe(@PathVariable("point") int point) {
System.out.println("科比一直在打球!!");
}
@RequestMapping(value = "/LeBron")
@Logs
public void LeBron() {
System.out.println("詹姆斯上场打球了!!");
}
@RequestMapping(value = "/Curry")
@Logs
public void Curry() {
System.out.println("库里上场打球了!!");
}
@RequestMapping(value = "/Harden")
@Logs
public void Harden() {
System.out.println("哈登上场打球了!!");
}
@Logs
@RequestMapping(value = "/Antetokounmpo")
public void Antetokounmpo() {
System.out.println("字母哥上场打球了!!");
}
@Logs
@RequestMapping(value = "/Jokic")
public void Jokic() {
System.out.println("约基奇上场打球了!!");
}
@Logs
@RequestMapping(value = "/Durant/{point}")
public void Durant(@PathVariable("point") int point) {
System.out.println(1 / 0);
System.out.println("杜兰特上场打球了!!");
}
}
切面类
注意:在类上添加@Aspect 和@Component 注解即可将一个类定义为切面类。
@Aspect 注解 使之成为切面类
@Component 注解 把切面类加入到IOC容器中
/**
* @author Lxin
* @version 1.0
* @date 2020/5/7 9:37
*/
@Aspect
@Component
public class LogsAspect {
private static final Logger logger = LoggerFactory.getLogger(LogsAspect.class);
/**
* 切入点 所有打上 Logs 的注解都会被扫描到
*/
@Pointcut("@annotation(com.text.demo.text.aop.Logs)")
public void aspect() {
}
/**
* @description 在连接点执行之前执行的通知
*/
@Before("aspect()")
public void doBeforeGame(){
System.out.println("经纪人正在处理球星赛前事务!");
}
/**
* @description 在连接点执行之后执行的通知(返回通知和异常通知的异常)
*/
@After("aspect()")
public void doAfterGame(){
System.out.println("经纪人为球星表现疯狂鼓掌!");
}
/**
* @description 在连接点执行之后执行的通知(返回通知)
*/
@AfterReturning("aspect()")
public void doAfterReturningGame(){
System.out.println("返回通知:经纪人为球星表现疯狂鼓掌!");
}
/**
* @description 在连接点执行之后执行的通知(异常通知)
*/
@AfterThrowing("aspect()")
public void doAfterThrowingGame(){
System.out.println("异常通知:球迷要求退票!");
}
执行
调用 localhost:8080/Kobe/Forever/80
我们还可以使用更为强大的环绕通知
/**
* 环绕通知可以将你所编写的逻辑将被通知的目标方法完全包装起来。我们可以使用一个环绕通知来代替之前多个不同的前置通知和后置通知。
* 如下所示,前置通知和后置通知位于同一个方法中,不像之前那样分散在不同的通知方法里面。
*
* @description 使用环绕通知
*/
@Around("aspect()")
public void doAroundGame(ProceedingJoinPoint pjp) throws Throwable {
try {
System.out.println("经纪人正在处理球星赛前事务!");
//这个方法就相当于业务代码 它在上面 下面的代码就是相当于执行后,它在下面 就是相当于执行前
pjp.proceed();
//c先获取被织入增强处理的目标对象,再获取目标类的clazz
Class<?> aClass = pjp.getTarget().getClass();
//先获取目标方法的签名,再获取目标方法的名
String methodName = pjp.getSignature().getName();
// 输出目标方法名
logger.info("方法名: " + methodName);
//获取目标方法参数类型
Class[] parameterTypes = ((MethodSignature) pjp.getSignature()).getParameterTypes();
//获取目标方法的入参
Object[] args = pjp.getArgs();
for (int i = 0; i < args.length; i++) {
//输出目标方法的参数
logger.info("argsName: " + args[i]);
System.out.println(methodName + "得到了 " + args[i] + " 分!!!");
}
//获取目标方法
Method method = aClass.getMethod(methodName, parameterTypes);
//获取方法上的注解
Logs annotation = method.getAnnotation(Logs.class);
//获取注解函数值
Opts opts = annotation.opts();
System.out.println(opts);
System.out.println("返回通知:经纪人为球星表现疯狂鼓掌!");
} catch (Throwable e) {
System.out.println("异常通知:球迷要求退票!");
}
}
结果
调用 localhost:8080/Kobe/Forever/80
异常通知也是OK的
调用 localhost:8080/Durant/60