iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >怎么解决Spring AOP拦截抽象类父类中方法失效问题
  • 684
分享到

怎么解决Spring AOP拦截抽象类父类中方法失效问题

2023-06-21 20:06:43 684人浏览 薄情痞子
摘要

这篇文章主要介绍怎么解决spring aop拦截抽象类父类中方法失效问题,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!背景最近工作中需要对组内各个系统依赖的第三方接口进行监控报警,对于下游出现问题的接口能够

这篇文章主要介绍怎么解决spring aop拦截抽象类父类中方法失效问题,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

背景

最近工作中需要对组内各个系统依赖的第三方接口进行监控报警,对于下游出现问题的接口能够及时感知.首先我们写了一个Spring AOP注解,用于收集调用第三方时返回的信息.而我们调用第三方的类抽象出一个父类.并在父类的方法中加入我们的自定义注解用于监控日志并打印日志.

怎么解决Spring AOP拦截抽象类父类中方法失效问题

很多子类继承了这个父类并使用父类中的方法.如:

怎么解决Spring AOP拦截抽象类父类中方法失效问题

当调用子类的doSomething方法时问题出现了,发现Spring AOP没有拦截doPost()方法.而将注解加在子类方法上时,Spring AOP可以拦截子类的方法,但这不是我们想要的结果.而当我们将父类通过@Autowired方式注入到子类中代替使用继承的方式调用父类中方法时Spring AOP可以拦截父类中的方法.至此发现问题出现在继承上面.

原因分析

Spring AOP拦截器的实现原理就是利用动态代理技术实现面向切面编程,Spring 的代理实现有两种:一是基于 jdk Dynamic Proxy 技术而实现的;二是基于 CGLIB 技术而实现的。如果目标对象实现了接口,在默认情况下Spring会采用JDK的动态代理实现AOP,在本例目标对象没有实现接口,因此使用的CGLIB实现动态代理对SuperClass对象进行代理,然后增强doPost()方法.下面的代码展示了为什么Spring AOP没有增强doPost()方法.

怎么解决Spring AOP拦截抽象类父类中方法失效问题

图2等价于图3,即使用super关键字调用doPost()方法,这就表明我们使用的SuperClass的实例调用的doPost()方法,在我们在使用Spring AOP的时候,我们从ioc容器中获取的Bean对象其实都是代理对象,而不是那些Bean对象本身.因此AOP不能使用代理对象调用这些父类的方法.

解决方案

知道了问题原因,解决问题就比较容易了,由于我们使用的super关键字调用父类的方法行不通,那么我们就强制使用代理对象调用父类方法.

怎么解决Spring AOP拦截抽象类父类中方法失效问题

好了,我们运行程序,发现不但没有拦截方法而且还报错了.

java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.

异常信息非常明确,找不到当前的代理,需要在暴露出代理,我们看下AopContext这个类的源码,看看到底哪里出错了,看到了我们输出错误信息的地方.

package org.springframework.aop.framework;import org.springframework.core.NamedThreadLocal;import org.springframework.lang.Nullable;public final class AopContext {    private static final ThreadLocal<Object> currentProxy = new NamedThreadLocal("Current AOP proxy");    private AopContext() {    }    public static Object currentProxy() throws IllegalStateException {        Object proxy = currentProxy.get();        if (proxy == null) {            throw new IllegalStateException("Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.");        } else {            return proxy;        }    }    @Nullable    static Object setCurrentProxy(@Nullable Object proxy) {        Object old = currentProxy.get();        if (proxy != null) {            currentProxy.set(proxy);        } else {            currentProxy.remove();        }        return old;    }}

说名setCurrentProxy方法没有被调用,通过查找发现有两个类调用了该方法,分别为CglibAopProxyJdkDynamicAopProxy,是不是很熟悉,这两个就是Spring aop的代理方式,由于我们讨论的目标对象不是基于接口的,因此本文使用的代理都是基于CglibAopProxy,我们找到该类中调用setCurrentProxy方法的地方,程序中判断this.advised.exposeProxy是否为true,如果为true,设置当前代理,而通过调试这个字段为false

if (this.advised.exposeProxy) {                    oldProxy = AopContext.setCurrentProxy(proxy);                    setProxyContext = true;                }

那么我们就在需要通知的地方,即你需要拦截方法的类上加上如下注解.

@EnableAspectJAutoProxy(exposeProxy = true)

这次在调用,发现已经可以拦截注解标注的方法了.

后记

解决这个问题的方式有很多,可以子类不继承父类,而是改为@Autowired方式,然后每一个调用的地方需要加上父类的对象.

最终我们在程序中的方案是加了一个父类的代理类,用于强制使用代理对象调用父类的方法.而原来父类的子类继承代理类即可.

import org.springframework.aop.framework.AopContext;import org.springframework.stereotype.Component;import java.util.Map;@Componentpublic class ProxyAgent extends BaseAgent{    private BaseAgent getProxyObject() {        return ((BaseAgent)AopContext.currentProxy());    }    protected String doGet(String url, Map<String, Object> headers, Map<String, Object> params, Object... uriVariables) {        return getProxyObject().doGetBase(url, headers, params, uriVariables);    }    protected String doPost(String url, Map<String, Object> headers, Object body) {        return getProxyObject().doPostBase(url, headers, body);    }    protected String doPostFORM(String url, Map<String, Object> params) {        return doPostForm(url, null, params);    }    protected String doPostForm(String url, Map<String, Object> headers, Map<String, Object> params) {        return getProxyObject().doPostFormBase(url, headers, params);    }    protected String doPostFormWithContentHeader(String url, Map<String, Object> headers,                                                 Map<String, Object> params, byte[] boundary) {        return getProxyObject().doPostFormWithContentHeaderBase(url, headers, params, boundary);    }    protected String doPostFormUpload(String url, Map<String, Object> headers, Map<String, Object> params) {        return getProxyObject().doPostFormUploadBase(url, headers, params);    }}

同理,调用内部方法使用this关键字时同样会出现这个问题,同样采用强制使用代理对象即可.

以上是“怎么解决Spring AOP拦截抽象类父类中方法失效问题”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网精选频道!

--结束END--

本文标题: 怎么解决Spring AOP拦截抽象类父类中方法失效问题

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

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

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

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

下载Word文档
猜你喜欢
  • 解决Spring AOP拦截抽象类(父类)中方法失效问题
    目录背景原因分析解决方案后记背景 最近工作中需要对组内各个系统依赖的第三方接口进行监控报警,对于下游出现问题的接口能够及时感知.首先我们写了一个Spring AOP注解,用于收集调用...
    99+
    2024-04-02
  • 怎么解决Spring AOP拦截抽象类父类中方法失效问题
    这篇文章主要介绍怎么解决Spring AOP拦截抽象类父类中方法失效问题,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!背景最近工作中需要对组内各个系统依赖的第三方接口进行监控报警,对于下游出现问题的接口能够...
    99+
    2023-06-21
  • 解决Spring AOP 同类调用失效问题
    目录背景一 目标二 概述三 工作中遇到的实例1.源代码2.原因分析四 解决方法1.方法一2.方法二原理:3.方法三4.总结背景 当初刚到公司实习不久,就遇到一个问题:在同一个类中,调...
    99+
    2024-04-02
  • mybatis的integer类型为0的失效问题怎么解决
    本篇内容介绍了“mybatis的integer类型为0的失效问题怎么解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!integer类型为0...
    99+
    2023-06-26
  • 解决Springboot全局异常处理与AOP日志处理中@AfterThrowing失效问题的方法
    本篇文章和大家了解一下解决Springboot全局异常处理与AOP日志处理中@AfterThrowing失效问题的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。目录一、前言二、问题三、失效场景一、前言在实际业务场景中...
    99+
    2023-07-06
  • 怎么理解PHP7.2忽略父类方法以及Liskov替换原则相关问题
    这篇文章主要介绍“怎么理解PHP7.2忽略父类方法以及Liskov替换原则相关问题”,在日常操作中,相信很多人在怎么理解PHP7.2忽略父类方法以及Liskov替换原则相关问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希...
    99+
    2023-06-25
  • 怎么解决使用Hashcode中distinct()方法没有起效问题
    本篇内容介绍了“怎么解决使用Hashcode中distinct()方法没有起效问题”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔...
    99+
    2024-04-02
  • JavaScript中怎么解决document.getElementBy系列方法获取不到对象的问题
    这篇文章将为大家详细讲解有关JavaScript中怎么解决document.getElementBy系列方法获取不到对象的问题,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。JavaScript的作用是什么...
    99+
    2023-06-08
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作