面试必问-Spring常见问题及源码分析之持续更新|大白话解说

116 阅读6分钟

IOC bean的执行流程以及生命周期

先写一个dome

在这里插入图片描述 在这里插入图片描述

catBean对象

/**
 * 功能描述:bean 对象
 *
 * @author Songxianyang
 * @date 2022-05-13 15:42
 */
@Data
public class CatBean {
    private String name;
}

spring-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  
  <bean id="catBean" class="com.song.boot.springstudy.myspring.bean.CatBean">
    <property name="name" value="洛洛"></property>
  </bean>
</beans>

TestXmlSpring

/**
 * 功能描述:学习  Spring 源码
 *
 * @author Songxianyang
 * @date 2022-05-13 15:35
 */
public class TestXmlSpring {
    
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "spring-config.xml");
        CatBean cat = (CatBean) context.getBean("catBean");
        System.out.println(cat.getName());
    }
}

org.springframework.context.support.AbstractApplicationContext#refresh()方法

setConfigLocations(configLocations); 显然装在我们的配置文件

在这里插入图片描述

Spring中的核心方法,会了它 你就会了全世界,哈哈哈

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// 准备此上下文以进行刷新。
			prepareRefresh();

			// 告诉子类刷新内部 bean 工厂。去获取工程中自己配置的bean
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 准备 bean 工厂以在此上下文中使用。 准备好自己工厂里面的bean 
			prepareBeanFactory(beanFactory);

			try {
				// 允许在上下文子类中对 bean 工厂进行后处理。
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// 调用在上下文中注册为 bean 的工厂处理器。
				invokeBeanFactoryPostProcessors(beanFactory);

				//注册拦截 bean 创建的 bean 处理器。
				registerBeanPostProcessors(beanFactory);
				beanPostProcess.end();

				// 为此上下文初始化消息源。
				initMessageSource();

				// 为此上下文初始化事件多播器
				initApplicationEventMulticaster();

				// 初始化特定上下文子类中的其他特殊 bean。
				onRefresh();

				// 检查侦听器 bean 并注册它们。
				registerListeners();

				//实例化所有剩余的(非惰性初始化)单例。
				finishBeanFactoryInitialization(beanFactory);

				//最后一步:发布相应的事件。
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// 销毁已经创建的单例以避免悬空资源。
				destroyBeans();

				// 重置“活动”标志。
				cancelRefresh(ex);

				// 将异常传播给调用者。
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				//重置 Spring 核心中的常见自省缓存,因为我们可能不再需要单例 bean 的元数据......
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

告诉子类刷新内部 bean 工厂。去获取工程中自己配置的bean

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

在这里插入图片描述 后续我们在跟到里面........这里先放在这里 。先大概再到具体分析

准备 bean 工厂以在此上下文中使用。 准备好自己工厂里面的bean

		prepareBeanFactory(beanFactory);

大概意思就是:我们已经实例话一个bean工厂,但是这个beanFactory 并不是我们拿来就能用的。这个方法就是对这个beanFactory 上下问的初始化工作。有了这些初始化我们才能进行,系统环境才能使用这个beanFactory。

具体初始化了什么?

这个方法比较简单 我们就在这里说说:先看这段code 简明知意

/**
	 * Configure the factory's standard context characteristics,
	 * such as the context's ClassLoader and post-processors.
	 * @param beanFactory the BeanFactory to configure
	 * 配置工厂的标准上下文特征,例如上下文的 ClassLoader 和后处理器。 @param beanFactory 要配置的 BeanFactory
	 */
	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		// 告诉内部 bean 工厂使用上下文的类加载器等。
		// 获取获取默认的类加载器 放进 bean工厂
		beanFactory.setBeanClassLoader(getClassLoader());
		if (!shouldIgnoreSpel) {
			beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		}
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		// 使用上下文回调配置 bean 工厂。 配置 环境、解析器、信息资源、上下文、类加载器 等等
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		//BeanFactory 接口未在普通工厂中注册为可解析类型。 MessageSource 作为 bean 注册(并为自动装配找到)。
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		// Register early post-processor for detecting inner beans as ApplicationListeners.
		// 将用于检测内部 bean 的早期后处理器注册为 ApplicationListener。
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		// 检测 LoadTimeWeaver 并准备编织(如果找到)。
		if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// Register default environment beans.
		// 给 bean 赋值默认的环境配置
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
		if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
			beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
		}
	}

初始化Bean工厂中的Bean对象 等方法

finishBeanFactoryInitialization(beanFactory);

在这里插入图片描述

重点来了 我们来分析 bean工厂,怎么获取bean工厂。加油奥里给

在这里插入图片描述

ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory();
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		return getBeanFactory();
	}

第一步 刷新bean 工厂

来分析
/**
	 * This implementation performs an actual refresh of this context's underlying
	 * bean factory, shutting down the previous bean factory (if any) and
	 * initializing a fresh bean factory for the next phase of the context's lifecycle.
	 */
	@Override
	protected final void refreshBeanFactory() throws BeansException {
	//先判断这个BeanFactory 是不是存在
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
		//不存在 DefaultListableBeanFactory 就创建这种bean工厂
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			// 序列化id 赋值
			beanFactory.setSerializationId(getId());
			// 可以不看这个方法   这个方法是定制bean工厂的方法 暂时用不上
			customizeBeanFactory(beanFactory);
			// 这个方法是实际干活的方法  :从配置文件xml中读取到我们定义的bean
			loadBeanDefinitions(beanFactory);
			this.beanFactory = beanFactory;
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

这是还没有执行 实际干活的方法 在这里插入图片描述 实际干活的方法:执行后 在这里插入图片描述 因为我在spring-config.xml 就配置了一个bean 在这里插入图片描述

给大家看一下 这个干活的实现方式 是什么样的

loadBeanDefinitions(beanFactory);
/**
	 * Loads the bean definitions via an XmlBeanDefinitionReader.
	 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
	 * @see #initBeanDefinitionReader
	 * @see #loadBeanDefinitions
	 */
	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		创建一个去读取XML的对象
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		下面是给对象赋值的一些操作
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		初始化bean的一个阅读器 去读
		initBeanDefinitionReader(beanDefinitionReader);
		实际去加载 xml 获取bean的方法,下面进行说明
		loadBeanDefinitions(beanDefinitionReader);
	}

实际去加载 xml 获取bean的方法,下面进行说明

	loadBeanDefinitions(beanDefinitionReader);
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		这个方法 从Resource目录下面读到的xml 文件中的bean
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		我们给定字符串的 xml配置,一下进行说明
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
	}
截图:

在这里插入图片描述

拿到配置后 就开始执行 读取这个配置文件xml

在这里插入图片描述

此时这个bean工厂创建成功 ,并返回。

在这里想一下 他怎么实例化并初始化我们在xml中配置的bean。我也不知道 接着跟代码(苦笑)

干活的代码,哈哈哈。也是断点的位置。

finishBeanFactoryInitialization(beanFactory);
	beanFactory.preInstantiateSingletons();
	this.getBean(beanName);
	 return this.doGetBean(name, (Class)null, (Object[])null, false);
	  return this.createBean(beanName, mbd, args);
	  // 获取bean 实例
	  beanInstance = this.doCreateBean(beanName, mbdToUse, args);
	  创建 bean 实例
	  instanceWrapper = this.createBeanInstance(beanName, mbd, args);
	  return ctors != null ? this.autowireConstructor(beanName, mbd, ctors, (Object[])null) : this.instantiateBean(beanName, mbd);
	  反射构造器
	   constructorToUse = clazz.getDeclaredConstructor();
	   实例化bean对象
	 return BeanUtils.instantiateClass(constructorToUse, new Object[0]);
	

分析它的执行流程。也是bean的初始化过程。

因为代码太多 我就在关键代码上打断点 给大家 解释

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

在这里插入图片描述 在这里插入图片描述

在这里插入图片描述

在这里插入图片描述 在这里插入图片描述

到这里 什么是 bean 的初始化

在这里说一下 。我们平时在 new 对象的时候 这么给对象赋值的。这个赋值的操作就是初始化工作。 那么仔细看 我那个catBean 这个对象 赋值赋值没。很显然 没有 在这里插入图片描述

那么怎么初始化 执行那段代码 可以执行对属性 的初始化工作

现在他来了

this.populateBean(beanName, mbd, instanceWrapper);

在这里插入图片描述

那么执行完了 bean 实例化与初始化之后,下一步该干啥