Spring IoC容器的依赖注入源码解析(4)—— Bean的创建(createBean)

 2023-02-04
原文作者:小王曾是少年 原文地址:https://juejin.cn/post/7032095539818659854

createBean方法的执行流程如下:

202301012100134221.png 在AbstractBeanFactory的doGetBean的创建bean的方法里打上断点:

202301012100155412.png 多放行几次看到了自定义的bean:

202301012100161663.png step into之后来到AbstractAutowireCapableBeanFactor的createBean中:

    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 {
          // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
          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 {
          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);
       }
    }

最开始是BeanDefinition的定义,由于之前以及定义了BeanDefinition,所以要根据Definition的属性创建出来bean实例,这里用RootBeanDefinition接收容器中获取到的BeanDefinition实例。

    RootBeanDefinition mbdToUse = mbd;

接下来尝试会用类加载器加载出class对象

    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

进入到resolveBeanClass

    protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
          throws CannotLoadBeanClassException {
    
       try {
          if (mbd.hasBeanClass()) {
             return mbd.getBeanClass();
          }
          if (System.getSecurityManager() != null) {
             return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ->
                doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
          }
          else {
             return doResolveBeanClass(mbd, typesToMatch);
          }
       }
       catch (PrivilegedActionException pae) {
          ClassNotFoundException ex = (ClassNotFoundException) pae.getException();
          throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
       }
       catch (ClassNotFoundException ex) {
          throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex);
       }
       catch (LinkageError err) {
          throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err);
       }
    }

如果是注解方式定义的话,会执行

    if (mbd.hasBeanClass()) {
       return mbd.getBeanClass();
    }

如果是xml方式定义的话,会执行来做解析的工作

    doResolveBeanClass(mbd, typesToMatch);

doResolveBeanClass方法里有很多classLoader,即调用事先保存的各种各样的类加载器去尝试加载class对象,由于class对象和类加载器一一对应,所以class对象会存在于其中的一个类加载器中,通过该加载器找到了对应的class对象之后,就会用对应的classLoader加载出对象来


回到createBean,下面如果获取到的class对象不为空,并且当前的BeanDefinition在解析之前没有class对象,但是却有className时(对应xml方式),此时就会拷贝一个RootBeanDefinition的副本,然后给这个副本设置上先前解析出来的class对象实例。

这样做的目的是不希望将解析的class绑定到缓存里的BeanDefinition,因为class有可能是每次都需要动态解析出来的。

    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
       mbdToUse = new RootBeanDefinition(mbd);
       mbdToUse.setBeanClass(resolvedClass);
    }

注解方式不会执行上面那个if,所以会来到下面这个逻辑

    mbdToUse.prepareMethodOverrides();

该方法判断BeanDefinition是否有定义方法的覆盖

    public void prepareMethodOverrides() throws BeanDefinitionValidationException {
       // Check that lookup methods exist and determine their overloaded status.
       if (hasMethodOverrides()) {
          getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
       }
    }

prepareMethodOverride先获取需要覆盖的方法数量,如果count==1则不存在重载,在使用CGLIB增强阶段就不需要进行校验了,直接找到某个方法进行增强即可,否则在增强阶段还需要做特殊的处理

    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.
          mo.setOverloaded(false);
       }
    }

样例:

    <bean id="my TestBean" class="io.spring.test.MyTestBean">
        <lookup-method name="getUserBean" bean="teacher"/> 
        <reblaced-method name="changedMethod" replacer="replacer"/> 
    </bean> 
    
    <bean id="teacher" class="io.spring.test.Teacher"/> 
    <bean id="student" class="io.spring.test.Student"/> 
    <bean id="replacer" class="io.spring.test.Replacer"/>

对于replaced-method,会去验证一下MyTestBean里是否有changedMethod这个即将被替换的方法,对于lookup-method,如果该属性存在,则会去判断一下Teacher这个bean里是否有getUserBean这个方法,没有则报错。


回到createBean,通过方法覆盖验证之后来到

    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

主要是执行某些类型的后置处理器的操作。

    @Nullable
    protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
       Object bean = null;
       // 如果beforeInstantiationResolved还没有设置或者是false(说明还没有进行需要在实例化前执行的操作)
       if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
          // Make sure bean class is actually resolved at this point.
          // mbd.isSyntheticO默认是false
          // 如果注册了InstantiationAwareBeanPostProcessors类型的BeanPostProcessor
          if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
             Class<?> targetType = determineTargetType(beanName, mbd);
             if (targetType != null) {
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                   bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
             }
          }
          mbd.beforeInstantiationResolved = (bean != null);
       }
       return bean;
    }

Spring在AOP过程中产生的中间代理类就是isSynthetic的,此时的targetType是自己定义的WelcomeController,进入到applyBeanPostProcessorsBeforeInstantiation方法里:

    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;
    }

这里使用了责任链模式(Spring中的后置器基本都会使用责任链模式来处理),依次遍历实现了InstantiationAwareBeanPostProcessor接口的BeanPostProcessor实现类,并调用类里面的postProcessBeforeInstantiation看看谁来负责对bean实例的创建,如果去处理了并有了结果,就会立即返回,只要某一个后置处理器返回了结果,就会阻止后面后置处理器的执行。

只要

    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

可以获取到bean实例,则会终止后续创建bean的流程,此时就表明bean实例的创建被用户接管了,Spring容器可以不用去创建了。

继续resolveBeforeInstantiation,如果bean实例已经被创建出来的话,就会执行

    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);

前面按理说已经执行了初始化,所以这里就应该执行初始化之后的操作,进入到applyBeanPostProcessorsAfterInitialization:

    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;
    }

同样使用了责任链模式,但相比先前这里不局限于InstantiationAwareBeanPostProcessor,而是所有的BeanPostProcessor,只要前一个执行返回结果,当前就可以拿到上一次执行后的结果,直到获取不到结果就返回。

Spring中的拦截器都是用到了后置处理器,使用责任链的模式来层层处理。

resolveBeforeInstantiation最后如果bean不会空则就打上已经处理过的标记。


回到createBean,此时会来到doCreateBean来让Spring创建Bean容器了。

202301012100167574.png