spring bean的生命周期源码解析

源码分析Spring IOC与Bean的生命周期

    • 什么是Ioc(控制反转)/DI(依赖注入)?
    • Bean的生命周期源码分析

说在前面:spring的源码极其庞大,虽然这里我们只讨论bean的生命周期,所谓生命周期就是一个普通对象走完了spring为它设置好的“陷阱”,其实就是一系列函数改变这个对象,函数一环扣一环,希望大家耐心看第一次看可能会有些吃力,所以跟着debug会比较好,我这里只讲关于IOC和bean的生命周期的源码,其他方面源码的肯定会涉及到,但是这里就提一嘴,有机会会展开讲。

!!!!!!!!!!!
!!!!!!!!!!!
!!!!!!!!!!!
我的spring是5.0.x,用的是源码工程,代码很多所以有些我会删掉,如果和你debug的不一样别惊慌,仔细对应,我删掉的一定是和今天内容没关系的。

什么是Ioc(控制反转)/DI(依赖注入)?

IoC 容器:最主要是完成了完成对象的创建和依赖的管理注入等等。

先从我们自己设计这样一个视角来考虑:

所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的文件。

一:实例化对象有时候并不容易,有时候对象与对象之间关系很复杂,我们去维护十分复杂。

二:我们都交给容器,实现解藕

三:我们在类的生产过程中,要对类做一些事情,比如懒加载,代理,我们都交给容器,我们就不需要关心代理的过程是什么样的。

DI:为了实现Ioc这个目的,我们可以使用DI(依赖注入)

依赖:在A类中有一个B类的属性,我们就认为A类依赖B类。

注入:注入就是把需要的属性填充到依赖的类中,Spring中大致的过程就是容器初始化B类,然后用一些办法把属性填充到A类中,这里面的一些办法,有两种,构造方法和setter注入。

容器:在spring中就是一个map,就是一个能够容纳对象的器件。
总之就是一句话,以前我们 new 对象,现在不new了,啥都不干全部交给spring。

Bean的生命周期源码分析

依赖注入是在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)。
spring bean的生命周期源码解析_第1张图片
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并且存入容器的过程。
spring bean的生命周期源码解析_第2张图片
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这个方法执行结束,我们看看控制台,发现已经调用了构造函数了,这就是实例化的第一步
spring bean的生命周期源码解析_第3张图片
第二步是调用addSingletonFactory这个方法,把要实例化的bean加入一个工厂,这也是spring的一个缓存,这个缓存后面有用

第三步,调用populateBean注入属性,因为我们看到上面我们自己的TestService中有UserService的引用,如果没有这个UserService,那么到这里一个简单的bean就实例化结束了,但是我们有这个UserService,当spring填充这个UserService时候,发现没有这个对象,怎么办呢,又回到了第5步,去实例化UserService,也就是说又从第五步到这一步spring又走了一遍,大家可以自行debug,现在不要晕了,第二遍是为了实例化UserService,TestService还没有实例化结束,与此同时走到第8步,我们看控制台:这时候就两个类都已经被实例化,但是这时候线程还是在执行UserService的实例化,等走完后,方法持续返回,再继续实例化TestService,然后结束。
spring bean的生命周期源码解析_第4张图片

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 bean的实例化过程分析图:
spring bean的生命周期源码解析_第5张图片

下一篇:spring的循环依赖如何解决

你可能感兴趣的:(spring)