• 5.3:从bean的实例中获取对象


    5.3  bean的实例中获取对象

      在getBean方法中,getObjectForBeanInstance是个高频率使用的方法,无论是从缓存中获得bean还是根据不同的scope策略加载bean。总之,我们得到bean的实例后要做的第一步就是调用这个方法来检测一下正确性,其实就是用于检测当前bean是否是FactoryBean类型的bean,如果是,那么需要调用该bean对应的FactoryBean实例中的getObject()作为返回值。

      无论是从缓存中获取到的bean还是通过不同的scope策略加载的bean都只是最原始的bean状态,并不一定是我们最终想要的bean。举个例子,假如我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean的初始状态,但是我们真正需要的是工厂bean中定义的factory-method方法中返回的bean,而getObjectForBeanInstance方法就是完成这个工作的。

     

     1 protected Object getObjectForBeanInstance(
     2              Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
     3 
     4          //如果指定的name是工厂相关(以&为前缀)且beanInstance又不是FactoryBean类型则验证不通过
     5          if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
     6              throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance. getClass());
     7          }
     8 
     9          //现在我们有了个bean的实例,这个实例可能会是正常的bean或者是FactoryBean
    10          //如果是FactoryBean我们使用它创建实例,但是如果用户想要直接获取工厂实例而不是工厂的getObject方法对应的实例那么传入的name应该加入前缀&
    11          if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils. IsFactory Dereference(name)) {
    12              return beanInstance;
    13          }
    14 
    15          //加载FactoryBean
    16          Object object = null;
    17          if (mbd == null) {
    18              //尝试从缓存中加载bean
    19              object = getCachedObjectForFactoryBean(beanName);
    20          }
    21          if (object == null) {
    22              //到这里已经明确知道beanInstance一定是FactoryBean类型
    23              FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
    24              //containsBeanDefinition检测beanDefinitionMap中也就是在所有已经加载的类中检测是否定义beanName
    25              if (mbd == null && containsBeanDefinition(beanName)) {
    26                   //将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition,如果指定BeanName是子Bean的话同时会合并父类的相关属性
    27                  mbd = getMergedLocalBeanDefinition(beanName);
    28              }
    29              //是否是用户定义的而不是应用程序本身定义的
    30              boolean synthetic = (mbd != null && mbd.isSynthetic());
    31              object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    32          }
    33          return object;
    34 }

     

      从上面的代码来看,其实这个方法并没有什么重要的信息,大多是些辅助代码以及一些功能性的判断,而真正的核心代码却委托给了getObjectFromFactoryBean,我们来看看getObjectForBeanInstance中的所做的工作。

    1)对FactoryBean正确性的验证。

    2)对非FactoryBean不做任何处理。

    3)对bean进行转换。

    4)将从Factory中解析bean的工作委托给getObjectFromFactoryBean

     

     1 protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {
     2          //如果是单例模式
     3          if (factory.isSingleton() && containsSingleton(beanName)) {
     4              synchronized (getSingletonMutex()) {
     5                  Object object = this.factoryBeanObjectCache.get(beanName);
     6                  if (object == null) {
     7                      object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
     8                      this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
     9                  }
    10                  return (object != NULL_OBJECT ? object : null);
    11              }
    12          }
    13          else {
    14              return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
    15          }
    16      }

     

      很遗憾,在这个代码中我们还是没有看到想要看到的代码,在这个方法里只做了一件事情,就是返回的bean如果是单例的,那就必须要保证全局唯一,同时,也因为是单例的,所以不必重复创建,可以使用缓存来提高性能,也就是说已经加载过就要记录下来以便于下次复用,否则的话就直接获取了。

      在doGetObjectFromFactoryBean方法中我们终于看到了我们想要看到的方法,也就是object = factory.getObject(),是的,就是这句代码,我们的历程犹如剥洋葱一样,一层一层的直到最内部的代码实现,虽然很简单。

     

     1 private Object doGetObjectFromFactoryBean(
     2              final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
     3              throws BeanCreationException {
     4 
     5          Object object;
     6          try {
     7              //需要权限验证
     8              if (System.getSecurityManager() != null) {
     9                  AccessControlContext acc = getAccessControlContext();
    10                  try {
    11                      object = AccessController.doPrivileged(new PrivilegedExceptionAction< Object>() {
    12                          public Object run() throws Exception {
    13                                  return factory.getObject();
    14                              }
    15                          }, acc);
    16                  }
    17                  catch (PrivilegedActionException pae) {
    18                      throw pae.getException();
    19                  }
    20              }
    21              else {
    22                  //直接调用getObject方法
    23                  object = factory.getObject();
    24              }
    25          }
    26          catch (FactoryBeanNotInitializedException ex) {
    27              throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    28          }
    29          catch (Throwable ex) {
    30              throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    31          }
    32          if (object == null && isSingletonCurrentlyInCreation(beanName)) {
    33              throw new BeanCurrentlyInCreationException(
    34                      beanName, "FactoryBean which is currently in creation returned null from getObject");
    35          }
    36 
    37          if (object != null && shouldPostProcess) {
    38              try {
    39                  //调用ObjectFactory的后处理器
    40                  object = postProcessObjectFromFactoryBean(object, beanName);
    41              }
    42              catch (Throwable ex) {
    43                  throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex);
    44              }
    45          }
    46 
    47          return object;
    48 }

     

      上面我们已经讲述了FactoryBean的调用方法,如果bean声明为FactoryBean类型,则当提取bean时提取的并不是FactoryBean,而是FactoryBean中对应的getObject方法返回的beandoGetObjectFromFactoryBean正是实现这个功能的。但是,我们看到在上面的方法中除了调用object = factory.getObject()得到我们想要的结果后并没有直接返回,而是接下来又做了些后处理的操作,这个又是做什么用的呢?于是我们跟踪进入AbstractAutowireCapableBeanFactory类的postProcessObjectFromFactoryBean方法:

     

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

     

      对于后处理器的使用我们还未过多接触,后续章节会使用大量篇幅介绍,这里,我们只需了解在Spring获取bean的规则中有这样一条:尽可能保证所有bean初始化后都会调用注册的BeanPostProcessorpostProcessAfterInitialization方法进行处理,在实际开发过程中大可以针对此特性设计自己的业务逻辑。

     

     

     

     

     

  • 相关阅读:
    jQuery遍历
    jQuery DOM
    jQuery表单事件
    jQuery事件对象
    jQuery绑定事物处理器
    jQuery事件
    JQuery基础选择器
    JQuery基础 接下来我将把我最近学习jQuery所做的笔记发布,希望对初学者有些许帮助,也方便自己以后复习
    C# 连接Oracle数据库 遇到“System.Data.OracleClient 需要 Oracle 客户端软件 8.1.7 或更高版本”的解决方案
    安装oracle11版本报错此先决条件将测试系统物理内存总量是否至少为 922MB
  • 原文地址:https://www.cnblogs.com/mjorcen/p/3583015.html
Copyright © 2020-2023  润新知