SpringBoot使用AOP,内部方法失效的解决方案

 更新时间:2021年08月28日 14:46:27   作者:Lpepsi  
这篇文章主要介绍了SpringBoot使用AOP,内部方法失效的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

SpringBoot使用AOP,内部方法失效

最近在使用AOP的时候,发现一个问题,普通的方法AOP就能够有用,而内部调用的方法AOP就会失效,下面重现下问题

AOP切面

@Aspect
@Component
public class AuthorityAspect {
    @Pointcut("execution(* authority.service.AuthorityService.getExecutableSql(..))")
    private void pointCut() {}
    @Around(value = "pointCut()")
    public Object handle(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        String sql = (String) args[1];
        args[1] = sql + " AOP ";
        return joinPoint.proceed(args);
    }

该切面的作用就是,当执行getExecutableSql()方法,织入切面,获取到该方法的参数,修改参数然后再执行该方法

现在有两个方法

@Service
public class AuthorityService {
    public String getExecutableSql(String dataSourceId, String sql, Object page){
        return sql;
    }
    public String getInner(String dataSourceId, String sql, Object page){
        String str = this.getExecutableSql(dataSourceId, sql, page);
        return str;
    }
}
  • 一个是普通方法getExecutableSql(),
  • 一个是在内部调用了getExecutableSql()的getInner()方法

同时运行这两个方法

在这里插入图片描述

可以发现内部调用了getExecutableSql()的方法,AOP对它并没有生效,直接调用的就生效了。在说原因前,我们先说说动态代理 因为AOP的原理就是动态代理

动态代理简单来说就是在程序运行的过程中,自动生成一个指定的代理类,然后执行程序,这个代理类可以在破坏原来被代理对象的情况下做一下额外的工作。

写一个简单的动态代理的例子

//接口
public interface ProxyService {
    void save();
    void email();
    void register();
}
//实现类
@Service
public class ProxyServiceImpl implements ProxyService{
    @Override
    public void save() {
    }
    @Override
    public void email() {
    }
    @Override
    public void register() {
        this.save();
        this.email();
    }
}
//获得代理
public class ServiceProxy {
    public static Object getProxy(Class<?> clazz,Object target){
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{clazz}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object invoke = method.invoke(target, args);
                System.out.println("after method: "+method.getName());
                return invoke;
            }
        });
    }
}
//测试类
public class ProxyTest {
    public static void main(String[] args) {
        ProxyService proxyService = (ProxyService) ServiceProxy.getProxy(ProxyService.class, new ProxyServiceImpl());
        proxyService.register();
    }
}

结果:

在这里插入图片描述

可以看到动态代理中,内部方法调用也是没有生效,通过对代理类的Class文件分析,我们可以知道只有通过代理类的实例执行的方法才会进入到拦截处理中

在这里插入图片描述

而动态代理的方法真实调用,会使用真实被代理对象实例进行方法调用,故在实例方法中通过this获取的都是被代理的真实对象的实例,而不是代理对象自身。通过Debug可以看到

在这里插入图片描述

this获取的不是代理对象,因此无法进入拦截处理,所以代理增强的方法没有执行。原因知道了,那就解决办法就是让代理对象去调用这些方法,就能够进入拦截处理了,修改下代码

@Service
public class ProxyServiceImpl implements ProxyService{
    
    @Override
    public void save() {
    }
    @Override
    public void email() {
    }
    @Override
    public void register() {
        //获取代理对象
        ProxyService proxyService = (ProxyService) ServiceProxy.getProxy(ProxyService.class, new ProxyServiceImpl());
        proxyService.save();
        proxyService.email();
    }
}

执行一下

在这里插入图片描述

在SpringBoot中可以用下面的方法,来使内部调用的方法AOP也能对其生效

@Service
public class AuthorityService {
	//获取代理对象
    @Autowired
    private AuthorityService authorityService;
    public String getExecutableSql(String dataSourceId, String sql, Object page){
        return sql;
    }
    public String getInner(String dataSourceId, String sql, Object page){
        String str = authorityService.getExecutableSql(dataSourceId, sql, page);
        return str;
    }
}

在这里插入图片描述

可以看到内部调用的方法也生效了

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java获得指定区间数的方法

    Java获得指定区间数的方法

    这篇文章主要介绍了Java获得指定区间数的方法,涉及java数值运算的相关技巧,需要的朋友可以参考下
    2015-05-05
  • 简单的理解java集合中的HashSet和HashTree几个重写方法

    简单的理解java集合中的HashSet和HashTree几个重写方法

    这篇文章主要介绍了简单的理解java集合中的HashSet和HashTree几个重写方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • Java中的CompletableFuture原理与用法

    Java中的CompletableFuture原理与用法

    CompletableFuture 是由Java8引入的,这让我们编写清晰可读的异步代码变得更加容易,该类功能比Future 更加强大,在Java中CompletableFuture用于异步编程,异步通常意味着非阻塞,运行任务单独的线程,与主线程隔离,这篇文章介绍CompletableFuture原理与用法,一起看看吧
    2024-01-01
  • Java TCP编程之Scoket

    Java TCP编程之Scoket

    TCP/IP是一种面向连接的、可靠的、基于字节流的传输层通信协议,它会保证数据不丢包、不乱序。TCP全名是Transmission Control Protocol,它是位于网络OSI模型中的第四层
    2022-11-11
  • Java多线程中Lock的使用小结

    Java多线程中Lock的使用小结

    jdk1.5 以后,提供了各种锁,本文主要介绍了Java多线程中Lock的使用小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • Java 线程的生命周期详细介绍及实例代码

    Java 线程的生命周期详细介绍及实例代码

    这篇文章主要介绍了Java 线程的生命周期的相关资料,并附简单实例代码,帮助大家理解,需要的朋友可以参考下
    2016-10-10
  • Java日常练习题,每天进步一点点(52)

    Java日常练习题,每天进步一点点(52)

    下面小编就为大家带来一篇Java基础的几道练习题(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望可以帮到你
    2021-08-08
  • IDEA 2020.1 搜索不到Chinese ​(Simplified)​ Language Pack EAP,无法安装的问题

    IDEA 2020.1 搜索不到Chinese ​(Simplified)​ Language

    小编在安装中文插件时遇到IDEA 2020.1 搜索不到Chinese &#8203;(Simplified)&#8203; Language Pack EAP,无法安装的问题,本文给大家分享我的解决方法,感兴趣的朋友一起看看吧
    2020-04-04
  • SpringBoot使用knife4j进行在线接口调试

    SpringBoot使用knife4j进行在线接口调试

    这篇文章主要介绍了SpringBoot使用knife4j进行在线接口调试,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • commons fileupload实现文件上传的实例代码

    commons fileupload实现文件上传的实例代码

    这篇文章主要介绍了commons fileupload实现文件上传的实例代码,包括文件上传的原理分析等相关知识点,本文给大家介绍的非常详细,具有参考借鉴价值,感兴趣的朋友一起看看吧
    2016-10-10

最新评论