【Spring成神之路】一次SpringIOC源码之旅,女朋友也成为了Spring大神!

文章目录

  • 一、前言
  • 二、前置准备
  • 三、IOC容器的使用
  • 四、Spring IOC源码解读
    • 1. prepareRefresh源码解读
    • 2. obtainFreshBeanFactory源码解读
      • 2.1 refreshBeanFactory源码解读
    • 3. prepareBeanFactory源码解读
    • 4. postProcessBeanFactory源码解读
    • 5. invokeBeanFactoryPostProcessors源码解读
    • 6. registerBeanPostProcessors源码解读
    • 7. initMessageSource源码解析
    • 8. initApplicationEventMulticaster源码解读
    • 9. onRefresh源码解读
    • 10. registerListeners源码解读
    • 11. finishBeanFactoryInitialization源码解读
      • 11.1 preInstantiateSingletons源码解读
    • 12. finishRefresh源码解读
    • 13. IOC容器加载失败源码解读
    • 14. IOC容器销销毁源码解读
  • 五、流程图

一、前言

无论你是一个经验丰富的Java-er,还是一个Java初学者,都会听过Spring框架的大名,我在初学这个Spring框架的时候都是对这个框架当成一个工具使用,只知道这样做能够达到这样的效果,但是具体里面是怎么实现的也说不清楚,不过随着现在技术的越来越卷,我感觉有必要揭开Spring框架的内幕,深度学习领悟这一优秀的框架了!

本文是针对Spring框架中的IOC核心功能进行源码解读的,准备好的话,那就一起出发喽

若文章有错误之处,欢迎各位大佬指正!


二、前置准备

本文会对Spring框架的IOC源码进行解读,推荐各位去GitHub下载一份Spring源码配合本篇文章食用更佳!

本文是针对Spring 4.0.0 的源码而编写的,不同版本源码会有差异,但整体业务逻辑不变。

<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.0.0.RELEASE</version>
</dependency>

不推荐阅读高版本的源码而更推荐老版本的代码,因为老版本的代码既保留了最初的设计思想,也不会被新出的功能弄得花里胡哨!


三、IOC容器的使用

首先,咱们先来复习一下Spring IOC容器的使用。

public interface UserService {String selectList();}
public class UserServiceImpl implements UserService {@Overridepublic String selectList() {return "小明, 小红, 小蓝";}
}
<?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="messageService" class="spring.ioc.UserServiceImpl"/></beans>
public class SpringTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");System.out.println("context 启动成功");UserService userService = context.getBean(UserService.class);System.out.println(userService.selectList());}
}

image-20240623201246675

Spring IOC的使用中,很直观就能感受到的就是Spring IOC代替我们程序缘完成了对一个对象的new

把创建实例的工作交给了Spring IOC,可以简化不少程序员的工作。

这时候有人就说了,new 一个对象那么简单,用不用Spring IOC也差不多呀!

那不可不是喔,随着系统的迭代开发,一个对象的依赖关系会越来越复杂,比如类A同时依赖类B、类C、类D,而类B又依赖类X、类Y、类Z,当你尝试new一个这样的对象不可避免的会感觉心累。。。


四、Spring IOC源码解读

对于Spring IOC的源码,我认为必须带着“Bean存储在哪?什么时候被实例化?怎么获取的?”这三个问题去阅读!

还是从上面的Demo代码入手阅读。

public class SpringTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");System.out.println("context 启动成功");UserService userService = context.getBean(UserService.class);System.out.println(userService.selectList());}
}

在这个Demo代码中,干了三件事:

  1. 使用application.xml 配置文件作为构造参数,创建了一个Spring容器
  2. Spring容器中获取UserService实例
  3. 调用UserService实例的方法

针对这三步,我合理猜测Spring容器创建的时候就完成了Spring Bean的注入。

接下来进入ApplicationContext context = new ClassPathXmlApplicationContext("application.xml") 源码查看是不是这样子的。

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {public ClassPathXmlApplicationContext(String configLocation) throws BeansException 	{this(new String[] {configLocation}, true, null);}public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {super(parent);setConfigLocations(configLocations);if (refresh) {refresh();}}}

这里干了三件事:

  1. 调用了父类ApplicationContext的构造函数,并将parent参数传递给它
  2. 调用setConfigLocations方法,将传入的配置文件路径设置到当前的ClassPathXmlApplicationContext实例中
  3. 如果refreshtrue,则调用refresh方法。这个方法会触发Spring容器的刷新过程,重新加载所有的bean定义

其他都不重要,重要的是refresh()方法,这个方法会触发Spring容器的刷新,加载Bean的定义。

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}}
}

下面会针对refresh()的每一步进行解析!


1. prepareRefresh源码解读

prepareRefresh方法主要是进行Spring容器刷新前的一些准备工作,并不主要特别关注!

protected void prepareRefresh() {// 记录Spring容器开始刷新的时间this.startupDate = System.currentTimeMillis();// 标志Spring容器刷新工作开始synchronized (this.activeMonitor) {this.active = true;}if (logger.isInfoEnabled()) {logger.info("Refreshing " + this);}// 初始化上下文中的占位符属性源initPropertySources();// 调用getEnvironment方法获取环境对象,并调用其validateRequiredProperties方法来验证必需的属性getEnvironment().validateRequiredProperties();
}

2. obtainFreshBeanFactory源码解读

obtainFreshBeanFactory的作用是刷新内部Bean工厂返回一个新的BeanFactory实例。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {refreshBeanFactory();ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (logger.isDebugEnabled()) {logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);}return beanFactory;
}

2.1 refreshBeanFactory源码解读

refreshBeanFactory 是解析application.xml配置文件并生成BeanDefinition注册到Spring IOC中去,具体怎么操作,请看下面org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory源码解读

protected final void refreshBeanFactory() throws BeansException {// 如果BeanFactory已经存在,先销毁原来的BeanFactoryif (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {// 创建一个DefaultListableBeanFactoryDefaultListableBeanFactory beanFactory = createBeanFactory();beanFactory.setSerializationId(getId());// 设置bean是否允许覆盖 是否允许循环依赖customizeBeanFactory(beanFactory);// 加载BeanDefinitionloadBeanDefinitions(beanFactory);synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);}
}

DefaultListableBeanFactory 这个类,十分重要!!!它是Spring IOC容器的核心!!!

org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory)源码如下

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// 将读取XML操作交付给XmlBeanDefinitionReader,且生成的BeanDefinition注册进IOC中XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// 设置Spring容器beanDefinitionReader.setEnvironment(this.getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));initBeanDefinitionReader(beanDefinitionReader);// 读取xmlloadBeanDefinitions(beanDefinitionReader);
}

接下来,着重看loadBeanDefinitions(beanDefinitionReader),深入了解如何加载BeanDefition

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {// 获取配置资源的数组Resource[] configResources = getConfigResources();if (configResources != null) {reader.loadBeanDefinitions(configResources);}// 配置位置的路径字符串数组,以加载这些路径指定的Bean定义String[] configLocations = getConfigLocations();if (configLocations != null) {reader.loadBeanDefinitions(configLocations);}
}

接着看loadBeanDefinitions

public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {Assert.notNull(locations, "Location array must not be null");int count = 0;for (String location : locations) {// 只需要关注loadBeanDefinitions这个方法count += loadBeanDefinitions这个方法(location);}return count;
}

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions(org.springframework.core.io.Resource)

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {return loadBeanDefinitions(new EncodedResource(resource));
}public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {/** 省略部分代码  **/return doLoadBeanDefinitions(inputSource, encodedResource.getResource());}

继续看org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions这里开始就是加载BeanDefinitions

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {// 因为配置文件是一个xml文件,因此将inputSource进行解析封装成一个DocumentDocument doc = doLoadDocument(inputSource, resource);// 注册Bean定义int count = registerBeanDefinitions(doc, resource);return count;  
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {// 创建一个DocumentReader, 负责读取和解析XML文档中的Bean定义BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();// 记录加载Bean之前容器的Bean数量int countBefore = getRegistry().getBeanDefinitionCount();// 注册BeandocumentReader.registerBeanDefinitions(doc, createReaderContext(resource));return getRegistry().getBeanDefinitionCount() - countBefore;
}

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#registerBeanDefinitions

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext;// 从根元素开始遍历doRegisterBeanDefinitions(doc.getDocumentElement());
}protected void doRegisterBeanDefinitions(Element root) {BeanDefinitionParserDelegate parent = this.delegate;// 创建一个新的BeanDefinitionParserDelegate对象,这个对象将用于解析XML中的bean定义this.delegate = createDelegate(getReaderContext(), root, parent);// 解析Bean定义之前执行一些预处理操作,Spring框架并没有给出实现类, 属于一种扩展点preProcessXml(root);// 重点!!加载Bean定义parseBeanDefinitions(root, this.delegate);// 解析Bean定义之后执行一些后处理操作,Spring框架也并没有给出实现类, 属于一种扩展点postProcessXml(root);this.delegate = parent;
}

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions的作用是根据XML配置文件的标签的不同,进行不同的处理

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {if (delegate.isDefaultNamespace(root)) {NodeList nl = root.getChildNodes();for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);if (node instanceof Element) {Element ele = (Element) node;if (delegate.isDefaultNamespace(ele)) {parseDefaultElement(ele, delegate);}else {delegate.parseCustomElement(ele);}}}}else {delegate.parseCustomElement(root);}
}/**
* 根据标签不同进行不同的操作,这里重点介绍processBeanDefinition方法
**/
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {importBeanDefinitionResource(ele);}else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele);}else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {// 加载beanprocessBeanDefinition(ele, delegate);}else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// recursedoRegisterBeanDefinitions(ele);}
}

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition这个方法是将Bean定义注册进容器中

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {// 将XML元素解析成BeanDefinitionHolder对象BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);if (bdHolder != null) {// 对Bean进行适当装饰bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try {// 将Bean定义注册进容器中BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());}catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to register bean definition with name '" +bdHolder.getBeanName() + "'", ele, ex);}// 触发注册时间getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));}
}

debugorg.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition方法,看看是如何进行注册的

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {// 获取Bean定义的名字String beanName = definitionHolder.getBeanName();// 注册Bean定义registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());// 获取别名String[] aliases = definitionHolder.getAliases();if (aliases != null) {for (String alias : aliases) {registry.registerAlias(beanName, alias);}}
}
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {// 根据BeanName获取BeanDefinitionBeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);if (existingDefinition != null) {// bean已经存在 进行一些操作,感兴趣自己去看源码}else {// BeanName不存在if (hasBeanCreationStarted()) {// Cannot modify startup-time collection elements anymore (for stable iteration)synchronized (this.beanDefinitionMap) {this.beanDefinitionMap.put(beanName, beanDefinition);List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);updatedDefinitions.addAll(this.beanDefinitionNames);updatedDefinitions.add(beanName);this.beanDefinitionNames = updatedDefinitions;removeManualSingletonName(beanName);}}else {// 将beanName与beanDefinition放至beanDefinitionMap中this.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);removeManualSingletonName(beanName);}this.frozenBeanDefinitionNames = null;}
}

到这里BeanDefinition的注册就基本完成了,主要是以下这些步骤:

  1. 将XML文件包装成一个Document对象
  2. 利用BeanDefinitionDocumentReader解析Document
  3. 从XML的root进行遍历,针对不同标签import、bean、beans等进行不同的处理
  4. bean标签而言,在parseBeanDefinitionElement方法中将bean标签的组装成一个BeanDefinitionHolder
  5. 调用BeanDefinitionRegistryregisterBeanDefinition进行BeanDefinition注册
  6. 检查beanName是否已经注册,如果没有注册则将该BeanDefinition注册进org.springframework.beans.factory.support.DefaultListableBeanFactory#beanDefinitionMap中去
  7. 如果存在别名,也可以进行别名注册。

3. prepareBeanFactory源码解读

prepareBeanFactory方法主要是完善beanFactory, 对其进行一些属性填充

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// 配置类加载器beanFactory.setBeanClassLoader(getClassLoader());// 配置表达式解析器, 用于解析Spring表达式beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver());// 注册属性编辑注册器beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));// 添加BeanPostProcessor, 用于处理实现了ApplicationContextAware接口的BeanbeanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));// 忽略特定的依赖接口beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);beanFactory.ignoreDependencyInterface(EnvironmentAware.class);// 注册可解析的依赖beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);beanFactory.registerResolvableDependency(ResourceLoader.class, this);beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);beanFactory.registerResolvableDependency(ApplicationContext.class, this);// 检查和准备AOP织入if (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()));}// 注册环境相关beanif (!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());}
}

4. postProcessBeanFactory源码解读

没有给出实现,交由子类去实现

image-20240625230703942


5. invokeBeanFactoryPostProcessors源码解读

invokeBeanFactoryPostProcessors的作用是调用所有注册的BeanFactoryPostProcessor实例

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
}

6. registerBeanPostProcessors源码解读

registerBeanPostProcessors的作用是实例化BeanPostProcessor

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
}

这里的操作会先把BeanPostProcessor创建出来并注入Spring容器中,但是不会立刻调用BeanPostProcessor中的方法


7. initMessageSource源码解析

initMessageSource方法主要是为了初始化Spring框架中的MessageSource组件——Spring的国际化

protected void initMessageSource() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);// Make MessageSource aware of parent MessageSource.if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;if (hms.getParentMessageSource() == null) {// Only set parent context as parent MessageSource if no parent MessageSource// registered already.hms.setParentMessageSource(getInternalParentMessageSource());}}if (logger.isDebugEnabled()) {logger.debug("Using MessageSource [" + this.messageSource + "]");}}else {// Use empty MessageSource to be able to accept getMessage calls.DelegatingMessageSource dms = new DelegatingMessageSource();dms.setParentMessageSource(getInternalParentMessageSource());this.messageSource = dms;beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);if (logger.isDebugEnabled()) {logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +"': using default [" + this.messageSource + "]");}}
}

什么是Spring国际化?

Spring的国际化(Internationalization,简称i18n)是指使应用程序能够适应不同语言和地区的过程。国际化的目的是让应用程序能够显示和处理多种语言,从而满足全球用户的需求。Spring框架提供了一套机制来支持国际化


8. initApplicationEventMulticaster源码解读

initApplicationEventMulticaster的作用是初始化事件广播器,相对比较简单

protected void initApplicationEventMulticaster() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {this.applicationEventMulticaster =beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);if (logger.isDebugEnabled()) {logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");}}else {this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);if (logger.isDebugEnabled()) {logger.debug("Unable to locate ApplicationEventMulticaster with name '" +APPLICATION_EVENT_MULTICASTER_BEAN_NAME +"': using default [" + this.applicationEventMulticaster + "]");}}
}

9. onRefresh源码解读

在Spring中没有给出实现,属于一个模板方法,但是在SpringBoot中启动了Web服务器

protected void onRefresh() throws BeansException {// For subclasses: do nothing by default.
}

10. registerListeners源码解读

registerListeners的作用是为了注册监听器,方便接收广播事件

protected void registerListeners() {// Register statically specified listeners first.for (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let post-processors apply to them!String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String lisName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(lisName);}
}

11. finishBeanFactoryInitialization源码解读

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// 初始化上下文转化服务,主要用于类型转化、数据转换等等if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));}// 提前实例化LoadTimeWeaverAware的类String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);for (String weaverAwareName : weaverAwareNames) {getBean(weaverAwareName);}// 在BeanFactory初始化完成后,不再需要临时类加载器,因此将其设置为null。beanFactory.setTempClassLoader(null);// BeanFactory将不再期望对Bean的定义进行进一步的更改,这有助于提高性能。beanFactory.freezeConfiguration();// 实例化所有非延迟初始化的单例Bean。这意味着所有剩余的单例Bean都将被创建,即使它们尚未被显式请求。beanFactory.preInstantiateSingletons();
}

11.1 preInstantiateSingletons源码解读

这里的preInstantiateSingletons是经过简化的

public void preInstantiateSingletons() throws BeansException {List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);for (String beanName : beanNames) {// 获取Bean定义RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);// 需要实例化的bean不是抽象的 并且是单例 并且不属于懒加载if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {if (isFactoryBean(beanName)) {// 获取工厂BeanObject bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {FactoryBean<?> factory = (FactoryBean<?>) bean;// 为true表示需要被立刻实例化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 {// 不属于工厂Bean,就可以立即创建BeangetBean(beanName);}}}}

这里干了这几件事情:

  1. 获取当前所有Bean定义的BeanName集合
  2. 遍历BeanName集合,进行判断
    • 如果该Bean是一个FactoryBean,则检查它是否实现了 SmartFactoryBean 接口,调用 isEagerInit 方法来确定是否需要立即初始化。
    • 如果不是FactoryBean,立刻实例化

12. finishRefresh源码解读

finishRefresh的完成容器的启动,清除上下文,初始化生命周期处理器,并发送刷新事件

protected void finishRefresh() {// 初始化生命周期处理器initLifecycleProcessor();// 刷新事件传播到生命周期处理器。getLifecycleProcessor().onRefresh();// 创建并发布一个ContextRefreshedEvent事件,通知所有监听器应用程序上下文已经刷新完成publishEvent(new ContextRefreshedEvent(this));// Participate in LiveBeansView MBean, if active.LiveBeansView.registerApplicationContext(this);
}

13. IOC容器加载失败源码解读

当Spring容器启动的时候出现异常后会走catch流程,首当其冲就是调用destroyBeans,也就是销毁所有bean,让JVM能够回收内存。

protected void destroyBeans() {getBeanFactory().destroySingletons();
}public void destroySingletons() {if (logger.isTraceEnabled()) {logger.trace("Destroying singletons in " + this);}synchronized (this.singletonObjects) {this.singletonsCurrentlyInDestruction = true;}String[] disposableBeanNames;synchronized (this.disposableBeans) {disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());}for (int i = disposableBeanNames.length - 1; i >= 0; i--) {destroySingleton(disposableBeanNames[i]);}this.containedBeanMap.clear();this.dependentBeanMap.clear();this.dependenciesForBeanMap.clear();clearSingletonCache();
}public void destroySingletons() {super.destroySingletons();updateManualSingletonNames(Set::clear, set -> !set.isEmpty());clearByTypeCache();
}

接着将IOC容器的活跃状态设置为false

protected void cancelRefresh(BeansException ex) {synchronized (this.activeMonitor) {this.active = false;}
}

14. IOC容器销销毁源码解读

当IOC容器被关闭的时候,会调用close方法

public void close() {synchronized (this.startupShutdownMonitor) {doClose();}
}

close方法调用了doClose方法

protected void doClose() {boolean actuallyClose;synchronized (this.activeMonitor) {actuallyClose = this.active && !this.closed;this.closed = true;}// 发布容器关闭事件publishEvent(new ContextClosedEvent(this));getLifecycleProcessor().onClose();// 销毁Bean,上面有解释destroyBeans();// 将beanFactory设置为null,方便JVM回收closeBeanFactory();synchronized (this.activeMonitor) {this.active = false;}
}

五、流程图

暂时略~后面有时间再补充哈哈哈


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/38178.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机Java项目|基于SpringBoot的作业管理系统设计与实现

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、Python项目、前端项目、人工智能与大数据、简…

Lumos学习王佩丰Excel第三讲:查找替换定位

一、查找和替换 1、按值查找 2、按格式查找 将红色的单元格替换成黄色的单元格&#xff0c;其他格式同理处理。 3、是否开启单元格匹配 若不打开选项卡直接全部替换&#xff0c;会出现“苏州市市”的情况&#xff1b;加入单元格匹配的规则&#xff0c;检索时会以整个单元格内…

运维.Linux下执行定时任务(上:Cron简介与用法解析)

运维专题 Linux下执行定时任务&#xff08;上&#xff1a;Cron简介与用法解析&#xff09; - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAd…

AI陪伴产品的情感设计:从孤独感到恋爱感评分:9/10

本文主要阐述三个话题&#xff1a; 1. 市面上有哪些AI陪伴产品&#xff1f; 2. 我们团队要怎么做&#xff1f; 3. 为什么要做&#xff1f; 市面上有哪些陪伴类产品&#xff1f; Role-play&#xff08;角色扮演&#xff09; 在当前市场上&#xff0c;有不少以角色扮演为核心的…

灵魂拷问,如何应对平行志愿的天坑?

高考填报志愿实行平行志愿&#xff0c;关于这个概念这里不重复说&#xff0c;不了解平行志愿的可以百度补课&#xff0c;这里只说平行志愿的坑挖得实在太大了&#xff0c;以至于很多同学都入坑了&#xff0c;怎么办&#xff1f; &#xff08; 欢迎 评论区 咨询 and 交流....&am…

淀山湖之行随笔

我们仰望清新&#xff0c;但又不得不被世俗所伴。 近日上海开始进入梅雨季节&#xff0c;每天大大小小的雨水不断&#xff0c;整个环境也格外的潮湿&#xff0c;不过已经逐渐习惯这种气候&#xff0c;所谓的见怪不怪。 今日是周日&#xff0c;思绪好久&#xff0c;准备去淀山湖…

前端优化:首屏加载速度的实践

目录 目录 前言 多图片的懒加载 避免用户多次点击请求 骨架屏原理 结束语 前言 随着互联网技术的飞速发展&#xff0c;前端网页逐渐取代了传统客户端成为用户获取信息、进行交互的重要渠道&#xff0c;但是网页也有常见的弊端&#xff0c;比如网页首屏加载速度的快慢直接…

vant 图片放大预览(vue3)

最近在写移动端的时候要实现图片放大预览的功能&#xff0c;当时用的是vant&#xff0c;原本想的是直接用vant里面的组件来实现放大预览&#xff0c;后面仔细找了一下发现没有找到这个功能&#xff08;可能是我没找到&#xff09;&#xff0c;后面想到了用遮罩层来实现放大预览…

捕获野生的登录页,暴改Vue3

1.实现效果 2.Vue组件 <script setup> import {onMounted} from "vue";onMounted(()>{// getAllData() }) </script><template><div class"login"><div class"form-cont"><div class"form-top"&…

全面解析自然语言处理(NLP):基础、挑战及应用前景

自然语言处理 (NLP) 简介与应用前景 自然语言处理&#xff08;NLP&#xff09;是人工智能和计算语言学的一个分支&#xff0c;致力于使计算机能够理解、解释和生成人类语言。这篇博文将深入探讨自然语言处理的基础知识、挑战、典型任务及其广泛的应用前景。 一、自然语言处理的…

Linux服务器上安装CUDA11.2和对应的cuDNN 8.4.0

一、检查 检查本机是否有CUDA工具包&#xff0c;输入nvcc -V: 如图所示&#xff0c;服务器上有CUDA&#xff0c;但版本为9.1.85&#xff0c;版本过低&#xff0c;因此博主要重装一个新的。 二、安装CUDA 1.查看服务器最高支持的CUDA版本 在命令行输入nvidia-smi查看显卡驱动…

秋招季的策略与行动指南:提前布局,高效备战,精准出击

6月即将进入尾声&#xff0c;一年一度的秋季招聘季正在热火进行中。对于即将毕业的学生和寻求职业发展的职场人士来说&#xff0c;秋招是一个不容错过的黄金时期。 秋招的序幕通常在6月至9月间拉开&#xff0c;名企们纷纷开启网申的大门。在此期间&#xff0c;求职备战是一个系…

【ai】 梳理一下yolov4及 trition部署的心路历程

yolov4是darknetv5开始逐渐采用pytorchjetson上部署darknet比较直接因此这里采用的是yolov4 版本。isarsoft/yolov4-triton-tensorrt1. 2024-06-20 : 2.17.0 在jetson4.6 上可以跑 2.17版本server 在 jetson 运行 ./tritonserver --model-repository=…/docs/examples/model_r…

2.linux操作系统CPU使用率和平均负载区别

目录 概述cpu使用率区别 结束 概述 linux操作系统CPU 使用率 和 平均负载 区别 负载高并不一定使用率高&#xff0c;有可能 cpu 被占用&#xff0c;但不干活。 cpu使用率 cpu使用率&#xff1a;cpu非空闲态运行的时间占比&#xff0c;反映cpu的繁忙程度&#xff0c;和平均负载…

如何使用VScode创建和上传Arduino项目

Visual Studio Code &#xff08;VS Code&#xff09; 是一种非常流行的通用集成开发环境 &#xff08;IDE&#xff09;。IDE 是一种将文本编辑器、编程界面、调试视图和项目管理集成在一个地方的软件。这个开源项目由微软领导&#xff0c;可以在所有操作系统上运行。使 VS Cod…

介绍两个压测工具pgbench\sysbench,可视化监控工具NMON

性能评估做不好&#xff0c;开会又领导点名叼了。/(ㄒoㄒ)/~~ /(ㄒoㄒ)/~~ /(ㄒoㄒ)/~~ 挨叼了&#xff0c;也要写文章&#xff0c;记录下我的笔记。 写篇文章 对数据库、OS性能的性能评估&#xff0c;需要选择合适的压测工具&#xff0c;给找出数据库的运行瓶颈 pgbench 这是…

AI音乐的何去何从

引言 在过去的一个月里&#xff0c;多个先进的音乐生成大模型相继上线。这些AI模型不仅降低了普通人创作音乐的门槛&#xff0c;还在音乐圈内引发了关于AI是否会彻底颠覆传统音乐创作的广泛讨论。在短暂的兴奋过后&#xff0c;人们开始理性地审视这些AI产品的版权归属问题&…

【图像超分辨率】一个简单的总结

文章目录 图像超分辨率(Image Super-Resolution, ISR)1 什么是图像超分辨率&#xff1f;2 图像超分辨率通常有哪些方法&#xff1f;&#xff08;1&#xff09;基于插值的方法&#xff08;2&#xff09;基于重建的方法&#xff08;3&#xff09;基于学习的方法&#xff08;LR im…

Leetcode 78 数组子集

题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的 子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1…

动手学深度学习(Pytorch版)代码实践 -计算机视觉-46语义分割和数据集

46语义分割和数据集 # 图像分割和实例分割 """ 图像分割将图像划分为若干组成区域&#xff0c;这类问题的方法通常利用图像中像素之间的相关性。 它在训练时不需要有关图像像素的标签信息&#xff0c;在预测时也无法保证分割出的区域具有我们希望得到的语义。 图…