SpringBoot学习2.0-SpringAOP简单例子

目录

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


版权声明:本文为lee2358232原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。