美文网首页Java 杂谈
04-Spring 初始化过程中GetBean方法分析

04-Spring 初始化过程中GetBean方法分析

作者: AcientFish | 来源:发表于2019-03-28 11:30 被阅读0次

    Spring 初始化过程中GetBean方法分析

    经过前面的铺垫我们终于来到了IOC容器初始化最核心的部分(我个人认为)。在getBean时会调用AbstractBeanFactory#doGetBean()方法来获取单例Bean,在doGetBean中会先做一个缓存检查,判断是否之前手动插入到ioc,若存在缓存会根据缓存来拿Bean,暂不分析。
    随后会判断当前Bean是否存在依赖,存在依赖时会先实例化依赖的Bean,此处暂不讨论,后续单独讨论。
    不存在依赖的情况下,调用父类DefaultSingletonBeanRegistry#getSingleton方法,并且传入一个单例工厂,通过AbstractAutowireCapableBeanFactory#createBean方法来创建Bean,这个方法的注解中说明这是此类的核心方法,用来创建、填充Bean,并且调用BeanPostProcessor。关键代码如下所示

        /**
         * Central method of this class: creates a bean instance,
         * populates the bean instance, applies post-processors, etc.
         * @see #doCreateBean
         */
        @Override
        protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){
            // 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.
            // 此处根据beanName将class load到jvm,并且给mbd的instanceclass字段赋值
            Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
            ...........................................................
            // 此处真正创建对象
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        }
    

    Spring中不管前面如何铺垫,最终执行操作的方法均为doXXX,所以,看到这个关键字我们就应该知道我们马上要解开面纱了。

        protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
            // 实例化一个空对象出来
            instanceWrapper = createBeanInstance(beanName, mbd, args);
            // 给对象的属性赋值
            populateBean(beanName, mbd, instanceWrapper);
            // 调用各种回调
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
    

    上面只列出了doCreateBean中我认为最关键的三个方法,下面我们注意分析这三个方法。

    首先我们来看实例化对象核心代码

    
        protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
            // No special handling: simply use no-arg constructor.
            return instantiateBean(beanName, mbd);
        }
    
        /**
         * Instantiate the given bean using its default constructor.
         * @param beanName the name of the bean
         * @param mbd the bean definition for the bean
         * @return a BeanWrapper for the new instance
         */
        protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
             // 通过实例化策略来实例化对象,默认策略是cglib,但是不存在Override方法的对象调用的实例化方法在父类SimpleInstantiationStrategy中
            beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
        }
    

    在SimpleInstantiationStrategy#instantiate方法没什么特别的,基本就是通过bd获取class,再获取constructor,之后通过反射创建对象后返回。

    其次我们来关注给对象的属性赋值

    此方法会处理AutoWired注解的注入逻辑,实现依赖注入。具体核心代码如下

        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                if (pvsToUse == null) {
                    if (filteredPds == null) {
                        filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                      }
                    pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                    if (pvsToUse == null) {
                                return;
                    }
               }
               pvs = pvsToUse;
           }
        }
    

    如上所示,ioc容器会遍历已有的BeanPostProcessor,在遍历到AutoWiredAnnotationBeanPostProcessor(第一章介绍入口时registerBeanPostProcessors方法中提到了)时会实现自动装配。
    可以参考AutoWiredAnnotationBeanPostProcessor类的官方注解

    /**
     * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
     * that autowires annotated fields, setter methods and arbitrary config methods.
     * Such members to be injected are detected through a Java 5 annotation: by default,
     * Spring's {@link Autowired @Autowired} and {@link Value @Value} annotations.
     *
     * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
     * if available, as a direct alternative to Spring's own {@code @Autowired}.
     */
    

    从官方注解中可以看到,这个后置处理器的功能是为标有Spring的@AutoWired、@Value注解和JSR-330的@Injected的注解的属性赋值。另外其他的BeanPostProcessor也各有功能,后面有机会的话单独分析。我们先来关注自动装配模块。
    通过跟源码我们发现,实际上的处理过程在DefaultListableBeanFactory#doResolveDependency()方法中,关键代码如下

        Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
    
        /**
         * Find bean instances that match the required type.
         * Called during autowiring for the specified bean.
         * @param beanName the name of the bean that is about to be wired
         * @param requiredType the actual type of bean to look for
         * (may be an array component type or collection element type)
         * @param descriptor the descriptor of the dependency to resolve
         * @return a Map of candidate names and candidate instances that match
         * the required type (never {@code null})
         * @throws BeansException in case of errors
         * @see #autowireByType
         * @see #autowireConstructor
         */
        protected Map<String, Object> findAutowireCandidates(
                @Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
            // 从ioc容器中根据bean类型来加载所有的单例(包括祖先类实例)
            String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
                    this, requiredType, true, descriptor.isEager());
            for (String candidate : candidateNames) {
                if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
                    // 这个方法里面会调用getBean方法从容器中获取待注入的对象
                    addCandidateEntry(result, candidate, descriptor, requiredType);
                }
            }
            return result;
        }
    

    通过上述代码会获取到需要注入的对象,后面要做的就是通过反射,将值赋给需要注入的字段。
    需要注意的是,在跟踪源码的过程中发现@Autowired和@Inject注解其实都是按类型注入,而@Resource则是按名称注入,@Autowired注解是Spring实现的注解,如果需要注入的Bean不是单例而存在多个,比如说多数据源,此时需要配套@Qualified注解来使用。而@Inject是JSR-330标准的注解,在类似多数据源的情况下需要使用@Named来确定。另外,@Autowired注解支持required属性,如果该属性为false,则在容器中不存在对应类型时会注入为空,而@Inject注解不存在这个特性,除此之外@Auto wired和@Inject完全没区别

    最后我们来关注调用回调

    从方法注解上我们可以看到,在该阶段主要是负责调用工厂的各类回调(主要是BeanNameAware、BeanClassLoaderAware以及BeanFactoryAware),同时调用init方法(Spring在XML或@Bean的方式声明一个Bean时可以指定InitMethod和DestoryMethod)以及Bean的后置处理器(主要是BeanPostProcessor中的postProcessBeforeInitialization和postProcessAfterInitialization方法),下面我们通过代码来分析。

        /**
         * Initialize the given bean instance, applying factory callbacks
         * as well as init methods and bean post processors.
         * <p>Called from {@link #createBean} for traditionally defined beans,
         * and from {@link #initializeBean} for existing bean instances.
         * @param beanName the bean name in the factory (for debugging purposes)
         * @param bean the new bean instance we may need to initialize
         * @param mbd the bean definition that the bean was created with
         * (can also be {@code null}, if given an existing bean instance)
         * @return the initialized bean instance (potentially wrapped)
         * @see BeanNameAware
         * @see BeanClassLoaderAware
         * @see BeanFactoryAware
         * @see #applyBeanPostProcessorsBeforeInitialization
         * @see #invokeInitMethods
         * @see #applyBeanPostProcessorsAfterInitialization
         */
        protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
            // 调用工厂的回调
            invokeAwareMethods(beanName, bean);
            // 调用后置处理器的beforeInitialization
            applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
            // 调用InitializingBean#afterPropertiesSet或initMethod
            invokeInitMethods(beanName, wrappedBean, mbd);    
            // 调用后置处理器的afterInitialization
            applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
    

    在applyBeanPostProcessorsBeforeInitialization方法中会调用ApplicationContext级别的相关回调,包括EnvironmentAware、EmbeddedValueResolverAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware
    在Spring MVC中会通过invokeInitMethods方法来调用InitializingBean#afterPropertiesSet方法实例化RequestMappingHandlerMapping等信息。后面在分析Spring MVC源码时在单独分析。
    而applyBeanPostProcessorsAfterInitialization方法大多都是直接返回bean,Spring保留了用户扩展的需求。
    至此Spring容器的getBean就已经介绍完了。结束这一步基本上Spring容器的启动过程也就快结束了。通过分析我们了解了很多Spring的原理,更重要的是开始慢慢了解Spring的设计思想,相信这些思想能让我们更好的编码,写出更好、更优雅的code。

    相关文章

      网友评论

        本文标题:04-Spring 初始化过程中GetBean方法分析

        本文链接:https://www.haomeiwen.com/subject/kxxqbqtx.html