bean 的加载(二)

之前文章次要对 getBean 办法进行简略的介绍,和 FactoryBean 的作用,以及是如何从缓存中获取 bean。本文持续解说 bean 的加载流程。

从 bean 的实例中获取对象

在 getBean 办法里,getObjectForBeanInstance()是个罕用的办法,无论是从缓存中获取 bean 还是依据不同 scope 策略来加载 bean。总而言之,咱们在获取到 bean 实例后第一步就是调用这个办法来检测正确性,其实就是检测以后 bean 是否为 FactoryBean 类型的 bean,如果是则调用 FactoryBean 实例的 getObject()作为返回值。

须要留神的是无论是缓存中获取到的 bean 还是通过 scope 策略加载的 bean 都是原始的 bean 状态,咱们须要的是工厂 bean 中定义 factory-method 办法中返回的 bean,而 getObjectForBeanInstance 办法就是实现这个工作的。

protected Object getObjectForBeanInstance(      Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {   //如果指定的name是工厂相干以"&"为前缀,并且beanInstance又不是FactoryBean则校验不通过   if (BeanFactoryUtils.isFactoryDereference(name)) {      if (beanInstance instanceof NullBean) {         return beanInstance;      }      if (!(beanInstance instanceof FactoryBean)) {         throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());      }      if (mbd != null) {         mbd.isFactoryBean = true;      }      return beanInstance;   }   //当初咱们有了这个bean实例,这个实例可能是FactoryBean,也可能是失常的bean   //如果是FactoryBean的话,咱们应用它创立实例,但如果是用户想要间接获取工厂实例而不是工厂的getObject办法则须要在BeanName前加上"&"   if (!(beanInstance instanceof FactoryBean)) {      return beanInstance;   }   //加载FactoryBean   Object object = null;   if (mbd != null) {      mbd.isFactoryBean = true;   }   else {      //尝试从缓存中加载bean      object = getCachedObjectForFactoryBean(beanName);   }   if (object == null) {      // 执行到这里表明beanInstance肯定是一个FactoryBean      FactoryBean<?> factory = (FactoryBean<?>) beanInstance;      // containsBeanDefinition检测BeanDefinitionMap中也就是在所有一键加载的类中检测是否定义beanName      if (mbd == null && containsBeanDefinition(beanName)) {         //将GenericBeanDefinition转换为RootBeanDefinition,如果指定BeanName是子bean的话同时会合并父类的属性         mbd = getMergedLocalBeanDefinition(beanName);      }      //是否是用户定义的而不是应用程序自身定义的      boolean synthetic = (mbd != null && mbd.isSynthetic());      object = getObjectFromFactoryBean(factory, beanName, !synthetic);   }   return object;}

咱们先看一下 getObjectForBeanInstance 次要做了什么:

  • 对 FactoryBean 正确性进行验证
  • 对非 FactoryBean 不作任何解决
  • 对 bean 进行转换
  • 将从 Factory 中解析 bean 的工作委托给了getObjectFromFactoryBean

该段代码大多都是辅助代码,真正的外围代码委托给了getObjectFromFactoryBean

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {   if (factory.isSingleton() && containsSingleton(beanName)) {      synchronized (getSingletonMutex()) {         Object object = this.factoryBeanObjectCache.get(beanName);         if (object == null) {               //重点办法 doGetObjectFromFactoryBean            object = doGetObjectFromFactoryBean(factory, beanName);            //...省略   }   else {      //重点办法 doGetObjectFromFactoryBean      Object object = doGetObjectFromFactoryBean(factory, beanName);      if (shouldPostProcess) {         try {            object = postProcessObjectFromFactoryBean(object, beanName);         }         catch (Throwable ex) {            throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);         }      }      return object;   }}

这段代码就是返回的 bean 如果是单例的则须要保障全局惟一,也正因为是单例的所以不用反复创立,能够用缓存来进步性能。

咱们进入doGetObjectFromFactoryBean办法中。

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)      throws BeanCreationException {   Object object;   try {      //是否须要权限校验      if (System.getSecurityManager() != null) {         AccessControlContext acc = getAccessControlContext();         try {            object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);         }         catch (PrivilegedActionException pae) {            throw pae.getException();         }      }      else {         //间接调用getObject办法(重点)         object = factory.getObject();      }   }   catch (FactoryBeanNotInitializedException ex) {      throw new BeanCurrentlyInCreationException(beanName, ex.toString());   }   catch (Throwable ex) {      throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);   }   // Do not accept a null value for a FactoryBean that's not fully   // initialized yet: Many FactoryBeans just return null then.   if (object == null) {      if (isSingletonCurrentlyInCreation(beanName)) {         throw new BeanCurrentlyInCreationException(               beanName, "FactoryBean which is currently in creation returned null from getObject");      }      object = new NullBean();   }   return object;}

在该办法中,咱们终于看到了想要看到的代码,也就是object = factory.getObject()。之前咱们曾经讲过了 FactoryBean 的调用办法,如果 bean 是 FactoryBean 类型,则当提取 bean 时提取的并不是 factoryBean 而是 factoryBean 的 getObject 办法的返回值。

获取单例

之前咱们说过如果缓存中不存在曾经加载的 bean 则须要重头开始 bean 的加载,在 Spring 中应用 getSingleton 的重载办法实现了 bean 的加载过程。

getBean 办法:
// 实例化依赖的bean后就能够实例化mbd自身了// 如果BeanDefinition为单例if (mbd.isSingleton()) {   //创立Bean实例对象,并且注册给所依赖的对象   sharedInstance = getSingleton(beanName, () -> {      try {         return createBean(beanName, mbd, args);      }      catch (BeansException ex) {         //从单例缓存中删除bean实例         //因为单例模式下为了解决循环依赖,可能它曾经存在了,所以将其销毁         destroySingleton(beanName);         throw ex;      }   });   //如果是一般bean,间接返回,如果是FactoryBean,则返回它的getObject   bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}

进入 getSingleton 办法:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {   Assert.notNull(beanName, "Bean name must not be null");   //加锁   synchronized (this.singletonObjects) {      //首先查看对应的bean是否曾经加载过,      Object singletonObject = this.singletonObjects.get(beanName);      //如果为空则须要进行singleton的bean初始化      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 + "'");         }         //代码(1)         beforeSingletonCreation(beanName);         boolean newSingleton = false;         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);         if (recordSuppressedExceptions) {            this.suppressedExceptions = new LinkedHashSet<>();         }         try {            // 通过回调形式获取bean实例。            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.            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;            }            //代码(2)            afterSingletonCreation(beanName);         }         if (newSingleton) {            //退出缓存 代码(3)            addSingleton(beanName, singletonObject);         }      }      return singletonObject;   }}

上述代码应用了回调办法,在单例创立的前后做了些筹备及解决操作,而真正获取单例 bean 的办法是在 ObjectFactory 类型的实例 singletonFactory 中。咱们先看一下 getSingleton 办法次要做了什么:

  1. 查看缓存是否曾经加载过
  2. 若没有加载,则记录 beanName 为正在加载状态
  3. 加载单例前记录加载状态,代码(1)
protected void beforeSingletonCreation(String beanName) {   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {      throw new BeanCurrentlyInCreationException(beanName);   }}

这个办法次要做的就是记录加载状态,this.singletonsCurrentlyInCreation.add(beanName)将以后正要创立的 bean 记录在缓存中,这样就能够对循环依赖进行检测。

  1. 获取 bean 实例
  2. 调用加载单例后的解决办法,代码(2)
protected void afterSingletonCreation(String beanName) {   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {      throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");   }}

和上述相似,只是这里是从缓存中移除 bean 的正在加载状态。

  1. 将 bean 退出缓存,并删除加载 bean 过程中所记录的各种辅助状态。
protected void addSingleton(String beanName, Object singletonObject) {   synchronized (this.singletonObjects) {      this.singletonObjects.put(beanName, singletonObject);      this.singletonFactories.remove(beanName);      this.earlySingletonObjects.remove(beanName);      this.registeredSingletons.add(beanName);   }}
  1. 返回处理结果

当初咱们曾经理解了 bean 的逻辑架构,然而 bean 的加载逻辑是在传入 ObjectFactory 类型的参数 singletonFactory 中定义的。

//创立Bean实例对象,并且注册给所依赖的对象sharedInstance = getSingleton(beanName, () -> {   try {      return createBean(beanName, mbd, args);   }   catch (BeansException ex) {      //从单例缓存中删除bean实例      //因为单例模式下为了解决循环依赖,可能它曾经存在了,所以将其销毁      destroySingleton(beanName);      throw ex;   }});

咱们进入 createBean 办法中持续查看。

筹备创立 bean

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,依据设置的class属性或者依据className来解析Class   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 {      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.      //给BeanPostProcessors一个机会来返回代理用于代替真正的实例      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 {      //代码(1)      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. 依据设置的 class 属性或者依据 className 来解析 Class
  2. 对 override 属性进行标记及验证

咱们晓得在 Spring 的配置中并没有相似于 override-methdo 之类的配置,那么该办法的作用是什么?

咱们之前说过 Spring 配置中存在 lookup-method 和 replace-method 的,这两个配置的加载就是将配置对立寄存在 BeanDefinition 中的 methodOverrides 属性中,而这个函数其实也就是针对这两个配置的。

  1. 利用初始化前的后处理器,解析指定 bean 是否存在初始化前的短路操作
  2. 创立 bean

咱们先看一下 override 属性标记及验证的逻辑实现

解决 override 属性

进入 prepareMethodOverrides 办法:

public void prepareMethodOverrides() throws BeanDefinitionValidationException {   // Check that lookup methods exist and determine their overloaded status.   if (hasMethodOverrides()) {      getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);   }}
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {   // 获取对应类中对应办法名的个数   int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());   if (count == 0) {      throw new BeanDefinitionValidationException(            "Invalid method override: no method with name '" + mo.getMethodName() +            "' on class [" + getBeanClassName() + "]");   }   else if (count == 1) {      // Mark override as not overloaded, to avoid the overhead of arg type checking.      // 标记MethodOverride暂未被笼罩,防止参数类型查看的开销      mo.setOverloaded(false);   }}

方才说到 lookup-method 和 replace-method 两个配置性能是对立寄存在 BeanDefinition 中的 methodOverrides 属性中,这两个性能实现原理就是在 bean 实例化的时候如果检测到存在 methodOverrides 属性,就会动静地为以后 bean 生成代理并应用对应的拦截器对 bean 做加强解决。

须要提到的是,对于办法的匹配来说,如果一个类中有多个重载办法则须要依据参数类型进行匹配。如果类中只有办法只有一个那么就设置该办法没有被重载,这样在后续时候能够间接应用找到的办法,不须要进行办法的参数匹配验证,而且还能够提前对办法存在性进行验证,所谓一举两得。

实例化的前置解决

在调用 doCreateBean 之前,还应用了 resolveBeforeInstantiation(beanName, mbdToUse)办法对 BeanDefinition 中的属性做些前置解决。

Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {   return bean;}

该段代码的重点就是这个 if 条件,当处理结果不为 null 的时候就会跳过后续 bean 的创立间接返回后果。咱们熟知的 AOP 性能就是基于这里判断的。

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) {                    //代码(1)                    bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);                    if (bean != null) {                        //代码(2)                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);                    }                }            }            mbd.beforeInstantiationResolved = (bean != null);        }        return bean;}

该办法中的重点就是这两个办法:applyBeanPostProcessorsBeforeInstantiation、applyBeanPostProcessorsAfterInitialization。这两个办法实现都很简略,就是对后处理器中所有的 InstantiationAwareBeanPostProcessor 类型的后处理器进行 postProcessBeforeInstantiation 办法和 BeanPostProcessor 的 postProcessAfterInitialization 办法的调用。

1. 实例化前的后处理器利用

bean 的实例化前调用,也就是将 AbstractBeanDefinition 转换为 BeanWrapper 前的解决。给子类一个批改 BeanDefinition 的机会,也就是调用这个办法后 bean 就有可能产生变动,有可能是通过解决的代理 bean,也可能是 cglib 生成的。后续会具体介绍,当初只须要明确在 bean 实例化前会调用后处理器的办法进行解决。

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {   for (BeanPostProcessor bp : getBeanPostProcessors()) {      if (bp instanceof InstantiationAwareBeanPostProcessor) {         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;         Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);         if (result != null) {            return result;         }      }   }   return null;}

2. 实例化后的后处理器利用

Spring 的规定是在 bean 初始化后尽可能保障将注册的后处理器 postProcessAfterInitialization 办法利用到 bean 中,如果返回的 bean 不为空,则不须要再经验 bean 的创立过程。

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)      throws BeansException {   Object result = existingBean;   for (BeanPostProcessor processor : getBeanPostProcessors()) {      Object current = processor.postProcessAfterInitialization(result, beanName);      if (current == null) {         return result;      }      result = current;   }   return result;}