Spring source code learning ② BeanFactory doGetBean execution process

spring-logo.png

Spring source code learning ② BeanFactory doGetBean execution process

The Spring source series articles will follow the principle of going from shallow to deep, from easy to difficult, and from macro to micro. The goal is to reduce the difficulty of learning as much as possible, instead of getting lost in the source code. It is very purposeful to explore and study Spring's implementation principle and source code for this scenario. What will this series of articles give you? Become a Spring expert from a Spring user. This article will be synchronized on the WeChat public account [DevXJava], which is convenient for reading on the WeChat client.

The content of this article is BeanFactory doGetBean the exploration of the method, which will involve part of the source code, but will not explain a lot of source code. The goal is to let readers doGetBean have a general macro understanding of the things and processes in the method.

Scenes

public class BeanFactoryGetBeanExp {

    public static void main(String[] args) throws Exception {

        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        // 在 beanFactory 中注册 bean1
        BeanDefinition bdf = BeanDefinitionBuilder.genericBeanDefinition(Bean1.class).getBeanDefinition();
        beanFactory.registerBeanDefinition("bean1" , bdf);
        
        for (String name : beanFactory.getBeanDefinitionNames()) {
            System.out.println("bean ----------> " + name);
        }

        // 调用 getBean , debug 进入观察获取 bean1 过程
        Bean1 bean1 = beanFactory.getBean(Bean1.class);
        System.out.println(bean1);

    }

    static class Bean1 {
        public Bean1() {
            System.out.println("Bean1 默认构造函数执行 >>>>>>>>>>>>>>>>>>>>>>");
        }
    }
}

This scenario is very simple. First of all, we provide a pure DefaultListableBeanFactory , by BeanDefinition registering Bean1 in beanFactory; after completing the registration, get the instance of Bean1 from beanFactory.
Why not use it ApplicationContext ? Because ApplicationContext it is actually BeanFactory an encapsulation of , and Spring itself ApplicationContext will add it when creating Many frameworks have built-in configurations. It is used in order to eliminate interference BeanFactory .

doGetBean execution process

BeanFactory All getBean methods will eventually call doGetBean the method, so we only need to pay attention to doGetBean the method.

BeanFactory#getBean.drawio (1).png

The above figure shows doGetBean the general execution process of the method. In order to facilitate the comparison with the source code for viewing and learning, the doGetBean source code will be attached below; the corresponding Chinese annotations will be attached to the source code;

protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
      throws BeansException {

   String beanName = transformedBeanName(name);
   Object beanInstance;

   // 从单例缓存中获取 bean 实例
   // Eagerly check singleton cache for manually registered singletons.
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
      if (logger.isTraceEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      
      // 针对 FactoryBean 实例进行处理
      beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   // 没有从单例缓存中获取到实例
   else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

      // 尝试从父 BeanFactory 中获取 bean , 如果获取到会直接返回
      // Check if bean definition exists in this factory.
      BeanFactory parentBeanFactory = getParentBeanFactory();
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
         // Not found -> check parent.
         String nameToLookup = originalBeanName(name);
         if (parentBeanFactory instanceof AbstractBeanFactory) {
            return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                  nameToLookup, requiredType, args, typeCheckOnly);
         }
         else if (args != null) {
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else if (requiredType != null) {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
         else {
            return (T) parentBeanFactory.getBean(nameToLookup);
         }
      }

      if (!typeCheckOnly) {
         markBeanAsCreated(beanName);
      }

      StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
            .tag("beanName", name);
      try {
         if (requiredType != null) {
            beanCreation.tag("beanType", requiredType::toString);
         }
         RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         // 检查 bean 是否存在循环引用 , 并初始化当前 bean 所依赖的 bean 实例
         
         // Guarantee initialization of beans that the current bean depends on.
         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);
               }
            }
         }

         // 这里开始真正进行 bean 的创建过程
         
         // Create bean instance.
         if (mbd.isSingleton()) {
         
            // 尝试从单例缓存(singletonObjects)中获取 bean , 如果没有获取到会进行 bean 的创建
            // bean 创建完成后会被存放到单例缓存中 (singletonObjects)
            
            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);
         }

         // 对范围为 Prototype 类型的 bean 进行创建,直接调用 createBean 方法进行创建
         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 对 bean 进行创建
         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);
            }
         }
      }
      catch (BeansException ex) {
         beanCreation.tag("exception", ex.getClass().toString());
         beanCreation.tag("message", String.valueOf(ex.getMessage()));
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
      finally {
         beanCreation.end();
      }
   }

   // bean 创建成功后对 bean 进行类型转换后返回
   return adaptBeanInstance(name, beanInstance, requiredType);
}

More detailed details and source code will be provided in the follow-up content of the series of articles. This article will be synchronized on the WeChat public account [DevXJava], which is convenient for reading on the WeChat client.
Get full code and notes: https://gitee.com/kernelHP/spring-certified-professional-edu

おすすめ

転載: blog.csdn.net/weixin_45839894/article/details/128788189