基于spring AOP @Around @Before @After的区别说明

 更新时间:2021年02月19日 12:02:16   作者:Rainyn  
这篇文章主要介绍了基于spring AOP @Around @Before @After的区别说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

此段小代码演示了spring aop中@Around @Before @After三个注解的区别

@Before是在所拦截方法执行之前执行一段逻辑。

@After 是在所拦截方法执行之后执行一段逻辑。

@Around是可以同时在所拦截方法的前后执行一段逻辑。

连接点(JoinPoint) 这个就更好解释了,就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。

其他如AspectJ还可以让你在构造器或属性注入时都行,不过那不是咱们关注的,只要记住,和方法有关的前前后后都是连接点。

package com.itsoft.action;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Controller;
/**
 * 
 * @author zxf
 * 演示aop测试类
 */
@Controller
public class UserAction {
 public void queryUsers(){
  System.out.println("查询所有用户【all users list】");
 }
 public static void main(String[] args) {
  ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("application-aop.xml");
  UserAction userAction = (UserAction)ctx.getBean("userAction");
  userAction.queryUsers();
  ctx.destroy();
 }
}
package com.itsoft;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
 * 
 * @author Administrator
 * 通过aop拦截后执行具体操作
 */
@Aspect
@Component
public class LogIntercept {
 @Pointcut("execution(public * com.itsoft.action..*.*(..))")
 public void recordLog(){}
 @Before("recordLog()")
 public void before() {
  this.printLog("已经记录下操作日志@Before 方法执行前");
 }
 @Around("recordLog()")
 public void around(ProceedingJoinPoint pjp) throws Throwable{
  this.printLog("已经记录下操作日志@Around 方法执行前");
  pjp.proceed();
  this.printLog("已经记录下操作日志@Around 方法执行后");
 }
 @After("recordLog()")
 public void after() {
  this.printLog("已经记录下操作日志@After 方法执行后");
 }
 private void printLog(String str){
  System.out.println(str);
 }
}
<?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:aop="http://www.springframework.org/schema/aop"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-3.0.xsd
  http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/aop 
  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
 <context:annotation-config />
 <context:component-scan base-package="com.itsoft"/>
 <aop:aspectj-autoproxy />
</beans>

补充:spring aop的@Before,@Around,@After,@AfterReturn,@AfterThrowing的理解

1.AOP的基本概念

切面(Aspect) :通知(advice)和切入点(pointcut)共同组成了切面(aspect),时间、地点和要发生的“故事”。

可以从注解方式来理解,代码如下。

@aspect为类上面的注解——切面

@pointcut(…)——切入点。为此类内一个空方法上面的注解。可以把拦截的地址表达式表示为方法签名,利于使用起来方便。

@before@after等——通知。为此类下面的方法上面的注解。

三者在一块组成一个切面。

@Aspect
public class ExampleAspect {
 @Pointcut("execution(* com.psjay.example.spring.aop.*.*(..))")
 public void aPointcut() {
 }
 @Before("aPointcut()")
 public void beforeAdvice() {
  System.out.println("before advice is executed!");
 }
}

连接点(Joinpoint) :程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。——可以理解为被aop拦截的类或者方法就是连接点。

通知(Advice) :通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。——可以理解为被注解有@Before等advice注解的安全校验的方法,拦截了过来的请求要做什么逻辑的校验。

切入点(Pointcut) :通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称。——可以理解为切面切向哪里?是个类或者某层的包路径。

目标对象(Target Object) :即被通知的对象。

AOP代理(AOP Proxy) 在Spring AOP中有两种代理方式,JDK动态代理和CGLIB代理。默认情况下,TargetObject实现了接口时,则采用JDK动态代理;反之,采用CGLIB代理。

织入(Weaving)把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:

(1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才能做到,例如AspectJ的织入编译器;

(2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码;

(3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理是使用了JDK的动态代理。

2 通知(Advice)类型的说明

@Before 前置通知(Before advice) :在某连接点(JoinPoint)——核心代码(类或者方法)之前执行的通知,但这个通知不能阻止连接点前的执行。

为啥不能阻止线程进入核心代码呢?

因为@Before注解的方法入参不能传ProceedingJoinPoint,而只能传入JoinPoint。

要知道从aop走到核心代码就是通过调用ProceedingJionPoint的proceed()方法。

而JoinPoint没有这个方法。

这里牵扯区别这两个类:Proceedingjoinpoint 继承了 JoinPoint 。

是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要,这个是aop代理链执行的方法。

暴露出这个方法,就能支持 aop:around 这种切面(而其他的几种切面只需要用到JoinPoint,这跟切面类型有关), 能决定是否走代理链还是走自己拦截的其他逻辑。

建议看一下 JdkDynamicAopProxy的invoke方法,了解一下代理链的执行原理。

这样你就能明白 proceed方法的重要性。

@After 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

@AfterReturning 返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。

@Around 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。

可以在方法的调用前后完成自定义的行为,也可以选择不执行。

这时aop的最重要的,最常用的注解。

用这个注解的方法入参传的是ProceedingJionPoint pjp,可以决定当前线程能否进入核心方法中——通过调用pjp.proceed();

@AfterThrowing 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。

3 advice(通知)注解的执行先后顺序

这里说下简单情况——针对一个方法只被一个aspect类拦截时,aspect类内部的 advice 将按照以下的顺序进行执行情况如下:

解释:执行到核心业务方法或者类时,会先执行AOP。在aop的逻辑内,先走@Around注解的方法。

然后是@Before注解的方法,然后这两个都通过了,走核心代码,核心代码走完,无论核心有没有返回值,都会走@After方法。

然后如果程序无异常,正常返回就走@AfterReturn,有异常就走@AfterThrowing。

复杂的同一个方法被多个Aspect类拦截请参看博文:Spring AOP @Before @Around @After 等 advice 的执行顺序。

4 在aop中校验不通过如何不让程序进入核心代码?

通过aop中注解的执行的先后顺序我们知道,校验发生在核心代码前面的只剩下两个——@Before,@Around。

@Before : 这个注解只有在异常时才不会走核心方法——连接点。正常@Before无法阻止当前线程进入连接点。

@Around : 这个注解在连接点前后执行。并且注解的方法传入的ProceedingJionPoint 类中封装的代理方法proceed()可以让当前线程从aop方法转到连接点——核心代码方法。

所以一般我们用这个注解,如果aop的安全校验不通过,则不调用proceed()方法,就永远不会进入连接点。

除此外,要注意除了Around注解的方法可以传ProceedingJionPoint 外,别的几个都不能传这个类。

但是普通的数据类型是不限制的。

注解的方法的返回值也不限制,可以自由限制。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。

相关文章

  • Mybatis源码解析之初始化分析

    Mybatis源码解析之初始化分析

    这篇文章主要介绍了Mybatis源码解析之初始化分析,Mybatis的初始化过程就是mybatis配置文件的解析过程并将解析结果保存到Configuration类。,需要的朋友可以参考下
    2024-01-01
  • java 数据的加密与解密普遍实例代码

    java 数据的加密与解密普遍实例代码

    本篇文章介绍了一个关于密钥查询的jsp文件简单实例代码,需要的朋友可以参考下
    2017-04-04
  • 详解SpringBoot中如何使用Reactor模型

    详解SpringBoot中如何使用Reactor模型

    Reactor模型主要提供了一种在Java虚拟机上构建非阻塞应用的方式,这种方式使用了响应式编程原理,通过响应式流标准来实现,下面我们就来看看它在SpringBoot中是如何使用的吧
    2024-04-04
  • 深入浅析Random类在高并发下的缺陷及JUC对其的优化

    深入浅析Random类在高并发下的缺陷及JUC对其的优化

    这篇文章主要介绍了Random类在高并发下的缺陷及JUC对其的优化 ,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-04-04
  • 利用Jasypt如何对Spring Boot配置文件加密

    利用Jasypt如何对Spring Boot配置文件加密

    这篇文章主要给大家介绍了关于利用Jasypt如何对Spring Boot配置文件加密的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-07-07
  • spring的pointcut正则表达式的实现

    spring的pointcut正则表达式的实现

    本文主要介绍了spring的pointcut正则表达式的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • Spring boot注解@Async线程池实例详解

    Spring boot注解@Async线程池实例详解

    这篇文章主要介绍了Spring boot注解@Async线程池实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Java简单实现约瑟夫环算法示例

    Java简单实现约瑟夫环算法示例

    这篇文章主要介绍了Java简单实现约瑟夫环算法,简单描述了约瑟夫环问题,并结合实例形式分析了Java实现约瑟夫环的具体操作技巧,需要的朋友可以参考下
    2017-09-09
  • 解决使用httpclient传递json数据乱码的问题

    解决使用httpclient传递json数据乱码的问题

    这篇文章主要介绍了解决使用httpclient传递json数据乱码的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • Java数据结构与算法之栈(Stack)实现详解

    Java数据结构与算法之栈(Stack)实现详解

    这篇文章主要为大家详细介绍了Java数据结构学习笔记第二篇,Java数据结构与算法之栈Stack实现,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09

最新评论