Spring Bean的创建过程及相关扩展点(上)

简介: Spring Bean的创建过程及相关扩展点

首先,我们最基本的常识是从ApplicationContext入手,从AbstractApplicationContext的refresh()作为入口,找到finishBeanFactoryInitialization()方法,这个方法的作用是实例化非懒加载的Bean实例。那么我们就可以进入AbstractBeanFactory的getBean()方法。

@Override
  public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
  }
  @Override
  public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
    return doGetBean(name, requiredType, null, false);
  }
  @Override
  public Object getBean(String name, Object... args) throws BeansException {
    return doGetBean(name, null, args, false);
  }
复制代码

下面来看看doGetBean()方法:

protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
      throws BeansException {
    // 转换一下,比如有别名、&开头的名字等这些请求,全部都转换成统一的beanName
    String beanName = transformedBeanName(name);
    Object 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 + "'");
        }
      }
      // 扩展点---------扩展点-----------扩展点-------------
      // 判断name是不是&开头的,如果是&开头的话,并且sharedInstance是FactoryBean类型,就直接返回
      // 如果不是&开头,也不是FactoryBean类型,直接返回
      // 如果不是&开头,是FactoryBean类型,调用getObject()方法返回Bean对象
      // 也就是说,我们可以通过实现FactoryBean来创建Bean对象
      bean = 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);
      }
      // 下面是从父容器中找对应的Bean实例
      // 注意:容器是存在父子关系的。spring mvc就是一个父子关系的容器
      // 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);
      }
      // 下面准备查找当前Bean对象依赖的其他Bean。比如在创建当前这个Bean之前必须要创建另外一个Bean
      try {
        RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        checkMergedBeanDefinition(mbd, beanName, args);
        // 找到所有在这个Bean创建之前一定要创建出来的依赖,依次调用getBean()创建
        // 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);
            }
          }
        }
        // Create bean instance.
        if (mbd.isSingleton()) {
          // ******这是重点******这是重点******这是重点******这是重点******
          // 这里理解起来有点绕。注意这个getSingleton(String beanName,ObjectFactory<?> singletonFactory)方法。
          // 第二个参数使用lamble表达式,可以先忽略
          // getSingleton()里面就做了两件事情:
          // 1.通过lamble表达式创建Bean对象
          // 2.把创建好的Bean对象放到一级缓存中
          // 最后返回创建好的Bean对象
          sharedInstance = getSingleton(beanName, () -> {
            try {
              // 一定要先理清楚getSingleton()方法,再来看createBean()方法
              // ******这是重点******这是重点******这是重点******这是重点*****
              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;
            }
          });
          // 同样的,检查一下是不是FactoryBean,并且name是否以&开头
          // 扩展点---------扩展点-----------扩展点-------------
          // 判断name是不是&开头的,如果是&开头的话,并且sharedInstance是FactoryBean类型,就直接返回
          // 如果不是&开头,也不是FactoryBean类型,直接返回
          // 如果不是&开头,是FactoryBean类型,调用getObject()方法返回Bean对象
          // 也就是说,我们可以通过实现FactoryBean来创建Bean对象
          bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
        // 其实到这里就可以不用看非单例的情况了,因为基本都差不多。重点关注如何创建Bean对象。
        else if (mbd.isPrototype()) {
          // It's a prototype -> create a new instance.
          Object prototypeInstance = null;
          try {
            beforePrototypeCreation(beanName);
            // 还是创建Bean对象,这是重点
            // ******这是重点******这是重点******这是重点******这是重点*****
            prototypeInstance = createBean(beanName, mbd, args);
          }
          finally {
            afterPrototypeCreation(beanName);
          }
          // 同上,检查是否是FactoryBean
          bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
        }
        // 这里也一样,其他scope,重点还是在createBean()
        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);
              }
            });
            bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
          }
          catch (IllegalStateException ex) {
            throw new BeanCreationException(beanName,
                "Scope '" + scopeName + "' is not active for the current thread; consider " +
                "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                ex);
          }
        }
      }
      catch (BeansException ex) {
        cleanupAfterBeanCreationFailure(beanName);
        throw ex;
      }
    }
  //下面都不是重点,可忽略
    // Check if required type matches the type of the actual bean instance.
    if (requiredType != null && !requiredType.isInstance(bean)) {
      try {
        T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
        if (convertedBean == null) {
          throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
        return convertedBean;
      }
      catch (TypeMismatchException ex) {
        if (logger.isTraceEnabled()) {
          logger.trace("Failed to convert bean '" + name + "' to required type '" +
              ClassUtils.getQualifiedName(requiredType) + "'", ex);
        }
        throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
    }
    return (T) bean;
  }
复制代码

下面简单分析一下getSingleton():

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    synchronized (this.singletonObjects) {
      // 先从一级缓存中取,先试试
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
        if (this.singletonsCurrentlyInDestruction) {
          throw new BeanCreationNotAllowedException(beanName,
              "Singleton bean creation not allowed while singletons of this factory are in destruction " +
              "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
        }
        if (logger.isDebugEnabled()) {
          logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
        }
        // 这不用看,就是做一个数据校验
        beforeSingletonCreation(beanName);
        boolean newSingleton = false;
        boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
        if (recordSuppressedExceptions) {
          this.suppressedExceptions = new LinkedHashSet<>();
        }
        try {
          // ******这是重点******这是重点******这是重点******这是重点*****
          // 这里就是调用lamble表示式里面的逻辑了,千万要理清楚
          // lamble表达式里面就是做了createBean()的逻辑
          singletonObject = singletonFactory.getObject();
          newSingleton = true;
        }
        // 处理创建Bean对象出异常的情况,不用管
        catch (IllegalStateException ex) {
          // Has the singleton object implicitly appeared in the meantime ->
          // if yes, proceed with it since the exception indicates that state.
          singletonObject = this.singletonObjects.get(beanName);
          if (singletonObject == null) {
            throw ex;
          }
        }
        catch (BeanCreationException ex) {
          if (recordSuppressedExceptions) {
            for (Exception suppressedException : this.suppressedExceptions) {
              ex.addRelatedCause(suppressedException);
            }
          }
          throw ex;
        }
        finally {
          if (recordSuppressedExceptions) {
            this.suppressedExceptions = null;
          }
          afterSingletonCreation(beanName);
        }
        if (newSingleton) {
          // 最后就是把创建好的Bean对象放到一级缓存中。因为这个Bean对象已经是可以安全发布的了。
          addSingleton(beanName, singletonObject);
        }
      }
      // 返回创建好的Bean对象
      return singletonObject;
    }
  }
复制代码

核心重点createBean()方法:

@Override
  protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
    if (logger.isTraceEnabled()) {
      logger.trace("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;
    // Make sure bean class is actually resolved at this point, and
    // clone the bean definition in case of a dynamically resolved Class
    // which cannot be stored in the shared merged bean definition.
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
    }
    // Prepare method overrides.
    try {
      mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
          beanName, "Validation of method overrides failed", ex);
    }
    try {
      // ********重点1,这是一个扩展点,此时还没有任何Bean实例被创建出来
      // ********这里就是把Bean的创建机会开放给开发者
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
        return bean;
      }
    }
    catch (Throwable ex) {
      throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
          "BeanPostProcessor before instantiation of bean failed", ex);
    }
    try {
      // 如果开发者自己不创建Bean对象,那么就spring自己来亲自处理
      // 重点2,这是spring框架创建Bean的过程
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isTraceEnabled()) {
        logger.trace("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
      // A previously detected exception with proper bean creation context already,
      // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
      throw ex;
    }
    catch (Throwable ex) {
      throw new BeanCreationException(
          mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    }
  }
复制代码

扩展点1:开发者自己创建Bean

@Nullable
  protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
      // Make sure bean class is actually resolved at this point.
      if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        Class<?> targetType = determineTargetType(beanName, mbd);
        if (targetType != null) {
          // 这里就是创建Bean的入口
          bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
          if (bean != null) {
            // 如果真的把Bean实例创建出来了,那么再继续后续的生命周期的逻辑调用
            bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
          }
        }
      }
      mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
  }
@Nullable
  protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
      // 一定要是InstantiationAwareBeanPostProcessor的实现类,才会在Bean没有实例化的时候被调用
      if (bp instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
        if (result != null) {
          return result;
        }
      }
    }
    return null;
  }
@Override
  public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
      throws BeansException {
    Object result = existingBean;
    // 这里面可以对已经创建出来的Bean实例增强
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
      Object current = processor.postProcessAfterInitialization(result, beanName);
      if (current == null) {
        return result;
      }
      result = current;
    }
    return result;
  }
复制代码

1.实现了InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation()方法,就有机会自己创建Bean对象

2.实现了BeanPostProcessor接口的postProcessAfterInitialization()方法就能在Bean对象创建出来后,还有机会对创建出来的Bean对象进行增强或者扩展。注意:可以在这个点做AOP增强。



相关文章
|
4天前
|
XML Java 数据格式
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
这篇文章是Spring5框架的实战教程,主要介绍了如何在Spring的IOC容器中通过XML配置方式使用外部属性文件来管理Bean,特别是数据库连接池的配置。文章详细讲解了创建属性文件、引入属性文件到Spring配置、以及如何使用属性占位符来引用属性文件中的值。
Spring5入门到实战------7、IOC容器-Bean管理XML方式(外部属性文件)
|
4天前
|
XML Java 数据格式
Spring5入门到实战------4、IOC容器-Bean管理XML方式、集合的注入(二)
这篇文章是Spring5框架的实战教程,主题是IOC容器中Bean的集合属性注入,通过XML配置方式。文章详细讲解了如何在Spring中注入数组、List、Map和Set类型的集合属性,并提供了相应的XML配置示例和Java类定义。此外,还介绍了如何在集合中注入对象类型值,以及如何使用Spring的util命名空间来实现集合的复用。最后,通过测试代码和结果展示了注入效果。
Spring5入门到实战------4、IOC容器-Bean管理XML方式、集合的注入(二)
|
4天前
|
XML Java 数据格式
Spring5入门到实战------6、IOC容器-Bean管理XML方式(自动装配)
这篇文章是Spring5框架的入门教程,详细讲解了IOC容器中Bean的自动装配机制,包括手动装配、`byName`和`byType`两种自动装配方式,并通过XML配置文件和Java代码示例展示了如何在Spring中实现自动装配。
Spring5入门到实战------6、IOC容器-Bean管理XML方式(自动装配)
|
4天前
|
XML Java 数据格式
Spring5入门到实战------5、IOC容器-Bean管理(三)
这篇文章深入探讨了Spring5框架中IOC容器的高级Bean管理,包括FactoryBean的使用、Bean作用域的设置、Bean生命周期的详细解释以及Bean后置处理器的实现和应用。
Spring5入门到实战------5、IOC容器-Bean管理(三)
|
4天前
|
XML Java 数据格式
Spring5入门到实战------3、IOC容器-Bean管理XML方式(一)
这篇文章详细介绍了Spring框架中IOC容器的Bean管理,特别是基于XML配置方式的实现。文章涵盖了Bean的定义、属性注入、使用set方法和构造函数注入,以及如何注入不同类型的属性,包括null值、特殊字符和外部bean。此外,还探讨了内部bean的概念及其与外部bean的比较,并提供了相应的示例代码和测试结果。
Spring5入门到实战------3、IOC容器-Bean管理XML方式(一)
|
4天前
|
XML Java 数据格式
Spring5入门到实战------8、IOC容器-Bean管理注解方式
这篇文章详细介绍了Spring5框架中使用注解进行Bean管理的方法,包括创建Bean的注解、自动装配和属性注入的注解,以及如何用配置类替代XML配置文件实现完全注解开发。
Spring5入门到实战------8、IOC容器-Bean管理注解方式
|
23天前
|
Java Spring 容器
Spring Boot 启动源码解析结合Spring Bean生命周期分析
Spring Boot 启动源码解析结合Spring Bean生命周期分析
60 11
|
16天前
|
Java Spring
Spring的Bean生命周期中@PostConstruct注解
【8月更文挑战第3天】在Spring框架中,`@PostConstruct`注解标示Bean初始化完成后立即执行的方法。它在依赖注入完成后调用,适用于资源加载、属性设置等初始化操作。若方法中抛出异常,可能影响Bean初始化。与之对应,`@PreDestroy`注解的方法则在Bean销毁前执行,用于资源释放。
|
21天前
|
IDE Java 开发工具
解决非Spring Bean访问Spring Bean的问题:实用指南
在非SpringBean类中直接获取SpringBean可能会引发问题,例如上面案例里提到的空指针和自动装配失败。为避免这些问题,建议将需要访问Spring Bean的类也注册为Spring Bean,以确保依赖关系得到正确管理。
15 0