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

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


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

先写一个dome

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

/ * 功能描述:bean 对象 * * @author Songxianyang * @date 2022-05-13 15:42 */@Datapublic 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常见问题及源码分析之持续更新|大白话解说

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

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");// 准备此上下文以进行刷新。prepareRefresh();// 告诉子类刷新内部 bean 工厂。去获取工程中自己配置的beanConfigurableListableBeanFactory 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();

面试必问-Spring常见问题及源码分析之持续更新|大白话解说
后续我们在跟到里面…这里先放在这里 。先大概再到具体分析

准备 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);

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

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

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

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. */@Overrideprotected final void refreshBeanFactory() throws BeansException {//先判断这个BeanFactory 是不是存在if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {//不存在 DefaultListableBeanFactory 就创建这种bean工厂DefaultListableBeanFactory beanFactory = createBeanFactory();// 序列化id 赋值beanFactory.setSerializationId(getId());// 可以不看这个方法   这个方法是定制bean工厂的方法 暂时用不上customizeBeanFactory(beanFactory);// 这个方法是实际干活的方法  :从配置文件xml中读取到我们定义的beanloadBeanDefinitions(beanFactory);this.beanFactory = beanFactory;}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}}

这是还没有执行 实际干活的方法
面试必问-Spring常见问题及源码分析之持续更新|大白话解说
实际干活的方法:执行后
面试必问-Spring常见问题及源码分析之持续更新|大白话解说
因为我在spring-config.xml 就配置了一个bean
面试必问-Spring常见问题及源码分析之持续更新|大白话解说

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

loadBeanDefinitions(beanFactory);
/ * Loads the bean definitions via an XmlBeanDefinitionReader. * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader * @see #initBeanDefinitionReader * @see #loadBeanDefinitions */@Overrideprotected 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 文件中的beanResource[] configResources = getConfigResources();if (configResources != null) {reader.loadBeanDefinitions(configResources);}我们给定字符串的 xml配置,一下进行说明String[] configLocations = getConfigLocations();if (configLocations != null) {reader.loadBeanDefinitions(configLocations);}}
截图:

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

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

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

此时这个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的初始化过程。

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

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

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

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

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

到这里 什么是 bean 的初始化

在这里说一下 。我们平时在 new 对象的时候 这么给对象赋值的。这个赋值的操作就是初始化工作。
那么仔细看 我那个catBean 这个对象 赋值赋值没。很显然 没有
面试必问-Spring常见问题及源码分析之持续更新|大白话解说

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

现在他来了

this.populateBean(beanName, mbd, instanceWrapper);

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

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