SpringAOP——JoinPoint 和 ProceedingJoinPoint

导读:本篇文章讲解 SpringAOP——JoinPoint 和 ProceedingJoinPoint,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

AOP 的几个概念

名称 解释
Pointcut 切点,决定处理如权限校验、日志记录等在何处切入业务代码中(即织入切面)。切点分为execution方式和annotation方式。前者可以用路径表达式指定哪些类织入切面,后者可以指定被哪些注解修饰的代码织入切面。
Advice 增强,包括处理时机和处理内容。处理内容就是要做什么事,比如校验权限和记录日志。处理时机就是在什么时机执行处理内容,分为前置处理(即业务代码执行前)、后置处理(业务代码执行后)等。
Aspect 切面,即,Pointcut 和 Advice。
Joint point 接入点,是程序执行的一个点。例如,一个方法的执行或者一个异常的处理。在 Spring AOP 中,一个连接点总是代表一个方法执行
Weaving 织入,就是通过动态代理,在目标对象方法中执行处理内容的过程。

增强类型

  1. 前置通知(Before Advice)

在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。ApplicationContext中在<aop:aspect>里面使用<aop:before>元素进行声明。

  1. 后置通知(After Advice)

当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。ApplicationContext 中在<aop:aspect>里面使用<aop:after>元素进行声明。

  1. 返回后通知(After Return Advice)

在某连接点正常完成后执行的通知,不包括抛出异常的情况。ApplicationContext 中在<aop:aspect>里面使用<after-returning>元素进行声明。

  1. 异常通知(After Throwing Advice)

在 方 法 抛 出 异 常 退 出 时 执 行 的 通 知 。 ApplicationContext 中 在 <aop:aspect> 里 面 使 用<aop:after-throwing>元素进行声明。

  1. 环绕通知(Around Advice)

包围一个连接点的通知,类似 Web 中 Servlet 规范中的 Filter 的 doFilter 方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。ApplicationContext 中在<aop:aspect>里面使用<aop:around>元素进行声明。例如,ServiceAspect 中的 around 方法。

JoinPoint 和 ProceedingJoinPoint 的关系

rQkWH1.png

AspectJ 使用 org.aspectj.lang.JoinPoint接口表示目标类连接点对象,如果是环绕增强时,使用org.aspectj.lang.ProceedingJoinPoint表示连接点对象,该类是JoinPoint的子接口。任何一个增强方法都可以通过将第一个入参声明为JoinPoint访问到连接点上下文的信息。

在增强(advice)方法中可以声明一个JoinPoint类型的参数, 通过JoinPoint可以访问连接点的细节。

JoinPoint

JoinPoint对象封装了SpringAop中切面方法的信息, 在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息:

  1. 切入点的方法名字及其参数;

  2. 切入点方法标注的注解对象(通过该对象可以获取注解信息);

  3. 切入点目标对象(可以通过反射获取对象的类名,属性和方法名)。

例如:

/**
 * 切点:
 * 定义一个切入点表达式,用来确定哪些类需要代理 
 * 代表com.gitee.tangmonkmeat.common.service包下UserService类的create*方法都会被代理
 */
@Pointcut("execution(* com.gitee.tangmonkmeat.common.service.UserService.create*(..))")
public void create(){}

/**
 * 前置增强:在目标方法执行前执行
 */
@Before(value = "create()")
public void before(JoinPoint joinPoint){
    System.out.println("【" +joinPoint.getSignature().getName() + "】方法执行,参数是:" + Arrays.asList(joinPoint.getArgs()));
    System.out.println(joinPoint.getSignature());
    System.out.println("目标方法名为:" + joinPoint.getSignature().getName());
    System.out.println("目标方法所属类的简单类名:" +        joinPoint.getSignature().getDeclaringType().getSimpleName());
    System.out.println("目标方法所属类的类名:" + joinPoint.getSignature().getDeclaringTypeName());
    System.out.println("目标方法声明类型:" + Modifier.toString(joinPoint.getSignature().getModifiers()));
    System.out.println(Arrays.toString(joinPoint.getArgs()));
    System.out.println(joinPoint.getKind());
    System.out.println(joinPoint.getSourceLocation());
    System.out.println(joinPoint.getStaticPart());
    System.out.println(joinPoint.getTarget());
    System.out.println(joinPoint.getThis());
}

输出如下:

【createUser】方法执行,参数是:[八戒, 100]

User com.gitee.tangmonkmeat.common.service.UserService.createUser(String,int)

目标方法名为:createUser
目标方法所属类的简单类名:UserService
目标方法所属类的类名:com.gitee.tangmonkmeat.common.service.UserService
目标方法声明类型:public abstract

[八戒, 100]

method-execution

org.springframework.aop.aspectj.
MethodInvocationProceedingJoinPoint$SourceLocationImpl@2101b44a

execution(User com.gitee.tangmonkmeat.common.service.UserService.createUser(String,int))

com.gitee.tangmonkmeat.common.service.impl.UserServiceImpl@2cc3ad05

com.gitee.tangmonkmeat.common.service.impl.UserServiceImpl@2cc3ad05

常用 api

方法名 功能
Signature getSignature(); 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
Object[] getArgs(); 获取传入目标方法的参数对象
Object getTarget(); 获取被代理的对象
Object getThis(); 获取代理对象

ProceedingJoinPoint

ProceedingJoinPoint继承JoinPoint子接口,它新增了两个用于执行连接点方法的方法

方法名 功能
Object proceed() throws Throwable 通过反射执行目标对象的连接点处的方法
Object proceed(java.lang.Object[] args) throws Throwable 通过反射执行目标对象连接点处的方法,不过使用新的参数替换原来的参数

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/69744.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!