解决使用注解的spring中aop,无法拦截方法中调用其他的方法(函数内部调用无法拦截)问题

本文介绍了一个关于Spring AOP中方法内部调用不被拦截的问题,并提供了解决方案。通过使用自定义注解结合Spring AOP,实现方法级别的日志记录,但发现在方法内部调用其他方法时,这些方法不会被AOP拦截。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在项目中要记录用户日志,使用自定义注解进行aop拦截,发现可以拦截调用类的第一个方法,方法中调用其他方法,则其他方法无法拦截,经过查询,发现是aop自身的动态代理造成的,下面我贴出项目的代码:

1、自定义注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogController {
    String operationContent() default "";
}

2、spring的aop代码

@Aspect
@Component
public class UserLogAspect {

    @Pointcut("@annotation(com.jingli.creditchain.service.userlog.LogController)")
    public void methodAspect() {

    }

    @SuppressWarnings("rawtypes")
    @After("methodAspect()")
    public void doAfter(JoinPoint joinPoint) {
        try {
            //拦截的实体类
            Object target = joinPoint.getTarget();
            //拦截的方法名称
            String methodName = joinPoint.getSignature().getName();
            //拦截的参数类型
            Class[] parameterTypes = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes();
            //通过反射获得拦截的method
            Method method = target.getClass().getMethod(methodName, parameterTypes);
            String content = method.getAnnotation(LogController.class).operationContent();
            //打印注解上的说明
            System.out.println("================="+content);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

3、controller中进行方法拦截

    @LogController(operationContent = "findApply")
    @RequestMapping(path = "/list", method = RequestMethod.POST)
    public List<ApplyVm> findApply(@RequestBody QueryInnerApplyVm query) {
        //转换请求vm,在转换的方法上也加上拦截(转换方法在同一个类中)
        QueryParam queryParam = queryInnerApplyVmToQueryParam(query);
        return applyService.findApply(queryParam)
            .stream()
            .filter(Objects::nonNull)
            .map(this::assignApplyVm)
            .collect(Collectors.toList());
    }


//转换方法
@LogController(operationContent = "queryInnerApplyVmToQueryParam")
public QueryParam queryInnerApplyVmToQueryParam(QueryInnerApplyVm vm) {
    return new QueryParam();
}

4、测试,看打印结果

=================findApply

可以看到,方法中调用的第二个方法并没有拦截。

原因:

当调用这个类的时候,调用的是代理对象,代理类内部代码大致是:

private ApplyController applyController;

public List<ApplyVm> findApply(@RequestBody QueryInnerApplyVm query) {

    //也就是说,在调用其他函数时,其实是被代理对象调用的,所以方法是不会被增强,也就是没
        有拦截。调用其他函数时,如果是代理对象调用的,那就可以被拦截。
    QueryParam queryParam = applyController.queryInnerApplyVmToQueryParam(query);
       
}

5、修改代码

拿到ApplicationContext,从容器中拿对象,如果那个对象有代理对象,就可以获得代理对象。

//工具类
@Component
public class BeanUtil implements ApplicationContextAware {
    private  static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(@NotNull ApplicationContext applicationContext){
        BeanUtil.applicationContext = applicationContext;
    }

    public static <T> T getBean(Class<T> bean){
        return applicationContext.getBean(bean);
    }
}
    @LogController(operationContent = "findApply")
    @RequestMapping(path = "/list", method = RequestMethod.POST)
    public List<ApplyVm> findApply(@RequestBody QueryInnerApplyVm query) {
        QueryParam queryParam = BeanUtil.getBean(this.getClass()).queryInnerApplyVmToQueryParam(query);
    }

6、测试

=================queryInnerApplyVmToQueryParam

=================findApply

第二个方法也被拦截了。

7、总结

spring是不建议这种使用aop有函数内部调用的,可以把调用的函数写到另一个类中。但是这样的话,代码会有点乱,所以我项目中看情况如果上面的写法方便的话我还是用上面的方法把=。=

这个问题一开始困扰我好久,上网查查这问题有大神解答,十分感谢,也记录一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值