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

本文阅读 5 分钟
首页 代码,Java 正文

createBean方法的执行流程如下: img 在AbstractBeanFactory的doGetBean的创建bean的方法里打上断点: img 多放行几次看到了自定义的bean: img 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容器了。 img

本文为互联网自动采集或经作者授权后发布,本文观点不代表立场,若侵权下架请联系我们删帖处理!文章出自:https://wangjiawei.blog.csdn.net/article/details/121404464
-- 展开阅读全文 --
安全面试之XSS(跨站脚本攻击)
« 上一篇 07-24

发表评论

成为第一个评论的人

热门文章

标签TAG

最近回复