Spring 配置使用 - AOP 通知参数

本文详细介绍了Spring AOP中通知方法获取被通知方法参数的两种方式:自动获取和手动指定。通过JoinPoint、ProceedingJoinPoint和JoinPoint.StaticPart,我们可以自动获取连接点信息。同时,展示了如何在配置切面时手动指定参数。当混合使用时,自动获取的参数必须作为通知方法的第一个参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基本概念

若想要在通知方法获取被通知方法的参数共有两种方式:自动获取、手动指定。下面来探究下这两种方式的不同之处。


自动获取参数

在介绍 AOP 的通知类型时有提到过环绕通知,该通知类型可以通过参数 ProceedingJoinPoint 自动获取被通知方法的参数值并调用该方法。除了 ProceedingJoinPoint 外,还有 JoinPoint,JoinPoint.StaticPart 也都能自动获取被通知方法的参数。


1.JoinPoint

JoinPoint 即连接点,通过该参数可以获取连接点(被通知方法)的相关信息。

首先来看该接口的继承关系,如下图。可以发现在环绕通知中所使用的 ProceedingJoinPoint 就是继承自该接口。

这里写图片描述

再来看看该接口的定义:

public interface JoinPoint {

    // 连接点的具体信息
    String toString();

    // 连接点的简单信息
    String toShortString();

    // 连接点的所有信息
    String toLongString();

    // AOP 代理对象
    Object getThis();

    // 目标对象   
    Object getTarget();

    // 被通知方法的参数列表
    Object[] getArgs();

    // 连接点签名  
    Signature getSignature();

    // 连接点方法所在类文件中的位置  
    SourceLocation getSourceLocation();

    // 连接点类型  
    String getKind();

   // 内部接口,暂不探究(下面会提到)
    public interface StaticPart {
        //... 省略部分代码
    }

    public interface EnclosingStaticPart extends StaticPart {}

    // 返回连接点静态部分 
    StaticPart getStaticPart();

    // getKind 方法的返回值
    static String METHOD_EXECUTION = "method-execution";
    static String METHOD_CALL = "method-call";
    static String CONSTRUCTOR_EXECUTION = "constructor-execution";
    static String CONSTRUCTOR_CALL = "constructor-call";
    static String FIELD_GET = "field-get";
    static String FIELD_SET = "field-set";
    static String STATICINITIALIZATION = "staticinitialization";
    static String PREINITIALIZATION = "preinitialization";
    static String INITIALIZATION = "initialization";
    static String EXCEPTION_HANDLER = "exception-handler";
    static String SYNCHRONIZATION_LOCK = "lock";
    static String SYNCHRONIZATION_UNLOCK = "unlock";
    static String ADVICE_EXECUTION = "adviceexecution"; 
}

下面通过简单的例子来探究该接口的作用:

  • 定义一个 Bean,用它来表示连接点(joinpoint)的一部分
public class Animals {
    public void setName(String name) {
        System.out.println(name);
    }
}
  • 定义一个 Bean,用来表示切面
public class AnimalsAspect {
    public void beforeAdvice() {
        System.out.println(point.toString());
        System.out.println(point.toShortString());
        System.out.println(point.toLongString());
        System.out.println(point.getThis().toString());
        System.out.println(point.getTarget().toString());
        System.out.println(point.getArgs()[0]);
        System.out.println(point.getSignature());
        System.out.println(point.getSourceLocation());
        System.out.println(point.getKind());
        System.out.println(point.getStaticPart());
        System.out.println("before advice..." );
    }
}
  • 在 xml 文件中配置
<!-- 1.容器中注入 Bean -->
<bean id="joinpoint" class="com.demo.Animals" />
<bean id="aspect" class="com.aop.AnimalsAspect"/>

<!-- 2.AOP 配置 -->
<aop:config>
    <aop:aspect ref="aspect">
        <aop:before method="beforeAdvice" pointcut="execution(* com.demo.Animals.setName(..))" />
    </aop:aspect>
</aop:config>
  • 调用验证
String location = ...
ApplicationContext factory = new FileSystemXmlApplicationContext(location);
Animals animals = (Animals) factory.getBean("joinpoint");
animals1.setName("cat");

// 输出结果:
// execution(void com.demo.Animals.setName(String))
// execution(Animals.setName(..))
// execution(public void com.demo.Animals.setName(java.lang.String))
// com.demo.Animals@4245c97b
// com.demo.Animals@4245c97b
// cat
// void com.demo.Animals.setName(String)
// org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@58e22f2b
// method-execution
// execution(void com.demo.Animals.setName(String))
// before advice...
// cat

2.ProceedingJoinPoint

该连接点接口只能用于环绕通知,并且该接口继承自 JoinPoint 接口。

public interface ProceedingJoinPoint extends JoinPoint {

    void set$AroundClosure(AroundClosure arc);

    // 调用无参的被通知方法
    public Object proceed() throws Throwable;

    // 调用带参的通知方法
    public Object proceed(Object[] args) throws Throwable;

}

3.JoinPoint.StaticPart

刚连接点是 Joinpoint 的内部接口,作用功能与 JoinPoint 基本一致。

public interface StaticPart {  

    Signature getSignature();   

    String getKind();   

    // 连接点标识
    int getId();  

    String toString();  

    String toShortString();  

    String toLongString();    
}  

手动指定参数

手动指定参数,即在配置切面时,需在切面的通知与切面的切点中明确指定参数。

下面通过一个实例来阐明:

  • 定义一个 Bean,用它来表示连接点(joinpoint)的一部分
public void Animals {
    // 该被通知方法存在两个方法参数
    public void setName(String param1 , String param2) {
        System.out.println(param1 +"-"+ param2);
    }
}
  • 定义一个 Bean,用来表示切面
public class AnimalsAspect {
    // 关键 -> 在通知中需明确指定参数名称
    public void beforeAdvice(Object param1, Object param2) {
        System.out.println(param1.toString() + "-" + param2.toString());
    }
}
  • 在 xml 文件中配置
<!-- 1.容器中注入 Bean -->
<bean id="joinpoint" class="com.demo.Animals" />
<bean id="aspect" class="com.aop.AnimalsAspect"/>

<!-- 2.AOP 配置 -->
<aop:config>
    <aop:aspect ref="aspect">
        <!-- 关键 -> 在切点中也需明确指定参数名称 -->
        <aop:before method="beforeAdvice" pointcut="execution(* com.demo.Animals.setName(..)) and args(param1,param2)" />
    </aop:aspect>
</aop:config>
  • 调用验证
String location = ...
ApplicationContext factory = new FileSystemXmlApplicationContext(location);
Animals animals = (Animals) factory.getBean("joinpoint");
animals1.setName("cat","dog");

// 输出结果:
// cat-dog
// before advice...
// cat-dog

混合使用

当同时采用自动获取参数与手动指定参数时,自动获取参数必须是第一个参数,即 JoinPoint 、ProceedingJoinPoint 等参数并需是通知方法定义的第一个参数。

  • 切面通知定义如下:
public void Animals {
    // JoinPoint 必须是方法定义的第一个参数
    public void setName(JoinPoint point , String param1,String param2) {
        System.out.println(param1 +"-"+ param2);
    }
}
  • 在 xml 的配置同上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oxf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值