zoukankan      html  css  js  c++  java
  • 5.5 准备创建bean

    5.5  准备创建bean

      我们不可能指望在一个函数中完成一个复杂的逻辑,而且我们跟踪了这么多Spring代码,经历了这么多函数,或多或少也发现了一些规律:一个真正干活的函数其实是以do开头的,比如doGetObjectFromFactoryBean;而给我们错觉的函数,比如getObjectFromFactoryBean,其实只是从全局角度去做些统筹的工作。这个规则对于createBean也不例外,那么让我们看看在createBean函数中做了哪些准备工作。

     

     1 protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)    throws BeanCreationException {
     2 
     3          if (logger.isDebugEnabled()) {
     4              logger.debug("Creating instance of bean '" + beanName + "'");
     5          }
     6          //锁定class,根据设置的class属性或者根据className来解析Class
     7          resolveBeanClass(mbd, beanName);
     8 
     9          //验证及准备覆盖的方法
    10          try {
    11              mbd.prepareMethodOverrides();
    12          }
    13          catch (BeanDefinitionValidationException ex) {
    14              throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
    15                      beanName, "Validation of method overrides failed", ex);
    16          }
    17 
    18          try {
    19              //给BeanPostProcessors一个机会来返回代理来替代真正的实例
    20              Object bean = resolveBeforeInstantiation(beanName, mbd);
    21              if (bean != null) {
    22                  return bean;
    23              }
    24          }
    25          catch (Throwable ex) {
    26              throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    27                      "BeanPostProcessor before instantiation of bean failed", ex);
    28          }
    29 
    30          Object beanInstance = doCreateBean(beanName, mbd, args);
    31          if (logger.isDebugEnabled()) {
    32              logger.debug("Finished creating instance of bean '" + beanName + "'");
    33          }
    34          return beanInstance;
    35      }

     

    从代码中我们可以总结出函数完成的具体步骤及功能。

    1)根据设置的class属性或者根据className来解析Class

    2)对override属性进行标记及验证。

    很多读者可能会不知道这个方法的作用,因为在Spring的配置里面根本就没有诸如override-method之类的配置,那么这个方法到底是干什么用的呢?

    其实在Spring中确实没有override-method这样的配置,但是如果读过前面的部分,可能会有所发现,在Spring配置中是存在lookup-methodreplace-method的,而这两个配置的加载其实就是将配置统一存放在BeanDefinition中的methodOverrides属性里,而这个函数的操作其实也就是针对于这两个配置的。

    3)应用初始化前的后处理器,解析指定bean是否存在初始化前的短路操作。

    4)创建bean

    我们首先查看下对override属性标记及验证的逻辑实现。

     

    处理ovverride属性

     

    查看源码中AbstractBeanDefinition类的prepareMethodOverrides方法:

     

     1 public void prepareMethodOverrides() throws BeanDefinitionValidationException {
     2          // Check that lookup methods exists.
     3          MethodOverrides methodOverrides = getMethodOverrides();
     4          if (!methodOverrides.isEmpty()) {
     5              for (MethodOverride mo : methodOverrides.getOverrides()) {
     6                  prepareMethodOverride(mo);
     7              }
     8          }
     9 }
    10   protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
    11      //获取对应类中对应方法名的个数
    12          int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
    13          if (count == 0) {
    14              throw new BeanDefinitionValidationException(
    15                      "Invalid method override: no method with name '" + mo.getMethodName() +
    16                      "' on class [" + getBeanClassName() + "]");
    17          }
    18          else if (count == 1) {
    19              //标记MethodOverride暂未被覆盖,避免参数类型检查的开销。
    20              mo.setOverloaded(false);
    21          }
    22 }

     

      通过以上两个函数的代码你能体会到它所要实现的功能吗?之前反复提到过,在Spring置中存在lookup-methodreplace-method两个配置功能,而这两个配置的加载其实就是将配置统一存放在BeanDefinition中的methodOverrides属性里,这两个功能实现原理其实是在bean实例化的时候如果检测到存在methodOverrides属性,会动态地为当前bean生成代理并使用对应的拦截器为bean做增强处理,相关逻辑实现在bean的实例化部分详细介绍。

      但是,这里要提到的是,对于方法的匹配来讲,如果一个类中存在若干个重载方法,那么,在函数调用及增强的时候还需要根据参数类型进行匹配,来最终确认当前调用的到底是哪个函数。但是,Spring将一部分匹配工作在这里完成了,如果当前类中的方法只有一个,那么就设置重载该方法没有被重载,这样在后续调用的时候便可以直接使用找到的方法,而不需要进行方法的参数匹配验证了,而且还可以提前对方法存在性进行验证,正可谓一箭双雕。

    5.5.2  实例化的前置处理

      在真正调用doCreate方法创建bean的实例前使用了这样一个方法resolveBeforeInstantiation (beanName, mbd)BeanDefinigiton中的属性做些前置处理。当然,无论其中是否有相应的逻辑实现我们都可以理解,因为真正逻辑实现前后留有处理函数也是可扩展的一种体现,但是,这并不是最重要的,在函数中还提供了一个短路判断,这才是最为关键的部分。

     

    if (bean != null) {
             return bean;
    }

     

      当经过前置处理后返回的结果如果不为空,那么会直接略过后续的Bean的创建而直接返回结果。这一特性虽然很容易被忽略,但是却起着至关重要的作用,我们熟知的AOP功能就是基于这里的判断的。

     

     1 protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
     2          Object bean = null;
     3 //如果尚未被解析
     4          if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
     5              // Make sure bean class is actually resolved at this point.
     6              if (mbd.hasBeanClass() && !mbd.isSynthetic() && hasInstantiationAware BeanPostProcessors()) {
     7                  bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(), beanName);
     8                  if (bean != null) {
     9                      bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
    10                  }
    11              }
    12              mbd.beforeInstantiationResolved = (bean != null);
    13          }
    14          return bean;
    15      }

     

      此方法中最吸引我们的无疑是两个方法applyBeanPostProcessorsBeforeInstantiation以及applyBeanPostProcessorsAfterInitialization。两个方法实现的非常简单,无非是对后处理器中的所有InstantiationAwareBeanPostProcessor类型的后处理器进行postProcessBeforeInstantiation方法和BeanPostProcessorpostProcessAfterInitialization方法的调用。

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

      bean的实例化前调用,也就是将AbsractBeanDefinition转换为BeanWrapper 前的处理。给子类一个修改BeanDefinition的机会,也就是说当程序经过这个方法后,bean可能已经不是我们认为的bean了,而是或许成为了一个经过处理的代理bean,可能是通过cglib生成的,也可能是通过其它技术生成的。这在第7章中会详细介绍,我们只需要知道,在bean的实例化前会调用后处理器的方法进行处理。

     

     1   protected Object applyBeanPostProcessorsBeforeInstantiation(Class beanClass, String beanName)
     2              throws BeansException {
     3 
     4          for (BeanPostProcessor bp : getBeanPostProcessors()) {
     5              if (bp instanceof InstantiationAwareBeanPostProcessor) {
     6                  InstantiationAwareBeanPostProcessor ibp = (Instantiation AwareBean PostProcessor) bp;
     7                  Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
     8                  if (result != null) {
     9                      return result;
    10                  }
    11              }
    12          }
    13          return null;
    14      }

     

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

      在讲解从缓存中获取单例bean的时候就提到过,Spring中的规则是在bean的初始化后尽可能保证将注册的后处理器的postProcessAfterInitialization方法应用到该bean中,因为如果返回的bean不为空,那么便不会再次经历普通bean的创建过程,所以只能在这里应用后处理器的postProcessAfterInitialization方法。

     

     1 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
     2              throws BeansException {
     3 
     4          Object result = existingBean;
     5          for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
     6              result = beanProcessor.postProcessAfterInitialization(result, beanName);
     7              if (result == null) {
     8                  return result;
     9              }
    10          }
    11          return result;
    12      } 

     

     

     

     

     

     

     

     

  • 相关阅读:
    HDU 5213 分块 容斥
    HDU 2298 三分
    HDU 5144 三分
    HDU 5145 分块 莫队
    HDU 3938 并查集
    HDU 3926 并查集 图同构简单判断 STL
    POJ 2431 优先队列
    HDU 1811 拓扑排序 并查集
    HDU 2685 GCD推导
    HDU 4496 并查集 逆向思维
  • 原文地址:https://www.cnblogs.com/mjorcen/p/3611578.html
Copyright © 2011-2022 走看看