【小家Spring】AbstractBeanFactory#getBean()、doGetBean完成Bean的初始化、实例化,以及BeanPostProcessor后置处理器源码级详细分析(上)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【小家Spring】AbstractBeanFactory#getBean()、doGetBean完成Bean的初始化、实例化,以及BeanPostProcessor后置处理器源码级详细分析(上)

前言


这边博文,主要讲解我们Spring IOC容器的主菜:Bean的实例化、初始化。

通过之前跟踪Spring IOC刷新的源码,我们所有的剩余的单例Bean都是通过这一步:finishBeanFactoryInitialization(beanFactory);来进行初始化的。最重要的一个方法就为:DefaultListableBeanFactory#preInstantiateSingletons

其内部核心方法为:getBean --> doGetBean方法


Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)

Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)

Spring源码基于的Spring版本为:5.0.6.RELEASE(下同)


getBean方法概述


getBean()是顶层接口BeanFactory提供的,一共有五个原型:

Object getBean(String name) throws BeansException;
<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
// Spring2.5以后才有的接口
Object getBean(String name, Object... args) throws BeansException;
// Spring3.0以后才有的接口
<T> T getBean(Class<T> requiredType) throws BeansException;
// Spring4.1以后才有的接口
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;


说明:很多人都不理解这个args是干什么用的,这里解释一下。首先我们要明白,getBean()内部不仅仅是get,如果get不到还可能去实例化一个Bean的(默认根据空构造函数进行实例化),因此本处的args其实就是为了匹配构造函数而提供的扩展功能~


使用前提:

1、传入的参数必须有相对应的构造函数入参与之匹配

2、bean的scope必须设置成prototype,因为动态传参话bean不可以是单例的


AbstractBeanFactory作为抽象实现,复写了其中3个方法:

  @Override
  public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
  }
  @Override
  public <T> T getBean(String name, @Nullable 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,就是Bean实例化的核心逻辑


DefaultListableBeanFactory继承自AbstractBeanFactory,复写了剩余的2个方法:


  @Override
  public <T> T getBean(Class<T> requiredType) throws BeansException {
    return getBean(requiredType, (Object[]) null);
  }
  // 上面那个方法是调用这个方法的逻辑。
  @Override
  public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {]
    // resolveNamedBean里面的逻辑,也是根据requiredType去找的。若不止一个会抛错:NoUniqueBeanDefinitionException
    NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args);
    if (namedBean != null) {
      return namedBean.getBeanInstance();
    }
    // 从这里我们可以看到,如果子容器里没有找到Bean,还回去父容器(若存在的话)里找找看
    BeanFactory parent = getParentBeanFactory();
    if (parent != null) {
      return (args != null ? parent.getBean(requiredType, args) : parent.getBean(requiredType));
    }
    throw new NoSuchBeanDefinitionException(requiredType);
  }


那么接下里,我们就得看看这里面最最核心的逻辑:doGetBean()


AbstractBeanFactory#doGetBean


依赖注入主要有两个过程,一个是实例化Bean,另一个是将依赖关系注入到Bean中


从命名上我们也可以看出:他是doGetBean,是有do这个动作的。因此不是简单的get有就返回,没有就返回null这么简单的操作。而是里面做了实例化、依赖注入、属性赋值、解决循环依赖等一些列操作~


先贴上源码(本方法源码不可为不长,超过150行):

  protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
      @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    // 该方法作用:1、 如果是FactoryBean,会去掉Bean开头的&符号
    // 2、能存在传入别名且别名存在多重映射的情况,这里会返回最终的名字,如存在多层别名映射A->B->C->D,传入D,最终会返回A
    final String beanName = transformedBeanName(name);
    Object bean;
    // Eagerly check singleton cache for manually registered singletons.
    // getSingleton()方法的实现,在父类DefaultSingletonBeanRegistry中,请先移步下面,看详解
    //这里先尝试从缓存中获取,若获取不到,就走下面的创建
    // 特别注意的是:这里面走创建(发现是个new的),就加入进缓存里面了 if (newSingleton) {addSingleton(beanName, singletonObject);}   缓存的字段为全局的Map:singletonObjects
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
      if (logger.isDebugEnabled()) {
        // 这里虽然只是一句日志,但是能说明用意。
        // 若条件为true,表示这个Bean虽然在缓存里,但是还并没有完全被初始化(循环引用)
        if (isSingletonCurrentlyInCreation(beanName)) {
          logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
              "' that is not fully initialized yet - a consequence of a circular reference");
        } else {
          logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
        }
      }
      // 在getBean方法中,getObjectForBeanInstance是个频繁使用的方法。因此为了更好的知道细节,下面会详解这个方法的
      // 其实简单理解就是处理FactoryBean的getObject()方法
      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);
      }
      // Check if bean definition exists in this factory.
      // 这一步也是必须要做的,若存在父容器,得看看父容器是否实例化过它了。避免被重复实例化(若父容器被实例化,就以父容器的为准)
      // 这就是为何,我们扫描controller,哪怕不加排除什么的,也不会出问题的原因~,因为Spring中的单例Bean只会被实例化一次(即使父子容器都扫描了)
      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 {
          // No args -> delegate to standard getBean method.
          return parentBeanFactory.getBean(nameToLookup, requiredType);
        }
      }
      //alreadyCreated字段增加此值。表示此Bean已经创建了
      // 备注,此处我们就以 `helloServiceImpl` 这个Bean的创建为例了~~~
      if (!typeCheckOnly) {
        markBeanAsCreated(beanName);
      }
      try {
        // 根据名字获取合并过的对应的RootBeanDefinition
        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        // 检查mbd是否为抽象的或mbd为单例,但存在args的情况(args只有初始化原型对象才允许存在)
        checkMergedBeanDefinition(mbd, beanName, args);
        // Guarantee initialization of beans that the current bean depends on.
        // 这里就重要了,因为我们会有属性注入等等  所以这里就是要保证它依赖的那些属性先初始化才行
        // 这部分是处理循环依赖的核心,这里稍微放一放。下面有大篇幅专门讲解这方面的以及原理解决方案
        // @DependsOn注解可以控制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);
            }
          }
        }
        // Create bean instance.
        // 从这里开始,就正式开始着手创建这个Bean的实例了~~~~
        if (mbd.isSingleton()) {
          // 也是一样先尝试从缓存去获取,获取失败就通过ObjectFactory的createBean方法创建
          // 这个getSingleton方法和上面是重载方法,它支持通过ObjectFactory去根据Scope来创建对象,具体源码解析见下面
          sharedInstance = getSingleton(beanName, () -> {
            try {
              // 这是创建Bean的核心方法,非常重要~~~~~~~~~~~~~~~下面会有
              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.
              // 执行失败,就销毁Bean。然后执行对应的destroy方法,等等销毁Bean时候的生命周期方法们~~~~~~~~~这个就不多说了   主要看看上面的createBean方法吧
              destroySingleton(beanName);
              throw ex;
            }
          });
          bean = 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);
          }
          bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
        }
        else {
          String scopeName = mbd.getScope();
          final 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.
    // 这里就比较简单了,就是requiredType,比如要求是Integer,获得的是String,俺么就会调用转换器转换过来
    // 绝大多数情况下,没啥卵用
    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.isDebugEnabled()) {
          logger.debug("Failed to convert bean '" + name + "' to required type '" +
              ClassUtils.getQualifiedName(requiredType) + "'", ex);
        }
        throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
    }
    return (T) bean;
  }

DefaultSingletonBeanRegistry#getSingleton详解:


  @Override
  @Nullable
  public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
  }
  @Nullable
  protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 此处是先从已经缓存好了的singletonObjects的Map中,查看有木有(至于当前已经有哪些了,下面有个截图,相信什么时候进来的都应该有些印象吧)
    Object singletonObject = this.singletonObjects.get(beanName);
    // 若缓存里没有。并且,并且,并且这个Bean必须在创建中,才会进来。
    // singletonsCurrentlyInCreation字段含义:会缓存下来所有的正在创建中的Bean,如果有Bean是循环引用的  会把这种Bean先放进去,这里才会有值
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) {
          ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
          if (singletonFactory != null) {
            singletonObject = singletonFactory.getObject();
            this.earlySingletonObjects.put(beanName, singletonObject);
            this.singletonFactories.remove(beanName);
          }
        }
      }
    }
    return singletonObject;
  }


image.png


DefaultSingletonBeanRegistry#getSingleton详解(根据ObjectFactory结合Scope来创建合适的对象)


  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) {
        // 如果这个Bean正在被销毁,就抛异常了
        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!)");
        }
        // 创建前置检查:1、若在inCreationCheckExclusions面校验名单里,是ok的
        //2、singletonsCurrentlyInCreation把它添加进去,证明这个Bean正在创建中
        beforeSingletonCreation(beanName);
        // 此处先打标机为为false
        boolean newSingleton = false;
        boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
        if (recordSuppressedExceptions) {
          this.suppressedExceptions = new LinkedHashSet<>();
        }
        try {
          // 把这个实例生成出来,并且标志位设为true
          singletonObject = singletonFactory.getObject();
          newSingleton = true;
        } catch (IllegalStateException ex) {
          // Has the singleton object implicitly appeared in the meantime ->
          // if yes, proceed with it since the exception indicates that state.
          // in the meantime再次旗舰,若有人已经把这个Bean放进去了,那就抛出这个异常吧
          singletonObject = this.singletonObjects.get(beanName);
          if (singletonObject == null) {
            throw ex;
          }
        } catch (BeanCreationException ex) {
          // 处理异常
          // 比如我们经常遇到的UnsatisfiedDependencyException异常:@Autowired的时候找不到依赖的Bean就是这个异常(一般由NoSuchBeanDefinitionException这个异常导致)
          // 这里会吧异常链接拼接起来,然后一起打印出来~~~~非常方便查找问题
          if (recordSuppressedExceptions) {
            for (Exception suppressedException : this.suppressedExceptions) {
              ex.addRelatedCause(suppressedException);
            }
          }
          throw ex;
        } finally {
          if (recordSuppressedExceptions) {
            this.suppressedExceptions = null;
          }
          // 创建完成后再检查一遍。做的操作为:从正在创建缓存中移除
          afterSingletonCreation(beanName);
        }
        // 这里也非常重要:若是新的Bean,那就执行addSingleton这个方法,这个方法做了什么,就下面4步操作:
        //this.singletonObjects.put(beanName, singletonObject); //缓存起来
        //this.singletonFactories.remove(beanName); //把对应ObjectFactory的缓存移除
        //this.earlySingletonObjects.remove(beanName);
        //this.registeredSingletons.add(beanName);
        if (newSingleton) {
          addSingleton(beanName, singletonObject);
        }
      }
      return singletonObject;
    }
  }


开始创建Bean AbstractAutowireCapableBeanFactory#createBean 提供此方法的抽象类为:AbstractBeanFactory,由子类去实现创建的逻辑。


  @Override
  protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
    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.
    // 确保对应BeanClass完成解析(已经加载进来了Class对象)具体表现是进行了ClassLoder.loadClass或Class.forName完成了类加载
    // 主要根据传入的typesToMatch生成特定的ClassLoader,之后还要调用RootBeanDefinition#resolveBeanClass,根据特定的加载器或者默认加载器加载出class属性对应的Class对象
    // 我们这里解析出来,显然就是class com.fsx.service.HelloServiceImpl这个Class了
    // 判断需要创建的Bean是否可以实例化,这个类是否可以通过类装载器来载入(也就说它甚至可能来源于网络)
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
    }
    // Prepare method overrides.
    try {
      // 这里主要是解析<lookup-method name="getFruit" bean="bananer"/>类似这种方式的依赖注入(Spring支持lookup-method,replace-method两个依赖注入的方式)
      // 它相当于调用指定类里面的指定方法进行注入,所以需要考虑到方法重载的情况,因此这个方法解析的就是这种情况
      // 由于项目中一般这么使用,也非常的不大众,具体原理此处省略
      mbdToUse.prepareMethodOverrides();
    } catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
          beanName, "Validation of method overrides failed", ex);
    }
    try {
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      // 从doc解释:给BeanPostProcessors一个机会来返回一个代理对象代替目标对象   什么动态代理之类的,都在这里实现的~~~~~~~~~~~~~~~~~~~
      // 1、具体逻辑是判断当前Spring容器是否注册了实现了InstantiationAwareBeanPostProcessor接口的后置处理器如果有,则依次调用其中的applyBeanPostProcessorsBeforeInstantiation方法,如果中间任意一个方法返回不为null,直接结束调用。
      // 2、然后依次所有注册的BeanPostProcessor的postProcessAfterInitialization方法(同样如果任意一次返回不为null,即终止调用。
      // 这个方法也非常的重要,后续有详细讲解
      // 容器里所有的InstantiationAwareBeanPostProcessors实例,都会在此处生效,进行前置处理~~~~~~~~~~
      // 下面有解释:BeanPostProcessor和InstantiationAwareBeanPostProcessor的区别,可以分清楚他们执行的时机
      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);
    }
    // 这里又是一个核心逻辑:doCreateBean 创建Bean
    try {
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      // 创建完成后 直接短路掉返回 
      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天前
|
XML Java 数据格式
spring复习02,xml配置管理bean
详细讲解了Spring框架中基于XML配置文件管理bean的各种方式,包括获取bean、依赖注入、特殊值处理、属性赋值、集合类型处理、p命名空间、bean作用域及生命周期和自动装配。
spring复习02,xml配置管理bean
|
1天前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
12 5
|
4天前
|
消息中间件 设计模式 缓存
spring源码设计模式分析(四)-观察者模式
spring源码设计模式分析(四)-观察者模式
|
1天前
|
XML Java 数据格式
spring复习03,注解配置管理bean
Spring框架中使用注解配置管理bean的方法,包括常用注解的标识组件、扫描组件、基于注解的自动装配以及使用注解后的注意事项,并提供了一个基于注解自动装配的完整示例。
spring复习03,注解配置管理bean
|
3天前
|
XML 存储 Java
Spring-源码深入分析(二)
Spring-源码深入分析(二)
|
3天前
|
XML 设计模式 Java
Spring-源码深入分析(一)
Spring-源码深入分析(一)
|
1月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
|
2月前
|
Java 测试技术 数据库
Spring Boot中的项目属性配置
本节课主要讲解了 Spring Boot 中如何在业务代码中读取相关配置,包括单一配置和多个配置项,在微服务中,这种情况非常常见,往往会有很多其他微服务需要调用,所以封装一个配置类来接收这些配置是个很好的处理方式。除此之外,例如数据库相关的连接参数等等,也可以放到一个配置类中,其他遇到类似的场景,都可以这么处理。最后介绍了开发环境和生产环境配置的快速切换方式,省去了项目部署时,诸多配置信息的修改。
|
2月前
|
Java 应用服务中间件 开发者
Java面试题:解释Spring Boot的优势及其自动配置原理
Java面试题:解释Spring Boot的优势及其自动配置原理
99 0
|
1天前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。