
基本知识储备
1. Spring 的 Bean 注入方式
A. 构造器注入
@Service public class BeanOne { // 注入对象 BeanTwo private BeanTwo bt; // 构造器 public BeanOne(BeanTwo bt) { this.bt = bt; } } @Service public class BeanTwo { public BeanTwo(BeanOne bo) { ... } }总结:构造器注入方式,Spring 无法解决循环依赖问题。在项目启动时,会抛出 BeanCurrentlyInCreationException 异常。
B. Setter 方式单例注入
@Service public class BeanOne { // 注入对象 BeanTwo private BeanTwo bt; // setter 方法,必须写 public void setBeanTwo(BeanTwo bt) { this.bt = bt; } } @Service public class BeanTwo { ... }总结:此种方式也会产生循环依赖问题,但 Spring 在初始化时会处理,从而解决循环依赖问题。
C. Singleton 模式字段属性注入(循环依赖,默认模式)
@Service public class AServiceImpl implements AService { @Autowired private BService bService; ... } @Service public class BServiceImpl implements BService { @Autowired private AService aService; ... }总结:属性注入方式类似 Setter 注入方式,Spring 在初始化 bean 过程中都会解决,但两种注入仍然有区别。
2. 三种注入方式的不同
属性注入不能有效指明依赖,依赖注入的核心思想是类不应该依赖于被容器管理的依赖。变量注入的方式不能保证这一点。 构造器注入和 Set 注入可以避免以上问题: Set 方式是一种选择性注入,即使没有注入依赖,也不会影响整个类的运行。 构造器方式显式注明了必须强制注入,确保了类的正常运行。3. 循环依赖
循环依赖是指 N 个类循环(嵌套)引用。用图表示: ``` A ----> B | ^ v | C <----- ```Spring 如何解决单列循环依赖
1. Bean 创建流程
...2. 关键代码解析
创建 bean 的关键代码: ```java // 创建 bean 实例 BeanDefinition bd = getBeanDefinition(beanName); Object bean = createBeanInstance(bd, beanName, args); // 设置 bean 属性 applyPropertyValues(bean, bd, beanName); // 调用初始化方法 invokeInitMethods(beanName, bean, bd); if (bd.isSingleton) { // 如果是单例 bean,则放入一级缓存 singletonObjects.put(beanName, bean); earlySingletonObjects.remove(beanName); } ```3. 循环依赖解决原理
当遇到循环依赖时,Spring 会将 bean 暂时放入三级缓存(earlySingletonObjects)。 在一级缓存(singletonObjects)中查找bean,如果不存在,则创建 bean 实例并放入三级缓存。 在三级缓存中查找 bean,如果存在,则表明发生了循环依赖。 Spring 会创建 bean 的代理对象,将代理对象放入一级缓存。 初始化 bean,注入属性。 当 bean 初始化完成后,将 bean 从三级缓存中移除,放入一级缓存。 这样,Spring 就解决了单列循环依赖问题。mm.cehuawang.cc 提供内容。
暂无评论
发表评论