SpringBoot学习2.0-SpringAOP简单例子

本文深入探讨了Spring AOP的实战应用,包括如何通过配置pom依赖引入AOP,编写切面类实现前置、后置、环绕等通知类型,并详细解析了通知参数的使用方法。同时,文章对AOP的基本概念进行了清晰的阐述,如切面、切点、目标对象、连接点、通知和织入等,帮助读者全面理解面向切面编程。

目录

1. AOP简单例子

1.1 增加aop的pom依赖

1.2 简单AOP编程

1.3 环绕通知

1.4 AOP通知的参数

2. AOP的常见概念 


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容器中

 

github:https://github.com/zhangyangfei/springAOP

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值