IOC容器加载过程
这是单例的加载步骤:
- 执行
SpringApplication.run()
-> - 调用
SpringApplication
实例的refreshContext(context)
-> - 调用
SpringApplication
实例的refresh(context)
-> - 调用
((AbstractApplicationContext)applicationContext).refresh()
-> - 执行
AbstractApplicationContext
类的finishBeanFactoryInitialization
方法 -> - 调用
DefaultListableBeanFactory
类的preInstantiateSingletons
方法 -> - 执行
DefaultListableBeanFactory
类的getBean
方法 -> - 调用
AbstractBeanFactory
类getBean
方法 -> - 执行
AbstractBeanFactory
类doGetBean
方法 -> - 执行
AbstractBeanFactory
类的getMergedLocalBeanDefinition
方法获取Bean定义,所有的Bean
定义放在mergedBeanDefinitions
哈希里,如果没有找到Bean
定义,则调用DefaultListableBeanFactory
类的getBeanDefinition
方法,在beanDefinitionMap
获取 -> - 调用
DefaultSingletonBeanRegistry
类的getSingleton
方法,在singletonObjects
哈希里查找实例,如果实例不存在,则调用singletonFactory
对象(实现ObjectFactory
接口)的getObject
方法 -> - 调用
AbstractAutowireCapableBeanFactory
类的createBean
方法 -> - 执行
AbstractAutowireCapableBeanFactory
类的doCreateBean
方法 -> - 执行
AbstractAutowireCapableBeanFactory
类的initializeBean
方法 -> - 执行
AbstractAutowireCapableBeanFactory
类的invokeInitMethods
方法,如果实现InitializingBean
接口,则调用afterPropertiesSet
方法,如果有初始化方法,则调用初始化方法 -> - 调用
DefaultListableBeanFactory
类addSingleton
方法,把实例放进容器
Refresh源码解释
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
// startupShutdownMonitor对象在spring环境刷新和销毁的时候都会用到,确保刷新和销毁不会同时执行
synchronized(this.startupShutdownMonitor) {
// 准备工作,例如记录事件,设置标志,检查环境变量等,并有留给子类扩展的位置,用来将属性加入到applicationContext中
this.prepareRefresh();
// 创建beanFactory,这个对象作为applicationContext的成员变量,可以被applicationContext拿来用,
// 并且解析资源(例如xml文件),取得bean的定义,放在beanFactory中
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
// 对beanFactory做一些设置,例如类加载器、spel解析器、指定bean的某些类型的成员变量对应某些对象等
this.prepareBeanFactory(beanFactory);
try {
// 子类扩展用,可以设置bean的后置处理器(bean在实例化之后这些后置处理器会执行)
this.postProcessBeanFactory(beanFactory);
// 执行beanFactory后置处理器(有别于bean后置处理器处理bean实例,beanFactory后置处理器处理bean定义)
this.invokeBeanFactoryPostProcessors(beanFactory);
// 将所有的bean的后置处理器排好序,但不会马上用,bean实例化之后会用到
this.registerBeanPostProcessors(beanFactory);
// 初始化国际化服务
this.initMessageSource();
// 创建事件广播器
this.initApplicationEventMulticaster();
// 空方法,留给子类自己实现的,在实例化bean之前做一些ApplicationContext相关的操作
this.onRefresh();
// 注册一部分特殊的事件监听器,剩下的只是准备好名字,留待bean实例化完成后再注册
this.registerListeners();
// 单例模式的bean的实例化、成员变量注入、初始化等工作都在此完成
this.finishBeanFactoryInitialization(beanFactory);
// applicationContext刷新完成后的处理,例如生命周期监听器的回调,广播通知等
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
// 刷新失败后的处理,主要是将一些保存环境信息的集合做清理
this.destroyBeans();
// applicationContext是否已经激活的标志,设置为false
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
Spring创建Bean的流程
明白 对象的属性是可以延后设置的。 这点,就容易理解。
getBean() -> doGetBean() -> createBean() -> doCreateBean() -> 返回Bean
AbstractAutowireCapableBeanFactory
- doCreateBean():- createBeanInstance()实例化,调用对象的构造方法实例化对象
- populateBean()填充属性field,在此步骤完成Bean的实例化、初始化(@Autowired)
- initializeBean回调初始化方法,回调一些形如initMethod、InitializingBean等方法
Bean实例化
过程:
- 先执行Bean的构造函数,
@PostConstruct
注解 - 执行Bean的属性装配,实现
InitializingBean
接口,重写afterPropertiesSet()
方法 - 执行Bean的前置处理器
- 执行Bean的初始化方法,声明一个Bean的时候,可以同时指定一个
initMethod
属性,该属性会指向Bean的一个方法 - 执行Bean的后置处理器,实现
BeanPostProcessor
接口
BeanFactory接口介绍
它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory
是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。BeanFactory
只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory
、XmlBeanFactory
、ApplicationContext
等。BeanFactory
和ApplicationContext
就是spring框架的两个IOC容器,现在一般使用ApplicationnContext
,其不但包含了BeanFactory
的作用,同时还进行更多的扩展。而AbstractApplicationContext
就是ApplicationnContext
接口的实现类。所以使用getBean(String beanName)
方法就可以取得bean的实例;BeanFactory
提供的方法及其简单,仅提供了六种方法供客户调用:
boolean containsBean(String beanName)
判断工厂中是否包含给定名称的bean定义,若有则返回trueObject getBean(String)
返回给定名称注册的bean实例。根据bean的配置情况,如果是singleton模式将返回一个共享实例,否则将返回一个新建的实例,如果没有找到指定bean,该方法可能会抛出异常Object getBean(String, Class)
返回以给定名称注册的bean实例,并转换为给定class类型Class getType(String name)
返回给定名称的bean的Class,如果没有找到指定的bean实例,则排除NoSuchBeanDefinitionException异常boolean isSingleton(String)
判断给定名称的bean定义是否为单例模式String[] getAliases(String name)
返回给定bean名称的所有别名
DefaultListableBeanFactory类介绍
DefaultListableBeanFactory是整个bean加载的核心部分,是spring注册及加载bean的默认实现。
DefaultListableBeanFactory继承了AbstractAutowireCapableBeanFactory类,实现了ConfigurableListableBeanFactory和BeanDefinitionRegistry接口。
AbstractBeanFactory类介绍
AbstractBeanFactory类是DefaultListableBeanFactory的父类,getBean方法的真正实现是在AbstractBeanFactory,具体的实现方法是doGetBean。
FactoryBean接口介绍
用户可以通过实现该接口定制实例化Bean的逻辑。FactoryBean接口对于Spring框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。它们隐藏了实例化一些复杂Bean的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为FactoryBean
例子:
public class CarFactoryBean implements FactoryBean<Car> {
private String carInfo;
public Car getObject() throws Exception {
Car car = new Car();
String[] infos = carInfo.split(",");
car.setBrand(infos[0]);
car.setMaxSpeed(Integer.valueOf(infos[1]));
car.setPrice(Double.valueOf(infos[2])); return car;
}
public Class<Car> getObjectType() {
return Car.class;
}
public boolean isSingleton() {
return false;
}
}
有了这个CarFactoryBean后,就可以在配置文件中使用下面这种自定义的配置方式配置Car Bean了:
<bean id="car" class="com.test.factorybean.CarFactoryBean" carInfo="大众SUV,180,180000"/>
当调用getBean(“car”) 时,Spring通过反射机制发现CarFactoryBean实现了FactoryBean的接口,这时Spring容器就调用接口方法CarFactoryBean#getObject()方法返回。如果希望获取CarFactoryBean的实例,则需要在使用getBean(beanName) 方法时在beanName前显示的加上 “&” 前缀,例如getBean(“&car”)。
三级缓存
Spring为了解决单例的循环依赖问题,DefaultSingletonBeanRegistry
的getSingleton()
使用了三级缓存。
这三级缓存分别指:
- 一级缓存 singletonObjects:用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用
- 二级缓存 earlySingletonObjects :提前曝光的单例对象的cache,存放原始的 bean 对象(尚未填充属性),用于解决循环依赖
- 三级缓存 singletonFactories: 单例对象工厂的cache,存放 bean 工厂对象,用于解决循环依赖
Spring首先从一级缓存singletonObjects中获取。如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取。如果还是获取不到且允许singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取,如果获取到了则从singletonFactories中移除,并放入earlySingletonObjects中。其实也就是从三级缓存移动到了二级缓存。
默认情况下bean的scope为singleton,整个容器中仅有整个service的一个bean,还是假如a、b两service存在field循环依赖,当创建a的bean时,执行完构造方法后,a的实例已生成,将其factory对象存入第三级缓存singletonFactories中,在填充属性时,发现依赖b的bean,但是在缓存中没有b的bean;因此转而去创建b,在此过程中执行完b的构造方法后将其factory也放入三级缓存,此时执行b的属性填充,发现依赖a,从三级缓存中获取a的对象,即调用getSingleton(“a”),此时A的getEarlyBeanReference
方法就会被执行,并将a放入二级缓存中,之后执行intialize初始化,最后将b的bean转入一级缓存;再继续回来创建a,这个时候发现在一级缓存中已经有了b,那么属性填充成功,进行初始化,最后a也放入一级缓存,至此执行完毕。
那么大家可能会感到疑惑,为什么要使用三级缓存呢,感觉没有singletonFactories使用二级缓存也可以呀?
三级缓存实现bean的扩展,将代理对象放入二级缓存中,供其他依赖该bean的对象的使用,如果没有了三级缓存,将bean扩展放在二级缓存中实现,那么如果有bean a被其他多个bean依赖,那么在其他bean填充属性的过程中会多次获取bean a,这个过程中就会多次执行获取bean a代理,就有些多余,而三级缓存结构就是在第三级缓存完成bean的扩展,生成代理对象,放入二级缓存之中,供其他bean获取。