三天学会spring?第三天

spring面向切面编程AOP

① 什么是AOP?

在程序运行期间,动态的将一段代码插入到原来方法的某些位置
比如:我们购买东西会验证当前登录的账号,添加商品到购物车也可要验证。那么我们只需要单独设计一个用于验证用户的模块,插入到购买,添加购物车等操作。实现了功能与功能之间的解耦。

②AOP编程相关术语

通知(Advice)

前置通知,后置通知,异常通知

切面(Aspect)

切面就是包含通知代码的类

切点(Pointcut)

③AOP环境注解

导入jar包
三天学会spring?第三天_第1张图片

首先在applicationContext.xml文件中写上:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    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">
  
   <!-- 扫描com.student下面的所有的注解 -->
   <context:component-scan base-package="com.student"></context:component-scan>
   <!-- 
   		使用注解配置AOP切面编程(实现自动代理功能)
   		也就是说配置的@Aspect生效
   -->
   <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

写一个需要通知的方法,添加@Component注解,代表把这个类放到spring容器中去(id的名字为(add)即类名的首字母小写)

package com.student.method;

import org.springframework.stereotype.Component;

@Component
public class Add {
	
	public int addSomething(int a,int b) {
		return a+b;
	}
}

在写一个通知类

@Aspect是把这个类弄成一个通知类
@Component是将其放入到spring容器对象中去

package com.student.until;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class Advice {
   //前置通知,需要告诉这个通知你是哪个哪个类的哪个方法的通知
   //这个是spring切点表达式也就是你是哪个方法的前置通知
	@Before(value ="execution(* com.student.method.Add.addSomething(int, int))")
	public void beforeMathod() {
		System.out.println("我是前置通知");
	}
	@After(value ="execution(* com.student.method.Add.addSomething(int, int))")
	public void afterMathod() {
		System.out.println("我是后置通知");
	}
}

④spring切点表达

三天学会spring?第三天_第2张图片

三天学会spring?第三天_第3张图片

三天学会spring?第三天_第4张图片
三天学会spring?第三天_第5张图片

⑤常见的通知(4种)

package com.student.until;

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.springframework.stereotype.Component;

@Component
@Aspect
public class Advice {
	@Before(value ="execution(* com.student.method.Add.addSomething(int, int))")
	public void beforeMathod() {
		System.out.println("我是前置通知");
	}
	@After(value ="execution(* com.student.method.Add.addSomething(int, int))")
	public void afterMathod() {
		System.out.println("我是后置通知");
	}
	@AfterReturning(value = "execution(* com.student.method.Add.addSomething(int, int))")
	public void returnMethod() {
		System.out.println("我是返回通知");
	}
	@AfterThrowing(value = "execution(* com.student.method.Add.addSomething(int, int))")
	public void exceptionMethod() {
		System.out.println("我是异常通知");
	}
	
}

⑥获取连接点的信息

利用JoinPoint获取方法名和参数

@Before(value ="execution(* com.student.method.Add.addSomething(int, int))")
	public void beforeMathod(JoinPoint jp) {
		System.out.println("前置通知");
		System.out.println("方法名:"+jp.getSignature().getName()+"参数:"+Arrays.asList(jp.getArgs()));
	}

结果:
在这里插入图片描述

⑦返回通知中获取返回值

在方法上面添加一个参数Object result,切点值加returning="result"
三天学会spring?第三天_第6张图片

⑧在异常通知中获取异常信息

在方法上面添加Exception e接受抛出的异常
在配置切点的的注解中添加throwing="e"
三天学会spring?第三天_第7张图片

Spring之环绕通知

一个通知的功能相当于前面四个通知

@Around(value = "execution(* com.student.method.Add.addSomething(int, int))")
	public static Object around(ProceedingJoinPoint pjp) {
		Object  result=null;
		try {
			System.out.println("前置通知。");
			result=pjp.proceed();//执行方法
			System.out.println("后置通知");
		} catch (Throwable e) {
			System.out.println("异常通知。");
			e.printStackTrace();
			throw e;
		}finally {
			System.out.println("返回通知");
		
		}
		return result;
	}

注意事项:
如果写了普通通知和环绕通知
1.环绕通知优先于普通通知先执行
2.一定要把目标方法的返回值返回,要不然普通通知中收不到值
3.环绕方法出现异常,一定要把异常抛出,要不然普通方法不会出现异常,普通通知会执行返回值通知,获取的返回值为NULL

切入点表达式的复用:

1.定义一个 静态 的空的方法
2.@Pointcut写入需要设置的切点
3.直接在value后面写入方法名就可

@Pointcut("execution(* com.student.method.Add.addSomething(int, int))")
	public static void pointCutOne() {}
	@Before(value ="pointCutOne()")
	public void beforeMathod(JoinPoint jp) {
		System.out.println("前置通知");
		System.out.println("方法名:"+jp.getSignature().getName()+"参数:"+Arrays.asList(jp.getArgs()));
	}

多个切点的执行顺序

当一个切点有多个切面时,执行的顺序是怎么样的?

默认的顺序,是按照A到Z的首字母顺序排序(先进后出),但是在实际的开发中不可能特地的起名字,所以我们可以使用@Order(12344…),数字越小优先级越高。

AOP之XML文件的配置不使用注解

将注解都去掉

在applicationContext.xml文件中进行配置。

三天学会spring?第三天_第8张图片

因为这两天比较忙,所以占时只写了这么多笔记,明天继续补笔记,三天是不可能了,那就四天吧!!加油

你可能感兴趣的:(笔记)