Web容器整合ApplicationContext源码

在web容器(WebApplicationContext)中获取spring中的bean Spring把Bean放在这个容器中,普通的类在需要的时候,直接用getBean()方法取出 立即下载

一、web.xml配置开始

在使用Tomcat等容器整合Spring的时候,需要在web.xml中添加如下的配置:

  <!-- spring的环境监听器 -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

配置中首先引入了一个监听器ContextLoaderListener,该监听器主要功能就是创建ApplicationContext并且将其与ServletContext相互绑定。其次,为了让ApplicationContext获取到我们的配置,还需要在context-param标签中设置我们的配置文件位置contextConfigLocation。

二、ContextLoaderListener监听器实现

ContextLoaderListener继承自ContextLoader和ServletContextListener接口。该父类完成创建、初始化ApplicationContext的功能,而ServletContextListener 接口使得在ServletContext初始化完成后,Spring有机会可以创建ApplicationContext并且将其绑定到ServletContext上。

下面是ContextLoaderListener的实现。

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

	public ContextLoaderListener() {
	}

	//使用给定的WebApplicationContext创建监听器实例
	public ContextLoaderListener(WebApplicationContext context) {
		super(context);
	}


	/**
	 * Initialize the root web application context.
	 */
	@Override
	public void contextInitialized(ServletContextEvent event) {
		initWebApplicationContext(event.getServletContext());
	}


	/**
	 * Close the root web application context.
	 */
	@Override
	public void contextDestroyed(ServletContextEvent event) {
		closeWebApplicationContext(event.getServletContext());
		ContextCleanupListener.cleanupAttributes(event.getServletContext());
	}

}

ServletContext初始化后会调用contextInitialized方法,而方法中就是创建、装配ApplicationContext的地方(Web环境下,ApplicationContext的类型是WebApplicationContext):

	public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		//WebApplicationContext已绑定到ServletContext
		if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			throw new IllegalStateException(...);
		}

		Log logger = LogFactory.getLog(ContextLoader.class);
		//日志打印,略
		long startTime = System.currentTimeMillis();

		try {
			//创建WebApplicationContext
			if (this.context == null) {
				this.context = createWebApplicationContext(servletContext);
			}
			if (this.context instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
				if (!cwac.isActive()) {
					//为当前上下文配置父ApplicationContext(不常用)
					//如果initContextParam中配置父ApplicationContext相关属性的话(locatorFactorySelector、parentContextKey)
					if (cwac.getParent() == null) {
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					//配置并刷新WebApplication
					configureAndRefreshWebApplicationContext(cwac, servletContext);
				}
			}
			//将refesh后的WebApplicationContext绑定到servletContext
			//WebApplicationContext在上一步中也会将servletContext设置自己的属性中,形成双向绑定
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

			ClassLoader ccl = Thread.currentThread().getContextClassLoader();
			if (ccl == ContextLoader.class.getClassLoader()) {
				currentContext = this.context;
			}
			else if (ccl != null) {
				currentContextPerThread.put(ccl, this.context);
			}
			//日志打印,略

			return this.context;
		}
		catch (RuntimeException ex) {
			logger.error("Context initialization failed", ex);
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
			throw ex;
		}
		catch (Error err) {
			logger.error("Context initialization failed", err);
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
			throw err;
		}
	}

代码流程:

  1. 创建WebApplicationContext实例
  2. 配置WebApplicationContext属性,并调用其refresh方法,刷新上下文(这一步中也会将ServletContext设置到WebApplicationContext属性中)
  3. 将初始化好的WebApplicationContext绑定到ServletContext中

1、创建WebApplicationContext

创建的代码在createWebApplicationContext实现:

	protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
		//确定WebApplicationContext的class使用哪个
		Class<?> contextClass = determineContextClass(sc);
		//确保使用的class继承自ConfigurableWebApplicationContext
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException("...");
		}
		//通过放射实例化
		return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

代码流程分为两步:

  1. 确定所使用的ApplicationContext的类
  2. 通过反射,实例化ApplicationContext

确定类型:

	protected Class<?> determineContextClass(ServletContext servletContext) {
		//获取web.xml中contextInitParam的contextClass属性
		String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
		//如果用户配置了contextClass属性,就加载对应class并返回结果
		if (contextClassName != null) {
			try {
				return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException("Failed to load custom context class [" + contextClassName + "]", ex);
			}
		}
		else {
			//使用默认的WebApplicationContext的class
			contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
			try {
				return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException("Failed to load default context class [" + contextClassName + "]", ex);
			}
		}
	}

defaultStrategies定义声明如下:

	private static final Properties defaultStrategies;

	static {
		try {
			//加载与ContextLoader.class在同一目录下的ContextLoader.properties文件
			ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
		}
	}

Spring回家再与ContextLoader.class在同一目录下的ContextLoader.properties文件,文件声明如下:

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

因此,WebApplicationContext的默认实现类是XmlWebApplicationContext

实例化

	public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {
		Assert.notNull(clazz, "Class must not be null");
		//如果是接口,抛出异常
		if (clazz.isInterface()) {
			throw new BeanInstantiationException(clazz, "Specified class is an interface");
		}
		try {
			//获取默认的无参构造器,通过反射实例化
			return instantiateClass(clazz.getDeclaredConstructor());
		}
		catch (NoSuchMethodException ex) {
			throw new BeanInstantiationException(clazz, "No default constructor found", ex);
		}
	}

下面是反射创建对象的代码:

	public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
		Assert.notNull(ctor, "Constructor must not be null");
		try {
			ReflectionUtils.makeAccessible(ctor);
			return ctor.newInstance(args);
		}
		catch ...
	}

2、配置并刷新

	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
		//为ApplicationContext设置一个runId
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			//提取配置文件中contextId属性
			String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
			if (idParam != null) {
				wac.setId(idParam);
			}
			else {
				//未配置,使用默认的.
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(sc.getContextPath()));
			}
		}
		//将ServletContext实例设置到WebApplicationContext中
		wac.setServletContext(sc);
		//获取web.xml中配置的contextConfigLocation属性
		String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			//设置到WebApplication中
			wac.setConfigLocation(configLocationParam);
		}

		// 将ServletContext封装后设置到WebApplicationContext中,方便获取initParam
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
		}
		//获取配置的ApplicationContextInitializer并对ApplicationContext进行初始化
		customizeContext(sc, wac);
		//刷新上下文
		wac.refresh();
	}

代码流程:

  1. 设置runId
  2. 将ServletContext绑定到WebApplicationContext中
  3. 设置contextConfigLocation属性
  4. 将ServletContext封装后设置到WebApplicationContext中,方便获取initParam
  5. 获取配置的ApplicationContextInitializer,并对ApplicationContext设置初始化属性(通过globalInitializerClasses、contextInitializerClasses属性配置)
  6. 刷新上下文

再刷新上下文后,ApplicationContext就已经创建好了,可以在Web环境中使用

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相关推荐

基于PCIe的NVMe协议在FPGA中实现方法

NVMe协议是工作在PCIE的最上层协议层的,故需要先搞清楚PCIE。本文基于Xilinx的UltraScale+,开发工具为Vivado2021.2。NVMe的学习仍以spec为主,其它资料辅助理解,有冲突时以spec为准,必要时可对比最新版本spec。(此文重点介绍学习方法及资料,有时间再加细节)。 主要参考的文章是《老男孩读PCIe》,同时参考《古猫先生》,重点学习TLP报文部分,数据链路层和物理层的内容可以先不看。再买一本书《PCI Express 体系结构导读-王齐》用来查阅做笔记。

leixj的博客 1万+

获取spring容器上下文(webApplicationContext)的几种方法

首先很感谢大佬的指导,在web SERver容器里面的server,filter都不是spring容器去管理的我们也不可能在spring的配置里面去获取到这个东西的,比如: public class InitComponent implements ServletContextListener,ApplicationContextAware{ private static App...

JGnewbie的博客 1万+

C++开发基础之掌握常用的三种异步编程模型

以上是三种常见的C++异步编程模型,每种模型都有其适用的场景和特点。根据具体需求,你可以选择合适的模型来进行异步编程。

dotnet研习社 2175

获取webapplicationContext以及servletContext的几种方式

webapplicationContext是spring的核心context,所有的bean在初始化后都会在里面,当项目被加载,applicationContext.xml已经被加载了一次,如果此时用new ClassPathXmlApplicationContext.getBean("applicationContext.xml")的方式获取bean对象,applicationContext就相

永无止境的小白 7154

IC面试常考题 Verilog三分频电路设计(占空比50%,三分之一,三分之二)

实现三分频电路最简单的是: 利用计数器实现。 时序图分析(本人比较懒,平常科研忙,所以直接手画时序图了,懒得用软件画了): 直接上图分析:利用计数器每隔三个周期信号翻转一次,同时在不同的计数下翻转得到的同步信号 clk_1和clk_2,再利用异或即可实现出一个不同占空比的三分频信号(同样的方法也可扩展到其他奇数分频设计中)。 例如占空比50%: module Div_three( input clk, input rst_n, output div_three ); reg

qq_41884662的博客 1万+

SAP SLT REODPS_REPL API 的使用介绍

本文聚焦 SAP 数据复制生态中的 RODPS_REPL(常被误写为 REODPS_REPL),解析其作为 ODP(Operational Data Provisioning)标准接口的核心功能与应用场景。RODPS_REPL 是 SAP 提供的 ABAP 接口集合,支持从 ODP 上下文(如 ODP_SAPI、ODP_CDS)执行初始化装载和增量捕获,被 SAP BW、Datasphere 及第三方工具(如 Azure Data Factory、Qlik Replicate)广泛调用。 关键要点: 核心对

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 227

WebApplicationContext介绍

WebApplicationContext是专门为web应用准备的,他允许从相对于web根目录的路劲中装载配置文件完成初始化工作,从WebApplicationContext中可以获得ServletContext的引用,整个Web应用上下文对象将作为属性放置在ServletContext中,以便web应用可以访问spring上下文,spring中提供WebApplicationContex...

weixin_30437337的博客 788

节省人力成本40%!仓储物流AI机器人调度系统实战案例(含路径规划算法与系统架构图)

首先,我们需要定义一个Node类self.x = x # 节点x坐标self.y = y # 节点y坐标self.g = g # 从起点到当前节点的实际成本(g值)self.h = h # 从当前节点到终点的启发式成本(h值)self.f = g + h # 总成本(f值)self.parent = None # 父节点(用于回溯路径)self.task_id = task_id # 任务IDself.priority = priority # 任务优先级(1=最高,5=最低)

小程序开发 949

Java架构直通车——SpringApplication的初始化过程

文章目录SpringBoot启动流程分析推断web应用类型初始化应用上下文初始化监听器类推演主程序类小结 我们都知道SpringBoot自问世以来,一直有一个响亮的口号"约定优于配置",其实一种按约定编程的软件设计范式,目的在于减少软件开发人员在工作中的各种繁琐的配置,我们都知道传统的SSM框架的组合,会伴随着大量的繁琐的配置;稍有不慎,就可能各种bug,被人发现还以为我们技术很菜。而Sprin...

No_Game_No_Life_的博客 1032

AMDGPU SVM VRAM Migration 实现详解

AMD正在基于DRM SVM框架重构SVM实现,该框架即将广泛应用。本文分析了AMD开发者提交的POC验证版本的技术方案。该架构分为三层:AMDGPU SVM映射层、DRM Pagemap通用框架层和AMDGPU迁移后端硬件驱动层。系统涉及三个地址空间转换:VRAM分配器空间、HPA/PFN空间和GPU PTE地址空间。关键数据结构包括设备级迁移基础设施amdgpu_pagemap、迁移临时BO包装器amdgpu_svm_bo等。该方案通过地址空间转换实现VRAM迁移功能,目前仍处于POC阶段,设计可能变更

图形/计算GPU的驱动与虚拟化技术分享园地 863

手把手教你双目测距理论及生成视差图,深度图,点云图像

Stereo Vision, 也叫双目立体视觉,它的研究可以帮助我们更好的理解人类的双眼是如何进行深度感知的。双目视觉在许多领域得到了应用,例如城市三维重建、3D模型构建(如kinect fusion)、视角合成、3D跟踪、机器人导航(自动驾驶)、人类运动捕捉(Microsoft Kinect)等等。双目测距也属于双目立体视觉的一个应用领域,双目测距的基本原理主要是三角测量原理,即通过视差来判定物体的远近。

qq_53545309的博客 2280

应用程序获取 WebApplicationContext的多种方式

1.WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext(); 当前应用的WebApplicationContext就保存在 ContextLoader的currentContextPerThread属性当中 2.基于ServletContext上下文获取的方式 Servle

Aeroleo的博客 2228

基于MATLAB的导弹轨迹和撞击位置仿真

本文将介绍如何使用MATLAB进行导弹轨迹和撞击位置的仿真,提高导弹的精确打击能力。首先,我们需要确定导弹的初始位置和速度,以及导弹所受到的外部环境因素如重力、空气阻力等。在MATLAB中,可以通过ODE求解器来模拟导弹的运动轨迹。最后,我们通过控制器输出的控制信号来控制导弹的姿态。通过对导弹的运动轨迹和姿态进行仿真,可以更好地预测和规划导弹的运动轨迹,提高其精确打击能力。在实际作战中,为了提高导弹精确打击能力,需要对导弹的撞击位置进行预测和规划。我们可以通过控制导弹的姿态来实现撞击目标的精确命中。

CyberLynxO的博客 1982

Spring源码解析——前期环境准备

Spring源码解析前期准备工作,持续关注可关注码呆呆,所有内容基于《Spring源码》一书,相关技术博客持续更新中!!!!

D111111dwa的博客 1239

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Spring Boot(6) 原理和启动流程

SpringBoot是一个快速开发框架,快速的将一些常用的第三方依赖整合(原理:通过Maven子父工程的方式),简化XML配置,全部采用注解形式,内置Http服务器(Jetty和Tomcat),最终以java应用程序进行执行,它是为了简化Spring应用的创建、运行、调试、部署等而出现的,使用它可以做到专注于Spring应用的开发,而无需过多关注XML的配置。 一、核心原理 1.Spring...

黄规速博客:学如逆水行舟,不进则退 1268

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

【Spring】Spring&WEB整合原理及源码分析

表现层和业务层整合: 1. Jsp/Servlet整合Spring; 2. Spring MVC整合SPring; 3. Struts2整合Spring; 本文主要介绍Jsp/Servlet整合Spring原理及源码分析。

厚积薄发者,轻舟万重山 5403

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Jsp/Servlet整合Spring原理及源码分析

表现层和业务层整合: 1. Jsp/Servlet整合spring; 2. Spring MVC整合SPring; 3. Struts2整合Spring; 本文主要介绍Jsp/Servlet整合Spring原理及源码分析。 一、整合过程     Spring&WEB整合,主要介绍的是Jsp/Servlet容器和Spring整合的过程,当然,这个过程是

ljl18566743868的博客 1332

spring关于web容器获取ApplicationContext引用和Properties配置属性值

  前言:考虑到Spring的强大是尽人皆知的,所以能用就不必造轮子了,只需要改造即可。   1、web中如何控制ApplicationContext   在spring框架整合下,自己写的代码中要使用ApplicationContext是不方便的,但是在org.springframework.web.context.support.WebApplicationContextUtil...

zl378837964的专栏 2737

Spring&WEB整合原理及源码分析

表现层和业务层整合: 1. Jsp/Servlet整合spring; 2. Spring MVC整合SPring; 3. Struts2整合Spring; 本文主要介绍Jsp/Servlet整合Spring原理及源码分析。 一、整合过程     Spring&WEB整合,主要介绍的是Jsp/Servlet容器和Spring整合的过程,当然,这个过程是

雷新伟的博客 417

【死磕Spring】| Spring IoC容器:BeanFactory和ApplicationContext谁才是Spring IoC容器?

Spring IoC容器:BeanFactory和ApplicationContext谁才是Spring IoC容器? 对于我们初学者来说,我们是不是在写Demo的时候经常这样写: BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/META-INF/context-dependency-injection.xml"); 其实,BeanFactory 和 ApplicationContext 同为

MarkusZhang的博客 587

深度解析Spring IoC容器初始化:ApplicationContext的refresh()流程拆解

在Java企业级开发领域,Spring框架始终保持着不可撼动的统治地位。截至2025年,Spring Framework 6.x系列已成为主流版本,其核心设计理念"控制反转"(Inversion of Control,IoC)依然是理解整个框架架构的关键切入点。

zuiyuelong的博客 992

Spring源码解析(三):bean容器刷新

上一讲Spring源码解析(二):bean容器的创建、默认后置处理器、扫描包路径bean主要是刷新上下文的准备工作进入refresh();方法,此方法定义在注解上下文父类AbstractApplicationContext注解配置上下文只是它的子类之一,还有xml上下和web上下文等// 1、刷新前预处理 prepareRefresh();

从基础到源码解析的学习记录 1554

Spring 原理:BeanFactory 与 ApplicationContext

本文深入解析Spring框架两大核心接口BeanFactory与ApplicationContext的差异。BeanFactory作为基础IoC容器,提供懒加载、依赖注入等基础功能;而ApplicationContext作为高级容器,在继承BeanFactory基础上增加预实例化、国际化、事件机制等企业级特性。文章从功能对比、源码分析、生命周期等多个维度进行阐述,并指出ApplicationContext = BeanFactory + 增强功能,是生产环境的首选方案。通过容器层级、使用示例和面试问题总结,

ZHE|张恒的博客 1752

【Spring】Spring&WEB整合原理及源码剖析

一、ApplicationContext         Spring框架可以应用于web环境和非web环境。通常情况下,非web环境下ApplicationContext接口常用的是其实现子类ClassPathXmlApplicationContext(另一个是FileSystemXmlApplicationContext);Spring应用于web环境下,需要额外的导入web相关的jar包,

厚积薄发者,轻舟万重山 1883

Spring源码之容器(一)

spring源码分析一

weixin_45734473的博客 390

深入源码了解spring之IOC容器

前言 Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架。而 Spring 框架的系统架构简要说明如下:         Spring 总共大约有20个模块,由1300多个不同的文件构成。而这些组件被分别整合在核心容器(Core Conta

believedark的博客 399
上一篇: Spring源码:bean创建(六)初始化
下一篇: ApplicationContext拓展功能
finalcola
博客等级 码龄9年 37粉丝 21原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值