当前位置: 代码网 > it编程>编程语言>Java > Spring AOP之@Around,@AfterReturning使用、切不进去的解决方案

Spring AOP之@Around,@AfterReturning使用、切不进去的解决方案

2024年06月01日 Java 我要评论
本文主要举几个工作中典型aop的实操案例,还有经常出现的问题(切不进去,ctrl+左键跳不到被切方法中)等等。本文对于aop的实现原理概不讨论,百度一搜有的是。aop的使用背景和好处比如a模块是公司的

本文主要举几个工作中典型aop的实操案例,还有经常出现的问题(切不进去,ctrl+左键跳不到被切方法中)等等。

本文对于aop的实现原理概不讨论,百度一搜有的是。

aop的使用背景和好处

比如a模块是公司的核心模块,这块代码未经允许不得轻易篡改。

但是你又有新的需求,需要在公司的核心模块的某个方法上进行增强(比如在执行核心方法的之前打印自定义日志,或者修改该核心方法的入参和返回值等等)

这样你就可以在不修改核心模块源码的情况下,对源代码的方法进行增强,扩展原来方法的一些功能。

这样既能保证源代码不被破坏,又可以扩展源代码现有的功能。

一、几种使用姿势

1、@afterreturning和@before

@afterreturning是后置方法,在目标方法执行后执行,@before是前置方法,在目标方法执行前执行

它们一般配合joinpoint来使用(不能配合proceedingjoinpoint,会报错)。

直接看例子:

被切的方法:

@service
public class orifuncimpl implements orifunc{

    @override
    public string ori(string str){
        system.out.println("执行了原方法");
        return str;
    }
}

使用@afterreturning 和 @before:

@aspect
@component
public class aopfunc {
    @pointcut("execution(* com.daji.aop_test.orifuncimpl.ori(..))")
    public void test() {
    }

    @before("test()")
    public void before(joinpoint joinpoint) {
        object[] args = joinpoint.getargs();    //获取方法入参
        system.out.println("原方法的入参是:"+args[0]);
        system.out.println("原方法执行前会先执行我!!");
    }


    @afterreturning("test()")
    public void after(joinpoint joinpoint) {
        object[] args = joinpoint.getargs();    //获取方法入参
        system.out.println("原方法执行后会执行我!!");
    }

}

如果遇到异常,则不执行。

  • 当连接点方法成功执行后,返回通知方法才会执行,如果连接点方法出现异常,则返回通知方法不执行。
  • 返回通知方法在目标方法执行成功后才会执行,所以,返回通知方法可以拿到目标方法(连接点方法)执行后的结果。

@afterreturning获取被切方法返回值,篡改返回参数:

在注解中增加returning参数即可: returning = “methodresult”

@pointcut("execution(* com.daji.aop_test.aoptestcontroller.test1(..))")
    public void publish() {
    }

    @afterreturning(value = "publish()",returning = "methodresult")
    public object afterreturningpublish(joinpoint joinpoint, object methodresult) {
        //获取方法返回值
        string returnjson = jsonobject.tojsonstring(methodresult);
        object[] args = joinpoint.getargs();
        system.out.println("原方法执行后会执行我!!");
        //这个返回值可以被我们篡改。
        return methodresult;
    }

其实这个返回值也不是能任意篡改的:

  • 答案来了:可以改变返回值,但是分情况,

不能改变:

  • 第一种情况:如果返回的对象,改变了对象的引用地址,这种情况,是不能改变返回对象中的值的
  • 第二种情况:如果返回的对象是一个基本数据类型,或者是string的值,是不能改变返回值的,尤其是string这种final类型的。

可以改变:

  • 直接使用传入的object对象,改变其中的值,是可以的。

2、@around

@around是环绕通知,既可以控制入参,还可以控制原方法的执行和返回值

常常配合proceedingjoinpoint来使用。

直接看例子:

被切的方法:

@service
public class orifuncimpl implements orifunc{

    @override
    public string ori(string str){
        system.out.println("执行了原方法");
        return str;
    }
}

使用@around:

@aspect
@component
public class aopfunc {
    @pointcut("execution(* com.daji.aop_test.orifuncimpl.ori(..))")
    public void modifyreturn() {
    }

    @around("modifyreturn()")
    public object around(proceedingjoinpoint joinpoint) throws throwable {
        object[] args = joinpoint.getargs();
        object result = joinpoint.proceed(args);
        return result;
    }

}

3、@around可以篡改返回值,篡改入参

需要proceedingjoinpoint的配合

注意一定要将@around修饰的方法用object修饰其返回值,并且返回原方法执行的结果,如下图所示:

篡改入参一样的道理,只需要篡改下图中的 args数组,然后让其传入proceed中,即可完成篡改入参。

如下图所示:

所以,这个@around比较万能,尤其是配合proceedingjoinpoint的使用。使aop能做的事情更多了。

引申一下joinpoint 和 proceedingjoinpoint的关系:

  • proceedingjoinpoint 只能在@around中使用
  • joinpoint也可以获取入参(getargs()),它可以用于@before 和 @afterreturning
  • proceedingjoinpoint 继承了 joinpoint 。是在joinpoint的基础上暴露出 proceed 这个方法。它们之间的关系如下图:

4、@around如果不执行proceed(),那么原方法将不会执行

二、使用aop常见的问题和bug

1、切不进去

检查是否有如下注解:

<dependency>
    <groupid>org.aspectj</groupid>
    <artifactid>aspectjrt</artifactid>
    <version>1.9.4</version>
</dependency>
<dependency>
    <groupid>org.aspectj</groupid>
    <artifactid>aspectjweaver</artifactid>
    <version>1.9.2</version>
</dependency>

检查完毕后检查切面类,看看有没有以下注解:

2、ctrl+鼠标左键不能自动跳到被切方法

正常情况如图:

如果你存在上述问题,检查你有没有安装下列插件:

如果你是idea社区版,那么默认是没有的,你要么自己下,要么换成正式版。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

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

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com