目录
- 1. 理解AOP
- 2 @ Before
- 2.1 controller层
- 2.2 service层
- 2.3 自定义注解
- 2.4 切面 advice
- 3 @ After
- 4 @ Around
spring的三大核心:IOC控制反转、DI依赖注入、AOP面向切面编程
刚开始接触springboot项目,前两个使用的多,亲自使用AOP的机会并不多,在解决埋点bug时恰好遇到,特此梳理出来
1. 理解AOP
补充一点,这里切入就是插入的意思
参考博文,点击查看
参考博文,这篇文章的解释十分到位,本文就不多赘述什么是AOP。这里原作者解释不够严谨,记录操作日志应该在最后插入。
2 @ Before
2.1 controller层
@RestController
@RequestMapping("/a")
public class demo {
@Resource
private MyService myService;
@ResponseBody
@RequestMapping(value = "/b", method = RequestMethod.POST, produces = "text/html;charset=UTF-8")
public void getPolicyFile(@RequestParam("name") String name, @RequestParam("age") Integer age) {
myService.msgShow(name,age);
}
}
2.2 service层
Loggable是自定义的注解
@Service
public class MyService {
@Loggable
public void msgShow(String name,int age) {
System.out.println("这是service的输出结果");
}
}
2.3 自定义注解
/**
* @Description 定义注解:Loggable
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Loggable {
}
2.4 切面 advice
@Aspect
@Component
public class LoggingAspect {
// 定义一个切点(自定义注解的路径),表示被该注解修饰的方法都会注入advice
@Pointcut("@annotation(com.zjh.practice.AOP.Loggable)")
private void logPointcut() {
}
// joinPoint的作用就是获取msgShow()方法的参数
@Before("logPointcut()")
public void logadvice(JoinPoint joinPoint){
// 这里只是一个示例,你可以写任何处理逻辑
System.out.println("---------Before触发了----------");
// 获取签名
Signature signature = joinPoint.getSignature();
// 获取切入的包名
String declaringTypeName = signature.getDeclaringTypeName();
// 获取即将执行的方法名
String funcName = signature.getName();
System.out.println(String.format("即将执行方法为: %s ,属于%s包", funcName, declaringTypeName));
Object[] args = joinPoint.getArgs();
String itemName = (String) args[0];
int quantity = (int) args[1];
System.out.println(String.format("获取的参数是%s,%d",itemName,quantity));
}
}
输出效果
---------Before触发了----------
即将执行方法为: msgShow ,属于com.zjh.practice.AOP包
获取的参数是张三,21
这是service的输出结果
3 @ After
将@Before 换成 @After 有什么变化吗
输出效果
这是service的输出结果 (注意这条输出的位置)
---------After触发了----------
即将执行方法为: msgShow ,属于com.zjh.practice.AOP包
获取的参数是张三,21
4 @ Around
@Before只能控制在方法前执行,@After只能控制在方法后执行,那若想一起控制呢,就必须使用@Around
假设你有一个服务类 MyService,其中有一个 divide 方法执行除法操作。我们将创建一个 @Around 切面,拦截这个方法的执行,执行一些自定义逻辑,处理方法之前和之后的情况,以及异常。以下是例子:
@Aspect
@Component
public class DivisionAspect {
@Around("execution(* com.example.service.MyService.divide(..))")
public Object aroundDivideOperation(ProceedingJoinPoint joinPoint) throws Throwable {
// 在方法执行前
System.out.println("执行除法操作前");
try {
// 获取方法参数
Object[] args = joinPoint.getArgs();
if (args.length == 2 && (int) args[1] == 0) {
// 自定义逻辑:处理除以零的情况
System.out.println("检测到除以零。返回默认结果。");
return 0;
}
// 继续执行原始方法
Object result = joinPoint.proceed();
// 在方法执行后
System.out.println("执行除法操作后");
// 如果需要,可以修改或替代原始结果
// 为简单起见,我们将原始结果无修改地返回
return result;
} catch (Exception e) {
// 异常处理:记录异常并重新抛出
System.out.println("执行除法操作时发生异常:" + e.getMessage());
throw e;
} finally {
// 清理或额外的逻辑,无论如何都会执行
System.out.println("在执行除法操作后的finally块");
}
}
}
现在,假设你有一个 MyService 类如下:
package com.example.service;
import org.springframework.stereotype.Service;
@Service
public class MyService {
public int divide(int dividend, int divisor) {
// 模拟除法操作
return dividend / divisor;
}
}