循环依赖: a依赖b,b依赖a; 这是一种最简单的循环依赖,在spring中,所有的bean 都是单例的,spring帮助我们完美解决了循环依赖的问题;
依赖,也叫依赖注入,DI . 可能我这么说比较陌生,那么我举个例子:
DEMO:在 UserServiceImpl 中 我调用了 detpServcie; 然后我在 DeptServiceImpl 中 我调用了 userService; 这就是个循环依赖.
我所知道的DI方式有两种:一种是属性注入,一种是构造注入;
第一种属性注入:之所以我们平时没有任何问题是因为我们 大多数时候用的都是 DEMO 中的 注入方式,这是一种反射注入,我把他理解为一种另类的属性注入; 也就是说,在spring中,属性注入的循环依赖是不会有任何问题的;(为什么会没有问题?我最后会说明)
第二种构造注入: 通过构造器传入依赖的bean,这种方式你要清楚的知道调用关系方可使用,否则就会导致循环依赖的错误.举个栗子:
DEMO1:
@RestController
public class AccountController {
private static final Logger LOG = LoggerFactory.getLogger(AccountController.class);
private AccountService accountService;
// 构造函数依赖注入
// 不管是否设置为required为true,都会出现循环依赖问题
@Autowire
// @Autowired(required = false)
public AccountController(AccountService accountService) {
this.accountService = accountService;
}
}
===================================
@Service
public class AccountService {
private static final Logger LOG = LoggerFactory.getLogger(AccountService.class);
// 属性值依赖注入
@Autowired
private AccountController accountController;
}
由于在项目中,都是用controller 调用service,所以controller依赖service,而DEMO1中的就是在controller中采用构造注入sercie.在service 中采用 属性注入;
首先我说下,导致报错的原因: 因为类的加载一般通过三步,1:调用构造参数 2:放入三级缓存中(半成品) 3: 给类中的属性赋值.那么DEMO1 中的 controller在加载的时候, 在第一步就需要用到service,而此时service如果没加载,那么根本执行不到第二步,这样就会报错.
其次我说下,假如controller 调用service,controller依赖service,而DEMO1中的注入方式改变下,就是在controller中采用属性注入sercie.在service 中采用 构造注入;这样就不会有问题,因为: controller在加载的时候,第一步调用构造参数会成功,并执行第二步,放入三级缓存中,再执行第三步给属性赋值,此时发现需要加载service,那么就会加载servcie,然后service中无论是采用构造注入还是属性注入都是可以的,因为需要的controller半成品已经在三级缓存中,那么就不会产生问题.