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

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.
 *
 * 

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 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 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.
     * 

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方法分析)