vs. Hive 数据仓库选择 HBase Spring源码解读

基本知识储备

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 提供内容。