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 IOC源码剖析:lazy-init 延迟加载机制和循环依赖问题