AopContext.currentProxy的全面解析

发布时间:2023-05-21

一、 AopContext.currentProxy是什么?

AopContext.currentProxy是Spring框架中org.springframework.aop.framework.AopContext类中的静态方法。它可以让我们在Spring框架的代理类中获取到当前代理对象的引用。在Spring中AOP通常使用JDK动态代理或者CGLIB动态代理来实现。如果我们使用JDK动态代理的话,因为代理类和被代理类必须实现一个共同的接口,所以我们通常不能直接在代理类中调用被代理类中非公开的方法(non-public method)。而如果我们使用CGLIB动态代理,则可以直接在代理类中调用被代理类中的所有方法。但是,如果我们想要在CGLIB代理中调用被代理类中的方法,我们就需要使用AopContext.currentProxy方法获取到当前代理对象的引用。

public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Override
    public void addUser(User user) {
        // 调用了被代理类中的另一个方法
        this.addUserAndLog(user);
    }
    @Override
    public void addUserAndLog(User user) {
        // 非公开方法,不能在代理类中直接调用
        userDao.addUser(user);
        System.out.println("添加用户成功!");
    }
}
public class UserLogAspect {
    public void log() {
        // 获取当前代理对象的引用
        UserService userService = (UserService) AopContext.currentProxy();
        // 调用当前代理对象中的方法
        userService.addUserAndLog(loggedUser);
    }
}

二、 AopContext.currentProxy的使用场景

1. 调用自身类中的方法

如上述代码中的UserLogAspect.log()方法中,它需要在代理类中调用被代理类中的私有方法addUserAndLog()。这个时候,我们就可以使用AopContext.currentProxy()来获取当前代理对象的引用,然后再调用当前对象中的方法。

2. 解决循环依赖问题

Spring中循环依赖是指两个或多个Bean之间相互依赖。即BeanA依赖于BeanB,BeanB又依赖于BeanA,导致Bean的初始化出现问题。如果多个Bean之间存在循环依赖,我们可以通过使用AopContext.currentProxy()方法来解决这个问题。假设我们有两个Bean,分别是UserServiceUserRepository,它们之间存在循环依赖。为了解决这个问题,我们可以在UserService中使用AopContext.currentProxy()来获取UserRepository的实例。

@Component
public class UserServiceImpl implements UserService {
    @Autowired
    private UserRepository userRepository;
    @Override
    public void addUser(User user) {
        userRepository.save(user);
    }
    @Override
    public void addDemo() {
        System.out.println("添加Demo!");
        // 这里通过AopContext.currentProxy()获取到当前代理对象的引用
        ((UserService) AopContext.currentProxy()).addUser(new User("demo", "123456"));
        System.out.println("Demo添加成功!");
    }
}
@Component
public class UserRepositoryImpl implements UserRepository {
    @Autowired
    private UserService userService;
    @Override
    public void save(User user) {
        System.out.println("保存用户:" + user);
    }
}

三、 AopContext.currentProxy的使用注意事项

1. 需要开启AspectJ支持

在使用AopContext.currentProxy()方法之前,我们需要在Spring的配置文件中开启AspectJ支持。在XML配置文件中,我们可以通过以下方式开启支持:

<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

2. 只能在代理类中使用

AopContext.currentProxy()方法只能在Spring的代理类中使用,否则将报错。如果我们在非代理类中使用该方法,会抛出IllegalStateException异常。

3. 不要在循环中使用

AopContext.currentProxy()方法在使用过程中,可能会有循环依赖的问题。如果我们在循环中频繁使用该方法,会导致系统性能下降,甚至引发死循环。

四、 AopContext.currentProxy代码示例

public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Override
    public void addUser(User user) {
        // 调用了被代理类中的另一个方法
        this.addUserAndLog(user);
    }
    @Override
    public void addUserAndLog(User user) {
        // 非公开方法,不能在代理类中直接调用
        userDao.addUser(user);
        System.out.println("添加用户成功!");
    }
}
public class UserLogAspect {
    public void log() {
        // 获取当前代理对象的引用
        UserService userService = (UserService) AopContext.currentProxy();
        // 调用当前代理对象中的方法
        userService.addUserAndLog(loggedUser);
    }
}
@Component
public class UserRepositoryImpl implements UserRepository {
    @Autowired
    private UserService userService;
    @Override
    public void save(User user) {
        System.out.println("保存用户:" + user);
    }
}