spring循环依赖下几种报错的写法

发布时间 2023-08-14 21:46:10作者: 花开如梦

同为原型bean情况下的循环依赖,例如:

@Component
@Scope("prototype") //原型bean (多例)情况
public class ServletA {
    @Autowired
    ServletB servletB;

    @Override
    public String toString() {
        return "this servletA";
    }
}
@Component
@Scope("prototype") //原型bean (多例)情况
public class ServletB {
    @Autowired
    ServletA servletA;

    @Override
    public String toString() {
        return "this servletB";
    }
}

 构造方法导致的循环依赖:这个比较好理解,由于都是构造函数注入参数,导致构造函数都无法完成

@Component
public class UserA {
    UserB userB;
    /**
     * 构造函数的依赖注入
     * */
    public UserA(UserB userB) {
        this.userB = userB;
    }
    @Override
    public String toString() {
        return "UserA{}";
    }
}
@Component
public class UserB {
    UserA userA;
    /**
     * 构造函数的依赖注入
     * */
    public UserB(UserA userA) {
        this.userA = userA;
    }
    @Override
    public String toString() {
        return "UserB{}";
    }
}

@Async情况下的循环依赖解析

前提你已经在配置文件了 @EnableAsync 并且 context.getBean("userA", UserA.class) 保证 userA 优先被调用

@Component
public class UserA {
    @Autowired
    //可以通过添加@Lazy解决。本质是因为@Lazy 会注入userB的代理类。参考 AutowiredAnnotationBeanPostProcessor 的自动注入过程
    //@Lazy
    UserB userB;

    /**
     * 注意是顺序问题,是先调用的UserA,而UserA依赖注入了UserB,
     * 这样在 UserA 的 a() 方法添加 @Async 注解导致报错
     */
    @Async
    public void a() {
        System.out.println("aaaaaaa");
    }

    @Override
    public String toString() {
        return "UserA{}";
    }
}
@Component
public class UserB {
    @Autowired
    UserA userA;

    /**
     * 注意是顺序问题,是先调用的UserA,而UserA依赖注入了UserB,
     * 这样在 UserB 的 b() 方法添加 @Async 注解是不会报错的
     */
    //@Async
    //public void b(){
    //    System.out.println("bbbbbbb");
    //}

    @Override
    public String toString() {
        return "UserB{}";
    }
}

关于@Lazy 生成代理的源码

 关于@Async会使循环依赖失败的问题,是因为  @EnableAsync 引入了  AsyncAnnotationBeanPostProcessor 导致了如下

 而同样 @Transactional 并不会引起此以上的循环依赖的问题,因为 @Transactional 并没有引入 BeanPostProcessor 进行处理