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

    5.5  准备创建bean

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

     

     

    /**
         * Central method of this class: creates a bean instance, populates the bean instance,
         * applies post-processors, etc.
         * 
         * @see #doCreateBean
         */
        @Override
        protected Object createBean(final String beanName, final RootBeanDefinition mbd,
                final Object[] args) throws BeanCreationException {
    
            if (logger.isDebugEnabled()) {
                logger.debug("Creating instance of bean '" + beanName + "'");
            }
            // Make sure bean class is actually resolved at this point.
            // 锁定class,根据设置的class属性或者根据className来解析Class
            resolveBeanClass(mbd, beanName);
    
            // Prepare method overrides.
            // 验证及准备覆盖的方法
            try {
                mbd.prepareMethodOverrides();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
                        beanName, "Validation of method overrides failed", ex);
            }
    
            try {
                // Give BeanPostProcessors a chance to return a proxy instead of the target
                // bean instance.
                // 给BeanPostProcessors一个机会来返回代理来替代真正的实例
                Object bean = resolveBeforeInstantiation(beanName, mbd);
                if (bean != null) {
                    return bean;
                }
            }
            catch (Throwable ex) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "BeanPostProcessor before instantiation of bean failed", ex);
            }
    
            Object beanInstance = doCreateBean(beanName, mbd, args);
            if (logger.isDebugEnabled()) {
                logger.debug("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }

     

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

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

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

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

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

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

    4)创建bean

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

     

    5.5.1  处理ovverride属性

     

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

     

     

    public void prepareMethodOverrides() throws BeanDefinitionValidationException {
             // Check that lookup methods exists.
             MethodOverrides methodOverrides = getMethodOverrides();
             if (!methodOverrides.isEmpty()) {
                 for (MethodOverride mo : methodOverrides.getOverrides()) {
                     prepareMethodOverride(mo);
                 }
             }
    }
      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) {
                 //标记MethodOverride暂未被覆盖,避免参数类型检查的开销。
                 mo.setOverloaded(false);
             }
    }

     

     

     

     

      通过以上两个函数的代码你能体会到它所要实现的功能吗?之前反复提到过,在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功能就是基于这里的判断的。

     

     

     

        /**
         * Apply before-instantiation post-processors, resolving whether there is a
         * before-instantiation shortcut for the specified bean.
         * 
         * @param beanName the name of the bean
         * @param mbd the bean definition for the bean
         * @return the shortcut-determined bean instance, or {@code null} if none
         */
        protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
            Object bean = null;
            // 如果尚未被解析
            if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
                // Make sure bean class is actually resolved at this point.
                if (mbd.hasBeanClass() && !mbd.isSynthetic()
                        && hasInstantiationAwareBeanPostProcessors()) {
                    bean = applyBeanPostProcessorsBeforeInstantiation(mbd.getBeanClass(),
                            beanName);
                    if (bean != null) {
                        bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                    }
                }
                mbd.beforeInstantiationResolved = (bean != null);
            }
            return bean;
        }

     

     

     

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

     

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

     

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

     

     

     

      protected Object applyBeanPostProcessorsBeforeInstantiation(Class beanClass, String beanName)
                 throws BeansException {
    
             for (BeanPostProcessor bp : getBeanPostProcessors()) {
                 if (bp instanceof InstantiationAwareBeanPostProcessor) {
                     InstantiationAwareBeanPostProcessor ibp = (Instantiation AwareBean PostProcessor) bp;
                     Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
                     if (result != null) {
                         return result;
                     }
                 }
             }
             return null;
         }

     

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

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

     

     

     

     

    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
                 throws BeansException {
    
             Object result = existingBean;
             for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
                 result = beanProcessor.postProcessAfterInitialization(result, beanName);
                 if (result == null) {
                     return result;
                 }
             }
             return result;
         } 

     

     

     

     

  • 相关阅读:
    mysql lock
    yii2引入js和css
    Yii 2.x 和1.x区别以及yii2.0安装
    Curl https 访问
    boost::any 用法
    boost单元测试框架
    shared_ptr的线程安全
    nginx php fastcgi安装
    ip相关
    Design Pattern Explained 读书笔记二——设计模式序言
  • 原文地址:https://www.cnblogs.com/mjorcen/p/3679103.html
Copyright © 2011-2022 走看看