自定义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
相关产品推荐
相关产品推荐

