目录
- 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 {@Resourceprivate 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 {@Loggablepublic 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;}
}