Spring 是如何实例化 Bean 的?

1,331 阅读5分钟

Bean 的实例化_01

  在Spring中Bean的实例化是一个及其复杂的过程,从这篇文章开始,我就要学习容器初始化 refresh()方法中的 inishBeanFactoryInitialization(beanFactory);

finishBeanFactoryInitialization() 方法代码实现

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
                beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }

    // Register a default embedded value resolver if no bean post-processor
    // (such as a PropertyPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
    }

    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    // Stop using the temporary ClassLoader for type matching.
    beanFactory.setTempClassLoader(null);

    // Allow for caching all bean definition metadata, not expecting further changes.
    /**
     * 冻结 所有的bean定义,说明注册的bean定义将不被修改或任何进一步的处理
     */
    beanFactory.freezeConfiguration();

    // Instantiate all remaining (non-lazy-init) singletons.
    /**
     * 这里是重点代码
     * 初始化剩下的实例(非惰性的)
     * 这个 预实例化的完成 委托给容器来实现,如果需要预实例化,采用getBean() 触发依赖注入,
     * 与正常的依赖注入的触发相比,只有触发的时间和场合不同,这里依赖注入是发生在容器执行 refresh() 的过程,也就是IOC容器初始化的过程
     * 正常不是 Lazy-init 属性的依赖注入发生在IOC容器初始化完成之后,第一次向容器执行getBean() 时。
     */
    beanFactory.preInstantiateSingletons();
}

  在上述的方法中,最重要的就是 preInstantiateSingletons()。这里我自己的理解就是预实例化容器之非懒加载(Lazy-init)的对象。

preInstantiateSingletons()

public void preInstantiateSingletons() throws BeansException {
    if (logger.isTraceEnabled()) {
        logger.trace("Pre-instantiating singletons in " + this);
    }

    // Iterate over a copy to allow for init methods which in turn register new bean definitions.
    // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
    // 获取所有BeanDefinition的名字
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    // 触发所有非延迟加载单例Bean的实例化
    for (String beanName : beanNames) {
        // 合并父BeanDefinition
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        /**
         * 一个对象不是抽象的,并且是单例的,并且不是懒加载的
         * 若这个对象不是一个FactoryBean,进入getBean()方法
         */
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                // 如果是FactoryBean 加上 &
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    final FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                        ((SmartFactoryBean<?>) factory)::isEagerInit,
                                getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
            }
            else {
                /**
                 * 调用容器中的 getBean() 方法
                 */
                getBean(beanName);
            }
        }
    }

    // Trigger post-initialization callback for all applicable beans...
    for (String beanName : beanNames) {
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {
            final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    smartSingleton.afterSingletonsInstantiated();
                    return null;
                }, getAccessControlContext());
            }
            else {
                smartSingleton.afterSingletonsInstantiated();
            }
        }
    }
}

  从上述方法中可以看出,循环容器初始时添加到容器中的所有的 BeanName,然后根据 BeanName 获取到对应的 BeanDefinition。 通过 BeanDefinition中的属性来判断是否要触发相应的 getBean() 过程。   在 getBean() 之前,我首先要做的就是试着画一下对应的粗略流程图,后面的文章,将会一一的张开流程图里面的子流程。

doGetBean流程图
doGetBean流程图

  看完了整个流程图,下面就要开始第一个方法 getSingleton(String beanName) 的处理逻辑

getSingleton(String beanName)

public Object getSingleton(String beanName) {
    /** 参数true 设置标识允许早期依赖*/
    return getSingleton(beanName, true);
}

  调用重载的方法 getSingleton(String beanName, boolean allowEarlyReference) 来进行真正的逻辑处理,在Spring 中默认是允许 早期依赖的,也即 allowEarlyReferencetrue

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //从Map中获取Bean,如果不为空直接返回,不在进行初始化工作
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // 未被初始化 且 beanName 存在于正在被创建的单例Bean的池子中,进行初始化
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                /**
                 * 当某些方法需要提前初始化的时候会调用
                 * addSingletonFactory方法将对应的ObjectFactory初始化策略
                 * 存储在 singletonFactories中
                 */
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    /** 调用预先设定的getObject()方法*/
                    singletonObject = singletonFactory.getObject();
                    /**
                     * 记录在缓存中
                     * earlySingletonObjects 与 singletonFactories 互斥
                     */
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

在创建Bean的时候,首先,先到 singletonObjects 中获取,这对象是一个 Map,用来存放已经创建好的对象。里面的对象可以直接使用。   通过下面的图片来介绍上述 getSingleton() 的过程:

第一个getSingleton流程
第一个getSingleton流程

  对于这个 getSingleton() 方法而言,在容器初始化的时候,singletonObjects 中必然没有对象,返回的结果则必然为null。

初识 三个Map

  在上述的三个方法中,我们将会看到有用到如下的三个 Map; private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); 这三个Map,在之后的依赖注入的处理中起着重要的作用。其中 singletonObjects 用于存放完全初始化好的bean;singletonFactories 用于存放 bean工厂对象; earlySingletonObjects 存放原始的bean对象。在Spring中定义了三个Map,缓存Spring容器中实例化的 Bean,并解决了注入过程 中循环依赖的问题。

标记Bean是已创建的

protected void markBeanAsCreated(String beanName) {
    // 没有创建
    if (!this.alreadyCreated.contains(beanName)) {
        // 通过 synchronized 保证只有一个线程创建
        synchronized (this.mergedBeanDefinitions) {
            // 再次检查 没有创建
            if (!this.alreadyCreated.contains(beanName)) {
                // 从 mergedBeanDefinitions 中删除 beanName,
                // 并在下次访问时重新创建它
                clearMergedBeanDefinition(beanName);
                // 添加到已创建bean 集合中
                this.alreadyCreated.add(beanName);
            }
        }
    }
}

  容器初始化之处,这里我们自己的 Bean对应的 beanNamealreadyCreated 中必然是不存在的。因此,Spring在这里,就会将当前 的 BeanName 添加到 alreadyCreated 的集合中,用来标记当前的 Bean 是已创建的。这里为了保证添加一次,还采用了双重检测的方式。

本文使用 mdnice 排版