Spring AOP 前置通知、返回通知、异常通知、后置通知、环绕通知

前置技能:

Java、JDBC、Spring IOC快速入门Spring IOC 注解方式注入

什么是AOP:

面向切口编程(Aspect Oriented Programming),AOP是OOP的延续,是Spring框架的一个重要内容。
AOP利用称为"横切"的技术,剖解开封装的对象内部,把多个类的公共行为封装到一个可重用模块中,便于减少重复代码,降低模块之间的耦合度,AOP符合开闭原则,提高了代码的可拓展性。

AOP概念名词:

通知(advice)
在已存在的业务方法的前、后、异常、最终处加入的方法。

切面(aspect)
通知advice 方法所在的类,一个 aspect 类中可以有多个通知方法。

连接点(joinPoint)
已存在的业务方法。

切入点(pointCut)
joinPoint的集合。(为要添加advice的方法划定范围。)

目标对象(target)``
joinPoint方法所在的对象。

织入(Weave)``
advice方法放在joinPoint的前、后、异常、最终处。(只有织入后,advice才会有效。)

ps.温馨提示:你可以先看完Getting Started,再回来理解这些。

Getting Started

0、目录

aspect切面类
service服务层
Spring AOP 前置通知、返回通知、异常通知、后置通知、环绕通知_第1张图片

1、配置xml


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
    
	<context:component-scan base-package="com.aop">context:component-scan>
	
	<aop:aspectj-autoproxy>aop:aspectj-autoproxy>
beans>

一大堆都是标签头,这里只启动了两个注解而已。

2、将目标对象的类纳入容器

public interface IService {
	String update(String msg);
}

业务方法update就是连接点 joinPoint ,我们要在它的前后插入其他的方法(通知 advice)。

@Service
public class IServiceImpl implements IService {
	@Override
	public String update(int uid, String msg) {
		System.out.println("serviceimpl运行了");		
		return "更新了数据:"+msg;
	}
}

3、将切面类纳入容器

Componen纳入容器
Aspect 配置为切面类

@Component
@Aspect
public class DemoAspect {
	//配置切入点 
	@Pointcut("execution(* com.aop.service.*.*(..))")
	public void myPointCut() {}
	//配置前置通知
	@Before("myPointCut()")
	public void myBefore() {
		System.out.println("——————前置通知————");
	}
3.1、解读@Pointcut

此处Pointcut注解有两个参数,result是返回值的类型 , range是指定范围来配置通知的类,两个参数用空格隔开。

@Pointcut("execution("result range")

对照
在演示代码中,我是用的 * com.aop.service.*.*(..)),意义如下。

@Pointcut("execution(任意返回值     com包.aop包.service包.所有类.所有方法(任意参数))")

其中返回值、包、类、方法的通配符为 *
参数的通配符为 ..

3.2、解读@Before

此处Before有一个注解,是指定此通知的切入点。
即:myBefore()通知的切入点为myPointCut()

@Before("myPointCut()")
public void myBefore() {

4、阶段测试

public class Test {
	public static void main(String[] args) {
		ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
		IService ser=ac.getBean(IService.class);	
		//update方法只是返回了这段字符串,所以并不会打印。
		ser.update("测试字符串");

运行结果
service包下的所有类 的所有方法,都会被添加上此前置通知。
在这里插入图片描述
可以通过修改Pointcut的参数来选定范围。
例:只有IServiceImpl类的方法添加通知。

@Pointcut("* com.aop.service.IServiceImpl.*(..))")

5、返回通知、异常通知、后置通知

5.1、返回通知

只要连接点正常返回,就会执行返回通知。

	@AfterReturning(pointcut="myPointCut()",returning="obj")
	public void myAfterReturning(JoinPoint point,Object obj) {
		System.out.println("——————返回通知————");
		//获取连接点方法传入的实参
		Object[] args=point.getArgs();
		//获取连接点方法的方法名
		String methodName=point.getSignature().getName();
		//获取连接点方法所在的对象
		Object targetObj=point.getTarget();
		String targetClassName=point.getClass().getName();
	}

通过JoinPoint对象 可以获取连接点接收的实参,连接点的方法名,连接点所在的对象。

5.1.1、解读@AfterReturning

此处AfterReturning注解有两个参数,pointcut切入点 , returning为连接点的返回值,命名须与myAfterReturning()方法的Object参数一致。

@AfterReturning(pointcut="myPointCut()",returning="objeeeee")
//注意那串eeeee了吗,那是为了引起你的注意,告诉你这两个命名须一致。
public void myAfterReturning(JoinPoint point,Object objeeeee) {
5.2、异常通知

可以得到连接点信息和异常信息。

	@AfterThrowing(pointcut="myPointCut()",throwing="eeeee")
	public void myAfterThrowing(JoinPoint point,Exception eeeee) {
	//注意那串eeeee了吗,那是为了引起你的注意,告诉你这两个命名须一致。
		System.out.println("——————异常通知————"+eeeee.getMessage());
	}
5.2.1、解读@AfterThrowing

此处AfterThrowing注解有两个参数,pointcut切入点 , throwing为连接点的返回值,命名须与AfterThrowing()方法的Exception 参数一致。

5.3、最终通知

执行顺序在异常通知和后置通知 之前,得不到返回值和异常信息。

	@After("myPointCut()")
	public void myAfter(JoinPoint point) {
		System.out.println("——————最终通知————"+point.getSignature().getName());
	}
5.4、阶段测试

运行结果

这个顺序很迷,最终通知在返回通知的前面,等博主有空学习了Spring的源码再回来填坑。
Spring AOP 前置通知、返回通知、异常通知、后置通知、环绕通知_第2张图片

6、环绕通知

@Around
环绕通知就是,包括以上以上所有通知。
环绕通知很强大,但不常用,通常我们只需要用到其中一两项通知。
环绕通知的返回值必须是Object,形参必须是ProceedingJoingPoint

@Component
@Aspect
public class DemoAspect {
	//配置切入点 
	@Pointcut("execution(* com.aop.service.*.*(..))")
	public void myPointCut() {}
	//环绕通知
	@Around("myPointCut()")
	public Object aroundAdvice(ProceedingJoinPoint proceeding) {
		//和JoinPoint一样,ProceedingJoinPoint也可以获取
		//连接点方法的实参
		Object[] args=proceeding.getArgs();
		//连接点方法的方法名
		String methodName=proceeding.getSignature().getName();
		//连接点方法所在的对象
		Object targetObj=proceeding.getTarget();
		String targetClassName=targetObj.getClass().getName();
		
		Object result=null;
		try {
			System.out.println("前置通知====");
			//执行连接点的方法 获取返回值
			result=proceeding.proceed(args);
			System.out.println("返回通知====");
			}catch (Throwable e) {
				System.out.println("异常通知===");
			}finally {
				System.out.println("最终通知===");
			} 
		return result;
	}

运行结果
在这里插入图片描述

你可能感兴趣的:(Java框架)