iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Spring AOP 对象内部方法间的嵌套调用方式
  • 767
分享到

Spring AOP 对象内部方法间的嵌套调用方式

2024-04-02 19:04:59 767人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录spring aop 对象内部方法间的嵌套调用我们先定义一个接口以及此接口的一个实现类增加AOP处理同一对象内的嵌套方法调用AOP失效原因分析举一个同一对象内的嵌套方法调用拦截失

Spring AOP 对象内部方法间的嵌套调用

前两天面试的时候,面试官问了一个问题,大概意思就是一个类有两个成员方法 A 和 B,两者都加了事务处理注解,定义了事务传播级别为 REQUIRE_NEW,问 A 方法内部直接调用 B 方法时能否触发事务处理机制。

答案有点复杂,Spring 的事务处理其实是通过AOP实现的,而实现AOP的方法有好几种,对于通过 jdk 和 cglib 实现的 aop 处理,上述问题的答案为否,对于通过AspectJ实现的,上述问题答案为是。

本文就结合具体例子来看一下

我们先定义一个接口


public interface AopActionInf {
    void doSomething_01();
    void doSomething_02();
}

以及此接口的一个实现类


public class AopActionImpl implements AopActionInf{
    public void doSomething_01() {
        System.out.println("AopActionImpl.doSomething_01()");
        //内部调用方法 doSomething_02
        this.doSomething_02();
    }
    public void doSomething_02() {
        System.out.println("AopActionImpl.doSomething_02()");
    }
}

增加AOP处理


public class ActionAspectXML {
    public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("进入环绕通知");
        Object object = pjp.proceed();//执行该方法
        System.out.println("退出方法");
        return object;
    }
}
<aop:aspectj-autoproxy/>
<bean id="actionImpl" class="com.maowei.learning.aop.AopActionImpl"/>
<bean id="actionAspectXML" class="com.maowei.learning.aop.ActionAspectXML"/>
<aop:config>
    <aop:aspect id = "aspectXML" ref="actionAspectXML">
        <aop:pointcut id="anyMethod" expression="execution(* com.maowei.learning.aop.AopActionImpl.*(..))"/>
        <aop:around method="aroundMethod" pointcut-ref="anyMethod"/>
    </aop:aspect>
</aop:config>

运行结果如下:

这里写图片描述

下图是断点分析在调用方法doSomething_02时的线程栈,很明显在调用doSomething_02时并没有对其进行AOP处理。

默认情况下,Spring AOP使用Jdk的动态代理机制实现,当然也可以通过如下配置更改为cglib实现,但是运行结果相同,此处不再赘述。


<aop:aspectj-autoproxy proxy-target-class="true"/>

那有没有办法能够触发AOP处理呢?答案是有的,考虑到AOP是通过动态生成目标对象的代理对象而实现的,那么只要在调用方法时改为调用代理对象的目标方法即可。

我们将调用 doSomething_02 的那行代码改成如下,并修改相应配置信息:


public void doSomething_01() {
    System.out.println("AopActionImpl.doSomething_01()");
    ((AopActionInf) AopContext.currentProxy()).doSomething_02();
}
<aop:aspectj-autoproxy expose-proxy="true"/>

先来看一下运行结果,

这里写图片描述

从运行结果可以看出,嵌套调用方法已经能够实现AOP处理了,同样我们看一下线程调用栈信息,显然 doSomething_02 方法被增强处理了(红框中内容)。

同一对象内的嵌套方法调用AOP失效原因分析

举一个同一对象内的嵌套方法调用拦截失效的例子

首先定义一个目标对象:



public class TargetClassDefinition {
    public void method1(){
        method2();
        System.out.println("method1 执行了……");
    }
    public void method2(){
        System.out.println("method2 执行了……");
    }
}

在这个类定义中,method1()方法会调用同一对象上的method2()方法。

现在,我们使用Spring AOP拦截该类定义的method1()和method2()方法,比如一个简单的性能检测逻辑,定义如下Aspect:



@Aspect
public class AspectDefinition {
    @Pointcut("execution(public void *.method1())")
    public void method1(){}
    @Pointcut("execution(public void *.method2())")
    public void method2(){}
    @Pointcut("method1() || method2()")
    public void pointcutCombine(){}
    @Around("pointcutCombine()")
    public Object aroundAdviceDef(ProceedingJoinPoint pjp) throws Throwable{
        StopWatch stopWatch = new StopWatch();
        try{
            stopWatch.start();
            return pjp.proceed();
        }finally {
            stopWatch.stop();
            System.out.println("PT in method [" + pjp.getSignature().getName() + "]>>>>>>"+stopWatch.toString());
        }
    }
}

由AspectDefinition定义可知,我们的Around Advice会拦截pointcutCombine()所指定的JoinPoint,即method1()或method2()的执行。

接下来将AspectDefinition中定义的横切逻辑织入TargetClassDefinition并运行,其代码如下:



public class StartUpDefinition {
    public static void main(String[] args) {
        AspectJProxyFactory weaver = new AspectJProxyFactory(new TargetClassDefinition());
        weaver.setProxyTargetClass(true);
        weaver.addAspect(AspectDefinition.class);
        Object proxy = weaver.getProxy();
        ((TargetClassDefinition) proxy).method1();
        System.out.println("-------------------");
        ((TargetClassDefinition) proxy).method2();
    }
}

执行之后,得到如下结果:

method2 执行了……
method1 执行了……
PT in method [method1]>>>>>>StopWatch '': running time = 20855400 ns; [] took 20855400 ns = 100%
-------------------
method2 执行了……
PT in method [method2]>>>>>>StopWatch '': running time = 71200 ns; [] took 71200 ns = 100%

不难发现,从外部直接调用TargetClassDefinition的method2()方法的时候,因为该方法签名匹配AspectDefinition中的Around Advice所对应的Pointcut定义,所以Around Advice逻辑得以执行,也就是说AspectDefinition拦截method2()成功了。但是,当调用method1()时,只有method1()方法执行拦截成功,而method1()方法内部的method2()方法没有执行却没有被拦截。

原因分析

这种结果的出现,归根结底是Spring AOP的实现机制造成的。众所周知Spring AOP使用代理模式实现AOP,具体的横切逻辑会被添加到动态生成的代理对象中,只要调用的是目标对象的代理对象上的方法,通常就可以保证目标对象上的方法执行可以被拦截。就像TargetClassDefinition的method2()方法执行一样。

不过,代理模式的实现机制在处理方法调用的时序方面,会给使用这种机制实现的AOP产品造成一个遗憾,一般的代理对象方法与目标对象方法的调用时序如下所示:


    proxy.method2(){
        记录方法调用开始时间;
        target.method2();
        记录方法调用结束时间;
        计算消耗的时间并记录到日志;
    }

在代理对象方法中,无论如何添加横切逻辑,不管添加多少横切逻辑,最终还是需要调用目标对象上的同一方法来执行最初所定义的方法逻辑。

如果目标对象中原始方法调用依赖于其他对象,我们可以为目标对象注入所需依赖对象的代理,并且可以保证想用的JoinPoint被拦截并织入横切逻辑。而一旦目标对象中的原始方法直接调用自身方法的时候,也就是说依赖于自身定义的其他方法时,就会出现如下图所示问题:

在代理对象的method1()方法执行经历了层层拦截器后,最终会将调用转向目标对象上的method1(),之后的调用流程全部都是在TargetClassDefinition中,当method1()调用method2()时,它调用的是TargetObject上的method2()而不是ProxyObject上的method2()。而针对method2()的横切逻辑,只织入到了ProxyObject上的method2()方法中。所以,在method1()中调用的method2()没有能够被拦截成功。

解决方案

当目标对象依赖于其他对象时,我们可以通过为目标对象注入依赖对象的代理对象,来解决相应的拦截问题。

当目标对象依赖于自身时,我们可以尝试将目标对象的代理对象公开给它,只要让目标对象调用自身代理对象上的相应方法,就可以解决内部调用的方法没有被拦截的问题。

Spring AOP提供了AopContext来公开当前目标对象的代理对象,我们只要在目标对象中使用AopContext.currentProxy()就可以取得当前目标对象所对应的代理对象。重构目标对象,如下所示:


import org.springframework.aop.framework.AopContext;

public class TargetClassDefinition {
    public void method1(){
        ((TargetClassDefinition) AopContext.currentProxy()).method2();
//        method2();
        System.out.println("method1 执行了……");
    }
    public void method2(){
        System.out.println("method2 执行了……");
    }
}

要使AopContext.currentProxy()生效,需要在生成目标对象的代理对象时,将ProxyConfig或者它相应的子类的exposeProxy属性设置为true,如下所示:



public class StartUpDefinition {
    public static void main(String[] args) {
        AspectJProxyFactory weaver = new AspectJProxyFactory(new TargetClassDefinition());
        weaver.setProxyTargetClass(true);
        weaver.setExposeProxy(true);
        weaver.addAspect(AspectDefinition.class);
        Object proxy = weaver.getProxy();
        ((TargetClassDefinition) proxy).method1();
        System.out.println("-------------------");
        ((TargetClassDefinition) proxy).method2();
    }
}
<!-- 在XML文件中的开启方式 -->
<aop:aspectj-autoproxy expose-proxy="true" />

再次执行代码,即可实现所需效果:

method2 执行了……
PT in method [method2]>>>>>>StopWatch '': running time = 180400 ns; [] took 180400 ns = 100%
method1 执行了……
PT in method [method1]>>>>>>StopWatch '': running time = 24027700 ns; [] took 24027700 ns = 100%
-------------------
method2 执行了……
PT in method [method2]>>>>>>StopWatch '': running time = 64200 ns; [] took 64200 ns = 100%

后记

虽然通过将目标对象的代理对象赋给目标对象实现了我们的目的,但解决的方式不够雅观,我们的目标对象都直接绑定到了Spring AOP的具体api上了。因此,在开发中应该尽量避免“自调用”的情况。

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

--结束END--

本文标题: Spring AOP 对象内部方法间的嵌套调用方式

本文链接: https://www.lsjlt.com/news/133879.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Spring AOP 对象内部方法间的嵌套调用方式
    目录Spring AOP 对象内部方法间的嵌套调用我们先定义一个接口以及此接口的一个实现类增加AOP处理同一对象内的嵌套方法调用AOP失效原因分析举一个同一对象内的嵌套方法调用拦截失...
    99+
    2024-04-02
  • Spring AOP对嵌套方法不起作用的解决方法
    本篇文章为大家展示了Spring AOP对嵌套方法不起作用的解决方法,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Spring AOP对嵌套方法不起作用今天在调研系统操作记录日志时,好多教...
    99+
    2023-06-22
  • Spring AOP对嵌套方法不起作用的解决
    目录Spring AOP对嵌套方法不起作用要解决这个问题Spring AOP、嵌套调用失效及解决加入注解获取当前代理的接口需要嵌套调用的Service实现它调用的时候改写代码Spri...
    99+
    2024-04-02
  • python函数嵌套调用的实现方法
    这篇文章主要讲解了“python函数嵌套调用的实现方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“python函数嵌套调用的实现方法”吧!说明在一个函数中又调用了另一个函数,调用函数tes...
    99+
    2023-06-20
  • Spring事务传播中嵌套调用实现方法详细介绍
    目录前言7种传播方式注解式事务事务的方法之间的调用注意事项前言 最近在使用Spring框架时遇到了一些问题,主要是Spring的事务传播问题,一个不带事务的方法调用带事务的方法,有时...
    99+
    2022-11-13
    Spring嵌套调用 Spring事务传播嵌套调用
  • 哪些小技巧能改变访问JavaScript嵌套对象的方式
    哪些小技巧能改变访问JavaScript嵌套对象的方式,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。JavaScript以众多技巧出名,了...
    99+
    2024-04-02
  • SpringBoot使用AOP,内部方法失效的解决方案
    目录SpringBoot使用AOP,内部方法失效AOP切面现在有两个方法写一个简单的动态代理的例子SpringBoot使用AOP,内部方法失效 最近在使用AOP的时候,发现一个问题,...
    99+
    2024-04-02
  • json多层嵌套转化实体类对象的方法是什么
    要将多层嵌套的JSON转化为实体类对象,可以使用以下方法:1. 创建对应的实体类对象,包括多层嵌套的属性。2. 使用JSON解析库(...
    99+
    2023-08-12
    json
  • CSS内联样式、页面嵌入、外部引用的方法
    这篇文章主要介绍“CSS内联样式、页面嵌入、外部引用的方法”,在日常操作中,相信很多人在CSS内联样式、页面嵌入、外部引用的方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”CSS内联样式、页面嵌入、外部引用...
    99+
    2023-06-27
  • Spring @Cacheable注解类内部调用失效的解决方法
    这期内容当中小编将会给大家带来有关Spring @Cacheable注解类内部调用失效的解决方法,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。@Cacheable注解类内部调用失效如果你只是想使...
    99+
    2023-06-22
  • java的main方法中调用spring的service方式
    目录main方法调用spring的servicemain方法调用spring的dao service方法main方法调用spring的service 将业务层类配置到Spring中:...
    99+
    2024-04-02
  • Spring Cloud Feign使用对象参数的方法
    本文小编为大家详细介绍“Spring Cloud Feign使用对象参数的方法”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring Cloud Feign使用对象参数的方法”文章能帮助大家解决...
    99+
    2023-06-29
  • java内部类调用的方法是什么
    在Java中,内部类调用的方法可以是外部类的方法,也可以是内部类自身的方法。如果内部类想要调用外部类的方法,可以使用以下语法:```...
    99+
    2023-10-08
    java
  • 解决spring AOP中自身方法调用无法应用代理的问题
    目录spring AOP中自身方法调用无法应用代理如下例可以使用如下两种方式修改代码以应用事务(1)在MyServiceImpl中声明一个MyService对象(2)使用AopCon...
    99+
    2024-04-02
  • vuewatch内部调用methods方法报错的解决方案
    目录watch内部调用methods方法报错例子错误原因理解methods,computed,watch的调用时机1.methods中定义的函数 2.computed中定义...
    99+
    2024-04-02
  • java的main方法中如何调用spring的service方式
    小编给大家分享一下java的main方法中如何调用spring的service方式,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!main方法调用spring的se...
    99+
    2023-06-21
  • Android中将Bitmap对象以PNG格式保存在内部存储中的方法
    在Android中进行图像处理的任务时,有时我们希望将处理后的结果以图像文件的格式保存在内部存储空间中,本文以此为目的,介绍将Bitmap对象的数据以PNG格式保存下来的方法。1、添加权限由于是对SD card进行操作,必不可少的就是为你的...
    99+
    2023-05-30
    android bitmap roi
  • Spring @Cacheable注解类内部调用失效的解决方案
    目录@Cacheable注解类内部调用失效@Cacheable注解缓存方法内部调用方法一方法二方法三方法四@Cacheable注解类内部调用失效 如果你只是想使用一个轻量级的缓存方案...
    99+
    2024-04-02
  • Java面向对象之方法中内部类的示例分析
    这篇文章主要为大家展示了“Java面向对象之方法中内部类的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java面向对象之方法中内部类的示例分析”这篇文章吧。public cl...
    99+
    2023-06-02
  • ES6的内置对象扩展方法怎么用
    本篇内容主要讲解“ES6的内置对象扩展方法怎么用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“ES6的内置对象扩展方法怎么用”吧!Array的扩展方法1.扩展运算符(展开语法)扩展运算符可以将数...
    99+
    2023-07-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作