承接前文Spring源码情操陶冶-AbstractApplicationContext#registerListeners

约定web.xml配置的contextClass为默认值XmlWebApplicationContext

AbstractRefreshableWebApplicationContext#finishBeanFactoryInitialization()

笔者直接去查看相应的的源码

	/**
* 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));
} // 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.
beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons.我们关注此方法即可
beanFactory.preInstantiateSingletons();
}

从上述的注释可知,spring会提前初始化那些作用域为singleton类型的bean对象,当然并不包括lazy-init属性的bean对象

DefaultListableBeanFactory#preInstantiateSingletons()

具体实现preInstantiateSingletons()方法便只有DefaultListableBeanFactory类,直接去翻阅代码

public void preInstantiateSingletons() throws BeansException {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Pre-instantiating singletons in " + this);
} //获取解析过的所有beanNames
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
//获取对应的RootBeanDefinition,其内部就含有BeanDefinition
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//非抽象、单例模式、非lay-init,满足以上条件的进入到实例化(默认情况下Bean为singleton单例模式)
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//对FactoryBean的类型实例化
if (isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
//getBean方法主要进行了对相应的beanName的实例化
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
//获取上述的实例化的静态对象,如果为SmartInitializingSingleton的实现类进行afterSingletonInstantiated()方法调用
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
smartSingleton.afterSingletonsInstantiated();
return null;
}
}, getAccessControlContext());
}
else {
//会调用InitializingBean的afterPropertiesSet()方法
smartSingleton.afterSingletonsInstantiated();
}
}
}

笔者提示这里的实例化指的是对beanFactory中beanName对应的RootBeanDefinition中的beanClass进行准确的实例化,包括属性以及方法复用等等,主要是通过DefaultListableBeanFactory#getBean()方法,因为其很复杂,我们后续再分析

需要注意的是,默认情况下Bean对象的作用域一般为singleton,所以默认情况下bean工厂上的bean都会进行实例化。除了以下情况先不参与

1.使用@Lazy注解修饰Bean对象,指定@Lazy(value=true)

2.使用@Scope注解修饰Bean对象,指定@Scope(value="prototype")

小结

  1. 主要是实例化RootDefinition中的beanClass类,并完成相应的属性设置,方法调用等等(默认情况下Bean的Scope类型为singleton单例模式)。即使当中的属性如果没有提前被初始化的话,其也会被调用getBean()方法来进行初始化后再被设置

  2. 调用所有实现InitializingBean接口的afterPropertiesSet()方法

  3. 调用BeanPostProcessors接口,比如postProcessBeforeInitialization()postProcessAfterInitialization()实例化前后方法。其中涉及@Resource@Autowired等注解的解析并进行相应的实例注入

  4. 此处插一句:BeanPostProcessors接口处理,优先处理InstantiationAwareBeanPostProcessor.class接口实现类,一旦其内部方法postProcessBeforeInstantiation(Class,String)执行后返回null,则不执行postProcessAfterInitialization()方法;随后处理其他BeanPostProcessor接口的postProcessBeforeInitialization()postProcessAfterInitialization()方法

附上springBean的生命周期图(含lazy-init的Bean)

上图示的第八步骤与第九步骤需要替换下,通过阅读源码发现执行InitializingBean#afterPropertiesSet()前还得优先执行BeanPostProcessors集合的postProcessBeforeInitialization()方法,也就是设置ApplicationContext以及Environment变量均在InitializingBean前

Bean销毁的触发机制:

1.实例化@Scope(value="singleton")类型的Bean对象过程中(默认),如果出现异常则会执行AbstractBeanFactory#destorySingleton()方法,当然也支持直接调用

2.在上述销毁的过程中也会去默认执行@Scope(value="prototype")类型Bean的close/destory()方法(倘若存在)

3.同样在上述的销毁过程中,如果对应的Bean对象为DisposableBean类型,则会调用destory()方法来进行销毁操作

Bean对象中指定Scope为singletonprototype的小区别

1.前者是指定Bean对象为单例模式, 即初始化一次后便会保存在内存中,专门由相应的集合去保存;后者则是实例模式,在主动销毁以及被动被回收之后再获取的时候则会被新建

2.前者是Spring的默认模式,后者是需要用户去指定的。前者比较节省资源

3.前者进行销毁时,优先先销毁依赖此Bean的Bean集合,然后再销毁自己,最后再销毁其内含的关联Bean属性;后者想销毁要么直接调用对应的销毁方法要么就是被前者波及进行销毁

下节预告

Spring源码情操陶冶-AbstractApplicationContext#finishRefresh

Spring源码情操陶冶-AbstractApplicationContext#finishBeanFactoryInitialization的更多相关文章

  1. Spring源码情操陶冶-AbstractApplicationContext#registerListeners

    承接前文Spring源码情操陶冶-AbstractApplicationContext#onRefresh 约定web.xml配置的contextClass为默认值XmlWebApplicationC ...

  2. Spring源码情操陶冶-AbstractApplicationContext#finishRefresh

    承接前文Spring源码情操陶冶-AbstractApplicationContext#finishBeanFactoryInitialization 约定web.xml配置的contextClass ...

  3. Spring源码情操陶冶-AbstractApplicationContext#onRefresh

    承接前文Spring源码情操陶冶-AbstractApplicationContext#initApplicationEventMulticaster 约定web.xml配置的contextClass ...

  4. Spring源码情操陶冶-AbstractApplicationContext#initApplicationEventMulticaster

    承接前文Spring源码情操陶冶-AbstractApplicationContext#initMessageSource 约定web.xml配置的contextClass为默认值XmlWebAppl ...

  5. Spring源码情操陶冶-AbstractApplicationContext#initMessageSource

    承接前文Spring源码情操陶冶-AbstractApplicationContext#registerBeanPostProcessors 约定web.xml配置的contextClass为默认值X ...

  6. Spring源码情操陶冶-AbstractApplicationContext#registerBeanPostProcessors

    承接前文Spring源码情操陶冶-AbstractApplicationContext#invokeBeanFactoryPostProcessors 瞧瞧官方注释 /** * Instantiate ...

  7. Spring源码情操陶冶-AbstractApplicationContext#invokeBeanFactoryPostProcessors

    阅读源码有利于陶冶情操,承接前文Spring源码情操陶冶-AbstractApplicationContext#postProcessBeanFactory 约定:web.xml中配置的context ...

  8. Spring源码情操陶冶-AbstractApplicationContext#postProcessBeanFactory

    阅读源码有利于陶冶情操,承接前文Spring源码情操陶冶-AbstractApplicationContext#prepareBeanFactory 约定:web.xml中配置的contextClas ...

  9. Spring源码情操陶冶-AbstractApplicationContext#prepareBeanFactory

    阅读源码有助于陶冶情操,本文承接Spring源码情操陶冶-AbstractApplicationContext#obtainFreshBeanFactory 瞧瞧官方注释 /** * Configur ...

随机推荐

  1. 利用base64库暴力破解base加密

    做个base加密题python语法出了一堆错误..... 附上py中关于base加密/解码的知识:http://www.open-open.com/lib/view/open1433990719973 ...

  2. bootstrap-datetimepicker bootstrap-datepicker bootstrap-timepicker 时间插件

    <!DOCTYPE html><head> <title>时间插件测试</title><style type="text/css&quo ...

  3. 使用JPA和Hibernate进行批量处理的最佳方式

    Tips 原文作者:Vlad Mihalcea 原文地址:The best way to do batch processing with JPA and Hibernate 在本文中,你将了解什么是 ...

  4. lftp的用法

    lftp是Linux下的一个ftp工具,支持ftp, ftps, http, https, hftp, fish, sftp, file, bittorrent等协议(支持https 和 ftps,必 ...

  5. [转] 面向对象原则之GOF是招式,九大原则才是精髓

    只有到了一定层次后才会真正的深入体会到面向对象的一些知识点啊! 不谈具体程序,谈的是你对软件的理解 模式: 每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心. “模式”这个 ...

  6. div中内容无法自动换行问题

    .l-text{ padding:.3em .5em; width:67%; height: auto; /*height:1.3em;*/ border:.1em #2294C3 solid; bo ...

  7. [原创]Floodlight+ovs的基本使用

    一.配置好openflow交换机 配置好交换机的管理地址,可先用串口登,使管理口地址与controller地址在同一个网络中. 在交换机上配置controller地址: 如: 先用命令新建一个brid ...

  8. Java基础语法实例(2)——实习第二天

    来到广州实习的第二天,广州好潮湿,这就是我的感觉,手表里面都开始产生了水雾,这就尴尬了...每天不断的雨.好吧,尽管我很喜欢这里的树,但是我以后应该也不会再来广州了,其实也说不准.想起了<谁动了 ...

  9. ASP.NET初始化流程分析2

    上一篇讲了从创建应用程序域到创建ISAPIRuntime实例的过程,本篇继续讲Asp.net处理第一次请求的必要的初始化过程. ISAPIRuntime分析 ISAPIRuntime在System.W ...

  10. mysqlclient和PyMySQL对比

    环境:Python 3.5+, Django 1.9+ 最初用django时,搜索时发现PyMySQL的文章很多,然而在django的官方文档中python3版的mysql客户端驱动确没有提到PyMy ...