zoukankan      html  css  js  c++  java
  • 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方法进行处理,在实际开发过程中大可以针对此特性设计自己的业务逻辑。

     

     

     

     

     

  • 相关阅读:
    mysql 历史版本下载
    mysql 5.7 版本 You must reset your password using ALTER USER statement before executing this statement报错处理
    5.7 zip 版本的安装 以及遇到的坑
    mysql 5.6zip版本的卸载与5.7 zip 版本的安装
    mysql数据库的备份与还原
    本地Navicat连接docker里的mysql
    docker修改数据库密码
    docker 在push镜像到本地registry出现的500 Internal Server Error
    linux 没有界面内容显示不全解决办法
    json与map互相转换
  • 原文地址:https://www.cnblogs.com/mjorcen/p/3583015.html
Copyright © 2011-2022 走看看