一、 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,分别是UserService
和UserRepository
,它们之间存在循环依赖。为了解决这个问题,我们可以在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);
}
}