目录
1. AOP简单例子
1.1 增加aop的pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
1.2 简单AOP编程
定义用户类:
@Component
public class User {
private int id;
private String name;
// setters and getters
}
service类定义,打印用户名:
@Service // 将被扫面到SpringIoC容器中
public class UserService {
public void printUserName(User user) {
System.out.println("用户的名字是" + user.getName());
}
}
定义切面类:
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component // 切面需要被装配到IoC容器中
@Aspect // @Aspect定义切面
public class AspectDemo {
// 定义切点
// 语法:@Pointcut("execution(* 目标对象.连接点(..))"),*和目标对象之间要一个空格,否则报错
@Pointcut("execution(* com.zyf.springAOP.service.UserService.printUserName(..))")
public void pointCut() {
}
// 通知-切点前方法
@Before("pointCut()")
public void before() {
System.out.println("执行方法:before");
}
// 通知-切点后方法
@After("pointCut()")
public void after() {
System.out.println("执行方法:after");
}
// 通知-切点返回后方法
@AfterReturning("pointCut()")
public void afterReturning() {
System.out.println("执行方法:afterReturning");
}
// 通知-切点异常后方法
@AfterThrowing("pointCut()")
public void afterThrowing() {
System.out.println("执行方法:afterThrowing");
}
}
测试:
@Autowired
private UserService userService;
void aspectTest() {
User user = getUser();
user.setName("zyf");
userService.printUserName(user);
}
输出:
执行方法:before
用户的名字是zyf
执行方法:after
执行方法:afterReturning
可见,在UserService.printUserName方法执行前后,AOP给该方法增加了部分逻辑,这就可以理解为AOP的作用。
1.3 环绕通知
在1.2 AspectDemo.java 增加一个环绕通知如下:
//环绕通知
@Around("pointCut()")
public void around(){
System.out.println("执行方法:around");
}
输出:
执行方法:around
执行方法:after
执行方法:afterReturning
可见,执行了环绕通知的方法,没有执行@Before的方法和UserService.printUserName方法,这很危险。环绕通知需要显式回调原来的方法,见如下改造环绕通知:
//环绕通知
@Around("pointCut()")
public void around(ProceedingJoinPoint pj) throws Throwable{
System.out.println("执行方法:around...回调前");
pj.proceed();//回调目标对象的原有方法
System.out.println("执行方法:around...回调后");
}
输出:
执行方法:around...回调前
执行方法:before
用户的名字是zyf
执行方法:around...回调后
执行方法:after
执行方法:afterReturning
可见,@Before的方法是在pj.proceed()调用时,且是在回调原来方法之前执行。这似乎不是我们期望的执行顺序,我们期望@Before在其他通知之前就执行。
一些书籍说慎用springbootAOP中的环绕通知!
1.4 AOP通知的参数
1.4.1 环绕通知的参数
// 环绕通知
@Around("pointCut()")
public void around(ProceedingJoinPoint pj) throws Throwable{
//目标对象的原有方法的参数列表
Object[] paraList = pj.getArgs();
User user = (User)paraList[0];
//回调目标对象的原有方法
pj.proceed();
}
1.4.1 一般通知的参数,以@Before为例
// 前置通知-切点前方法
@Before("pointCut() && args(user)")
public void before(JoinPoint point,User user) {
//目标对象的原有方法的参数列表
Object[] paraList = point.getArgs();
}
- 获取参数方式一:"&& args(user)"。注意:注解中的参数名称‘user’、befor方法中的参数名称‘user’,都必须和连接点的参数名称‘user’一致,否则报错 。这个参数的写法有点坑。
- 获取参数方式二: 利用类JoinPoint,其getArgs()方法能获取参数列表。注意:不是Joinpoint,而是 JoinPoint
- 可见,获取参数方式二比较靠谱,但要对参数类型进行强转。
2. AOP的常见概念
- 0.AOP,即Aspect Oriented Programming,面向切面编程,和IoC组成Spring的两个核心理念。
- 1.切面,@Aspect定义,所谓面,在这个面中可以定义流程中的各个元素:切点、通知。
- 2.切点,@Pointcut定义,切点就是我们定义的业务逻辑方法(即AOP中的目标对象.连接点)。
- 3.目标对象,即类的实例。
- 4.连接点,即类中业务逻辑方法。
- 5.通知,AOP流程中的方法,随着切点或在切点前或在切点后执行,或异常出现时执行。
- 6.织入,各类通知和切点按照一定顺序执行,形成一个流程,就是织入,也就是【面向切面编程,即AOP】
- 7.切面需要被装配到IoC容器中
本文深入探讨了Spring AOP的实战应用,包括如何通过配置pom依赖引入AOP,编写切面类实现前置、后置、环绕等通知类型,并详细解析了通知参数的使用方法。同时,文章对AOP的基本概念进行了清晰的阐述,如切面、切点、目标对象、连接点、通知和织入等,帮助读者全面理解面向切面编程。

4313

被折叠的 条评论
为什么被折叠?



