Java,同个类调用时AOP失效?

今天查看订单日志的时候发现有一些节点操作没有被日志记录到数据库,最后排查发现被同一个类直接this调用的方法都出现了日志注解失效的问题,因为不是同一个类调用是通过spring去实例化,但是直接this调用则不一样,网上有很多解决方法,想问一下大家有没有改动比较小的方案?

【以下回答由 GPT 生成】

问题分析: 这个问题是由于同一个类内部直接使用"this"关键字调用方法时,AOP切面失效的问题。而通过Spring实例化后调用方法时,AOP切面正常工作。

解决方案: 1. 首先,需要明确的是,AOP的切面只会在Spring管理的Bean之间有效。直接使用"this"关键字调用方法时,相当于在同一个类内调用,不会触发AOP切面。

  1. 如果希望在同一个类内部使用AOP切面,在调用方法时应该通过Spring容器获取Bean,而不是直接通过"this"关键字调用方法。

  2. 可以在同一个类内部使用@Autowired注解或者通过ApplicationContext获取Bean,并调用Bean的方法来达到目的。

示例代码如下:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class MyService {

    @Autowired
    private ApplicationContext applicationContext;

    public void methodA() {
        // 使用@Autowired注解获取Bean
        MyService self = applicationContext.getBean(MyService.class);
        self.methodB();

        // 或者使用ApplicationContext获取Bean
        MyService self2 = (MyService) applicationContext.getBean("myService");
        self2.methodB();
    }

    public void methodB() {
        // 执行具体的逻辑
    }
}

通过以上的改动,即可在同一个类内使用AOP切面,而不影响原有逻辑的实现。

总结: 通过在同一个类内部获取Spring管理的Bean,并调用Bean的方法来间接触发AOP切面,可以解决Java中同一个类调用时AOP失效的问题。这种解决方案不需要改动较大的代码,只需在调用方法时借助Spring容器获取Bean即可。



【相关推荐】



如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^

通过从上下文中获取bean再调用,样例如下

    @PostMapping("form")
    @Timing
    public RestResp<User> form(User user) {
        return new RestResp<>(user);
    }

    @GetMapping("list")
    public RestResp<?> list(String query) {
        TestRestApi bean = SpringBeanUtils.getBean(TestRestApi.class);
        return bean.form(new User());
    }


public abstract class SpringBeanUtils{
    
    private static volatile ApplicationContext context;

    public static Object getBean(String name) {  
        return getApplicationContext().getBean(name);
    }  
    
    public static <T> T getBean(String name,Class<T> clazz) {
        return getApplicationContext().getBean(name,clazz);
    } 
    
    public static <T> T getBean(Class<T> clazz) {  
        return getApplicationContext().getBean(clazz);
    }

    public static void setApplicationContext(ApplicationContext applicationContext) {
        if(context == null || applicationContext.getParent() != null){//if context is child
            context = applicationContext;
        }
    }

    public static ApplicationContext getApplicationContext() {
        McnAssert.notNull(context,"applicationContext not inject yet");
        return context;
    }

}