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

目录
  • SpringBoot使用AOP,内部方法失效
    • 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;
    }
}

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

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

(0)

相关推荐

  • Spring AOP注解失效的坑及JDK动态代理

    @Transactional @Async等注解不起作用 之前很多人在使用Spring中的@Transactional, @Async等注解时,都多少碰到过注解不起作用的情况. 为什么会出现这些情况呢?因为这些注解的功能实际上都是Spring AOP实现的,而其实现原理是通过代理实现的. JDK动态代理 以一个简单的例子理解一下JDK动态代理的基本原理: //目标类接口 public interface JDKProxyTestService { void run(); } //目标类 publ

  • 详解spring中aop不生效的几种解决办法

    先看下这个问题的背景:假设有一个spring应用,开发人员希望自定义一个注解@Log,可以加到指定的方法上,实现自动记录日志(入参.出参.响应耗时这些) package com.cnblogs.yjmyzz.springbootdemo.aspect; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy

  • 解决springboot的aop切面不起作用问题(失效的排查)

    检查下springboot的启动类是否开启扫描 @SpringBootApplication @ComponentScan(basePackages = {"com.zhangpu.springboot"}) 另外springboot默认开启的EnableAspectJAutoProxy为true 如果不放心可以增加: @EnableAspectJAutoProxy(proxyTargetClass=true) 第二种可能: 没有导入 相关的jar <dependency>

  • SpringBoot内部调用事务不起作用问题的解决方案

    在做业务开发时,遇到了一个事务不起作用的问题.大概流程是这样的,方法内部的定时任务调用了一个带事务的方法,失败后事务没有回滚.查阅资料后,问题得到解决,记录下来分享给大家. 场景 我在这里模拟一个场景,大概的调用方式就如下面的代码这样. @Override @Transactional(rollbackFor = RuntimeException.class) public void insertUser(User user) { userMapper.insertUser(user); thr

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

    目录 SpringBoot使用AOP,内部方法失效 AOP切面 现在有两个方法 写一个简单的动态代理的例子 SpringBoot使用AOP,内部方法失效 最近在使用AOP的时候,发现一个问题,普通的方法AOP就能够有用,而内部调用的方法AOP就会失效,下面重现下问题 AOP切面 @Aspect @Component public class AuthorityAspect { @Pointcut("execution(* authority.service.AuthorityService.ge

  • Spring @Cacheable注解类内部调用失效的解决方案

    目录 @Cacheable注解类内部调用失效 @Cacheable注解缓存方法内部调用 方法一 方法二 方法三 方法四 @Cacheable注解类内部调用失效 如果你只是想使用一个轻量级的缓存方案,那么可以尝试使用Spring cache方案. 那么在使用spring @Cacheable注解的时候,要注意,如果类A的方法f()被标注了@Cacheable注解,那么当类A的其他方法,例如:f2(),去直接调用f()的时候,@Cacheable是不起作用的,原因是@Cacheable是基于spri

  • SpringBoot JPA懒加载失效的解决方案(亲测有效)

    SpringBoot JPA懒加载失效 使用springBoot JPA 对两个实体类进行双向关联,并设置了懒加载,如下: 然后在查询后用到了roles,会报错, 解决办法如下: 1. 在配置文件中加入: spring.jpa.properties.hibernate.enable_lazy_load_no_trans =true 2. 如果你是在SpringBoot的测试类 中使用报错,则在方法上加入@Transactional注解 在百度查询时发现有人说 修改该配置: spring.jpa.

  • 利用Spring AOP记录方法的执行时间

    一.前言 对于spring aop这个我就不多介绍了,网上一搜一大把,使用过spring的人都知道spring的ioc和aop.ioc我们常用,但在我们自己的系统中,aop的使用几乎为零,除了这个监控的小功能应用到了,其他的基本上没有使用到.下面小编就给大家整理下利用Spring AOP记录方法执行时间的解决方案,有需要的一起看看吧. 二.解决方案 1.传统方法 最简单.粗暴的方法是给各个需要统计的方法开始和结尾处加的时间戳,然后差值计算结果即可,代码如下: long startTime = S

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

    目录 Spring AOP 对象内部方法间的嵌套调用 我们先定义一个接口 以及此接口的一个实现类 增加AOP处理 同一对象内的嵌套方法调用AOP失效原因分析 举一个同一对象内的嵌套方法调用拦截失效的例子 原因分析 解决方案 Spring AOP 对象内部方法间的嵌套调用 前两天面试的时候,面试官问了一个问题,大概意思就是一个类有两个成员方法 A 和 B,两者都加了事务处理注解,定义了事务传播级别为 REQUIRE_NEW,问 A 方法内部直接调用 B 方法时能否触发事务处理机制. 答案有点复杂,

  • 解决Spring AOP拦截抽象类(父类)中方法失效问题

    目录 背景 原因分析 解决方案 后记 背景 最近工作中需要对组内各个系统依赖的第三方接口进行监控报警,对于下游出现问题的接口能够及时感知.首先我们写了一个Spring AOP注解,用于收集调用第三方时返回的信息.而我们调用第三方的类抽象出一个父类.并在父类的方法中加入我们的自定义注解用于监控日志并打印日志. 很多子类继承了这个父类并使用父类中的方法.如: 当调用子类的doSomething方法时问题出现了,发现Spring AOP没有拦截doPost()方法.而将注解加在子类方法上时,Sprin

  • SpringBoot使用AOP记录接口操作日志的方法

    目录 一.操作日志简介 1.1.系统日志和操作日志的区别 1.2.操作日志记录实现方式 二.AOP面向切面编程 2.1.AOP简介 2.2.AOP作用 2.3.AOP相关术语 2.4.JointPoint和ProceedingJoinPoint 2.5.AOP相关注解 三.AOP切面实现接口日志记录 3.1.引入AOP依赖 3.2.创建日志信息封装类WebLog 3.3.创建切面类WebLogAspect 3.4.调用接口进行测试 四.AOP切面+自定义注解实现接口日志记录 4.1.自定义日志注

  • SpringBoot项目中使用AOP的方法

    本文介绍了SpringBoot项目中使用AOP的方法,分享给大家,具体如下: 1.概述 将通用的逻辑用AOP技术实现可以极大的简化程序的编写,例如验签.鉴权等.Spring的声明式事务也是通过AOP技术实现的. 具体的代码参照 示例项目 https://github.com/qihaiyan/springcamp/tree/master/spring-aop Spring的AOP技术主要有4个核心概念: Pointcut: 切点,用于定义哪个方法会被拦截,例如 execution(* cn.sp

  • 解析springboot集成AOP实现日志输出的方法

    开发接口系统中主要的一环就是日志输出,如果系统出现问题,日志能帮我们去定位问题,最常见的日志是调用方 所调用的IP 接口地址 对应方法 参数值 以及接口方接收到请求 所返回的参数.如果这需要在每一个controller层去写的话代码过于重复,于是就使用AOP定义切面 对其接口调用前后进行拦截日志输出. 1.加入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spr

随机推荐