Spring源码分析(二十四)初始化非延迟加载单例

Posted wuxiaofeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码分析(二十四)初始化非延迟加载单例相关的知识,希望对你有一定的参考价值。

摘要: 本文结合《Spring源码深度解析》来分析Spring 5.0.6版本的源代码。若有描述错误之处,欢迎指正。

 

 完成BeanFactory的初始化工作,其中包括ConversionService的设置、配置冻结以及非延迟加载的bean的初始化工作。

/**
 * Finish the initialization of this context‘s bean factory,
 * initializing all remaining singleton beans.
 */
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.
    // 初始化剩下的但实例(非惰性的)
    beanFactory.preInstantiateSingletons();
}

 一、ConversionService的设置

之前我们提到过使用自定义类型转换器从String转换为Date的方式,那么在Spring中还提供了另一种转换方式:使用Converter。同样,我们使用一个简单的示例来了解下Converter的使用方式。

(1)定义转换器。

public class String2DateConverter implements Converter<String, Date> {
    @Nullable
    @Override
    public Date convert(String source) {
        try {
            return DateUtils.parseDate(source, new String[] {"yyyy-MM-dd HH:mm:ss"});
        } catch (ParseException e) {
            return null;
        }
    }
}

(2)注册。

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="org.cellphone.uc.String2DateConverter"/>
        </list>
    </property>
</bean>

(3)测试。

public class UserManager {

    private Date dateValue;

    public Date getDateValue() {
        return dateValue;
    }

    public void setDateValue(Date dateValue) {
        this.dateValue = dateValue;
    }

    @Override
    public String toString() {
        return "dataValue: " + dateValue;
    }
}
public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("spring/beans-test.xml");
    UserManager manager = (UserManager) context.getBean("userManager");
    System.out.println(manager);
}

 通过以上的功能我们看到了Converter以及ConversionService提供的便利功能,其中的配置就是在当前函数中被初始化的。

二、冻结配置

冻结所有的bean定义,说明注册的bean定义将不被修改或进行任何进一步的处理。

@Override
public void freezeConfiguration() {
    this.configurationFrozen = true;
    this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}

三、初始化非延迟加载

ApplicationContext实现的默认行为就是在启动时将所有单例bean提前进行实例化。提前实例化意味者作为初始化过程的一部分,ApplicationContext实例会创建并配置所有的单例bean。通常情况下这是一件好事,因为这样在配置中的任何错误就会即刻被发现(否则的话可能要花几个小时甚至几天)。而这个实例的过程就是在finishBeanFactoryInitialization中完成的。

@Override
public void preInstantiateSingletons() throws BeansException {
    if (logger.isDebugEnabled()) {
        logger.debug("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.
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                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(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();
            }
        }
    }
}

 

以上是关于Spring源码分析(二十四)初始化非延迟加载单例的主要内容,如果未能解决你的问题,请参考以下文章

Spring源码分析

Spring IOC源码剖析:lazy-init 延迟加载机制和循环依赖问题

Spring源码研读中的知识盲区整理

Spring源码分析原型Bean实例化过程byName与byType及FactoryBean获取Bean源码实现

Spring 源码分析--bean的加载详细分析

Spring源码分析(十三)缓存中获取单例bean