AOP,面向切面

定义:多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中

 

通知,5种类型:

  • Before 在方法被调用之前调用

  • After 在方法完成后调用通知,无论方法是否执行成功

  • After-returning 在方法成功执行之后调用通知

  • After-throwing 在方法抛出异常后调用通知

  • Around 通知了好、包含了被通知的方法,在被通知的方法调用之前后调用之后执行自定义的行为

切点,即系统中的方法,在哪被调用。在指定包、类的方法调用
<aop:pointcut id="point" expression="execution(* wokao666.club.aop.spring01.Subject.*(..))" />
 

切面(Aspect)

切面是切点和通知的集合,一般单独作为一个类。通知和切点共同定义了关于切面的全部内容,它是什么时候,在何时和何处完成功能。

 

AOP中的代理模式:https://www.cnblogs.com/q540973436/p/12656028.html

  • 如果目标对象的实现类实现了接口,Spring AOP 将会采用 JDK 动态代理来生成 AOP 代理类;
  • 如果目标对象的实现类没有实现接口,Spring AOP 将会采用 CGLIB 来生成 AOP 代理类——不过这个选择过程对开发者完全透明、开发者也无需关心。
例子:
1
2
3
4
5
6
7
8
9
10
<aop:config>
   <!-- 这是定义一个切面,切面是切点和通知的集合-->
       <aop:aspect id="do" ref="PermissionVerification">
           <!-- 定义切点 ,后面是expression语言,表示包括该接口中定义的所有方法都会被执行-->
           <aop:pointcut id="point" expression="execution(* wokao666.club.aop.spring01.Subject.*(..))" />
           <!-- 定义通知 -->
           <aop:before method="canLogin" pointcut-ref="point" />
           <aop:after method="saveMessage" pointcut-ref="point" />
       </aop:aspect>
   </aop:config>

  



 
 

然后说下Spring AOP支持的几种类似于@Before的AspectJ注解:

  • 前置通知@Before: 前置通知通过@Before注解进行标注,并可直接传入切点表达式的值,该通知在目标函数执行前执行,注意JoinPoint,是Spring提供的静态变量,通过joinPoint 参数,可以获取目标对象的信息,如类名称,方法参数,方法名称等,该参数是可选的。
@Before("execution(...)")
public void before(JoinPoint joinPoint){
    System.out.println("...");
}

  • 后置通知@AfterReturning: 通过@AfterReturning注解进行标注,该函数在目标函数执行完成后执行,并可以获取到目标函数最终的返回值returnVal,当目标函数没有返回值时,returnVal将返回null,必须通过returning = “returnVal”注明参数的名称而且必须与通知函数的参数名称相同。请注意,在任何通知中这些参数都是可选的,需要使用时直接填写即可,不需要使用时,可以完成不用声明出来。
@AfterReturning(value="execution(...)",returning = "returnVal")
public void AfterReturning(JoinPoint joinPoint,Object returnVal){
   System.out.println("我是后置通知...returnVal+"+returnVal);
}

  • 异常通知 @AfterThrowing:该通知只有在异常时才会被触发,并由throwing来声明一个接收异常信息的变量,同样异常通知也用于Joinpoint参数,需要时加上即可.
@AfterThrowing(value="execution(....)",throwing = "e")
public void afterThrowable(Throwable e){
  System.out.println("出现异常:msg="+e.getMessage());
}
复制代码
  • 最终通知 @After:该通知有点类似于finally代码块,只要应用了无论什么情况下都会执行.
@After("execution(...)")
public void after(JoinPoint joinPoint) {
    System.out.println("最终通知....");
}

  • 环绕通知 @Around: 环绕通知既可以在目标方法前执行也可在目标方法之后执行,更重要的是环绕通知可以控制目标方法是否指向执行,但即使如此,我们应该尽量以最简单的方式满足需求,在仅需在目标方法前执行时,应该采用前置通知而非环绕通知。案例代码如下第一个参数必须是ProceedingJoinPoint,通过该对象的proceed()方法来执行目标函数,proceed()的返回值就是环绕通知的返回值。同样的,ProceedingJoinPoint对象也是可以获取目标对象的信息,如类名称,方法参数,方法名称等等
@Around("execution(...)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("我是环绕通知前....");
    //执行目标函数
    Object obj= (Object) joinPoint.proceed();
    System.out.println("我是环绕通知后....");
    return obj;
}

然后说下一直用"..."忽略掉的切入点表达式,这个表达式可以不是exection(..),还有其他的一些,我就不说了,说最常用的execution:

//scope :方法作用域,如public,private,protect
//returnt-type:方法返回值类型
//fully-qualified-class-name:方法所在类的完全限定名称
//parameters 方法参数
execution(<scope> <return-type> <fully-qualified-class-name>.*(parameters))
复制代码
<fully-qualified-class-name>.*(parameters)

注意这一块,如果没有精确到class-name,而是到包名就停止了,要用两个".."来表示包下的任意类:

  • execution(* com.zdy..*(..)):com.zdy包下所有类的所有方法.
  • execution(* com.zdy.Dog.*(..)): Dog类下的所有方法.

具体详细语法,大家如果有需求自行google了,我最常用的就是这俩了。要么按照包来定位,要么按照具体类来定位.

在使用切入点时,还可以抽出来一个@Pointcut来供使用:

/**
 * 使用Pointcut定义切点
 */
@Pointcut("execution(...)")
private void myPointcut(){}

/**
 * 应用切入点函数
 */
@After(value="myPointcut()")
public void afterDemo(){
    System.out.println("最终通知....");
}

可以避免重复的execution在不同的注解里写很多遍...

参考:
https://juejin.im/post/5a55af9e518825734d14813f

posted on   潮流教父孙笑川  阅读(23)  评论(0编辑  收藏  举报

(评论功能已被禁用)
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示