说在前面:spring的源码极其庞大,虽然这里我们只讨论bean的生命周期,所谓生命周期就是一个普通对象走完了spring为它设置好的“陷阱”,其实就是一系列函数改变这个对象,函数一环扣一环,希望大家耐心看第一次看可能会有些吃力,所以跟着debug会比较好,我这里只讲关于IOC和bean的生命周期的源码,其他方面源码的肯定会涉及到,但是这里就提一嘴,有机会会展开讲。
!!!!!!!!!!!
!!!!!!!!!!!
!!!!!!!!!!!
我的spring是5.0.x,用的是源码工程,代码很多所以有些我会删掉,如果和你debug的不一样别惊慌,仔细对应,我删掉的一定是和今天内容没关系的。
IoC 容器:最主要是完成了完成对象的创建和依赖的管理注入等等。
先从我们自己设计这样一个视角来考虑:
所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的文件。
一:实例化对象有时候并不容易,有时候对象与对象之间关系很复杂,我们去维护十分复杂。
二:我们都交给容器,实现解藕
三:我们在类的生产过程中,要对类做一些事情,比如懒加载,代理,我们都交给容器,我们就不需要关心代理的过程是什么样的。
DI:为了实现Ioc这个目的,我们可以使用DI(依赖注入)
依赖:在A类中有一个B类的属性,我们就认为A类依赖B类。
注入:注入就是把需要的属性填充到依赖的类中,Spring中大致的过程就是容器初始化B类,然后用一些办法把属性填充到A类中,这里面的一些办法,有两种,构造方法和setter注入。
容器:在spring中就是一个map,就是一个能够容纳对象的器件。
总之就是一句话,以前我们 new 对象,现在不new了,啥都不干全部交给spring。
依赖注入是在Spring初始化的时候完成的,初始化一个bean,bean有一个初始化的过程,这个过程就是Spring bean的生命周期。
bean是从哪里产生的呢:先产生一个类,这时候不是我们new对象了,对象的初始化交给spring后十分复杂,我们先来明白一个东西叫BeanDefinition,spring生成bean就是下面的步骤:
Class---------BeanDefinition--------Object(Bean)
BeanDefinition是干嘛的呢,它就是spring用来记录这到底对象都有啥特征的,如果你的类上面贴了@lazy等等这些标签的时候,spring怎么知道它懒加载等等一些信息的呢,当扫描到这些注解后,它把这些信息封存在这个BeanDefinition中,但是它只是一个对象,它只能存储这个类的一些信息,那么很多个类怎么办,于是有一个beanDefinitionMap(beanName, beanDefinition)来存储各种各样的BeanDefinition。下面我用源码证明:
首先我先声明我这里的环境以及代码:
@Component
public class TestService {
@Autowired
private UserService us;
TestService(){
System.out.println("调用testservice构造函数");
}
}
@Component
public class UserService {
public UserService(){
System.out.println("调用userservice构造函数");
}
}
@ComponentScan("你要扫描的包名")
@Configuration
public class AppConfig {}
大家用spring注解的时候都会有这一句代码,相当于你的ClasspathXmlApplicationContext:
/*测试类的初始化Spring容器的代码*/
public class test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);//可以在这里加断点
Student bean = applicationContext.getBean(UserService.class);
System.out.println(bean);
}
}
1.我们点进AnnotationConfigApplicationContext的源码
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
//这个方法的作用大致就是beanDefinitionMap.put(beanName, beanDefinition)
register(annotatedClasses);
refresh();
}
在执行完register(annotatedClasses)方法后,我们看打印的信息。我们发现,果然有个叫beanDefinitionMap的容器存储对象信息,我们看到了熟悉的一个类名appConfig类,这是我们的配置类,但是还有很多我们不认识的,不用管这是spring自己的,所以这个函数其实说到底做了一件很重要的事情--------beanDefinitionMap.put(beanName, beanDefinition)。
2.我们点进refresh()方法,点进去懵逼了,方法多的要死,我们选和这个文章有关系的,我把代码删了很多,主要就是下面两个方法
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
try {
/*
* Invoke factory processors registered as beans in the context.
* 主要是一些扫描的工作,执行完这行代码所有的添加一些注解(@Component)的类就会被扫描到加入beanDefinitionMap当中
* 当程序员自己实现了BeanFactoryPostProcessor也会被扫描到
*/
invokeBeanFactoryPostProcessors(beanFactory);
// Instantiate all remaining (non-lazy-init) singletons.
//实例化bean
finishBeanFactoryInitialization(beanFactory);
}
}
}
我们给这两个函数加断点,我们看invokeBeanFactoryPostProcessors函数执行完的结果:大家发现没有,我们自己定义的两个类也进入了这个容器,所以其实到这里,我们spring只是完成了将class转换为BeanDefinition并且存入容器的过程。
3.我们再看finishBeanFactoryInitialization(beanFactory)这个函数,这个我直接告诉大家,就是这个函数里完成了对我们bean的实例化,所以直接进去,老惯例删掉很多无关的函数:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}
4.点进preInstantiateSingletons这个函数,没什么意思都是封装套封装
这个方法里面就是在实例化之前,先判断你是不是单例,是不是支持懒加载等等,这里有时候面试被问,spring是不是默认支持单例的,答案是:是!isSingleton()函数你直接点你就会发现,默认支持单例,为什么我们后面再说。这里我们条件都符合,进入getBean。
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);
}
}
}
}
5.我们点进getBean,这是一个空壳方法,所以我们点进doGetBean()
doGetBean,重要的一匹!!!!!!!我删掉了很多无用的代码
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//第一次从缓存中拿
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//在这里解析FactoryBean,有没有加&符号
//如果你getBean("&beanName"),那么取出来就是那个类,如果
//getBean("beanName")取出来就是这个bean。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
return (T) bean;
}
我们先来看Object sharedInstance = getSingleton(beanName)这句代码,我上面写了注释,第一次从缓存中拿,spring中有三个缓存,我们点进getSingleton。这里大家可以不跟我debug,这里我要讲明白这个函数。缓存是什么?是这个叫singletonObjects的map,我们可以看到它第一步就去singletonObjects中去get,这个map就是著名的spring的单例池,单例池就是已经实例化好的对象我就放进去,我要用的时候直接从池子里面拿,不用再实例化一遍,好的,说到这里,不知道大家有没有疑惑,这时候从单例池中get,怎么可能get到,因为所有的对象第一次实例化都要过来这里,我们没有发现singletonObjects什么时候有put操作,这个对象还在实例化过程中,所以这个方法放在这里有什么用呢,拿又拿不到。好的带着这个疑问,我们往下看,get不到直接返回。又返回了上面的那个方法,倒回去看
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//从单例池中拿
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
6.在第一次从缓存取结束后,会走到下一次的 getSingleton,但是这是一个lambda表达式,会先调用getSingleton方法,它主要干两件事情
第一件事情:beforeSingletonCreation(beanName),这个方法看名字,就是意思是记录 正在创建状态的bean,点进源码你会发现存储正在创建状态bean的容器是一个set集合。值得注意的是,在中间我写注释的那段代码,调用getObject时会跳转到createBean方法,等createBean方法结束之后会继续向下执行,封装套封装,乱~~
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
//注意上面这个函数,调用这个函数的时候,会跳转到createBean
newSingleton = true;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
第二件事是addSingleton,我们点进源码看看,其实我们看到了put,remove,add操作,这一看就是许多数据结构的操作,这是什么呢,这就是著名的spring的三级缓存,缓存就是为了提升速度的,我们下一篇,专门讲讲为什么设置三个缓存,这些都是spring为提升性能所做的操作。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
7.实例化bean的最终是在createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
try {
//通过调用doCreateBean创建bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// A previously detected exception with proper bean creation context already,
// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
8.点进doCreateBean,这个方法最终完成了bean的实例化
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//创建bean实例,并将实例包裹在BeanWrapper实现类对象中返回。
//createBeanInstance(beanName, mbd, args)包含三种创建bean的方式
// 1.通过工厂方法创建bean实例
// 2.通过构造方法自动注入的方式创建实例
// 3.通过无参构造方法创建实例
//在这里会打印类的构造函数但是属性并没有注入
//
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//getEarlyBeanReference,第四次调用后置处理器
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
//在这个方法中进行属性的注入(调用set方法进行赋值)
populateBean(beanName, mbd, instanceWrapper);
//进行对象的初始化操作(可能生成代理对象),AOP在这里完成
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
createBeanInstance这个方法执行结束,我们看看控制台,发现已经调用了构造函数了,这就是实例化的第一步
第二步是调用addSingletonFactory这个方法,把要实例化的bean加入一个工厂,这也是spring的一个缓存,这个缓存后面有用
第三步,调用populateBean注入属性,因为我们看到上面我们自己的TestService中有UserService的引用,如果没有这个UserService,那么到这里一个简单的bean就实例化结束了,但是我们有这个UserService,当spring填充这个UserService时候,发现没有这个对象,怎么办呢,又回到了第5步,去实例化UserService,也就是说又从第五步到这一步spring又走了一遍,大家可以自行debug,现在不要晕了,第二遍是为了实例化UserService,TestService还没有实例化结束,与此同时走到第8步,我们看控制台:这时候就两个类都已经被实例化,但是这时候线程还是在执行UserService的实例化,等走完后,方法持续返回,再继续实例化TestService,然后结束。
9.直到TestService实例化结束,方法返回,bean的生命周期结束,因为我们不要忘了前面的lambda表达式,doCreatBean方法实例化了bean之后会返回到getSingleton,会执行的addSingleton
这个方法就是在bean实例化之后,终于把这个bean,加入到了spring的单例池,从二级和三级缓存移除这个bean,以后可以直接从单例池中拿了,十分方便
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
至此我们遗留了几个问题啊
为什么要默认支持单例模式
为什么在第5步的时候在前面就要调用getSingleton方法,而后在后面的重载的getSingleton方法中对类进行实例化?
为什么要设置三级缓存?
下一篇:spring的循环依赖如何解决