zoukankan      html  css  js  c++  java
  • 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();
                }
            }
        }
    }
  • 相关阅读:
    HTTP Handlers and HTTP Modules Overview
    NTLM Detail
    How to get report service instance name by wmi
    How to remove the history credential in IE8 .(OP is Win 7 64)
    Session 机制详解
    ES6map对象,for of 遍历,class类,extends继承
    MongoDB 安装及命令指令符基本操作
    nodeIO,path,http , url模块
    ES6promise
    node模块化简介, process全局对象, fs模块,Buffer对象 ,
  • 原文地址:https://www.cnblogs.com/warehouse/p/9390166.html
Copyright © 2011-2022 走看看