spring中AbstractApplicationContext的refresh()

news2024/11/18 16:54:16

这个部分的源码看的次数不计其数了,每次看不同开源组件的调用过程中走到这里都有不同的收获。

spring 中 AbstractApplicationContext 的 refresh() 是 spring 的核心,几乎所有的逻辑都在是这里间接被调用。

如下源码为 spring boot 2.7.15 自带的 spring 5.3.29

SpringApplication

通过 WebApplicationType 判断是哪个环境

public enum WebApplicationType {

	/**
	 * The application should not run as a web application and should not start an
	 * embedded web server.
	 */
	NONE,

	/**
	 * The application should run as a servlet-based web application and should start an
	 * embedded servlet web server.
	 */
	SERVLET,

	/**
	 * The application should run as a reactive web application and should start an
	 * embedded reactive web server.
	 */
	REACTIVE;

	private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };

	private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";

	private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";

	private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";

	static WebApplicationType deduceFromClasspath() {
		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
				&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
			return WebApplicationType.REACTIVE;
		}
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return WebApplicationType.NONE;
			}
		}
		return WebApplicationType.SERVLET;
	}

}

判断逻辑如下

使用响应式的条件是类路径中包含 org.springframework.web.reactive.DispatcherHandler
且不包含 org.springframework.web.servlet.DispatcherServlet 还有org.glassfish.jersey.servlet.ServletContainer

如果类路径不包含 javax.servlet.Servlet,说明不是web程序。

上述情况都不符合,就是 servlet 环境,即 tomcat、undertow、jetty等。

添加了依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

所以,按照 servlet 环境来执行。

public ConfigurableApplicationContext run(String... args) {
		long startTime = System.nanoTime();
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
			}
			listeners.started(context, timeTakenToStartup);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
			listeners.ready(context, timeTakenToReady);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

createApplicationContext() 创建上下文

在 spring boot 的 spring.factories 中指定了

# Application Context Factories
org.springframework.boot.ApplicationContextFactory=\
org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext.Factory,\
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext.Factory

加上当前web 应用类型是 servlet,所以默认创建的是 AnnotationConfigServletWebServerApplicationContext。

最终在 GenericApplicationContext 中创建了 DefaultListableBeanFactory,这个类很重要,其中维护了定义的 bean,方便后面进行注入。

BeanFactory 的最终实现是 DefaultListableBeanFactory

refresh()

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

       // 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);

          StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
          // Invoke factory processors registered as beans in the context.
          invokeBeanFactoryPostProcessors(beanFactory);

          // Register bean processors that intercept bean creation.
          registerBeanPostProcessors(beanFactory);
          beanPostProcess.end();

          // 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) {
          if (logger.isWarnEnabled()) {
             logger.warn("Exception encountered during context initialization - " +
                   "cancelling refresh attempt: " + ex);
          }

          // Destroy already created singletons to avoid dangling resources.
          destroyBeans();

          // Reset 'active' flag.
          cancelRefresh(ex);

          // Propagate exception to caller.
          throw ex;
       }

       finally {
          // Reset common introspection caches in Spring's core, since we
          // might not ever need metadata for singleton beans anymore...
          resetCommonCaches();
          contextRefresh.end();
       }
    }
}

容器初始化开始

prepareRefresh()

/**
	 * Prepare this context for refreshing, setting its startup date and
	 * active flag as well as performing any initialization of property sources.
	 */
	protected void prepareRefresh() {
		// Switch to active.
		this.startupDate = System.currentTimeMillis();
		this.closed.set(false);
		this.active.set(true);

		if (logger.isDebugEnabled()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Refreshing " + this);
			}
			else {
				logger.debug("Refreshing " + getDisplayName());
			}
		}

		// Initialize any placeholder property sources in the context environment.
		initPropertySources();

		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

看源码注释,是进行准备工作,有初始化占位符中的变量到上下文环境中,验证必须的属性。

obtainFreshBeanFactory()

/**
	 * Tell the subclass to refresh the internal bean factory.
	 * @return the fresh BeanFactory instance
	 * @see #refreshBeanFactory()
	 * @see #getBeanFactory()
	 */
	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		return getBeanFactory();
	}

由于上面已经进行了 beanFactory  的创建处理,可以直接可以获取到对应的对象。

prepareBeanFactory()

/**
	 * Configure the factory's standard context characteristics,
	 * such as the context's ClassLoader and post-processors.
	 * @param beanFactory the BeanFactory to configure
	 */
	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		if (!shouldIgnoreSpel) {
			beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		}
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		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.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.
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		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.
		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());
		}
	}

对 beanFactory 进行一系列设置。

postProcessBeanFactory()

/**
	 * Modify the application context's internal bean factory after its standard
	 * initialization. The initial definition resources will have been loaded but no
	 * post-processors will have run and no derived bean definitions will have been
	 * registered, and most importantly, no beans will have been instantiated yet.
	 * <p>This template method allows for registering special BeanPostProcessors
	 * etc in certain AbstractApplicationContext subclasses.
	 * @param beanFactory the bean factory used by the application context
	 */
	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	}

看文档注释,用于 beanFactory 标准初始化后的应用上下文内部修改操作。

用法参考

https://blog.csdn.net/qq_35971258/article/details/128222426

至此,BeanDefinition 处理完成。接下来是 bean 的获取,即依赖注入。

依赖注入

invokeBeanFactoryPostProcessors()

/**
	 * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
	 * respecting explicit order if given.
	 * <p>Must be called before singleton instantiation.
	 */

看注释含义是实例化并且调用所有注册的 BeanFactoryPostProcessor 相关 bean。

具体作用还未深入过

https://www.cnblogs.com/sishang/p/6588542.html

registerBeanPostProcessors()

给 beanFactory 添加 BeanPostProcessor,用于前置后置处理。

通过 postProcessBeforeInitialization() 和 postProcessAfterInitialization() 实现。

其他操作

initMessageSource()

还未深入过

initApplicationEventMulticaster()
 

跟事件相关的,还未深入过

onRefresh()

看英文意思,初始化其他指定 bean 在特殊上下文

使用的地方有 servlet 容器初始化,例如 tomcat 启动前的准备工作在这里执行。

在 ServletWebServerApplicationContext 中进行重写,注册相关的单例到 beanFactory 中。方便后面接下来的 servlet 容器启动操作。

Lifecycle 用于启动或停止操作的通用接口,这里使用的实现类 WebServerStartStopLifecycle。通过实现类间接调用 WebServer 接口的实现类实现对应的 web 服务器的启动或停止操作。

servlet 容器的相关操作通过接口 WebServer 进行抽象,对应的实现有

registerListeners()

注册监听,观察者模式

finishBeanFactoryInitialization()

初始化落下的单例 bean。

finishRefresh()

servlet 容器的启动和停止操作

通过接口 LifecycleProcessor 的实现类 DefaultLifecycleProcessor 调用 WebServerStartStopLifecycle 执行相关操作。

其中,bean 获取在 AbstractBeanFactory 中实现,单例调用了 DefaultSingletonBeanRegistry 的 getSingleton() 单独处理,最终创建 bean 还是通过 AbstractAutowireCapableBeanFactory 的 createBean() 来实现。

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

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

相关文章

MySQL主从复制与读写分离(附配置实例)

目录 一、主从复制1.1 什么是主从复制&#xff1f;1.2 MySQL支持的复制类型1.3 主从复制的工作过程1.4 主从复制的同步模式1.4.1 异步复制&#xff08;Asynchronous replication&#xff09;1.4.2 全同步复制&#xff08;Fully synchronous replication&#xff09;1.4.3 半同步…

其他网页都可以打开,只有知网打不开

问题&#xff1a;电脑自动获取DNS出现问题。 1、打开Internet协议版本4&#xff08;TCP/IPv4&#xff09; 控制面板—所有控制面板项----网络连接----WLAN—属性----Internet协议版本4&#xff08;TCP/IPv4&#xff09;—属性 2、修改DNS 将自动获得DNS服务器地址&#xff…

Sparta工具用法描述之信息收集(漏洞分析)

声明:本文仅做学习与交流,任何用于非法用途、行为等造成他人损失的,责任自负。本文不承担任何法律责任。 Sparta是python GUI应用程序,它通过在扫描和枚举阶段协助渗透测试仪来简化网络基础结构渗透测试。 通过点击并单击工具箱并以方便的方式显示所有工具输出,它可以使测…

Swing通过后台线程实现页面更新

业务场景 在swing程序中&#xff0c;我们想实现一个随着任务的执行而同步更新组件的功能&#xff0c;如果在主线程&#xff08;EDT&#xff09;中直接执行任务并更新组件&#xff0c;则会导致组件只显示最终更新的状态的问题&#xff0c;这是因为EDT是单线程的&#xff0c;在执…

【golang】深入理解Go语言垃圾回收(GC)

垃圾回收 垃圾回收版本1.3之前标记-清除&#xff08;mark and sweep&#xff09;算法标记-清除&#xff08;mark and sweep&#xff09;的缺点 版本1.5的三色并发标记法没有STW的三色标记法屏障机制强-弱 三色不等式插入屏障删除屏障 版本1.8的混合写屏障&#xff08;hybrid wr…

MQ - 25 RabbitMQ集群架构设计与实现

文章目录 导图集群构建节点发现元数据存储数据可靠性镜像队列仲裁队列安全控制传输加密身份认证资源鉴权可观测性总结导图 集群构建 集群构建由节点发现和元数据存储两部分组成。RabbitMQ 也是一样的实现思路。 节点发现 在节点发现方面,RabbitMQ 通过插件化的方式支持了多…

经典题记录 字符串相加/相乘

1. LeetCode 415 字符串相加 代码一&#xff1a;代码简短&#xff0c;但需要借助额外的一个string来保存结果&#xff0c;更占用内存。 class Solution { public:string addStrings(string num1, string num2) {string ans"";int size1num1.size();int size2num2.si…

php之导入导出csv文件

一、导入csv文件 1、创建导入页面 <!DOCTYPE html> <html lang"zh-CN"> <meta charset"UTF-8"> <head><title>文件提交表单</title> </head> <body> <form action"test5.php" method"…

嵌入式裸机架构的探索与崩塌

为什么会想着探索下嵌入式裸机的架构呢&#xff1f;是因为最近写了一个项目&#xff0c;项目开发接近尾声时&#xff0c;发现了一些问题&#xff1a; 1、项目中&#xff0c;驱动层和应用层掺杂在一起&#xff0c;虽然大部分是应用层调用驱动层&#xff0c;但是也存在驱动层调用…

6年Android开发前10月的总结,写给正在求职的安卓开发

进入大厂工作对许多人来说已经是一种挑战&#xff0c;但只要充分准备&#xff0c;很多问题都可以逐步解决。当然&#xff0c;运气也起到了一定的作用&#xff0c;但最终还是与自身的努力密不可分。运气是实力的一部分&#xff0c;因为自助者天助。 每到10月进行总结时&#xff…

华为ICT——第二章-数字图像处理私人笔记

目录 1&#xff1a;计算机视觉&#xff1a;​编辑 2&#xff1a;计算机视觉应用&#xff1a;​编辑 3&#xff1a;计算机视界核心问题&#xff1a;​编辑 4&#xff1a;相关学科&#xff1a; 5&#xff1a;计算机视觉与人工智能&#xff1a; 最成熟的技术方向是图像识别 6…

Django应用及分布式路由

Django应用及分布式路由 应用 应用在Django项目中一个完全独立的业务模块&#xff0c;可以包含自己的路由&#xff0c;视图&#xff0c;模板&#xff0c;模型 应用配置 在这里面添加你自定义的应用 INSTALLED_APPS [django.contrib.admin,django.contrib.auth,django.cont…

如何使用docker快速部署MinDoc文档系统

MinDoc是非常优秀的知识分享系统&#xff0c;但是很多刚接触的人会一脸懵逼&#xff0c;而且官方文档写的也并不清晰&#xff0c;所以和大家分享一下快速部署MinDoc的方法。 首先docker环境先自行安装好&#xff0c;这里不再赘述。 拉取docker镜像&#xff1a; docker pull …

解决 Github port 443 : Timed out

解决方法 打开代理页面 打开 设置 --> 网络与Internet --> 查找代理 记录下当前系统代理的 IP 地址和端口号 如上图所示&#xff0c;地址与端口号为&#xff1a;127.0.0.1:7890 注意修改成自己的IP和端口号 git config --global http.proxy http://127.0.0.1:7890 gi…

面试总结之微服务篇

一、概览 1、微服务常用组件 微服务给系统开发带来了诸多问题和挑战&#xff0c;如服务间通信和调用的复杂性、数据一致性和事务管理、服务治理和版本管理等&#xff0c;为解决应对这些问题和挑战&#xff0c;各种微服务组件应运而生微服务的常见组件和实现&#xff1a; 1…

解决react报错“JSX 表达式必须具有一个父元素“

现象如下&#xff1a; 原因&#xff1a; 新插入的dom元素跟已有的dom元素平级了&#xff0c;必须创建一个共有的根元素 解决办法&#xff1a; 使用<> </>标签作为根元素&#xff0c;把所有子元素包裹起来 <> ....原代码 </> 问题解决&#xff01;…

sun.reflect.annotation.TypeNotPresentExceptionProxy

解决方法 找到TypeNotPresentExceptionProxy类,在sun.reflect.annotation下在TypeNotPresentExceptionProxy方法里打断点debug项目,查看断点错误 如图是缺少redis依赖导致的错误 https://www.cnblogs.com/qingmuchuanqi48/p/11716706.html

Spring学习笔记7 Bean的生命周期

Spring其实就是一个管理Bean对象的工厂.它负责对象的创建,对象的销毁. 这样我们才可以知道在哪个时间节点上调用了哪个类的哪个方法,知道代码该写在哪里 Bean的生命周期之粗略5步 Bean生命周期的管理可以参考Spring的源码: AbstractAutowireCapableBeanFactory Bean的生命周期…

乐得瑞推出1拖2功率分配快充线方案,支持数据传输

随着PD3.1协议的市场应用越来越多&#xff0c;一些充电器的Type-C接口的输出功率达到百瓦及以上&#xff0c;如何充分利用好这类充电器设备&#xff0c;乐得瑞电子推出1拖2快充线缆解决方案&#xff0c;支持智能功率分配策略。 上图是乐得瑞1拖2功率分配快充线样线实物&#…

力扣刷题-链表-设计链表

题意&#xff1a; 在链表类中实现这些功能&#xff1a; get(index)&#xff1a;获取链表中第 index 个节点的值。如果索引无效&#xff0c;则返回-1。 addAtHead(val)&#xff1a;在链表的第一个元素之前添加一个值为 val 的节点。插入后&#xff0c;新节点将成为链表的第一个节…