Spring bean生命周期[3] - createBean[1]

409 阅读3分钟

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

书接上文,这里就到了比较复杂的构造bean这一部分了,回顾一下之前的部分:

自己创建

 RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 //这一步会检查一下是不是抽象的BD,是的话就直接报错了,因为根据之前的描述我们也知道抽象的BD是不能构造成bean的。
 checkMergedBeanDefinition(mbd, beanName, args);

获取到了BD,接下来要正式走创建bean的流程了。

第一步:保证依赖的bean都创建了

这里对应的代码如下:

 String[] dependsOn = mbd.getDependsOn();
 if (dependsOn != null) {
    for (String dep : dependsOn) {
       if (isDependent(beanName, dep)) {
          throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
       }
       registerDependentBean(dep, beanName);
       try {
           //这里又进行递归了
          getBean(dep);
       }
       catch (NoSuchBeanDefinitionException ex) {
          throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
       }
    }
 }

这里的依赖,指的是受@DependsOn()注释的相关类,并不指类中定义的属性。

  • 注意一下这里报错的内容:Circular depends-on,也就是说@DependsOn不能是互相依赖的。

    • 那么这里就会有另一个问题:如果发生了三角循环的相互依赖,那么不能直接判断,还需要看一看是不是有循环依赖的关系,因此isDependent(beanName, dep)这个方法里就会做这个判断,循环地来看看是否依赖的链表节点上存在循环依赖的问题。

      这里就得有记录,这个记录点在这里:registerDependentBean(dep, beanName);

      这里会把依赖的相关信息,存在一个map里面。

要注意:这里的循环依赖问题,指的是@DependsOn的依赖,而不是@Autowired的那个依赖,也就是说这里的dependsOn的优先级要比@Autowired高,这里的@DependsOn指的是必须初始化咯。

在记录之后,就会去创建依赖的bean:getBean(dep);

第二步:区分作用域(scope)

回忆一下,创建bean有几步?

  • 类加载,实例化,前后process,属性注入

而bean又分为:原型bean和单例bean。

这里就分为三个了。

  • 单例:

    这部分走这里:

     if (mbd.isSingleton()) {
        sharedInstance = getSingleton(beanName, () -> {
           try {
              return createBean(beanName, mbd, args);
           }
           catch (BeansException ex) {
              // Explicitly remove instance from singleton cache: It might have been put there
              // eagerly by the creation process, to allow for circular reference resolution.
              // Also remove any beans that received a temporary reference to the bean.
              destroySingleton(beanName);
              throw ex;
           }
        });
        beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
     }
    
  • 原型:

     else if (mbd.isPrototype()) {
        // It's a prototype -> create a new instance.
        Object prototypeInstance = null;
        try {
           beforePrototypeCreation(beanName);
           prototypeInstance = createBean(beanName, mbd, args);
        }
        finally {
           afterPrototypeCreation(beanName);
        }
        beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
     }
    
  • 其他scope(SpringMVC里的,比如request,session等):

     else {
        String scopeName = mbd.getScope();
        if (!StringUtils.hasLength(scopeName)) {
           throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
        }
        Scope scope = this.scopes.get(scopeName);
        if (scope == null) {
           throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
        }
        try {
           Object scopedInstance = scope.get(beanName, () -> {
              beforePrototypeCreation(beanName);
              try {
                 return createBean(beanName, mbd, args);
              }
              finally {
                 afterPrototypeCreation(beanName);
              }
           });
           beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
        }
        catch (IllegalStateException ex) {
           throw new ScopeNotActiveException(beanName, scopeName, ex);
        }
     }
    

    这里的scope其实和单例意思差不多,只是缓存的信息会存在scope里,对应的scope里的这些bean也都是单例的,只是单例的是全局的这里是scope的。

这里关键代码都差不多:

 //原型bean、其他scope记录下现在在创建,用map来存
 beforePrototypeCreation(beanName);
 createBean(beanName, mbd, args);
 //原型bean、其他scope记录下现在创建好了,也是用map来存
 afterPrototypeCreation(beanName);
 getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);

区别就是,原型的话就直接创建,单例会尝试获取。

这里关键就在createBean上:创建bean对象。