10. Spring-AOP的实现
本文最后更新于2023.11.30-17:38
,某些文章具有时效性,若有错误或已失效,请在下方留言或联系涛哥。
AOP的概念
Aspect Oreinted Programming 面向切面编程,通过预编译方式或者运行时动态代理的方式,实现程序功能的统一管理和维护的一种技术(AOP是一种思想,并不依赖于某个框架或者编程语言实现)。
为什么使用AOP?
利用AOP可以对 业务逻辑的各部分进行隔离,使程序员更加专注于业务核心逻辑,从而降低代码的耦合度,提供程序可重用性,提高开发的效率(主要应用场景:权限控制,日志记录,性能统计,事务管理,异常处理)
AOP相关的术语
1.目标对象
指需要被 增强的对象,Spring Aop通过代理增强实现 (target)
2.连接点(JoinPoint)
指的是被切面拦截到的点,在Spring当中指的是具体的方法.
3.切入点(pointcut)
表示一组连接点,通过正则表达式,通配符,aspectj切点表达式来进行定义和集中,定义了通知(advice)将要发生的地方. 简单的说:切入点就是我们对 哪些连接点 进行拦截的 定义。
4.通知:(advice)
通知指的是 拦截到连接点之后 要做的事情就是通知(功能增强) 按照分类:前置通知,后置通知,异常通知,环绕通知,最终通知。 前置通知:在目标对象的业务逻辑功能执行之前,发生. 通常用于:日志记录 权限控制
- 后置返回通知:发生目标功能对象的业务逻辑正常执行完之后,发生. 通常用于:对方法返回值进行处理.
- 后置异常通知:在目标对象的业务逻辑发生异常时发生 通常用于:项目的异常日志.
- 后置:不管目标对象的业务逻辑是否发异常,都会被执行. 通常用于:资源释放.
- 环绕通知:(使用最多),在目标对象的业务逻辑执行之前和之后发生。 通常用于:性能监控,事务管理.
顺序:环绕前置>普通前置>目标方法执行>环绕正常结束/出现异常>环绕后置>普通后置>普通返回或者异常。
5.切面: 切面指的是切入点(多个)和通知(多个)的结合
Spring Aop的实现
a.传统的Spring Aop编程(会在 通知 所使用的类中,实现各种接口,造成代码污染,不推荐)
b.Spring 整合AspectJ框架 实现aop
c.步骤:
1导入jar包(IOC相关 aop aopalliance aspectj相关jar包 ) org.aopalliance org.aspectj/weawer
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
2在配置文件中,配置aop相关的命名空间 context 在文档中搜索 the aop schema
<?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 http://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.edu.*"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
3.创建目标.
4.创建通知.
5.在配置文件中进行配置 或者(使用注解)
5-1.把目标和通知 都进行bean的相关配置(注解)
5-2.使用aop:config 来进行面向切面的配置
5-3.在config中 使用aop:aspect表示一个切面 补充ref属性 指定通知使用的类的bean的名字(id)
5-4.在aspect中 使用<aop:pointcut /> 表示一个切点 在pointcut标签中 使用expression属性 去定义(集合) 一个切点 通常该属性的值是一个 aspectj切点表达式 ps:Spring中对aspectj的切点表达式,只是部分支持,并不支持全部的表达式. aspectJ常用的切点表达式: execution(public * *) 表示切点是 所有的public方法.
execution(* com.demo.service.*(..))表示 service包下的所有的类的 任意参数的任意方法.(不包含子包)
(..)表示 方法的参数个数类型 任意
execution(* com.demo.service..*(..))表示service包下(包含子包)的所有类的....
execution(* com.demo.service.impl.UserServiceImpl.*(..)) 表示UserServiceImpl下的所有方法
execution(* com.demo.service..*.add*(..)) 表示Service下所有包和子包中的 以add开头的方法
(自习:spring支持的aspectj 切点表达式)
5-5.配置前置通知: <aop:before method="指定通知的方法" pointcut="指定切点(切点表达式)" pointcut-ref="切点的Id"> 对于前置通知的方法 可以在方法中加入(Joinpoint参数 jt) 可以用来获取 连接点的目标对象 和 连接点的方法名 jt.getSignature().getName() 获取连接点方法的名字 jt.getSignature().getDeclaringTypeName() 获取连接点的目标对象
5-6.配置后置通知: <aop:after-returning method="" pointcut-ref="" returning="用于定义通知中 代表 业务逻辑返回值 的参数 名"> ps:通知的方法中 参数的名字要和returning的字符串一-cut 也可以使用JoinPoint的参数
5-7.最终通知: <aop:after method="" pointcut-ref="">
5-8.环绕通知: <aop:around method="" pointcut-ref="">
使用注解去配置一个切面
1.需要配置 切面 切点 通知 切面的bean 业务逻辑类步骤:
1-1.在applicationContext中 加入 <aop:aspectj-autoproxy />配置 表示开启aspectj的自动代理功能.
1-2.在通知所在的类上 配置一个切面 @Aspect注解 ps:Aspect注解 用于修饰一个Spring的bean,保证通知不会对 这 个bean 本身进行增强
在方法切面的方法上 使用@Before 表示该方法是一个前置通知 before注解 需要添加 切点 @Before("execution(* com.demo.service..*(..))")
@Pointcut(切点表达式) 去表示一个切点. @Pointcut("execution(* com.demo.service..*(..))") public void mypointcut(){} 表示切点的方法 返回值一定是void 不需要方法参数和方法体 切点的名字 就是方法的名字
@AfterReturning(pointcut="切点",returning="业务逻辑方法 返回值的 参数名")表示一个 后置通知
后置通知中 可以的方法 可以加入两个参数:Joinpoint 表示连接点,还可以加入一个 Object 表示 业务方法的原始返回值. 一旦增加了 Object 那么要求 必须在 AfterReturning里 加入 returning="指定 返回值在通知方法中的形参的名字"。
@After("mypointcut") 表示一个最终通知
@AfterThrowing(pointcut="mypointcut()",throwing="e") 后置返回异常通知的方法 也可以加入两个参数:
Jointpoint 连接点 Exception e 表示 业务方法抛出的异常对象,一旦申明,必须在注解中 加入 throwing="e"
@Around("mypointcut") 修饰一个 环绕通知 修饰的方法 必须返回一个Object,方法中需要 ProceedingJoinPoint pjp类型的参数 pjp.proceed() 保证了 业务逻辑方法的执行.
PS:如果一个切点 被多个切面拦截,会先执行所有切面的前置通知 然后是环绕 .如果需要改变各个切面的优先级需要使用 @Order注解 可以在order中使用一个整形的属性 数值越小,说明该切面的优 先级越高
作业
要求:有UserDao AdminDao ProductDao使用 SpringAOP 完成以下功能
1 Dao层所有的方法在 执行前 提示 由SpringAOP 进行了增强
2 对于所有的 添加方法 计算 添加的用时 并打印
3 对于所有的删除方法 要求在抛出异常时 打印时间 方法 异常类型(自行在 对应的删除里面 产生各种异常)
4 对于 UserDao和ProductDao的所有方法在执行时 判断权限是否足够。
作者:涛哥
链接:https://ltbk.net/back/spring_family/spring/article/404.html
文章版权归作者所有,未经允许请勿转载。