You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义InterceptExecutionTime注解在内部调用方法上不生效求助

Spring AOP自定义注解内部方法调用失效问题分析与解决

问题描述

自定义注解@InterceptExecutionTime结合Spring AOP的@Around切面实现方法耗时记录,当注解标注在外部方法getCustomerDocument时功能正常,但标注在该方法内部直接调用的mapToCustomerDocument方法时,注解功能完全失效。

核心原因

Spring AOP默认采用动态代理机制(JDK动态代理或CGLIB代理),切面逻辑仅会在代理对象的方法调用时触发。当在getCustomerDocument内部直接调用mapToCustomerDocument时,实际执行的是this.mapToCustomerDocument(),这里的this是原始的CustomerQueryHandler对象,而非Spring生成的代理对象,因此切面不会拦截该方法调用,注解自然失效。

解决方案

方案1:自注入代理对象

在CustomerQueryHandler中注入自身的代理对象,通过代理对象调用内部方法:

@Component
public class CustomerQueryHandler {
    // 注入自身的Spring代理对象
    @Autowired
    private CustomerQueryHandler selfProxy;

    public CustomerDocument getCustomerDocument(int userId, String documentType) throws JsonProcessingException {
        CustomerDocument.DocumentType customerDocumentType = CustomerDocument.DocumentType.fromString(documentType);
        CustomerDocument customerDocument = customerDocumentRepository.findByUserIdAndDocumentTypeAndIsDeletedFalse(userId, customerDocumentType);

        if (customerDocument == null) {
            throw new NoSuchCustomerDocumentException(String.format("No %s document found for userId %s", documentType, userId));
        }

        // 通过代理对象调用标注了注解的方法
        return selfProxy.mapToCustomerDocument(customerDocument);
    }

    @InterceptExecutionTime(action = "fetch customer document")
    public CustomerDocument mapToCustomerDocument(CustomerDocument customerDocument) throws JsonProcessingException {
        return new CustomerDocument(customerDocument.getVerificationType() != null ?
                customerDocument.getVerificationType().name() : null,
                null);
    }
}

方案2:通过AopContext获取当前代理对象

首先在启动类开启代理暴露:

@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true)
public class YourApplication {
    public static void main(String[] args) {
        SpringApplication.run(YourApplication.class, args);
    }
}

然后在内部调用时获取代理对象:

@Component
public class CustomerQueryHandler {

    public CustomerDocument getCustomerDocument(int userId, String documentType) throws JsonProcessingException {
        // ... 原有逻辑
        // 获取当前代理对象并调用方法
        CustomerQueryHandler proxy = (CustomerQueryHandler) AopContext.currentProxy();
        return proxy.mapToCustomerDocument(customerDocument);
    }

    @InterceptExecutionTime(action = "fetch customer document")
    public CustomerDocument mapToCustomerDocument(CustomerDocument customerDocument) throws JsonProcessingException {
        // ... 原有逻辑
    }
}

方案3:重构代码拆分Bean

将内部方法抽离到独立的Spring Bean中,通过注入Bean的方式调用:

// 新建独立的Mapper Bean
@Component
public class DocumentMapper {
    @InterceptExecutionTime(action = "fetch customer document")
    public CustomerDocument mapToCustomerDocument(CustomerDocument customerDocument) throws JsonProcessingException {
        return new CustomerDocument(customerDocument.getVerificationType() != null ?
                customerDocument.getVerificationType().name() : null,
                null);
    }
}

修改原Handler类:

@Component
public class CustomerQueryHandler {
    @Autowired
    private DocumentMapper documentMapper;

    public CustomerDocument getCustomerDocument(int userId, String documentType) throws JsonProcessingException {
        // ... 原有逻辑
        // 通过注入的Bean调用方法,自动经过代理
        return documentMapper.mapToCustomerDocument(customerDocument);
    }
}

内容的提问来源于stack exchange,提问作者iftekhar khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 16:20:41